Automatische Bewegung von 2D Spielfiguren
- Vermilion
- Beiträge: 1846
- Registriert: 08.04.2006 16:00
- Computerausstattung: Apple iMac (2010) & HP Notebook
- Wohnort: Heidekreis
Automatische Bewegung von 2D Spielfiguren
Ja hallo erstmal, ich weiß ja nicht, ob ihr es schon wusstet, aber ich arbeite wieder an einem Spiel. Nun aber nicht mehr an dem was ich als "Frozen Heart" ankündigte, da ich 3D Programmierung unter PureBasic für "hoffnungslos" erklärte, sondern an einem 2D Spiel, wo ich auch Sprite3D ausnutzen kann etc.
So.
Nun ist es so, ich habe eine Spielfigur, die soll sich bewegen können. Aber nicht auf Kommando, also nicht wenn man eine Taste drückt, sondern sie hat eine bestimmt Position und eine bestimmte Zielposition(/Koordinate). Und auf diese bestimmte Zielposition soll sie sich nun direkt zu bewegen, in einem bestimmten Tempo. Die Zielposition unterscheidet sich von der Position der Einheit in der X- und Y-Achse.
Oder anders gesagt; kann mir jemand erklären, wie Stargate es in Dune mit seinen Fahrzeugen bzw. <IchkannmirseinenNamenniemerken> (Thomas?) es in Real FARM geschafft hat?
So.
Nun ist es so, ich habe eine Spielfigur, die soll sich bewegen können. Aber nicht auf Kommando, also nicht wenn man eine Taste drückt, sondern sie hat eine bestimmt Position und eine bestimmte Zielposition(/Koordinate). Und auf diese bestimmte Zielposition soll sie sich nun direkt zu bewegen, in einem bestimmten Tempo. Die Zielposition unterscheidet sich von der Position der Einheit in der X- und Y-Achse.
Oder anders gesagt; kann mir jemand erklären, wie Stargate es in Dune mit seinen Fahrzeugen bzw. <IchkannmirseinenNamenniemerken> (Thomas?) es in Real FARM geschafft hat?
-
- Beiträge: 17389
- Registriert: 10.11.2004 03:22
für luftlinien-wege ist das supereinfach,
für wege mit hindernissen brauchst du einen PathFind-algo
auf jeden fall läuft es darauf hinaus, dass du einen weg vorberechnest,
und für deine spielfigur schritte pro zeiteinheit angibst.
bei luftline bewegst du halt deine figur in jedem step um einen teilschritt der verbindung.
also z.b., wenn dein zielpunkt 200/300 entfernt ist, bewegst du die figur um jeweils 2/3,
und bist nach 100 steps angekommen.
für wege mit hindernissen brauchst du einen PathFind-algo
auf jeden fall läuft es darauf hinaus, dass du einen weg vorberechnest,
und für deine spielfigur schritte pro zeiteinheit angibst.
bei luftline bewegst du halt deine figur in jedem step um einen teilschritt der verbindung.
also z.b., wenn dein zielpunkt 200/300 entfernt ist, bewegst du die figur um jeweils 2/3,
und bist nach 100 steps angekommen.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Der Weise weiß, dass er ein Narr ist.
- Vermilion
- Beiträge: 1846
- Registriert: 08.04.2006 16:00
- Computerausstattung: Apple iMac (2010) & HP Notebook
- Wohnort: Heidekreis
Jo, Luftlinie will ich haben, das ist auch bis jetzt die Grundidee des Spiels (Flugzeuge).
Mh, ich schlug mich schon mit der Meshbewegung auf der X- Y-Achse in einer Map rum und hab es nie gebacken gekriegt.
Damit ich das richtig geschnallt habe:
Die X und Y Differenz immer um die Schrittzahl teilen um einen Schritt/Bewegung zu erhalten. Oder?
Edit:
Wie ermittele ich denn den Winkel, der zur aktuellen Sicht der Figur (nehmen wir mal nun 0°, einfach entlang der X-Achse) und der Zielkoordinate?
Mh, ich schlug mich schon mit der Meshbewegung auf der X- Y-Achse in einer Map rum und hab es nie gebacken gekriegt.
Damit ich das richtig geschnallt habe:
Die X und Y Differenz immer um die Schrittzahl teilen um einen Schritt/Bewegung zu erhalten. Oder?
Edit:
Wie ermittele ich denn den Winkel, der zur aktuellen Sicht der Figur (nehmen wir mal nun 0°, einfach entlang der X-Achse) und der Zielkoordinate?
-
- Beiträge: 17389
- Registriert: 10.11.2004 03:22
schau dir maln bissel trigonometrie in der Wikipedia an, und den Pythagoras.
der tangens ist definiert als gegenkathete durch ankathete.
für deine figur wäre also Y durch X = tangens zielwinkel,
also zielwinkel = arcustangens von Y / X
das liefert dir nen winkel zwischen 0° und 90°,
in welchem viertelkreis du dich befindest ermittelst du durch die vorzeichen.
(X und Y sind hier abstand zum zielpunkt, is klar)
der luftlinienabstand ist wurzel aus ( X² + Y² ),
das ist der Pythagoras...
wenn du vorab den winkel hast,
dann ist x-abstand = Sinus vom luftlinienabstand,
und y-abstand = Cosinus vom luftlinienabstand.
der tangens ist definiert als gegenkathete durch ankathete.
für deine figur wäre also Y durch X = tangens zielwinkel,
also zielwinkel = arcustangens von Y / X
das liefert dir nen winkel zwischen 0° und 90°,
in welchem viertelkreis du dich befindest ermittelst du durch die vorzeichen.
(X und Y sind hier abstand zum zielpunkt, is klar)
der luftlinienabstand ist wurzel aus ( X² + Y² ),
das ist der Pythagoras...
wenn du vorab den winkel hast,
dann ist x-abstand = Sinus vom luftlinienabstand,
und y-abstand = Cosinus vom luftlinienabstand.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Der Weise weiß, dass er ein Narr ist.
Hier hast du ein Beispiel von mir :
!Erneuert!
Das Ergibnis des ganzen wird sein :
Der BOT dreht sich elegant richtung Ziel (Die Maus) und beschleunigt sobalt er die ungefaire Richtung hat.
Wenn er nahe dran ist bremst er wieder ab.
Code: Alles auswählen
InitSprite()
InitKeyboard()
InitMouse()
OpenScreen(1024, 768, 32, "Bot 1.0")
b.f = 3.14159265/180
Bot_x.f = 512
Bot_y.f = 386
Bot_v.f = 0
Bot_w.f = 0
Bot_dw.f = 0
a = 1
max_v = 50
Repeat
ExamineMouse()
MouseX = MouseX()
MouseY = MouseY()
FlipBuffers()
ClearScreen(0,0,0)
StartDrawing(ScreenOutput())
Bot_x = Bot_x + Cos(Bot_w*b)*Bot_v*0.1
Bot_y = Bot_y + Sin(Bot_w*b)*Bot_v*0.1
Bot_w = Bot_w + Bot_dw
While Bot_w < 0 : Bot_w + 360 : Wend
While Bot_w >= 360 : Bot_w - 360 : Wend
deX = MouseX-Bot_x
deY = MouseY-Bot_y
If deX = 0 :
If deY < 0 : Winkel = -90 : EndIf
If deY >= 0 : Winkel = 90 : EndIf
Else
Winkel = ATan(deY/deX)/b
If deX < 0 : Winkel + 180 : EndIf
EndIf
Unterschied = Winkel-Bot_w
If Unterschied > 180 : Unterschied = Unterschied - 360 : EndIf
If Unterschied < -180 : Unterschied = Unterschied + 360 : EndIf
If Unterschied > 0 And Unterschied <= 180 : Bot_dw = Unterschied/10 : EndIf
If Unterschied < 0 And Unterschied >= -180 : Bot_dw = Unterschied/10 : EndIf
If Bot_dw > 45 : Bot_dw = 45 : ElseIf Bot_dw < -45 : Bot_dw = -45 : EndIf
If Bot_v > Sqr((Sqr(Pow(deX,2)+Pow(deY,2)))*2*a) : If Bot_v > 0 : Bot_v = Bot_v - a : EndIf : EndIf
If Bot_v < Sqr((Sqr(Pow(deX,2)+Pow(deY,2)))*2*a) : If Bot_v < max_v : Bot_v = Bot_v + a : EndIf : EndIf
;Bot
Circle(Bot_x, Bot_y, 10, RGB(255,255,255))
LineXY(Bot_x, Bot_y, Bot_x+Cos(Bot_w*b)*20, Bot_y+Sin(Bot_w*b)*20)
;Maus
Circle(MouseX, MouseY, 5, RGB(128,128,128))
StopDrawing()
ExamineKeyboard()
Until KeyboardReleased(#PB_Key_Escape) <> 0
End
Das Ergibnis des ganzen wird sein :
Der BOT dreht sich elegant richtung Ziel (Die Maus) und beschleunigt sobalt er die ungefaire Richtung hat.
Wenn er nahe dran ist bremst er wieder ab.
Zuletzt geändert von STARGÅTE am 02.04.2007 19:20, insgesamt 3-mal geändert.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
-
- Beiträge: 17389
- Registriert: 10.11.2004 03:22
coole demo
...für 4.0x muss nur bei ClearScreen von drei auf ein argument geändert werden....
aber sag mal.. er bremst bei mir irgendwie nicht rechtzeitig,
der fährt immer noch drüber weg und macht nen schlenker...
ist das absicht oder nur n side-effekt von quick'n'dirty?

...für 4.0x muss nur bei ClearScreen von drei auf ein argument geändert werden....
aber sag mal.. er bremst bei mir irgendwie nicht rechtzeitig,
der fährt immer noch drüber weg und macht nen schlenker...
ist das absicht oder nur n side-effekt von quick'n'dirty?
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Der Weise weiß, dass er ein Narr ist.
Das rechtzeitige abbremsen kann man beeinflussen:
An der stelle :
muss man ändern zu
Dabei müsste "Wert" zwischen 0 und 50 sein, muss man selber austesten.
Damit "verschiebe ich das Ziel" und der Bot bleibt früher stehn
oder mit der echten Beschleunigungsformel:
Dabei ist dann a der Beschleunigungswert (bei mir 1)
PS: Ich habe es oben geändert
An der stelle :
Code: Alles auswählen
...
If Bot_v > Sqr(Pow(deX,2)+Pow(deY,2))/2 : If Bot_v > 0 : Bot_v = Bot_v - 1 : EndIf : EndIf
If Bot_v < Sqr(Pow(deX,2)+Pow(deY,2))/2 : If Bot_v < 50 : Bot_v = Bot_v + 1 : EndIf : EndIf
...
Code: Alles auswählen
...
If Bot_v > (Sqr(Pow(deX,2)+Pow(deY,2))-Wert)/2 : If Bot_v > 0 : Bot_v = Bot_v - 1 : EndIf : EndIf
If Bot_v < (Sqr(Pow(deX,2)+Pow(deY,2))-Wert)/2 : If Bot_v < 50 : Bot_v = Bot_v + 1 : EndIf : EndIf
...
Damit "verschiebe ich das Ziel" und der Bot bleibt früher stehn
oder mit der echten Beschleunigungsformel:
Code: Alles auswählen
...
If Bot_v > Sqr((Sqr(Pow(deX,2)+Pow(deY,2)))*2*a) : If Bot_v > 0 : Bot_v = Bot_v - a : EndIf : EndIf
If Bot_v < Sqr((Sqr(Pow(deX,2)+Pow(deY,2)))*2*a) : If Bot_v < 50 : Bot_v = Bot_v + a : EndIf : EndIf
...
PS: Ich habe es oben geändert

PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
- Vermilion
- Beiträge: 1846
- Registriert: 08.04.2006 16:00
- Computerausstattung: Apple iMac (2010) & HP Notebook
- Wohnort: Heidekreis
Moin. Ich habe mal mit dem Code ein bisschen rumhantiert. Aber nur ein bisschen, hatte nicht viel Zeit in der Woche.
Nun habe ich eine Frage:
Das Sprite wackelt ziemlich stark kurz bevor es sein Zeil erreicht hat. Wie kriege ich hin, dass dies nicht geschieht?
Der Code sieht jetzt so aus:
Sprite ist hier:

Nun habe ich eine Frage:
Das Sprite wackelt ziemlich stark kurz bevor es sein Zeil erreicht hat. Wie kriege ich hin, dass dies nicht geschieht?
Der Code sieht jetzt so aus:
Code: Alles auswählen
UsePNGImageDecoder()
If InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0 Or InitSprite3D() = 0 Or OpenScreen(1280, 1024, 32, "Bot 1.0") = 0
MessageRequester("Error", "Konnte nicht initialisieren.", 0)
EndIf
If CreateSprite3D(0, LoadSprite(#PB_Any, "f15.png", #PB_Sprite_AlphaBlending | #PB_Sprite_Texture)) = 0
CloseScreen()
MessageRequester("Error", "Konnte Sprite nicht laden.", 0)
End
EndIf
b.f = 3.14159265/180
Bot_x.f = 640.0
Bot_y.f = 512.0
Bot_v.f = 0.0
Bot_w.f = 0.0
Bot_dw.f = 0.0
DestinationX = Bot_x
DestinationY = Bot_y
a.f = 0.01
max_v.f = 0.01
Sprite3DQuality(1)
Repeat
ExamineKeyboard()
If ExamineMouse() = 0
CloseScreen()
MessageRequester("Error", "Konnte Mausstatus nicht aktualisieren.", 0)
End
EndIf
MouseX = MouseX()
MouseY = MouseY()
ClearScreen(0)
Bot_x = Bot_x+Cos(Bot_w*b)*Bot_v*0.1
Bot_y = Bot_y+Sin(Bot_w*b)*Bot_v*0.1
Bot_w = Bot_w + Bot_dw
While Bot_w < 0
Bot_w + 360
Wend
While Bot_w >= 360
Bot_w - 360
Wend
deX = DestinationX-Bot_x
deY = DestinationY-Bot_y
If deX = 0
If deY < 0
Winkel = -90
EndIf
If deY >= 0
Winkel = 90
EndIf
Else
Winkel = ATan(deY/deX)/b
If deX < 0
Winkel + 180
EndIf
EndIf
Unterschied = Winkel-Bot_w
If Unterschied > 180
Unterschied = Unterschied - 360
EndIf
If Unterschied < -180
Unterschied = Unterschied + 360
EndIf
If Unterschied > 0 And Unterschied <= 180
Bot_dw = 2+Unterschied/10
EndIf
If Unterschied < 0 And Unterschied >= -180
Bot_dw = -2+Unterschied/10
EndIf
If Bot_dw > 45
Bot_dw = 45
ElseIf Bot_dw < -45
Bot_dw = -45
EndIf
If Bot_v > Sqr((Sqr(Pow(deX,2)+Pow(deY,2)))*2*a)
If Bot_v > 0
Bot_v = Bot_v - a
EndIf
EndIf
If Bot_v < Sqr((Sqr(Pow(deX,2)+Pow(deY,2)))*2*a)
If Bot_v < 50
Bot_v = Bot_v + a
EndIf
EndIf
If StartDrawing(ScreenOutput()) <> 0
If MouseButton(1)
Brightness = 255
DestinationX = MouseX
DestinationY = MouseY
Else
Brightness = 128
EndIf
Circle(MouseX, MouseY, 5, RGB(Brightness, Brightness, Brightness))
StopDrawing()
Else
CloseScreen()
MessageRequester("Error", "StartDrawing() = 0", 0)
End
EndIf
If Start3D() <> 0
RotateSprite3D(0, Winkel+90, 0)
DisplaySprite3D(0, Bot_x-64, Bot_y-64, 255)
Stop3D()
Else
CloseScreen()
MessageRequester("Error", "Start3D() = 0", 0)
End
EndIf
FlipBuffers()
If KeyboardPushed(#PB_Key_Escape)
CloseScreen()
End
EndIf
ForEver

Sorry konnte deinen Code leider nicht direkt verbessern, aber ich hab mich vor ein paar Tagen auch mit dem Thema beschäftigt und hab folgendes zu bieten. Die F15 folgt der Maus solange man klickt und alles läuft sauber ohne ruckeln oder so, solltest den Code nur noch anpassen, dann müsste alles passen. Allerdings kann ich nicht mit so einem Beschleunigen Bremsen Kram auftrumpfen. So hier der Code:
Code: Alles auswählen
UsePNGImageDecoder()
InitSprite()
InitSprite3D()
InitMouse()
InitKeyboard()
Procedure.f Dif(PosX1, PosY1, PosX2, PosY2)
ProcedureReturn Sqr(Pow(PosX1-PosX2, 2)+Pow(PosY1-PosY2, 2))
EndProcedure
Procedure.f GSin(winkel.f)
ProcedureReturn Sin(winkel*#PI/180)
EndProcedure
Procedure.f GCos(winkel.f)
ProcedureReturn Cos(winkel*#PI/180)
EndProcedure
Procedure.f AngleXY(x1.f, y1.f, x2.f, y2.f)
a.f = x2-x1
b.f = y2-y1
c.f = Sqr(Pow(a,2)+Pow(b,2))
winkel.f = ACos(a/c)*180/#PI
If y2 < y1 : winkel=360-winkel : EndIf
ProcedureReturn winkel+90
EndProcedure
#ScreenWidth = 1024
#ScreenHeight = #ScreenWidth/1.33333333
#Key_Quit = #PB_Key_Escape
OpenScreen(#ScreenWidth, #ScreenHeight, 16, "")
LoadSprite(1, "f15.png", #PB_Sprite_Texture)
CreateSprite3D(1, 1)
PosX = 120
PosY = 120
Speed = 10
TargetX = 200
TargetY = 300
Repeat
FlipBuffers()
ClearScreen(0)
ExamineKeyboard()
ExamineMouse()
If MouseButton(1)
TargetX = MouseX()
TargetY = MouseY()
EndIf
If Dif(TargetX, TargetY, PosX, PosY) >= Speed
Angle = AngleXY(PosX, PosY, TargetX, TargetY)
PosX+GSin(Angle)*Speed
PosY-GCos(Angle)*Speed
EndIf
RotateSprite3D(1, Angle, 0)
Start3D()
DisplaySprite3D(1, PosX-SpriteWidth(1)/2, PosY-SpriteHeight(1)/2)
Stop3D()
StartDrawing(ScreenOutput())
DrawingMode(1)
DrawText(10,10,StrF(Angle), #White)
DrawText(10,60,Str(PosX), #White)
DrawText(10,80,Str(PosY), #White)
Plot(MouseX(),MouseY(),#Red)
StopDrawing()
Until KeyboardReleased(#Key_Quit)
End
Abgeschlossen Projekte:
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea
PB-V: 4
WinXP
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea
PB-V: 4
WinXP