I have problem with handling ~1000 objects. This number of objects affects on performance (max 21 fps on Samsung Galaxy A6+). Most of them (95%) are static.
I've tried to set all of these static bodies inactive and apply filter masks, but it didn't increase number of fps. Even decreasing VelocityIterations doesn't help much. I'm able to maintain constant 60 fps only when I don't create all static bodies.
world.step(1/60f, 6, 2); //my default setting
///////////////////////////////
//experimentally for all static objects:
body.setActive(false);
body.setSleepingAllowed(true);
body.setAwake(false);
I'm thinking of runtime destroying and creating new bodies which are near main character, but I doubt it is a proper way to solve the problem.
Related
I am making an app with HTML5 video along with a canvas drawing on top of it (640x480 px). The objective was to record the canvas drawing along with the encoded video to produce it as a single video. I was able to do all these using FFMPEG. But the problem I am facing is, when the HTML5 video is running it takes around 50% of my CPU. Since drawing on canvas is also demanding CPU, the browser freezes after certain time and the CPU usage for that tab on chrome is showing continously > 100. I have tried to optimize html5 canvas rendering. But nothing helped. Is there a way to run this video with much less CPU usage? or any other optimizations possible?
There is not very much you can if the hardware need to use the CPU to decode and display the video. The keyword is compromise.
A few things can be done though that removes additional barriers. These must be considered general tips though:
Efficient looping
Make sure to use requestAnimationFrame() to invoke your loop in case you aren't.
setTimeout()/setInterval() are relatively performance-heavy and cannot sync properly to the monitor refresh rate.
Reduce update load
Also if you're not already doing this: the canvas is usually updated at 60 FPS while a video is rarely above 30/29.97 FPS (in Europe 25 FPS). This means you can skip every second frame update and still show the video at optimal rate. Use a toggle to achieve this.
Video at 25 FPS will be re-synced to 30 FPS (monitors typically runs at 60 Hz even for European models which are electronically re-synced internally, which also means the browser need to deal with drop/double-frames etc. internally - nothing we can do here).
// draw video at 30 FPS
var toggle = false;
(function loop() {
toggle = !toggle;
if (toggle) { /* draw frame here */ }
requestAnimationFrame(loop);
})();
Avoid scaling of the canvas element
Make sure canvas size and CSS size is the exact same. Or put simple: don't use CSS to set the size of the canvas at all.
Disable alpha channel composition
You can disable alpha composition of the canvas in some browsers to get a little more speed. Consumer-video never come with an alpha-channel.
// disable alpha-composition of the canvas element where supported
var context = canvas.getContext("2d", {alpha: false});
Tweak settings at encoding stage
Make sure to encode the video using a balance between size and decompression load. The more a video is compressed the more need to be reconstructed, at a cost. Encode with different encoder settings to find a balance that works in your scenario.
Also consider aspects such as color-depth i.e. 16 vs 24 bit.
The H264 codec is preferable as it has wide support in various display interface hardware.
Reduce video FPS
If the content of the video allows, f.ex. there is little movement or changes, encode using 15 FPS instead of 30 FPS. If so, also use a MODULO instead of a toggle (as shown above) where you can skip 3 frames and update canvas only at the 4.:
// draw video at 15 FPS
var modToggle = 0;
(function loop() {
if (modToggle++ % 4 === 0) { /* draw frame here */ }
requestAnimationFrame(loop);
})();
Encode video at smaller source size
Encode the video at a slightly smaller size dividable by 8 (in this case I would even suggest half size 320x240 - experiment!). Then draw using the scale parameters of the drawImage() method:
context.drawImage(video, 0, 0, video.videoWidth, video.videoHeight, 0, 0, 640, 480);
This help reduce the amount of data needed to be loaded and decoded but will of course reduce the quality. How it turns out depends again on the content.
You can also turn off interpolation using imageSmoothingEnabled set to false on the context (note: the property need a prefix in some browsers). For this you may not want to reduce the size as much as 50% but only slightly (something like 600x420 in this case).
Note: even if you "reduce" the frame rate the canvas is still redrawn at 60 FPS, but since it doesn't do any actual work on the intermediate frames it's still off-loading the CPU/GPU giving you a less tight performance budget over-all.
Hope this gives some input.
I'm creating this 2D, pixel art game. When the camera follows the player (it uses easing), on the final approach, the position gets several subpixel adjustments.
If I have smoothing ON (on my graphic assets), the graphics look good (sharp. it's pixel art) but the subpixel motion is jerky/jumpy.
If I have smoothing OFF, the subpixel motion is smooth, but the pixel art graphics look blurry.
I'm using Flash player v21. I've tried this with Starling and with Flash's display list.
You have a pixelated object that is moving in increments of less than the pixel size, but you don't want to restrict your mathematical easing to integers, or even worse, factors of 8 or what have you. The solution I am using in my project for this exact issue is posted below (I just got it working last week!)
Concept
create a driver that is controlled by the easing using floating point numbers.
Allow this driver to then control where the actual display object is rendered. We can use a constraint to only allow the display object to render on your chosen resolution.
Code Example
// you'll put these lines or equivalent in the correct spots for your particular needs.
// SCALE_UP will be your resolution control. If your pixels are 4 pixels wide, use 4.
const SCALE_UP: int = 4;
var d:CharacterDriver = new CharacterDriver();
var c:Character = new Character();
c._driver = d; // I've found it useful to be able to reference the driver
d._drives = c; // or the thing the driver drives via the linked object.
// you don't have to do this.
then when you are ready to do your easing of the driver:
function yourEase(c:Character, d:CharacterDriver):void{
c.x = Math.ceil(d.x - Math.ceil(d.x)%SCALE_UP);//this converts a floating point number into a factor of SCALE_UP
c.y = Math.ceil(d.y - Math.ceil(d.y)%SCALE_UP);
Now this will make your character move around 4 pixels at a time, but still be able to experience easing!
The bit with the modulo (%) operator is the key. For instance, 102-102%4 = 100. 103-103%4 = 100. 104-104%4 = 104.
In case anyone is confused by that, look at what 102%4 does: 4 goes into 102 25 times with a remainder of 2. so 102%4 = 2. Then 102 - 2 = 100.
In your case, since the "camera" is following the player (i.e. the background is moving, right?) then you really need to apply drivers to everything in the background instead, but it is basically the same idea.
Hope this helps.
since you specifically mentioned the "final approach" i think your problem comes from the fact that the easing equations puts your graphics at fractional coordinates, especially while getting closer to the target, but you should also notice it during the rest of the animation.
depending on the easing "engine" that you're using you should be able to set a "round values" flag, so all the coordinates set will be integer values and not fractional
if that's not possible, find a way in your display objects to round the x and y values every time they change
So I'm in the process of making an as3 game with a scrolling cave background. I have it set up to randomly generate a 30x30 cave (900 tiles). I would generate the cave then add all of the tiles as children to a "Background" movieclip. I was having some issues with it lagging so I decided to convert the background to a bitmap. Before I did this trace(System.totalMemory); output a value of around 20,000,000. Afterwards it's around 28,000,000, however the lagging/background-scrolling issues I had seem to have stopped. Why would it use more memory, and why would it alleviate my scrolling issues despite this? Here's the important part of the code.
//My cave is 1800 x 1800 pixels
var bitMapData:BitmapData = new BitmapData(1800, 1800);
//Drawing the cave to a bitmapdata
bitMapData.draw(background1);
var bitMap:Bitmap = new Bitmap(bitMapData);
//Removing all of the tiles from the background
while(background1.numChildren > 0) {
background1.removeChildAt(0);
}
//adding the bitmap to my background
background1.addChild(bitMap);
Any insight is greatly appreciated.
See, drawing a MovieClip is always done through vector renderer, this involves querying its structure, querying display list and more, also in case those MCs of yours have uneven scale (unequal and not in the line of powers of 2) even bitmap rendering is slowed. Having one Bitmap instead of 900 MCs lowers display list traversal time by a great margin (900 vs 1 - isn't it a decent improvement?). Of course, bitmaps occupy more memory than MCs, but this is same old memory vs performance issue that every programmer hits sooner or later. Don't worry about this 8M bitmap, just don't make too many bitmaps this big for mobile platform.
I'm making a game using libgdx. For now, every character has a speed, corresponding actually to the number of render the game wait before update the character. For example, if the character has a speed of 15, it will be updated every 15 renders. I'm conscious that this is not how it has to be done.
What is the proper way to do this? I really want to make a speed in %, for example a character will have a speed of 85%.
Use delta.
Gdx.graphics.getDeltaTime() method return secods since last render frame. Usually this value is very small, and it equal 1 / FPS.
#Override
public void render()
{
// limit it with 1/60 sec
float dt = Math.min(Gdx.graphics.getDeltaTime(), 1 / 60f);
// then move your characted according to dt
player.pos = player.pos + player.speed * dt;
// or, you could mute the speed like this:
player.pos = player.pos + player.speed * dt * 0.85;
}
When you calculate you object's next position just multiply it's speed with Gdx.graphics.getDeltaTime(), so the more time has pass since last render the more object will move. Movement speed will be constant, no matter of FPS.
However, simple solutions like this one always come with a catch! If you are i.e. moving a bullet it may happen that too much time has passed since last rendering (specially on mobile device). I.e. half of second, and for that time your bullet moved i.e. 100px and moved trough some target, but since it was never in range of detection (skipped it) target will be missed even it's not suppose to do so - player aimed well.
So, if just moving some object is not what you want, but you need that movement to be in some regular steps better way is not to multiply speed with delta time, but to repeat movement and all calculations (detections and stuff) depending on delta time. I.e.:
You have method move left(), which moves object one step and with that amount of movement everything works well.
Your method should be called 20 times per second (step takes 50mS).
You measured time since last render and it's 100mS, means that your objects need to be moved 2 steps
Don't just multiply it's speed and do one calculation - instead of that repeat whole calculation process 2 times! Call your left() method twice!
If time since last drawing is less then 50mS - then skip calculations and just draw graphics as you did in last frame.
This way you will have separated calculation rate from drawing rate. Calculation rate will be same on all devices, but drawing will depend on devices performance..
I have created a collision class to detect collisions using pixels. In my class I've also developed some functions for determining the collsion angle. Based on this I created some examples:
http://megaswf.com/serve/25437/
http://megaswf.com/serve/25436/
(Space to change gravity, right/left to give some speed to the ball.)
As you will probably notice, there are strange things that happen:
When the ball speed is very low
When the direction of the ball is
almost tangent to the obstacle.
collision http://img514.imageshack.us/img514/4059/colisao.png
The above image shows how I calculate the collision angle.
I call the red dots the keypoints. I search for a maximum number of keypoints (normally 4). If I find more then 2 keypoints, I choose the 2 farthest ones (as shown in one of the blue objects). Thats how I then find the normal angle to where in the surface the object collided. I don't know if this is an obsolete way of doing things.
based on that angle, I rotate the speed vector to do the bouncing.
The piece of code to do the maths is here:
static public function newSpeedVector(speedX: Number, speedY: Number, normalAngle: Number): Object{
var vector_angle: Number = Math.atan2(speedY, speedX) * (180/Math.PI);
var rotating_angle: Number = (2*(normalAngle - vector_angle) + 180) % 360;
var cos_ang: Number = Math.cos(rotating_angle/DEGREES_OF_1RAD);
var sin_ang: Number = Math.sin(rotating_angle/DEGREES_OF_1RAD);
var final_speedX: Number = speedX * cos_ang - speedY * sin_ang;
var final_speedY: Number = speedX * sin_ang + speedY * cos_ang;
return {x_speed: final_speedX, y_speed: final_speedY};
}
This is how the new speed vector is calculated...
My question is, has anyone faced this kind of problem or has some idea on how to avoid this from happening?
Without seeing your code, this is the best I can provide.
Collision physics should have some velocity threshold that is considered "stopped". That is, once the velocity gets small enough you should explicitly mark an object as stopped and exempt it from your collision code. This will help stabilize slow moving objects. Trial and error is required for a good threshold.
When a collision happens, it is important to at least attempt to correct any inter-penetration. This is most likely the reason why tangent collisions are behaving strangely. Attempt to move the colliding object away from what it hit in a reasonable manner.
Your method of determining the normal should work fine. Game physics is all about cheating (cheating in a way that still looks good). I take it rotation and friction isn't a part of what you're going for?
Try this. You have the contact normal. When you detect a collision, calculate the penetration depth and move your object along the normal so that is isn't penetrating anymore. You can use the two points you have already calculated to get one point of penetration, you'll need to calculate the other though. For circles it's easy (center point + radius in direction of normal). There are more complex ways of going about this but see if the simple method works well for you.
I have read and recommend this book: Game Physics Engine Development
I did something a little like that and got a similar problem.
What I did is that when the pixels from the bouncing object (a ball in your case) overlap with the pixels from the obstacle, you need to move the ball out of the obstacle so that they are not overlapping.
Say the ball is rolling on the obstacle, before your render the ball again you need to move it back by the amount of 'overlap'. If you know at what angle the ball hit the obstable just move it out along that angle.
You also need to add some damping otherwise the ball will never stop. Take a (very) small value, if the ball velocity is bellow that value, set the velocity to 0.
You can try one more thing, which I think is very effective.
You can make functions such as getNextX() and getNextY()(Which of course give their position coordinated after the next update) in your game objects and Check collision on objects based on their next position instead of their current position.
This way, the objects will never overlap, you'll know when they are about collide and apply your after collision physics gracefully!