Rotating canvas and drawing bitmap performance - java

I am trying to make a game where the planet would be in the center of user's screen and very slowly rotate like planet would.. So first I decided to test it if everything would work fine, and it doesn't.. I get a simple "planet" image like this:
Bitmap image = BitmapFactory.decodeResource(getResources(),R.mipmap.totone);
I also have a variable that stores the angle. Then in the draw function I just rotate the canvas, draw my planet (now rotated), and rotate canvas back. like this:
//the planet's image is 512x512px
canvas.rotate(ang,256,256); //256, 256 is the center of rotation
canvas.drawBitmap(image, 0,0, null);
canvas.rotate(-ang,256,256); //rotate back
I have no idea why, but it looks like when the image is rotated by 90 and 270 degrees the game fps slows a little? I made a little gif to show the problem. The fps is perfectly 60 all the time but then it drops at 50ish for couple miliseconds for no reason? What is causing this? I tried to change my thread's target fps to 30 and it looks like no fps drops happened then.. So it's probably performance issue. Note that I tried rotating the bitmap using maany different methods, the fps drop effect is still the same..
Gif

Most likely, this is an interaction between the device's fixed screen refresh rate and a slight variation in the time it takes to draw the bitmap at certain angles.
I'm guessing that you increment ang by a constant amount in onDraw(). This fact can be used to explain the sharp change in rotation rate.
EXPLANATION
Your device refreshes its screen at 60Hz. That means onDraw() gets called at 60Hz, max, under ideal conditions: About once every 16.7ms.
Let's assume that onDraw() takes about 15ms to execute. There's 1.7ms left over; everything's fine! You get a nice, smooth, 60Hz rotation.
Then assume that, at certain values of ang, onDraw() takes just a little bit longer; say, 18ms. (I will speculate on why the execution time of drawBitmap() varies based on the angle in a moment. For now, let's look at what happens with this 18ms drawing time.)
Ideally, onDraw() gets called at 60Hz. But now you're taking too long; more than 1 cycle. The compositor now has to drop a frame from your app, because you couldn't supply it fast enough! So, instead of onDraw() executing every 16.7ms, now it can only be called every 33.4ms.
In other words, the screen hardware refreshes at a constant rate, and when your onDraw() crosses that 16.7ms threshold, your update rate gets cut exactly in half.
This is hinted at in your GIF. The displayed frame rate goes from 60 to 51, but it seems pretty clear to me the actual rotation rate drops by almost exactly 50%. I suspect the discrepancy is simply due to the way you calculated the displayed frame rate.
SPECULATION ON VARIATION IN drawBitmap() EXECUTION TIME
Could be the caching performance of the processor. At certain rotation angles, the graphics logic could be accessing bitmap memory in a way that is not ideal for the L1 cache/prefretching logic. In other words, you could be getting a lot of cache misses at these angles.
RECOMMENDED FIXES FOR PLAYABILITY
Use a faster graphics pipeline, such as OpenGL, and/or:
Base ang on a time hack (uptimeMillis()) instead of an increment. You'll still drop frames, but the apparent rotation rate will be corrected.
If you want to go really crazy, you could supply a second bitmap, pre-rotated 90 degrees to the first, and use this bitmap for draws that take place at angles closer to 90/270 degrees. If I'm right about the cache misses, this would ameliorate the problem.

Related

Set offset for BitmapDrawable while repeating in the x and y direction?

I'm making a 2D platformer game. I have created a texture for the platform, that is meant to be repeated over and over to fill the entire platform, without going over. My first attempt was to draw all the pixels from the bitmap manually, but this caused the background to flicker through while moving the platform (the movement and drawing threads are seperate, so the movement can run at a specific speed, while the FPS doesn't need to suffer). I found this technique worked better:
// Init
bitmap = new BitmapDrawable(res, Texture.PLATFORM.getBitmap());
bitmap.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
// Drawing loop
int x = getX() + (isStill() ? 0 : (int)MainActivity.offsetX);
int y = getY() + (isStill() ? 0 : (int)MainActivity.offsetY);
bitmap.setBounds(x, y, x + getWidth(), y + getHeight());
bitmap.draw(canvas);
However, the bitmap appears to be staying static while the platform is acting as a "view hole" to see through to the bitmap. The only work around I can think of is to somehow "offset" the static bitmap:
bitmap.offset(x, y);
Obviously, that isn't a function. I couldn't find one that would do what I want when looking through the docs.
To summon things up, the BitmapDrawable is causing the background to not move with the platform, making it look super weird.
Thanks in advance!
Try these tips in your code:(I assumed the game moves forward in the horizontal direction)
The GUY should only move up and down(with the appropriate touch input) and not forward and backward as you want the focus(or camera alternatively) solely on the GUY.I noticed that the WALL was moving up in your video when the GUY moved from initial higher position of the wall to little bit lower position later, rectify this because the GUY should move down(try to implement Gravity effect).
The WALL should only move forward(mostly) and backward(less often I guess).The WALL shouldn't move up and down normally. Do not apply Gravity effect to it. You can create at least 2 BitmapDrawable instance of WALL for a screen. They are going to be reused sequencially(for eg: If the 1st one goes totally outside of the screen, reshow it in the desired position using setBounds() method) and continue same for others the whole game.
The currently BLUE BACKGROUND, if it is a part of a larger map, then it needs to be appropriately offsetted.
One of the obstacles that I can think of at the time of writing this is to move the WALL down until it goes out of the screen which results in the death of the GUY.
At those places, where I have used the word move, you need to use the setBounds(a, b, c, d) method to make necessary position based changes as I didn't find other way to update the position of a BitmapDrawable instance. I think, you need to use game framework like libGdx to get method of luxury like setOffset(x, y) or of similar sort.
Sorry that I could only present you the ideas without specific code as I do not have past experience working in a project like this. Hope, it helps you in anyway possible.

