Page 2 of 2

Posted: Sat Dec 20, 2003 12:18 pm
by Psychophanta
Nice examples :)

There are another alternative, which could be much easier to understand than the trigonometric functions use (Sin, Cos, Tan, ATan, etc), which consist in check each quadrant (upleft, upright, downleft and downright) and relation between coords (this is y/x).
Trigonometric isn't needed.

Posted: Sat Dec 20, 2003 1:58 pm
by DriakTravo
Thank you SOOOO much! Here is another example:

Code: Select all

InitSprite()
InitMouse()

OpenScreen(800,600,32,"")

Structure bullet
  X.f
  Y.f
  XS.f
  YS.f
EndStructure

NewList bullets.bullet()

Procedure Addbullet(X.f,Y.f,XS.f,YS.f)
  AddElement(Bullets())
  Bullets()\X = X
  Bullets()\Y = Y
  Bullets()\XS = XS
  Bullets()\YS = YS
EndProcedure

Global mouseangle, BulletSpeed
BulletSpeed = 20

Procedure.f GetMouseAngle() 
  ExamineMouse()
  x1 = 400
  y1 = 300
  x2 = MouseX()
  y2 = MouseY()
  a.f = x2-x1 
  b.f = y2-y1 
  c.f = Sqr(a*a+b*b) 
  winkel.f = ACos(a/c)*57.29577 
  If y1 < y2 : winkel=360-winkel : EndIf 
  ProcedureReturn winkel+90
EndProcedure

Repeat
  ClearScreen(0,0,0)
  ExamineMouse()
  
  If CountList(bullets()) > 1
    ResetList(Bullets())
    While NextElement(Bullets())
      StartDrawing(ScreenOutput())
        Line(Bullets()\X,Bullets()\Y,Bullets()\XS,Bullets()\YS,RGB(Random(150),Random(255),0))
      StopDrawing()
      Bullets()\X + Bullets()\XS
      Bullets()\Y + Bullets()\YS
      If Bullets()\X > 800 + Bullets()\XS
        DeleteElement(Bullets())
      EndIf
      If Bullets()\X < 0 - Bullets()\XS
        DeleteElement(Bullets())
      EndIf
      If Bullets()\Y > 600 + Bullets()\YS
        DeleteElement(Bullets())
      EndIf
      If Bullets()\Y < 0 - Bullets()\YS
        DeleteElement(Bullets())
      EndIf
    Wend
  EndIf
  
  StartDrawing(ScreenOutput())
    Circle(MouseX(),MouseY(),2,RGB(0,255,255))
  StopDrawing()
  
  If MouseButton(2) = 1
    End
  ElseIf MouseButton(1) = 1
    Angle.f = GetMouseAngle()
    SpeedX.f = Sin(Angle*(3.14/180))*Bulletspeed
    SpeedY.f = Cos(Angle*(3.14/180))*Bulletspeed
    dudecounter + 1
    If dudecounter = 10
      dudecounter = 0
      Addbullet(400,300,SpeedX,SpeedY)
      Angle.f = GetMouseAngle()+10
      SpeedX.f = Sin(Angle*(3.14/180))*Bulletspeed
      SpeedY.f = Cos(Angle*(3.14/180))*Bulletspeed
      Addbullet(400,300,SpeedX,SpeedY)
      Angle.f = GetMouseAngle()+350
      SpeedX.f = Sin(Angle*(3.14/180))*Bulletspeed
      SpeedY.f = Cos(Angle*(3.14/180))*Bulletspeed
      Addbullet(400,300,SpeedX,SpeedY)
      beep_(500,1)
    EndIf 
  EndIf
  
  FlipBuffers()
ForEver

Posted: Sat Dec 20, 2003 2:58 pm
by Psychophanta
Here you have a NOT TRIGONOMETRIC based method to obtain angle (faster for those CPUs without FPU, and perhaps for all CPUs).
I've just replaced gATan() ChaOsKid first example (posted above by Danilo) by mine without trigonometric functions: getangle().
Result is not so accurate because the angle value is obtained with lineal relation (not angular relation) between both coords.

Code: Select all

; 
; by ChaOsKid, 27.06.03  - german forum 
; 
; http://www.robsite.de/php/pureboard/viewtopic.php?t=1518
;
;Modified Angle obtain method (needed for RotateSprite3D() parameter) WITHOUT USING TRIGONOMETRY (by Psychophanta): 

Procedure.f getangle(a.f,b.f)
  If Abs(b)>Abs(a)
    winkel.f=(a/b)*45
    If b<0:winkel+180:EndIf
  Else
    winkel.f=90-((b/a)*45)
    If a<0:winkel.f+180:EndIf
  EndIf
  If winkel<0:winkel+360:EndIf 
  ProcedureReturn winkel 
EndProcedure 

If InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0 
  MessageRequester("Error", "DirectX 7 Fehler!", 0) 
  End 
