My render method:
public void render(float delta) {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
int w = GateRunner.WIDTH;
int h = GateRunner.HEIGHT;
cam.update();
cam.setToOrtho(false, w, h);
Gdx.input.setInputProcessor(this);
game.batch.begin();
game.batch.draw(title_background, 0, 0, GateRunner.WIDTH, GateRunner.HEIGHT);
game.batch.draw(title, (w / 2) - (w / 2), h / 2 + h * 12 / 90, w, (int) (w * 0.5));
playButtonSprite.setPosition((w / 2) - (w / 2), h / 2 + h / 20);
playButtonSprite.setSize(w, (int) (w * (144.0 / 1080)));
playButtonSprite.draw(game.batch);
game.batch.draw(instructions_button, (w/2) - (w/2), h/2 + h/20 - h*3/40, w, (int) (w * (144.0 / 1080)));
game.batch.draw(about_button, (w / 2) - (w / 2), h / 2 + h/20 - 2*h*3/40, w, (int)(w*(144.0/1080)));
game.batch.end();
}
My touchDown method.
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
float pointerX = InputTransform.getCursorToModelX(windowWidth, screenX);
float pointerY = InputTransform.getCursorToModelY(windowHeight, screenY);
if(playButtonSprite.getBoundingRectangle().contains(pointerX, pointerY)) //Play button
{
game.setScreen(new PlayScreen(game));
dispose();
}
return true;
}
I wanted to make it so when I clicked the Play "button", which is just a Sprite, it would move to PlayScreen. I did this by checking if the rectangle where the Play sprite was clicked. However, even though this part works, whenever I click in that rectangle area in PlayScreen, it runs the code again - it starts the PlayScreen over. How can I fix this?
Edit: also, there might be a better name for this question, so feel free to suggest.
This is happenning because when you change screen, you still have the same input processor in place which is checking whether that rectangle of the screen is tapped. Whether the button is visible or not is irrelevant.
You can do one of these to fix it...
Make each screen have its own input processor specific to its needs - this is the preferred option
Have a single input processor that checks what the current screen is before handling actions
Alternatively, look into frameworks like scene2d.ui to handle this sort of stuff for you.
Related
I want to print numbers from 0 to 100 clockwise on canvas it will work when we have values from 0 to 12 but once i changed the values or increased the it is stopped working in my case can anyone help me here?
private int[] mClockHours = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12};
private void drawNumeral(Canvas canvas) {
mPaint.setTextSize(fontSize);
for (int number : mClockHours) {
String tmp = String.valueOf(number);
mPaint.getTextBounds(tmp, 0, tmp.length(), mRect);
double angle = Math.PI / 6 * (number - 2);
Log.d("drawNumeral", "number: "+number);
Log.d("drawNumeral", "Math.PI: "+Math.PI);
Log.d("drawNumeral", "angle: "+angle);
Log.d("drawNumeral", "temp: "+tmp);
int x = (int) (width / 2 + Math.cos(angle) * mRadius - mRect.width() / 2);
int y = (int) (height / 2 + Math.sin(angle) * mRadius - mRect.height() / 2);
canvas.drawText(tmp, x, y, mPaint);
}
}
You need to invalidate() the view to see changes you made. Here is a good tutorial to understand how to draw on canvas.
Good day.I am creating a siri like wave for android and i encounter an big issue.I need the wave to be in 4 colors.Lets assume i only have one single line which is drawing on the screen accordingly to the voice decibels.Anyway i am able to do it but no way i am able to give 4 different colors for same path.Assume it is 1 single path which moves from screen start to screen end,i need that line to have 4 different colors,mainly i had to divide the path into 4 parts and draw the color for each parts,but neither google,nor any other source give me anything (not even found anything similar to what i want).
Meanwhile i am posting the code where actually i am drawing the lines.
for (int l = 0; l < mWaveCount; ++l) {
float midH = height / 2.0f;
float midW = width / 2.0f;
float maxAmplitude = midH / 2f - 4.0f;
float progress = 1.0f - l * 1.0f / mWaveCount;
float normalAmplitude = (1.5f * progress - 0.5f) * mAmplitude;
float multiplier = (float) Math.min(1.0, (progress / 3.0f * 2.0f) + (1.0f / 3.0f));
if (l != 0) {
mSecondaryPaint.setAlpha((int) (multiplier * 255));
}
mPath.reset();
for (int x = 0; x < width + mDensity; x += mDensity) {
float scaling = 1f - (float) Math.pow(1 / midW * (x - midW), 2);
float y = scaling * maxAmplitude * normalAmplitude * (float) Math.sin(
180 * x * mFrequency / (width * Math.PI) + mPhase) + midH;
// canvas.drawPoint(x, y, l == 0 ? mPrimaryPaint : mSecondaryPaint);
//
// canvas.drawLine(x, y, x, 2*midH - y, mSecondaryPaint);
if (x == 0) {
mPath.moveTo(x, y);
} else {
mPath.lineTo(x, y);
// final float x2 = (x + mLastX) / 2;
// final float y2 = (y + mLastY) / 2;
// mPath.quadTo(x2, y2, x, y);
}
mLastX = x;
mLastY = y;
}
if (l == 0) {
canvas.drawPath(mPath, mPrimaryPaint);
} else {
canvas.drawPath(mPath, mSecondaryPaint);
}
}
I tried to change color on if (l == 0) {
canvas.drawPath(mPath, mPrimaryPaint);
} but if i change it here,no result at all,either the line is separate and not moving at all,but it should,either the color is not applied,propably because i am doing it in loop as i had to and everytime the last color is picked to draw.Anyway can you help me out?Even an small reference is gold for me because really there is nothing at all in the internet.
Anyway even though Matt Horst answer fully correct,i found the simplest and easiest solution...i never thought it would be so easy.Anyway if in world there is someone who need to make an path divided into multiple colors,here is what you can do
int[] rainbow = getRainbowColors();
Shader shader = new LinearGradient(0, 0, 0, width, rainbow,
null, Shader.TileMode.REPEAT);
Matrix matrix = new Matrix();
matrix.setRotate(90);
shader.setLocalMatrix(matrix);
mPrimaryPaint.setShader(shader);
Where getRainbowColors() is an array of colors you wish your line to have and width is the length of the path so the Shader knows how to draw the colors in right way to fit the length of path.Anyway .....easy isnt it?and pretty purged me a lot to get into this simple point.Nowhere in internet you could find only if you are looking for something completelly different,than you might come across this.
It seems to me like you could set up one paint for each section, each with a different color. Then set up one path for each section too. Then as you draw across the screen, wherever the changeover point is between sections, start drawing with the new path. And make sure first to use moveTo() on the new path so it starts off where the old one left off.
For my solution, I tried changing the color of the linePaint in the onDraw Call. But it was drawing a single color.
So i used two different paints for two different colors and draw path on the canvas.
And it worked. Hope it helps someone out there.
I'm working on an app where we hand rolled some star maps. So I don't have to talk in the abstract, here is the app in question: https://play.google.com/store/apps/details?id=com.tw.fireballs
If you look on the store listing, you can see we use an image just above the horizon...mostly because it looks super pretty. It's not an issue on lower resolution devices, they don't seem to suffer a huge issue rendering it due to lower number of pixels involved. On a higher resolution device like my HTC One or my wifes Nexus 5, there is a big framerate drop when it's on the screen. It's not bad enough to prevent me releasing it, but I'd like to improve it if possible.
I'm currently just using a SurfaceView, and drawing to a canvas acquired by mSurfaceHolder.lockCanvas(null), so it's not hardware accelerated. I tried implementing it as a regular view which is, but overall it actually went slower, so before I take the plunge into OpenGL land I want to explore if there is something I can do to speed this up.
Essentially, we start with a thin (opaque) image "slice" through the horizon, scale it up to the size of the diagonal of the screen and rotate it around to match the orientation of the device.
The drawing code is as follows:
private void loadResources() {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
mHorizonImage = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.star_map_background, options);
}
#Override
public void updateDimensions(int width, int height) {
super.updateDimensions(width, height);
int horizonHeight = mCanvasHeight / 3;
int horizonWidth = (int) Math.sqrt(Math.pow(mCanvasHeight, 2) + Math.pow(mCanvasWidth, 2));
mHorizonImage = Bitmap.createScaledBitmap(mHorizonImage, horizonWidth, horizonHeight, false);
}
#Override
public void drawOn(Canvas canvas) {
double upScreen = -mProjection.distanceFromScreen * Math.tan(Math.toRadians(mOrientation.elevation));
double rightWithTiltCheat = upScreen * Math.sin(Math.toRadians(mOrientation.tilt));
double upWithTiltCheat = upScreen * Math.cos(Math.toRadians(mOrientation.tilt));
float x = (float) (mCanvasWidth / 2 * (1 + rightWithTiltCheat / mProjection.screenWidthInCm));
float y = (float) (mCanvasHeight / 2 * (1 - upWithTiltCheat / mProjection.screenHeightInCm));
canvas.save();
canvas.translate(x, y);
canvas.rotate((float) mOrientation.tilt);
canvas.drawBitmap(mHorizonImage, -mHorizonImage.getWidth() / 2, -mHorizonImage.getHeight(), null);
canvas.restore();
}
Is there a more efficient way to do this that won't be so affected by screen resolution? We've bandied around a few ideas, but I'd be keen to hear from someone who knows this stuff better than I. If you have any questions, please ask, I'd be grateful for any assistance.
Cheers,
Nathan
#pskink hit the nail on the head. Drawing the bitmap with a Matrix param is much more performant than the scaled bitmap and canvas rotation I was experiencing. On 1080P devices like my HTC One I used to watch the frame rate drop from 50+ to ~10 if I held the phone on a diagonal. Now I'd be lucky if it drops 5.
The modified code now looks like:
#Override
public void updateDimensions(int width, int height) {
super.updateDimensions(width, height);
mHorizonHeight = mCanvasHeight / 3;
mHeightScale = (float)mHorizonHeight / (float)mHorizonImage.getHeight();
mHorizonWidth = (int) Math.sqrt(Math.pow(mCanvasHeight, 2) + Math.pow(mCanvasWidth, 2));
mWidthScale = (float)mHorizonWidth / (float)mHorizonImage.getWidth();
}
#Override
public void drawOn(Canvas canvas) {
double upScreen = -mProjection.distanceFromScreen * Math.tan(Math.toRadians(mOrientation.elevation));
double rightWithTiltCheat = upScreen * Math.sin(Math.toRadians(mOrientation.tilt));
double upWithTiltCheat = upScreen * Math.cos(Math.toRadians(mOrientation.tilt));
float x = (float) (mCanvasWidth / 2 * (1 + rightWithTiltCheat / mProjection.screenWidthInCm));
float y = (float) (mCanvasHeight / 2 * (1 - upWithTiltCheat / mProjection.screenHeightInCm));
mDrawMatrix.reset();
mDrawMatrix.postScale(mWidthScale, mHeightScale);
mDrawMatrix.postTranslate(x - mHorizonWidth / 2, y - mHorizonHeight);
mDrawMatrix.postRotate((float) mOrientation.tilt, x, y);
canvas.drawBitmap(mHorizonImage, mDrawMatrix, null);
canvas.save();
}
I'm facing a very strange issue with OpenCV for Android :
when I'm accessing pixel with Mat.at it gives me the wrong pixel on the screen :
A simple example :
for( double y = (mat.rows - h) / 2 ; y < (mat.rows + h) / 2 ; y++ ) {
for( double x = (mat.cols - w) / 2; x < (mat.cols + w) / 2; x++ ) {
for( int c = 0; c < 3; c++ ) {
mat.at<Vec3b>(y,x)[c] =
saturate_cast<uchar>( 255 );
}
}
}
circle(mat, Point((mat.cols - w) / 2, (mat.rows - h) / 2), 10, Scalar(255,0,0,255));
circle(mat, Point((mat.cols + w) / 2, (mat.rows - h) / 2), 10, Scalar(255,0,0,255));
circle(mat, Point((mat.cols - w) / 2, (mat.rows + h) / 2), 10, Scalar(255,0,0,255));
circle(mat, Point((mat.cols + w) / 2, (mat.rows + h) / 2), 10, Scalar(255,0,0,255));
I should have the corners aligned with the box but not.
Is there a conversion to make in order to access to the true coordinates ?
You don't post the initialization of mat, but it appears to be initialized as type CV_8UC4. This means that accessing the image using mat.at<cv::Vec3b> will give you incorrect pixel locations. Four-channel images must be accessed using at<cv::Vec4b> to give correct pixel locations, even if you are only modifying three of the channels, as in your example.
Unrelated: it's not advisable to use double as a counter variable type.
This is a long shot, but it might help you. Is this a SDK emulation? I remember having issues with thoes. When I tried my code in a device it worked like a charm.
I m woring on an android opengl 1.1 2d game with a top view on a vehicule and a camera zoom relative to the vehicule speed. When the speed increases the camera zoom out to offer the player a best road visibility.
I have litte trouble finding the exact way to detect if a sprite is visible or not regarding his position and the current camera zoom.
Important precision, all of my game's objects are on the same z coord. I use 3d just for camera effect. (that's why I do not need frustrum complicated calculations)
here is a sample of my GLSurfaceView.Renderer class
public static float fov_degrees = 45f;
public static float fov_radians = fov_degrees / 180 * (float) Math.PI;
public static float aspect; //1.15572 on my device
public static float camZ; //927 on my device
#Override
public void onSurfaceChanged(GL10 gl, int x, int y) {
aspect = (float) x / (float) y;
camZ = y / 2 / (float) Math.tan(fov_radians / 2);
Camera.MINIDECAL = y / 4; // minimum cam zoom out (192 on my device)
if (x == 0) { // Prevent A Divide By Zero By
x = 1; // Making Height Equal One
}
gl.glViewport(0, 0, x, y); // Reset The Current Viewport
gl.glMatrixMode(GL10.GL_PROJECTION); // Select The Projection Matrix
gl.glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
GLU.gluPerspective(gl, fov_degrees, aspect , camZ / 10, camZ * 10);
GLU.gluLookAt(gl, 0, 0, camZ, 0, 0, 0, 0, 1, 0); // move camera back
gl.glMatrixMode(GL10.GL_MODELVIEW); // Select The Modelview Matrix
gl.glLoadIdentity(); // Reset The Modelview Matrix
when I draw any camera relative object I use this translation method :
gl.glTranslatef(position.x - camera.centerPosition.x , position.y -camera.centerPosition.y , - camera.zDecal);
Eveything is displayed fine, the problem comes from my physic thread when he checks if an object is visible or not:
public static boolean isElementVisible(Element element) {
xDelta = (float) ((camera.zDecal + GameRenderer.camZ) * GameRenderer.aspect * Math.atan(GameRenderer.fov_radians));
yDelta = (float) ((camera.zDecal + GameRenderer.camZ)* Math.atan(GameRenderer.fov_radians));
//(xDelta and yDelta are in reallity updated only ones a frame or when camera zoom change)
Camera camera = ObjectRegistry.INSTANCE.camera;
float xMin = camera.centerPosition.x - xDelta/2;
float xMax = camera.centerPosition.x + xDelta/2;
float yMin = camera.centerPosition.y - yDelta/2;
float yMax = camera.centerPosition.y + yDelta/2;
//xMin and yMin are supposed to be the lower bounds x and y of the visible plan
// same for yMax and xMax
// then i just check that my sprite is visible on this rectangle.
Vector2 phD = element.getDimToTestIfVisibleOnScreen();
int sizeXd2 = (int) phD.x / 2;
int sizeYd2 = (int) phD.y / 2;
return (element.position.x + sizeXd2 > xMin)
&& (element.position.x - sizeXd2 < xMax)
&& (element.position.y - sizeYd2 < yMax)
&& (element.position.y + sizeYd2 > yMin);
}
Unfortunately the object were disapearing too soon and appearing to late so i manuelly added some zoom out on the camera for test purpose.
I did some manual test and found that by adding approx 260 to the camera z index while calculating xDelta and yDelta it, was good.
So the line is now :
xDelta = (float) ((camera.zDecal + GameRenderer.camZ + 260) * GameRenderer.aspect * Math.atan(GameRenderer.fov_radians));
yDelta = (float) ((camera.zDecal + GameRenderer.camZ + 260)* Math.atan(GameRenderer.fov_radians));
Because it's a hack and the magic number may not work on every device I would like to understand what i missed. I guess there is something in that "260" magic number that comes from the fov or ration width/height and that could be set as a formula parameter for pixel perfect detection.
Any guess ?
My guess is that you should be using Math.tan(GameRenderer.fov_radians) instead of Math.atan(GameRenderer.fov_radians).
Reasoning:
If you used a camera with 90 degree fov, then xDelta and yDelta should be infinitely large, right? Since the camera would have to view the entire infinite plane.
tan(pi/2) is infinite (and negative infinity). atan(pi/2) is merely 1.00388...
tan(pi/4) is 1, compared to atan(pi/4) of 0.66577...