How do you wait a little before drawing a Path on the Canvas?

I have a wave that moves according to the amplitude that the speaker is currently picking up, but if I'm quiet and then make a sudden noise, the wave "jumps" to that amplitude immediately, and I want to make the effect slightly more gradual. How can I accomplish this task?
I'm drawing the wave now using:
Canvas.drawPath(path,paint);
path.reset();
invalidate();
All in the onDraw method of my custom View. So the path is essentially drawn with whatever amplitude the mic is currently picking up (with a limit), which means that if the amplitude picked up is at say 100 right now then suddenly jumps to say 4000, the path will "jump" considerably as well.
It depends on actually what you need to do. If you want to smooth your path, i suggest you to draw a curve instead a path with some angle (you also can make with lines).
Otherwise, you can do the same using sleeps regarding that the whole transition should be small enought to fit into the frequency that you collect data.
I don't think adding sleeps would be be best solution, as you could possibly loose incoming data that you may want to graph. I'd suggest saving the last x samples and then averaging in the incoming packets. So if you're at 10 and the next few samples come in at 4000 and then back down, your average would be not nearly has high. If it rose to 4000 and stayed there, the graph would eventually rise to 4000 in a few samples, depending on how you are averaging.

libgdx user switches off screen

I just noticed that when I turn off my screen on my mobile device and turn it on again some graphics resize or disappear. My game is coded towards 800x480 resolution and my HTC Desire HD doesn't have this problem (it has a 800x480 resolution). However, when tested on my HTC One or a Samsung Galaxy S3 the graphics scale or behave weird.
The only thing those objects who behave weird have in common are that they rotate every frame. Stationary objects don't seem to be affected at all.
I have stars who rotates and scales up/down every frame and I have a moving block who goes left/right or up/down. The moving block seems to ignore collision when the screen is restarted and disappears to places he should not be able to reach.
Any ideas?
Thanks in advance.
When you turn off the screen, rendering is paused (i.e. no calls to render() are made). When you resume, Gdx.graphics.getDeltaTime() will be very large as the last frame was rendered at least some seconds ago. So the delta time values that are normally in the order of 0.0166 (60 FPS) will now be in the order of a 100 times greater.
If you are using this delta to take a physics simulation / collision check step, that will go beserk because it's way too large. Rotation shouldn't be a real problem, but scaling will also go out the roof.
A simple way to avoid this is to put in something like
if (delta > 0.1f)
delta = 0.0166f
to avoid taking really large steps.

