Collision problem

Advanced game related topics
User avatar
Demivec
Addict
Addict
Posts: 4282
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Post by Demivec »

ChebbyShabby wrote:also, i see you used mechanics/physics concepts to make FlightTime equal to 20 when falling down. can i just ask, what do you do in uni and what did you study at school?
I didn't study many things in university. I only had the rough equivalent of one quarter of one year (grades were all A's). My studies in school included 3 years of mechanical physics and mathematics through the calculus level. My personal studies though have included anything and everything, including computer science of course.

An equation that would be better is:

Code: Select all

;FlightTime=20 doesn't work if Power is not 10
FlightTime=Power/Gravity
The collision could be performed as an elastic collision with

Code: Select all

FlightTime=2*(Power/Gravity)-FlightTime
I think the overlap problem is just related to the order of the collision detection.
ChebbyShabby
Enthusiast
Enthusiast
Posts: 121
Joined: Mon Jun 26, 2006 10:47 am

Post by ChebbyShabby »

do you by any chance know how to make the downward collision elastic so that the player bounces a bit before he stops? i've only been studying advanced maths and physics for a year now (british system) and so i don't have much experience with these.
User avatar
Demivec
Addict
Addict
Posts: 4282
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Post by Demivec »

ChebbyShabby wrote:do you by any chance know how to make the downward collision elastic so that the player bounces a bit before he stops? i've only been studying advanced maths and physics for a year now (british system) and so i don't have much experience with these.
It would work the same way in the british system as it would for any other since we are not using any units of measure besides pixels/frame.

Code: Select all

FlightTime = 0
Power/4
ChebbyShabby
Enthusiast
Enthusiast
Posts: 121
Joined: Mon Jun 26, 2006 10:47 am

Post by ChebbyShabby »

nono i was talking about the system of education...
User avatar
Rook Zimbabwe
Addict
Addict
Posts: 4322
Joined: Tue Jan 02, 2007 8:16 pm
Location: Cypress TX
Contact:

Post by Rook Zimbabwe »

Actually I think you were talking about reflection... to make a the player reflect a small tangent from hitting a fixed point.

In Blitz we had 3 collision types...
1. Nothing
2. Sliding Type (useful for the floor of the platform)
3. Stop (useful for walls)

I always thoguht there should have been a 4th type like Reflection... People are doing that with a physics engine, but they were doing it long before a physics engine as well...

Let me dig in my old code a bit:

This is what I used for a circular pool game... I didn't write the entire thing but I did polish it for my uses. You should be able to see the math:

Code: Select all

;------------------------------------------
		;COLLISION CHECKING
		;------------------------------------------
		; Check each circle in the loop against
		; every other (c against c2)
		For c2.circle = Each circle
		
			collisionDistance# = c\radius+c2\radius
			actualDistance# = Sqr((c2\x-c\x)^2+(c2\y-c\y)^2)
			
			;Collided or not?
			If actualDistance<collisionDistance Then
				
				collNormalAngle#=ATan2(c2\y-c\y, c2\x-c\x)

				;Position exactly touching, no intersection
				moveDist1#=(collisionDistance-actualDistance)*(c2\mass/Float((c\mass+c2\mass)))
				moveDist2#=(collisionDistance-actualDistance)*(c\mass/Float((c\mass+c2\mass)))
				c\x=c\x + moveDist1*Cos(collNormalAngle+180)
				c\y=c\y + moveDist1*Sin(collNormalAngle+180)
				c2\x=c2\x + moveDist2*Cos(collNormalAngle)
				c2\y=c2\y + moveDist2*Sin(collNormalAngle)
				
				
				;------------------------------------------
				;COLLISION RESPONSE
				;------------------------------------------
				;n = vector connecting the centers of the circles.
				;we are finding the components of the normalised vector n
				nX#=Cos(collNormalAngle)
				nY#=Sin(collNormalAngle)
				
				;now find the length of the components of each movement vectors
				;along n, by using dot product.
				a1# = c\dx*nX  +  c\dy*nY
				a2# = c2\dx*nX +  c2\dy*nY
				
				;optimisedP = 2(a1 - a2)
				;             ----------
				;              m1 + m2
				optimisedP# = (2.0 * (a1-a2)) / (c\mass + c2\mass)
				
				;now find out the resultant vectors
				;r1 = c1\v - optimisedP * mass2 * n
				c\dx = c\dx - (optimisedP*c2\mass*nX)
				c\dy = c\dy - (optimisedP*c2\mass*nY)
				
				;r2 = c2\v - optimisedP * mass1 * n
				c2\dx = c2\dx + (optimisedP*c\mass*nX)
				c2\dy = c2\dy + (optimisedP*c\mass*nY)

			End If

		Next
		;------------------------------------------
		;------------------------------------------
		
		
		;Simple Bouncing off walls.
		If c\x<c\radius Then
			c\x=c\radius
			c\dx=c\dx*-0.9
		End If
		If c\x>GraphicsWidth()-c\radius Then
			c\x=GraphicsWidth()-c\radius
			c\dx=c\dx*-0.9
		End If
		If c\y<c\radius Then
			c\y=c\radius
			c\dy=c\dy*-0.9
		End If
		If c\y>GraphicsHeight()-c\radius Then
			c\y=GraphicsHeight()-c\radius
			c\dy=c\dy*-0.9
		End If
		
	Next