EndIf 

Breite = 800 
Hoehe = 600 

If OpenScreen ( Breite, Hoehe,32,"Standard") = 0 
  MessageRequester("Error", "Es konnte kein Bildschirm aufgebaut werden", 0) 
  End 
EndIf 

If InitSprite3D() = 0 
  MessageRequester("DirectX fehler !", "Fehler", #PB_MessageRequester_Ok) 
  End 
EndIf 


CreateSprite(0, 50, 50, #PB_Sprite_Texture) 
StartDrawing(SpriteOutput(0)) 
  Box(0, 0, 50, 50, RGB(155, 155, 55)) 
  FrontColor(240, 240, 240) 
  DrawingMode(1) 
  Locate(10, 10) 
  DrawText("CK") 
StopDrawing() 

Sprite3DQuality(1) 

CreateSprite3D(0, 0) 

Repeat 
  ClearScreen(0, 0, 0) 
  ExamineMouse() 
  ; a = grün 
  a.w = MouseY() - Hoehe/2 
  ; b = rot 
  b.w = MouseX() - Breite/2 
  winkel.w = getangle(a, b) 

  Start3D() 
    RotateSprite3D(0, Winkel, 0) 
    DisplaySprite3D(0, Breite/2 - 25, Hoehe/2 - 25) 
  Stop3D() 
  
  StartDrawing(ScreenOutput()) 
    ; a = grün 
    LineXY(MouseX(), MouseY(), MouseX(), Hoehe/2, $00F000) 
    ; b = rot 
    LineXY(MouseX(), Hoehe/2, Breite/2, Hoehe/2, $0000F0) 
    ; c = blau 
    LineXY(Breite/2, Hoehe/2, MouseX(), MouseY(),$500000) 
    DrawingMode(1) 
    FrontColor(255, 0, 0) 
    Locate(MouseX(), Hoehe/2 + 1) 
    DrawText("b: " + Str(b)) 
    FrontColor(0, 255, 0) 
    Locate(MouseX() + 1, MouseY()) 
    DrawText("a: " + Str(a)) 
    FrontColor(255, 255, 255) 
    Locate(Breite/2, Hoehe/2 + 25) 
    DrawText(Str(winkel) + " Grad") 
  StopDrawing() 
  FlipBuffers() 
  
  If ExamineKeyboard() 
    If KeyboardPushed(#PB_Key_Escape) 
      Quit = 1 
    EndIf 
  EndIf 
  Delay(10) 
Until Quit

Posted: Sat Dec 20, 2003 4:27 pm
by Psychophanta
DriakTravo.
I have seen your example.

Please try to understand this: In my previous post i search angle value just because RotateSprite3D need it, no other reason.

To do your matter:
-Lets suppose the target (T) point coords are (t1,t2), and the gunner (G)coords are (g1,g2).
-Well; now you must to know vector G->T; this is vector (t1-g1,t2-g2). Let v1=t1-g1 and v2=t2-g2.
-And now you must get the bullet movement vector (direction and speed):
simply just assign bullet speed (the speed you want; for example 20 pixels per frame) to that vector; this means getting a new vector with same direction but with modulo=speed.
To do that, lets M(m1,m2) the bullet movement vector:
m1=20/sqr(1+(v2*v2)/(v1*v1))
m2=20/sqr(1+(v1*v1)/(v2*v2))
-Now for each screen frame, add m1 value to bullet x coordenate and m2 value to bullet y coordenate. That's all :D

-Finally, if you want to shoot not only directly to target, but near target too, then you must get a perpendicular vector of G->T; this is (-v2,v1) to one side, and (v2,-v1) to the other side of target. And of course, you must "cut" (or "enlarge") the lenght (modulo) of that vector to the distance you want the bullets to pass near target.
For example, if you want those bullets to be directed to pass always at 15 pixels side from target, you must positionate a fictitious target at (fr1,fr2), being:
fr1=-15/sqr(1+(v1*v1)/(v2*v2))
fr2=15/sqr(1+(v2*v2)/(v1*v1))
and another at the other side of the target (fl1,fl2), being:
fl1=15/sqr(1+(v1*v1)/(v2*v2))
fl2=-15/sqr(1+(v2*v2)/(v1*v1))
and add this vectors to target position in order to get the fictitious target position and throw bullets there.
But if for example you want those bullets to be directed to pass near target to a distance which depends of target distance to gunner, then you must stablish relationship between distance from gunner; for example let be the relation 1/20 (this is, if there are 200 pixels from gunner to target, then bullets must be directed to 10 pixels at side of target). Then:
fr1=(1/20)*-v2
fr2=(1/20)*v1
and for the other side of target:
fl1=(1/20)*v2
fr2=(1/20)*-v1
and then add this vectors to target position in order to get the fictitious target position and throw bullets there.


If someone knows a best, process fastest, simplest .... way to do all this kind of things, please explain it.