Canvas/Stage Size in Flash is too small and cannot show entire level

This isn't directly a programing problem but I feel it still can fall under the catagory, I am sorry if this is the wrong place. I am making a game in flash using box2d and I decided to draw the levels in flash as the level design would look better, The levels are very large ( this level is 10,000 pixels long) and the canvas in flash just won't display anything.
The preview in the library seems to be able to display the drawing longer than the one on the stage. How do I go about making the canvas longer? Should I try upgrading to a newer version of flash, does that version allow this?
You just don't put everything at once over your canvas, instead draw only those level primitives or parts that are visible right now. Or, if your level is basically a pretty simple shape, you can just change its X and Y so that the relevant part of the level is displayed on stage.
Don't use giant bitmaps - they use a lot of memory, and even if not all of the content is visible, they will degrade performance considerably. For this reason, Flash imposes a size limit of 4095x4095 pixels (or an equal amount of pixels in rectangular formats).
The way to deal with this is to tile your graphics into parts of equal size, preferably smaller than the stage (1/2 or 1/3 side length is a good measure). You then place them all as a grid into a larger Sprite or MovieClip and set visible=false; on each tile. Then, at runtime, your game loop must check for each frame, which of the tiles should actually appear on the stage - and only those should then be set to visible=true;. That way, you reduce the amount of pixels drawn to what is absolutely necessary, and keep screen memory usage to a minimum.

LibGDX FrameBuffer scaling

I'm working on a painting application using the LibGDX framework, and I am using their FrameBuffer class to merge what the user draws onto a solid texture, which is what they see as their drawing. That aspect is working just fine, however, the area the user can draw on isn't always going to be the same size, and I am having trouble getting it to display properly on resolutions other than that of the entire window.
I have tested this very extensively, and what seems to be happening is the FrameBuffer is creating the texture at the same resolution as the window itself, and then simply stretching or shrinking it to fit the actual area it is meant to be in, which is a very unpleasant effect for any drawing larger or smaller than the window.
I have verified, at every single step of my process, that I am never doing any of this stretching myself, and that everything is being drawn how and where it should, with the right dimensions and locations. I've also looked into the FrameBuffer class itself to try and find the answer, but strangely found nothing in there either, but, given all of the testing I've done, it seems to be the only possible place for this issue to be created somehow.
I am simply completely out of ideas, having spent a considerable amount of time trying to troubleshoot this problem.
Thank you so much Synthetik for finding the core issue. Here is the proper way to fix this situation that you elude to. (I think!)
The way to make frame buffer produce a correct ratio and scale texture regardless of actual device window size is to set the projection matrix to the size required like so :
SpriteBatch batch = new SpriteBatch();
Matrix4 matrix = new Matrix4();
matrix.setToOrtho2D(0, 0, 480,800); // here is the actual size you want
batch.setProjectionMatrix(matrix);
I believe I've solved my problem, and I will give a very brief overview of what the problem is.
Basically, the cause of this issue lies within the SpriteBatch class. Specifically, assuming I am not using an outdated version of the class, the problem lies on line 181, where the projection matrix is set. The line :
projectionMatrix.setToOrtho2D(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
This is causing everything that is drawn to, essentially, be drawn at the scale of the window/screen and then stretched to fit where it needs to afterwards. I am not sure if there is a more "proper" way to handle this, but I simply created another method within the SpriteBatch class that allows me to call this method again with my own dimensions, and call that when necessary. Note that it isn't required on every draw or anything like that, only once, or any time the dimensions may change.

Categories