End Function
Don't know if that would help or hinder, meant to help! 8)
Binarily speaking... it takes 10 to Tango!!!

Image
http://www.bluemesapc.com/
User avatar
Demivec
Addict
Addict
Posts: 4282
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Post by Demivec »

Demivec wrote:I think the overlap problem is just related to the order of the collision detection.
To correct the order of collisions causing a problem the data for platform placement should be sorted by the y position in descending order then by the x position in either ascending or descending order. This means the platforms will be listed with the bottomost ones first always from the left (or right) and proceeding across the screen in order.

I also need to post a correction to a mistake I made by not entering the correct range for collisions from the left or right directions with respect to the y direction. Replace the corresponding lines with:

Code: Select all

If (xx - diffWidth)<x  And x<(xx + platformWidth) And (yy - playerHeight)<y And y<(yy+platformHeight) ;Collision with RIGHT of platform

Code: Select all

If (xx - playerWidth)<x And x<(xx - diffWidth) And (yy - playerHeight)<y And y<(yy+platformHeight) ;Collision with LEFT of platform
User avatar
Demivec
Addict
Addict
Posts: 4282
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Post by Demivec »

I simplified the code for velocity so that changes in velocity would be easier to code, especially for collisions. This allows other changes to occur in the environment besides jumping. I also included a lengthy description at the beginning for how the values were determined for gravity, velocity and so forth because I know you would probably want to tinker with them

Code: Select all

;-Physics variables
;Gravity is based on the largest value that will keep the velocity <=43 pixels/frame when player is dropped
;from a height of 480 pixels (screen height).  If velocity>43 the player will move through a platform and
;collide with the next platform instead. Using formula "Vf^2 = Vi^2 + 2 * g * d" where Vi = 0,d = 480,Vf = 43
;and solving for "g = (Vf^2) / (2 * d)".  This produces a range of 0<Gravity<=1.925.  The value is further
;limited by the method for collision detection.  It limits the velocity that can be obtained when the player
;is "not moving" for a single frame while on top of a platform (this value is 0.5 which will be rounded up to
;a 1 because of floating point to integer conversion).  The change in velocity is greatest during a collison
;because the direction of the velocity changes. It uses formula "(dV) = gt and/(1 + 1 / c)" where 
;dV = 0.5,t = 1,c = 5 (higher values of c represent a less elastic collision), simplifying and solving 
;for "g = .6".  The value for g is therefore now limited to the more restrictive range of 0<Gravity<=0.6 
;due to the collision method used.
;Velocity for a Jump is based on what is range of values that will not cause the velocity to exceed 
;43 pixels/frame if the player Jumps from the highest point on the screen (y = 0).  Solving the above equation 
;for Vi gives us "Vi = sqr(Vf^2 - 2 * g * d)". Substituting we get "Vi = sqr(1849 - 960 * g)". The legal 
;values of velocity are 0 to the max value based on substituting our Gravity value and solving the equation 
;for Vi.
#Elasticity = 1.0 / 5.0 ;what fraction of velocity remains after a collision
#Gravity = 0.5 + 0.5 * #Elasticity ;legal values are 0<Gravity<=0.6
#VelocityJump = 11 ;if (maxVelocity,Gravity)=(mV,g), maximum legal values are (35,0.6)<=(mV,g)<(43,0)

