Gravity
BlitzPlus Forums/BlitzPlus Programming/Gravity
| ||
Hi all, I`m having a small problem with gravity that I hope someone can help me with. In my game, a 2D platformer I have an item in the sky which slowly falls to the ground gradually increasing in speed (gravity). When the item hits an obstacle, in this case the ground, it stops. This worked fine when I used a simple item\yposition=item\yposition+1 method, the item fell and rested on the ground when and where it hit it but now I have added gravity the effect is ruined. The item still stops when it meets the ground but lands slightly out, either just to high or just to low. Here is what I`m using at the moment, ; create an items type. type items field xposition#,yposition#,fallspeed#,landed end type ; set a constant rate for gravity. const gravity#=0.1 ; test the item for a collision. item\collided=ImagesCollide(item\image,item\xposition,item\yposition,0,ground,groundxposition,groundyposition,0) ; if the item has collided with the ground then stop it otherwise gently increase its fallspeed by the constant ; gravity variable and add this to the items yposition to simulate simple gravity. if item\collided=True item\landed=true else item\yposition=item\yposition+item\fallspeed item\fallspeed=item\fallspeed+gravity endif Like I said what happens is the item does stop when it hits the ground but it is off by a couple of pixels which looks kind of ugly. This is obviously caused by the fallrate variable (er... I think) so I thought that just subtracting the fallrate (at the time of impact from the items yposition) would cure this but it doesn`t :( Maybe using floor or ceil would help round this floating point value to a whole value and cure the problem but I`m not really sure how to implement it. Any suggestions, Or other approaches? Thanks, Jason. |
| ||
Depending on how far the object has to fall your item\fallspeed could get quite high which is likely to be the reason for this. Just a suggestion but why don't you limit the speed with something like :- item\fallspeed=item\fallspeed + gravity * (item\fallspeed < max_speed ) Another method could be adding a bounce when the object hits the floor. i.e. hit floor then item\fallspeed=- item\fallspeed *.25 so that, while it may not land perfectly due to it's speed, the bounce will reduce it speed so that say, by the 2nd bounce the object will settle nicely on the ground. You would only say it has 'landed' when it's fallspeed was, say <1 pixel. |
| ||
WHen the object hits the ground it may be moving at more than 1 pixel so at the time of collision you might end up inside the ground. Just subtracting the fallspeed at collision wont fix it becuase you might end up above the ground. e.g. The object is 2 pixels above the ground. It moves down 3 pixels. So now it has fallen 1 pixel into the ground which is not good. If you subtract the speed it will end up hovering 2 pixels above the ground which is still no good. The quickest way I can think of fixing this would be to add code after the collision check. Set a loop up to subtract 1 from the yposisition until you are no longer colliding. This should make you end up sitting nicely onto of the ground. Hope that makes sense. |
| ||
No need for the loop described above. As soon as your item\collided=True just reposition the object at ground level. Or have I misunderstood? Unless your ground is uneven. Then do what QuietBloke says. |
| ||
Good point Joe. |
| ||
If you know what ground level is, then you can do that. But if you don't, or if you're bouncing on an irregularly shaped platform, you won't know what the ground level is, so you'll have to do the method described above where you move down 1 pixel (or 2 pixels if you want it quicker but less accurate) until the collision occurs. |
| ||
But then there would be no accelleration, which is what the thread is about. Blitz can do pixel-perfect collision using ImagesCollide() so why would irregular platforms or not knowing the ground level ever be a problem? Unless there was a huge amount of stuff going on. |
| ||
There is a very easy solution to this, There is no need to only check for collision when you draw the image, you have to check all pixels in the trajectory, in a for next loop whith an exit in case you have collided. This way the object can travel as fast as you like, it will detect even a 1 pixel platform. Hope this helps, if you DO need some sample code just ask. |
| ||
If you could provide some sample code it would be nice :) Jason. |
| ||
Am I wrog in thinking that gravity does not increase in speed as a object falls? It's the same all the way down correct? Or did my physics teacher tell us wrong =P |
| ||
The speed increases until it attains a fixed speed. All onjects fall at the same speed eventually. Before you ask, I can't remember the speed. But I do know it changes depending on the amout of gravity there is. This is all from memory, and the last physics book I read was 15 years ago! |
| ||
Well, I'll bieleve you then =P After all, I did just start physics class about 3 days ago |
| ||
Well here is some code,For n=1 To fall_speed If ReadPixel(x,y)<>ctrl_color y=y+1 Else Exit EndIf Next Here is a little sample so you can try it. ;**************************************************************** ;* * ;* PIXEL PERFECT COLLISION * ;* * ;* by MadMax * ;* * ;**************************************************************** x=400 y=100 fall_speed=5 Graphics 800,600,16 screen=CreateImage(800,600) sprite=CreateImage(20,64) cursor=CreateImage(32,32) HandleImage sprite,10,64 MidHandle cursor Color 255,0,0 SetBuffer ImageBuffer(screen) Rect 0,0,5,5,True Line 0,500,799,500 ctrl_color=ReadPixel(2,2) Color 0,0,0 Rect 0,0,5,5,True Color 0,0,255 SetBuffer ImageBuffer(sprite) Rect 0,0,20,64,True Color 255,0,255 SetBuffer ImageBuffer(cursor) Rect 15,0,2,32,True Rect 0,15,32,2,True Rect 8,0,16,2,True Rect 8,30,16,2,True Rect 0,8,2,16,True Rect 30,8,2,16,True Color 255,255,0 Rect 14,14,4,4,True Color 255,255,255 SetBuffer BackBuffer() While Not KeyDown(1) If MouseHit(1) x=MouseX() y=MouseY() EndIf If KeyHit(74) Then fall_speed=fall_speed-1 If KeyHit(78) Then fall_speed=fall_speed+1 Cls DrawImage screen,0,0 ;******************************************************* ; THE FOLLOWING IS THE RELEVANT BIT For n=1 To fall_speed If ReadPixel(x,y)<>ctrl_color y=y+1 Else Exit EndIf Next ;******************************************************* DrawImage sprite,x,y Text 20,20,"Fall Speed :"+fall_speed If MouseY()>484 Then MoveMouse(MouseX(),484) DrawImage cursor,MouseX(),MouseY() Color 255,255,0 Text 400,525,"USE '+' '-' KEYS ON KEYPAD TO CHANGE FALL SPEED.",True,True Color 155,200,255 Text 400,550,"USE LEFT MOUSE BUTTON TO PLACE SPRITE",True,True Color 255,255,255 Flip True Wend Hope it helps |
| ||
That method is slower than what quietbloke described, and it should do the same thing as his method only it could be used instead if you need to make sure that the object doesnt pass through the entire wall. |
| ||
this could be added, unless you wat something more flexible.; test the item for a collision. item\collided=ImagesCollide(item\image,item\xposition,item\yposition,0,ground,groundxposition,groundyposition,0) ; if the item has collided with the ground then stop it otherwise gently increase its fallspeed by the constant ; gravity variable and add this to the items yposition to simulate simple gravity. if item\collided=True item\landed=true repeat item\yposition=item\yposition-1 until ImagesCollide(item\image,item\xposition,item\yposition,0,ground,groundxposition,groundyposition,0)=false else item\yposition=item\yposition+item\fallspeed item\fallspeed=item\fallspeed+gravity endif |
| ||
@Corae,,, Nothing against the way QuietBloke suggested, only trouble is that in some cases it's possible to go through a wall. As for the speed overhead, I'd say this is insignificant, and I can hardly imagine a game that needs to have over 2000 sprites falling onto a platform (there is no way to display them all without them covering each other) also the FPS decrease is more due to drawing each Sprite than because of the collision system. I have also found out in my tests that there is a very slight performance hit of around with 2000 sprites falling at a speed of 1000 pixels per frame (still performs well over 60 FPS with 2000 sprites) and it still detects a one pixel platform. Also with the method QuietBloke suggested, once the sprite hits the platform, the speed hit will be very similar. So unless you need to have 20000 sprites falling at a rate of hundreds of pixels. And remember that in this case drawimage will dramaticaly slow down performance(maybe you'd need to write an ASM routine that's more optimized than Blitz' one). This method works very well. Note: locking the buffer and using readpixelfast will of course increment performance. |
| ||
Thanks guys, thats helped a lot. Regards, Jason. |