Calculating path from angle/power/gravity

Advanced game related topics
Godai
Enthusiast
Enthusiast
Posts: 171
Joined: Thu Oct 05, 2006 8:13 pm

Calculating path from angle/power/gravity

Post by Godai »

Hi. I'm doing a small scorched earth shooter for my son (with pirates) and I can't seem to remember the algorithm for shooting in an arc based on angle and power of cannon. (Affected by gravity ofcourse or else it would fire into outer space :))

Does anyone have a small example? Google didn´t turn up much usefull stuff, but admitted the time I have for it is short ;)

It's something with calculating y pos from the angle, then advancing in x with the power and then adding gravity to pull it towards earth... Or something...

Thanks in advance
User avatar
Joakim Christiansen
Addict
Addict
Posts: 2452
Joined: Wed Dec 22, 2004 4:12 pm
Location: Norway
Contact:

Post by Joakim Christiansen »

I think I can come up with something, wait a moment.
I like logic, hence I dislike humans but love computers.
Godai
Enthusiast
Enthusiast
Posts: 171
Joined: Thu Oct 05, 2006 8:13 pm

Post by Godai »

Wait wait. I got it. Using standard trig it should be easy enough. Using sin/cos with angle for drawing the cannon and then using sin/cos on the vector to shoot it in the right direction and then applying gravity to get it down again. The higher power, the slower gravity is applied :)

It's not an advanced math formula but it should do the trick.
I'd still be happy to see other peoples solutions though :)

Thanks
pjay
Enthusiast
Enthusiast
Posts: 288
Joined: Thu Mar 30, 2006 11:14 am

Post by pjay »

Yeah, that's how it's generally done.

Code: Select all

InitSprite() : InitKeyboard() : InitMouse()

gravity.f=0.1

ScreenWidth=640 : ScreenHeight=480 
CannonX=(ScreenWidth/2)-16 : CannonY=ScreenHeight-32

Structure missile
  posx.f
  posy.f
  vecx.f
  vecy.f
EndStructure

NewList missile.missile()

