Here's the thing : I have a ball bouncing using Tweens, and I want to detect collisions between the ball and platforms (only when the ball is falling down).
But, my solution is testing for collisions in an ENTER_FRAME loop, so when the ball speed is to high, at a x frame the ball is above the plateform, and at a x+1 frame the ball is below the platform, so my loop never detects collision (because the ball and the platform never really collide).
Here's the jump method of my ball :
public function jump():void
{
TweenLite.killTweensOf(this);
TweenLite.to(this, jumpSpeed, {y:250, ease:Cubic.easeOut});
TweenLite.to(this, jumpSpeed, {delay:jumpSpeed, y:stage.stageHeight-this.height, ease:Cubic.easeIn, onComplete:jump});
}
And here's what's executed in my ENTER_FRAME loop :
for each (var platform:Platform in platforms)
{
if (ball.hitTestObject(platform) && ballPreviousY < ball.y)
ball.jump();
}
ballPreviousY = ball.y;
I already started to work on a solution using the physics engine Box2D, but I would like to know if there was a simpler solution to that problem.
This is a common problem in collision detection - small, fast objects moving through thin obstacles. What your looking for is sweep testing
Instead of testing for intersection between two static shapes, we can
instead create new shapes by sweeping the original shapes along their
trajectory, and testing for overlap between these swept shapes.
From N Tutorial A - Fast Moving Objects, (I'd recommend reading all their stuff if your interested in more detail in collision algorithms).
For example, if you had a 1px by 1px square and it was travelling at 5px per frame along the x axis, you'll want to distort your square so that becomes a 6px by 1px rectangle for collision testing. Catching anything that it would hit next frame, but not anything more.
Circles are a little more difficult because when you stretch them they become ellipses (which are far harder to check collisions for). See this answer if you want to go the ellipse route.
Related
I'm attempting a to make a fighting game with multiple platforms. I've successfully made the controls, movement, (double)jumping, and gravity parts of the game.
The issue is, when a player jumps, upon reaching the ground, they seem to go a bit deeper than they should on the platform (they should land and stay on the surface of the platform). This is more visible when the player double jumps.
I know why this happens; it's because sometimes hitTestObject takes a while to react when objects come in too quickly.
So, the first thing I thought of is to make the player's foot's y axis equal to the y axis of the top of the platform he lands on.
Though, that solution resulted in a rather jerky landing.
My question is: Is there a way to make the player to land smoothly on the top surface of the platform?
Some things I've tried:
-Raising FPS, it just made the same effect happen, but more quickly.
-Decreasing the speed at which the player falls, but that makes the game less fun, so I've crossed it out.
And here's my relevant code:
stage.addEventListener(Event.ENTER_FRAME, loop);
var jumpConstant:Number = 30;
var gravityConstant:Number = 1.8;
function loop(e:Event):void //happens
{
if(player.leg1.foreleg1.foot1.hitTestObject(platforms.ground)||player.leg2.foreleg2.foot2.hitTestObject(platforms.ground)) //if either of the player's legs are colliding with the platform [ps: nested movieclips]
{
player.ySpeed = 0; //the player stops going downwards
player.y = platforms.y; //the player's y becomes the platform's y. don't worry, it puts the player in the right place, just not smoothly.
if (player.b_up) //if Up control button (W or Up Arrow) is being pressed
{
player.ySpeed = -player.jumpConstant; //make the player jump
}
else //if the player isn't colliding with the platform
{
player.ySpeed += player.gravityConstant; //the player is affected by gravity and is pulled downwards
}
Link to the game if you wanna try it out to see the jerky effect:
http://www.fastswf.com/-64Ux3I
The problem is that you are only checking for a collision at increments of ySpeed. Since y speed increases during a fall by 1.8 per step, you are quickly looking at collision checks spaced widely apart. If you want pixel precise collision checks, you need to check for collision at 1px increments. This means if y speed is 10, you need 10 collision checks during one loop update. Use a for loop within your loop function to accomplish this.
Why don't you set hitTestObject y coordinates a bit above the ground so the sinking into the ground will actually make it touch the ground now.
I'm working on a small game in Flash (AS3) that generates levels using small tiles.
The location,width,height and other properties of the tile are stored in an array upon generation. Each tile is added to the same container movieclip. When all tiles have been generated, the container movieclip is converted to a bitmap, all tiles are removed from the stage, and the original container is removed from the stage and then deleted. The bitmap is the only remaining "graphic" on the stage, aside from the player.
This yields far better performance than allowing all 60,000+ tiles to be rendered individually during gameplay; however, the framerate still reduces as the number of tiles is increased. This makes no sense, as all the tiles are added to a single bitmap that is always the same size, regardless of the amount of tiles.
With 20,000 tiles during generation, the game runs at the full FPS, but with 60,000 it runs relatively choppy, probably around 4-5 FPS.
I've removed collision detection and any/every script that runs through the tile array to rule out the possibility that some other CPU intensive part of the script is lagging the framerate.
Any idea why, despite the fact that all tiles have been removed from the stage and their container is deleted, the game is still running slow even though the background bitmap contains the same amount of data regardless of the number of tiles generated?
Here is the last part of the level generation algorithm which converts the container movieclip to a bitmap and then removes all the tiles:
var temp_bitmap_data:BitmapData = new BitmapData(this.stage_background_mc.width,this.stage_background_mc.height);
temp_bitmap_data.draw(this.stage_background_mc);
this.stage_background_bitmap = new Bitmap(temp_bitmap_data);
main_class.main.stage.addChild(this.stage_background_bitmap);
for (var block in blocks_array)
{
//every block in blocks_array has a child that is the actual graphic of the tile
blocks_array[block]["block"].removeChild(blocks_array[block]["block"].getChildAt(0));
if (blocks_array[block]["type"] == "bg_block")
{
this.stage_background_mc.removeChild(blocks_array[block]["block"]);
blocks_array[block]["block"] = null;
}
if (blocks_array[block]["type"] == "path_block")
{
//path_blocks have a second child in addition to the first one that's already been removed. the second child is the only other child
blocks_array[block]["block"].removeChild(blocks_array[block]["block"].getChildAt(0));
this.stage_background_mc.removeChild(blocks_array[block]["block"]);
}
}
this.stage_background_mc = null;
[Edit]
Here is a picture of the game to give you a better idea of what's going on:
[Update:]
Even removing the final created bitmap from the stage, ending up with only 1 child on stage, and setting that removed bitmap to null doesn't improve the speed.
A couple of thoughts.
First, you're sorta half taking advantage of AS3's quick work with blitting. You've got the right idea about having only one single Bitmap on the stage, but the steps before (adding DisplayObjects to a MovieClip and the doing draw on that MovieClip) isn't the fastest process. For one thing, BitmapData.draw is slower than BitmapData.copyPixels (here is a post on that). One of the best ways to get speed is to pre-blit all of your graphics, and store them as BitmapData. Then, keep Object references (containing position, etc) for each graphic. In your render loop, run through each object, and use copyPixels to copy the graphic's pixel information to the appropriate positon in your single, on-stage Bitmap. This way, all slow BitmapData.draw commands have happened upfront, and now you are just pushing pixels, which Flash is really fast at.
That process isn't without its downsides, however. For instance, you can't do easy transforms with it. You'd have to pre-blit all frames of a rotation, for instance, in order to rotate the individual graphic (since you can't rotate a BitmapData, and you aren't using draw on a DisplayObject). Still, it is mighty fast if you can live with the limitations.
Here is a post that serves as a tutorial of the process I explained above. It is old, but informative none-the-less.
Finally, 60,000 is a very large number. Flash isn't exactly a "speed demon." No matter how optimized, eventually you'll hit a limit. Just something to keep in mind.
Oh, and this additional post gives some great tips on performance in Flash.
I'm trying to find a clean way to "move the camera" of a canvas element.
This for my prototype game (side scroller). I'd love to think there's a better solution than moving the whole set of nodes to simulate a "camera" moving around.
Am almost certain to have read a simple how-to (using offsets?) but the fact I don't find anything like that starts to raise doubts... have I imagined reading that!?
Thanks to help me clarify...
J
Presumably you redraw your whole game scene 30 times a second (more or less)
You need to redraw your whole game scene but first translate the Canvas context by some offset.
context.translate(x,y) is precisely what you want. You'll want to read up on the use of that as well as the save() and restore() methods.
When you translate the context, everything drawn afterwards is shifted by that amount.
So you constantly draw something (maybe an enemy) at 50,50 using drawImage(badguy,50,50). Then the player moves, which changes the x of translate to -1 (because the player is moving to the right) instead of 0. You still draw the enemy sprite with the command drawImage(badguy,50,50), but when you draw it the enemy shows up as if it were at 49,50 because of the context.translate(-1,0) command shifting everything before its drawn.
Of course when you get into performance you'll want to be making sure that you are only ever drawing things that can actually be seen on the screen! If your are far down the level with context.translate(-2000,0), you dont want to be drawing objects at 50,50 anymore, only ones that intersect the viewable area.
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!
For practice, I'm coding a really simple 2D platforming game in Flash using AS3. I'd like to define two different types of terrain surfaces that the player can walk on based on classic platforming elements. Type1: the player can walk on, and if the player jumps, they will hit their head on it and bounce back to the ground. Type2: the player can also walk on, but if the player jumps and hits their head, they will simply pass through the surface and not bounce back to the ground.
I am using hitTestPoint to resolve collisions for this. My question is: What would be the best method to test for what TYPE of ground I am colliding with? Each ground type has it's own Class associated with it in my Flash IDE and all the different terrain surface types are in the same movie clip on the stage.
Currently I'm testing to see if it hit one type of ground surface, then i'm testing if it hit the other, and then based on those results, I process what I want to happen. This seems to work okay right now, but I'm imagining that I may want to create more than 2 types of ground to collide with. For example, moving platforms. It seems like the code will start to get complex
Eg.
if(_groundType1.hitTestPoint(_player.x, _player.y, true))
{
if(_groundType2.hitTestPoint(_player.x, _player.y, true))
{
//don't hit the players head
}
//hit the players head
}
Try using instanceof - http://www.adobe.com/support/flash/action_scripts/actionscript_dictionary/actionscript_dictionary389.html