Gravity.f = #Gravity ;
Velocity.f = 0 
newVelocity.f = 0
;-Load the level
Procedure CountLines(file$)
  If ReadFile(0,file$)
    l = Lof(0)
    m = AllocateMemory(l)
    ReadData(0,m,l)
    m$ = PeekS(m)
    FreeMemory(m)
    CloseFile(0)
  EndIf;
  ProcedureReturn CountString(m$,Chr(10))/2
EndProcedure;
n = CountLines("Level.txt")-1

Dim p.POINT(n)

ReadFile(1,"Level.txt")
For I=0 To n
  p(I)\x=Val(ReadString(1))
  p(I)\y=Val(ReadString(1))
Next 



CloseFile(1)

;-Prepare the screen
InitKeyboard()
InitSprite()

OpenScreen(640,480,32,"")
SetFrameRate(60)

;-Prepare the sprites
Enumeration
  #Player
  #Platform
EndEnumeration

LoadSprite(#Player,"Eraser.bmp")
LoadSprite(#Platform,"Platform.bmp")
playerHeight = SpriteHeight(#Player)
playerWidth = SpriteWidth(#Player)
platformHeight = SpriteHeight(#Platform)
platformWidth = SpriteWidth(#Platform)
diffWidth = (playerWidth - platformWidth) / 2
diffHeight = (playerHeight - platformHeight) / 2

x = 30
Repeat
  FlipBuffers()
  ClearScreen(RGB(0,0,0))
    
  ;-Display the level
  For I = 0 To n
      xx = p(I)\x
      yy = p(I)\y
      DisplayTransparentSprite(#Platform,xx,yy)
  Next
      
  DisplayTransparentSprite(#Player,x,y)
  
  ;-Jump
  ;If KeyboardPushed(#PB_Key_Space): Power = 10: EndIf  
  If KeyboardPushed(#PB_Key_Space) And Ground=1: Velocity = #VelocityJump: EndIf
  
  ;-Jump physics
  ;Velocity = Power - (Gravity * FlightTime) ;Adaptation of "v = u + at"
  Velocity - Gravity ;Adaptation of "v=u+dV", change in velocity(dV) = at, where t=1
  Ground - 1 ;if equal to 1 then player is on a surface he can jump from
  y - Velocity
  
  ;-Horizontal movement
  ExamineKeyboard()
  If KeyboardPushed(#PB_Key_Left)
    x - 5
  ElseIf KeyboardPushed(#PB_Key_Right)
    x + 5
  EndIf
  WriteStringN(0,StrF(Velocity,4)+" ("+Str(x)+","+Str(y)+")")
  
  ;-Collision detection
  For I = 0 To n
    xx = p(I)\x
    yy = p(I)\y
  
    If (xx - 19)<x And x<(xx + 15) And (yy - playerHeight)<y And y<(yy + platformHeight) And Velocity<0 ;Collision with TOP of platform
      Ground=1
      newVelocity = -Velocity * #Elasticity
      y = yy - playerHeight
    EndIf
    If (xx - 19)<x And x<(xx + 15) And (yy - playerHeight)<y And y<(yy + platformHeight) And Velocity>0 ;Collision with BOTTOM of platform
      newVelocity= - Velocity * #Elasticity
      y = yy + platformHeight
    EndIf
    If (xx - diffWidth)<x  And x<(xx + platformWidth) And (yy - playerHeight)<y And y<(yy+platformHeight) ;Collision with RIGHT of platform
      x = xx + platformWidth
    EndIf
    If (xx - playerWidth)<x And x<(xx - diffWidth) And (yy - playerHeight)<y And y<(yy+platformHeight) ;Collision with LEFT of platform
      x = xx - playerWidth
    EndIf
  Next I
  If newVelocity <>0: Velocity = newVelocity: newVelocity =  0:EndIf
  
Until KeyboardPushed(#PB_Key_Escape)
End
ChebbyShabby
Enthusiast
Enthusiast
Posts: 121
Joined: Mon Jun 26, 2006 10:47 am

Post by ChebbyShabby »

interesting math, rook :D, but i don't think i'll need precise circular collision in a platform game with blocks lol. anyway, since this is turning to a modify-the-code thread, for anyone following/using this code, i've added a double-jump feature; new things are indicated with "*****":

Code: Select all

;-Physics variables 
;Gravity is based on the largest value that will keep the velocity <=43 pixels/frame when player is dropped 
;from a height of 480 pixels (screen height).  If velocity>43 the player will move through a platform and 
;collide with the next platform instead. Using formula "Vf^2 = Vi^2 + 2 * g * d" where Vi = 0,d = 480,Vf = 43 
;and solving for "g = (Vf^2) / (2 * d)".  This produces a range of 0<Gravity<=1.925.  The value is further 
;limited by the method for collision detection.  It limits the velocity that can be obtained when the player 
;is "not moving" for a single frame while on top of a platform (this value is 0.5 which will be rounded up to 
;a 1 because of floating point to integer conversion).  The change in velocity is greatest during a collison 
;because the direction of the velocity changes. It uses formula "(dV) = gt and/(1 + 1 / c)" where 
;dV = 0.5,t = 1,c = 5 (higher values of c represent a less elastic collision), simplifying and solving 
;for "g = .6".  The value for g is therefore now limited to the more restrictive range of 0<Gravity<=0.6 
;due to the collision method used. 
;Velocity for a Jump is based on what is range of values that will not cause the velocity to exceed 
;43 pixels/frame if the player Jumps from the highest point on the screen (y = 0).  Solving the above equation 
;for Vi gives us "Vi = sqr(Vf^2 - 2 * g * d)". Substituting we get "Vi = sqr(1849 - 960 * g)". The legal 
;values of velocity are 0 to the max value based on substituting our Gravity value and solving the equation 
;for Vi. 
#Elasticity = 1.0 / 5.0 ;what fraction of velocity remains after a collision 
#Gravity = 0.5 + 0.5 * #Elasticity ;legal values are 0<Gravity<=0.6 
#VelocityJump = 13 ;if (maxVelocity,Gravity)=(mV,g), maximum legal values are (35,0.6)<=(mV,g)<(43,0) 

Gravity.f = #Gravity ; 
Velocity.f = 0 
newVelocity.f = 0 

;***** - Double jump variables
DJTimer = 30 ;interval between double jumps
DJump = 2 ;2 jumps initially available

;-Load the level 
Procedure CountLines(file$) 
  If ReadFile(0,file$) 
    l = Lof(0) 
    m = AllocateMemory(l) 
    ReadData(0,m,l) 
    m$ = PeekS(m) 
    FreeMemory(m) 
    CloseFile(0) 
  EndIf; 
  ProcedureReturn CountString(m$,Chr(10))/2 
EndProcedure; 
n = CountLines("Level.txt")-1 

Dim p.Point(n) 

ReadFile(1,"Level.txt") 
For I=0 To n 
  p(I)\x=Val(ReadString(1)) 
  p(I)\y=Val(ReadString(1)) 
Next 
CloseFile(1) 

;-Prepare the screen 
InitKeyboard() 
InitSprite() 

OpenScreen(640,480,32,"") 
SetFrameRate(60) 

;-Prepare the sprites 
Enumeration 
  #Player 
  #Platform 
EndEnumeration 

LoadSprite(#Player,"Eraser.bmp") 
LoadSprite(#Platform,"Platform.bmp") 
playerHeight = SpriteHeight(#Player) 
playerWidth = SpriteWidth(#Player) 
platformHeight = SpriteHeight(#Platform) 
platformWidth = SpriteWidth(#Platform) 
diffWidth = (playerWidth - platformWidth) / 2 
diffHeight = (playerHeight - platformHeight) / 2 

Delay(2000)
y = -200
x = 30 
Repeat 
  FlipBuffers() 
  ClearScreen(RGB(0,0,0)) 
    
  ;-Display the level 
  For I = 0 To n 
      xx = p(I)\x 
      yy = p(I)\y 
      DisplayTransparentSprite(#Platform,xx,yy) 
  Next 
      
  DisplayTransparentSprite(#Player,x,y) 
  
  ;-Jump 
  ;If KeyboardPushed(#PB_Key_Space): Power = 10: EndIf 
  ExamineKeyboard()
  If KeyboardPushed(#PB_Key_Space)
    If DJump = 2: Velocity = #VelocityJump: DJump = 1: EndIf ;***** 1 jump remaining
    If DJTimer <= 0 And DJump = 1: Velocity = (#VelocityJump / 2): DJTimer = 30: DJump = 0: EndIf ;***** if the timer has reached 0
                                                                                                   ;and there is 1 remaining jump,
                                                                                                   ;jump again (with half the velocity)
                                                                                                   ;and reset settings
  EndIf
  
  ;-Jump physics 
  ;Velocity = Power - (Gravity * FlightTime) ;Adaptation of "v = u + at" 
  Velocity - Gravity ;Adaptation of "v=u+dV", change in velocity(dV) = at, where t=1 
  Ground - 1 ;if equal to 1 then player is on a surface he can jump from 
  y - Velocity 
  
  ;-Horizontal movement 
  ExamineKeyboard() 
  If KeyboardPushed(#PB_Key_Left) 
    x - 5 
  ElseIf KeyboardPushed(#PB_Key_Right) 
    x + 5 
  EndIf 
  ;WriteStringN(0,StrF(Velocity,4)+" ("+Str(x)+","+Str(y)+")") 
  
  StartDrawing(ScreenOutput())
    DrawText(1, 1, Str(DJump))
  StopDrawing()
  
  If Velocity<>0: If DJTimer => 0: DJTimer-1: EndIf: EndIf ;***** the timer goes down if we are not on a platform
  
  ;-Collision detection 
  For I = 0 To n 
    xx = p(I)\x 
    yy = p(I)\y 
  
    If (xx - 19)<x And x<(xx + 15) And (yy - playerHeight)<y And y<(yy + platformHeight) And Velocity<0 ;Collision with TOP of platform 
      Ground=1
      newVelocity = -Velocity * #Elasticity 
      y = yy - playerHeight
      DJump = 2 ;***** 2 jumps available
      DJTimer = 30 ;***** reset the delay for the second jump
    EndIf 
    If (xx - 19)<x And x<(xx + 15) And (yy - playerHeight)<y And y<(yy + platformHeight) And Velocity>0 ;Collision with BOTTOM of platform 
      newVelocity= - Velocity * #Elasticity 
      y = yy + platformHeight 
    EndIf 
    If (xx - diffWidth)<x  And x<(xx + platformWidth) And (yy - playerHeight)<y And y<(yy+platformHeight) ;Collision with RIGHT of platform 
      x = xx + platformWidth 
    EndIf 
    If (xx - playerWidth)<x And x<(xx - diffWidth) And (yy - playerHeight)<y And y<(yy+platformHeight) ;Collision with LEFT of platform 
      x = xx - playerWidth 
    EndIf 
  Next I 
  If newVelocity <>0: Velocity = newVelocity: newVelocity =  0:EndIf 
  
Until KeyboardPushed(#PB_Key_Escape) 
End
Post Reply