OpenWindow(0,0,0,ScreenWidth,ScreenHeight,"Angled shot example: Esc to exit.",#PB_Window_ScreenCentered)

OpenWindowedScreen(WindowID(0),0,0,ScreenWidth,ScreenHeight,1,0,0)
CreateSprite(0,32,32) : StartDrawing(SpriteOutput(0)) : Box(0,0,32,32,RGB(220,200,20)) : StopDrawing()
CreateSprite(1,4,4) : StartDrawing(SpriteOutput(1)) : Box(0,0,4,4,RGB(220,20,20)) : StopDrawing()

Procedure.f findangle(x1.f,y1.f,x2.f,y2.f) 
  Protected a.f,b.f,c.f
  a.f = x2-x1 
  b.f = y2-y1 
  c.f = Sqr(a*a+b*b) 
  angle.f = ACos(a/c)*57.29577 
  If y1 < y2 : angle=360.0-angle : EndIf 
  ProcedureReturn angle.f+90.0
EndProcedure    

Repeat
  Event.l = WindowEvent()    
  ExamineKeyboard() : ExamineMouse()
  
  FlipBuffers()

  ClearScreen(RGB(20,140,160))

  If MouseButton(#PB_MouseButton_Left) =0 And Fire=1
    angle=findangle(CannonX,CannonY,MouseX(),MouseY())
    AddElement(missile())
    missile()\posx=CannonX+16 : missile()\posy=CannonY
    Power.f=Sqr( (MouseX()-CannonX)*(MouseX()-CannonX) + (MouseY()-CannonY)*(MouseY()-CannonY) )/32.0
    missile()\vecx=0.0 + Power * Sin(angle* 3.14159265 / 180.0)
    missile()\vecy=0.0 + Power * Cos(angle* 3.14159265 / 180.0)
    Fire=0
  EndIf
  If MouseButton(#PB_MouseButton_Left) : Fire=1 : EndIf
  
  ; draw target line
  StartDrawing(ScreenOutput())
    LineXY(CannonX+16,CannonY, MouseX(), MouseY(),RGB(200,200,200))
  StopDrawing()
  
  ; update missile, bounce off of sides & kill if posy > screen
  ForEach missile()
    missile()\vecy + gravity
    If missile()\posx<0 : missile()\posx=0 : missile()\vecx=0-missile()\vecx : EndIf
    If missile()\posx>ScreenWidth : missile()\posx=ScreenWidth : missile()\vecx=0-missile()\vecx : EndIf
    missile()\posx+missile()\vecx : missile()\posy+missile()\vecy
    If missile()\posy>ScreenHeight : DeleteElement(missile()) : EndIf
  Next
  
  ; display missile sprites
  ForEach missile()
    DisplaySprite(1, missile()\posx, missile()\posy)
  Next
  
  ; draw 'cannon'
  DisplaySprite(0, CannonX, CannonY)
  
  Delay(16)
Until Event = #PB_Event_CloseWindow Or KeyboardPushed(#PB_Key_Escape)

End   
User avatar
Joakim Christiansen
Addict
Addict
Posts: 2452
Joined: Wed Dec 22, 2004 4:12 pm
Location: Norway
Contact:

Post by Joakim Christiansen »

I think this may be what you want:

Code: Select all

InitSprite()
OpenWindow(0,0,0,500,150,"",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0),0,0,500,150,0,0,0)

#RAD = 0.0175

X.f = 50
Y.f = 130
Speed.f = 3
Direction = 320
Gravity.f = 0.02
GravityDirection = 90

SpeedX.f + Cos(Direction*#RAD) * Speed
SpeedY.f + Sin(Direction*#RAD) * Speed

GravityX.f + Cos(GravityDirection*#RAD)
GravityY.f + Sin(GravityDirection*#RAD)

Repeat
  X + SpeedX
  Y + SpeedY
  
  GravityForce.f + Gravity
  X + GravityX * GravityForce
  Y + GravityY * GravityForce
  
  Delay(2): FlipBuffers(): ClearScreen(#Black)
  StartDrawing(ScreenOutput())
    Circle(X,Y,10,#Red)
  StopDrawing()
Until WindowEvent() = #PB_Event_CloseWindow
I like logic, hence I dislike humans but love computers.
Godai
Enthusiast
Enthusiast
Posts: 171
Joined: Thu Oct 05, 2006 8:13 pm

Post by Godai »

Ahh yes. Exactly!

Thank you both :)
Anonymous

Post by Anonymous »

Code: Select all

;/ ANGLES , DISTANCE & PROJECTILLES
;/ PUREBASIC 4.0
;/ Par Cpl.Bator

Structure VECTOR2   
  x.f
  y.f
EndStructure

Structure Projectille
  Position.VECTOR2       ; Position courante de notre projectille
  Origin.VECTOR2         ; Point de départ du projectille
  angle.f                ; Angle en degrée du projectille
  Vitesse.f              ; Vitesse du projectille
  Physic_Timer.f         ; Temps du projectille (la gravité est basé sur son temps de "vie")
EndStructure

Global NewList Ball.Projectille()

#GRAVITE = 9.8

;/INITIALISATION DES COMPOSANTS DIRECTX
InitSprite() : InitKeyboard() : InitMouse()
OpenWindow(0,0,0,800,600,"ANGLES ET DISTANCE",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
OpenWindowedScreen(WindowID(0),0,0,800,600,1,0,0)


Declare Distance(x1,y1,x2,y2)
Declare Return_Angle(x1.f,y1.f,x2.f,y2.f)
Declare ShootProjectille(x.f,y.f,angle.f,Force.f)      ; Procedure qui va servir à tirer un projectille
Declare DisplayProjectilles()   ; Procedure d'affichage et de gestion de nos projectilles
  



ShowCursor_(1)

Repeat
  event.l = WindowEvent()
  ClearScreen(0)  : ExamineMouse() : ExamineKeyboard()
  
  _Distance.l = Distance(MouseX(),MouseY(),0,600)
  _Angle.f    = Return_Angle(0,600,MouseX(),MouseY())
  
  StartDrawing(ScreenOutput())
  
  ;INFOS 
  Box(0,0,182,62,RGB(255,255,255)) 
  Box(0,0,180,60,RGB(10,10,200)) 
  DrawingMode(#PB_2DDrawing_Transparent)
  FrontColor(RGB(0,128,255))
  DrawText(0,0 ,"DISTANCE (pixel) = "+Str(_Distance))
  DrawText(0,20,"ANGLE (degrée)   = "+Str(_Angle))
  DrawText(0,40,"CLICK FOR SHOOT!")
  
  
  ;TRACAGE DE LIGNE
  
  LineXY(0,600,MouseX(),MouseY(),RGB(255,0,0))
  
  StopDrawing()
  
  If MouseButton(#PB_MouseButton_Left)<>0 And Flag.b=0 
      Flag=1
      ShootProjectille(0,600,_Angle,_Distance)
    EndIf 
    
    If MouseButton(#PB_MouseButton_Left)=0 And Flag=1 
      Flag=0
    EndIf 
    
    
    
    DisplayProjectilles()
    
    FlipBuffers()
  Until event = #PB_Event_CloseWindow Or KeyboardPushed(#PB_Key_Escape)
  
  End
  
  
  
  ;/PROCEDURES MATHEMATIQUES
  
  Procedure Distance(x1,y1,x2,y2)
    Protected Result.f
    Result = Sqr(  (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)  )
    ProcedureReturn Result
  EndProcedure
  
  Procedure Return_Angle(x1.f,y1.f,x2.f,y2.f) ; DEGREE
    A.f = x1-x2
    B.f = y1-y2
    C.f = -Sqr(A*A+B*B)
    angle.f = ACos(A/C)*180/#PI
    If y1 < y2 : angle=360-angle : EndIf
      ProcedureReturn Abs(angle - 360)
    EndProcedure
    
    ;/GESTION DES PROJECTILLES
    Procedure ShootProjectille(x.f,y.f,angle.f,Force.f)
      AddElement(Ball())
      
      With Ball()
        \Origin\x = x
        \Origin\y = y
        \angle    = angle
        \Vitesse  = Force/2
      EndWith
      
    EndProcedure
    
    
    Procedure DisplayProjectilles()
      StartDrawing(ScreenOutput())
      ForEach Ball()
        With Ball()
          
          ;Gestion de la courbe
          \Position\x = \Origin\x + (\Vitesse*Cos((\angle)*#PI/180)*\Physic_Timer)
          \Position\y = \Origin\y + (\Vitesse*Sin((\angle)*#PI/180)*\Physic_Timer)+(0.5*#GRAVITE*(\Physic_Timer*\Physic_Timer))
          \Physic_Timer + 0.1             
          
          Circle(\Position\x,\Position\y,2,RGB(255,255,255))
          
          
          
          If \Position\y > 600 
            \angle = 360-\angle    ;/ Attention, le 360-angle ne fonctionne qu'avec le bas de l'écran, et oui, c'est trop facile sinon :D 
            \Physic_Timer = 0      ;/ imaginer que votre balle arrive avec un angle de 45° (vers le bas-droite) , elle doit repartir vers 
            \Origin\x= \Position\x ;/ un angle de 315° (360-45), je ne vais pas rentrer dans les détails, pour être au top, il faut utilisé les vecteurs
            \Origin\y= 600         ;/ et les normales d'une boite de collision, mais bon... on verra ca plus tard... :D 
            
            \Vitesse - 2   
          EndIf 
          
          
          
          
          ;Gestion de la sorite de l'écran 
        If \Position\x >800 Or \Vitesse<=0
            DeleteElement(Ball())
          EndIf
          
        EndWith 
      Next
      StopDrawing()
    EndProcedure
Try this :wink:
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

Cpl.Bator wrote:;/ Attention, le 360-angle ne fonctionne qu'avec le bas de l'écran, et oui, c'est trop facile sinon :D
;/ imaginer que votre balle arrive avec un angle de 45° (vers le bas-droite) , elle doit repartir vers
;/ un angle de 315° (360-45), je ne vais pas rentrer dans les détails, pour être au top, il faut utilisé les vecteurs
;/ et les normales d'une boite de collision, mais bon... on verra ca plus tard... :D
with all due respect, dear friend, I would kindly ask you to commend your code in english since this is an international forum.
It is hard enough to be confronted with french variable-names, what happens now and then,
but long comments should be translated. I don't commend codes I post here in german, neither.
oh... and have a nice day.
Anonymous

Post by Anonymous »

i have'nt the time for translate this code in english , sorry
User avatar
DoubleDutch
Addict
Addict
Posts: 3220
Joined: Thu Aug 07, 2003 7:01 pm
Location: United Kingdom
Contact:

Post by DoubleDutch »

I have no problems with that, like the code btw. :D
https://deluxepixel.com <- My Business website
https://reportcomplete.com <- School end of term reports system
Anonymous

Post by Anonymous »

i remove comments and rename variables and constant... :?

Code: Select all

;/ ANGLES , DISTANCE & Missiles
;/ PUREBASIC 4.0
;/ Par Cpl.Bator

Structure VECTOR2   
  x.f
  y.f
EndStructure

Structure Missile
  Position.VECTOR2       ; current Position of Missile
  Origin.VECTOR2         ; Origin of Missile
  angle.f                ; Angle of Missile
  Speed.f                ; Speed of Missile
  Physic_Timer.f         ; Time to life
EndStructure

Global NewList Ball.Missile()

#GRAVITY = 9.8

;/INITIALISATION DES COMPOSANTS DIRECTX
InitSprite() : InitKeyboard() : InitMouse()
OpenWindow(0,0,0,800,600,"ANGLES ET DISTANCE",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
OpenWindowedScreen(WindowID(0),0,0,800,600,1,0,0)


Declare Distance(x1,y1,x2,y2)
Declare Return_Angle(x1.f,y1.f,x2.f,y2.f)
Declare ShootMissile(x.f,y.f,angle.f,Force.f)      ; Proc for shoot missile
Declare DisplayMissiles()   ; Proc for display missile
 



ShowCursor_(1)

Repeat
  event.l = WindowEvent()
  ClearScreen(0)  : ExamineMouse() : ExamineKeyboard()
  
  _Distance.l = Distance(MouseX(),MouseY(),0,600)
  _Angle.f    = Return_Angle(0,600,MouseX(),MouseY())
  
  StartDrawing(ScreenOutput())
  
  ;INFOS
  Box(0,0,182,62,RGB(255,255,255))
  Box(0,0,180,60,RGB(10,10,200))
  DrawingMode(#PB_2DDrawing_Transparent)
  FrontColor(RGB(0,128,255))
  DrawText(0,0 ,"DISTANCE (pixel) = "+Str(_Distance))
  DrawText(0,20,"ANGLE (degrée)   = "+Str(_Angle))
  DrawText(0,40,"CLICK FOR SHOOT!")
  
  
  ;TRACAGE DE LIGNE
  
  LineXY(0,600,MouseX(),MouseY(),RGB(255,0,0))
  
  StopDrawing()
  
  If MouseButton(#PB_MouseButton_Left)<>0 And Flag.b=0
    Flag=1
    ShootMissile(0,600,_Angle,_Distance)
  EndIf
  
  If MouseButton(#PB_MouseButton_Left)=0 And Flag=1
    Flag=0
  EndIf
  
  
  
  DisplayMissiles()
  
  FlipBuffers()
Until event = #PB_Event_CloseWindow Or KeyboardPushed(#PB_Key_Escape)
 
End
 
 
 
  ;/PROCEDURES MATHEMATIQUES
 
Procedure Distance(x1,y1,x2,y2)
  Protected Result.f
  Result = Sqr(  (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)  )
  ProcedureReturn Result
EndProcedure
 
Procedure Return_Angle(x1.f,y1.f,x2.f,y2.f) ; DEGREE
  A.f = x1-x2
  B.f = y1-y2
  C.f = -Sqr(A*A+B*B)
  angle.f = ACos(A/C)*180/#PI
  If y1 < y2 : angle=360-angle : EndIf
  ProcedureReturn Abs(angle - 360)
EndProcedure
   
    ;/GESTION DES MissileS
Procedure ShootMissile(x.f,y.f,angle.f,Force.f)
  AddElement(Ball())
  
  With Ball()
    \Origin\x = x
    \Origin\y = y
    \angle    = angle
    \Speed  = Force/2
  EndWith
  
EndProcedure
   
   
Procedure DisplayMissiles()
  StartDrawing(ScreenOutput())
  ForEach Ball()
    With Ball()
      
      ;Gestion de la courbe
      \Position\x = \Origin\x + (\Speed*Cos((\angle)*#PI/180)*\Physic_Timer)
      \Position\y = \Origin\y + (\Speed*Sin((\angle)*#PI/180)*\Physic_Timer)+(0.5*#GRAVITY*(\Physic_Timer*\Physic_Timer))
      \Physic_Timer + 0.1             
      
      Circle(\Position\x,\Position\y,2,RGB(255,255,255))
      
      
      
      If \Position\y > 600
        \angle = 360-\angle   
        \Physic_Timer = 0     
        \Origin\x= \Position\x 
        \Origin\y= 600         
        
        \Speed - 2   
      EndIf
      
      
      
      
      ;Out of screen
      If \Position\x >800 Or \Speed<=0
        DeleteElement(Ball())
      EndIf
      
    EndWith
  Next
  StopDrawing()
EndProcedure

ps: Sorry for the header of code
;/ ANGLES , DISTANCE & Missiles
;/ PUREBASIC 4.0
;/ Par Cpl.Bator
Par = By
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

didn't want to upset you :oops:

I just felt a little unconvenient about the comments I didn't understand... :cry:


it's really good code, clear, descriptive, good to learn from.
thanks for sharing.
oh... and have a nice day.
Derek
Addict
Addict
Posts: 2354
Joined: Wed Apr 07, 2004 12:51 am
Location: England

Post by Derek »

See this article from Wiki

http://en.wikipedia.org/wiki/Trajectory_of_a_projectile

Scroll down to the picture showing the arc of a projectile to see the difference between plotting a parabolic curve and what really happens!

Cpl.Bator program, although very good and actually quite fun, plots a parabolic.
User avatar
DoubleDutch
Addict
Addict
Posts: 3220
Joined: Thu Aug 07, 2003 7:01 pm
Location: United Kingdom
Contact:

Post by DoubleDutch »

Cpl.Bator: I liked it better with the comments. Can you put them back. ;)
https://deluxepixel.com <- My Business website
https://reportcomplete.com <- School end of term reports system
User avatar
Comtois
Addict
Addict
Posts: 1432
Joined: Tue Aug 19, 2003 11:36 am
Location: Doubs - France

Post by Comtois »

here an old one (fast update for V4.02), added wind and mass.
Use cursor and [ENTER] to shoot.

http://herved25.free.fr/sources/Canon2.zip

Sorry , it's in french :?
Please correct my english
http://purebasic.developpez.com/
Post Reply