Problem mit der Distanz

Übersicht BlitzBasic Beginners-Corner

Neue Antwort erstellen

 

Ronon_Dex

Betreff: Problem mit der Distanz

BeitragMo, Jan 23, 2012 19:13
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo Leute ich bin es mal wieder Wink

Heute wollte ich euch fragen wie ich von mehrere Gegnern den nächsten herrausfinden kann.

Es spielt sich alles in 2D nur auf der X Achse ab, Außerdem verwende ich für meine Schüsse keine Images sondern ich ermittle einfach in welche Richtung ich schaue und ziehe dann jedem Gegner in der Richtung Leben ab.
Mein Problem ist jedoch, dass ich nur dem nächsten Gegner der an mir dran ist Schaden zu fügen will und nicht den anderen, die dahinter sind.
Könnt ihr mir vllt etwas helfen ?

wär echt Nett Wink
mfg
Ronon_Dex

Xeres

Moderator

BeitragMo, Jan 23, 2012 19:18
Antworten mit Zitat
Benutzer-Profile anzeigen
Wie sieht dein Code aus? Wie verwaltest du die Gegner und Schüsse?
Wenn es nur eine Achse ist, sollte es ja ausreichen, die Differenz zum Ziel zu bilden.
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus
T
HERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld)
 

PhillipK

BeitragMo, Jan 23, 2012 19:44
Antworten mit Zitat
Benutzer-Profile anzeigen
Aus dem stehgreif:

1) Richtung bestimmen (unterteilen in -1 und 1! 1 geht nach rechts, -1 nach links)
2) 2 Variablen festlegen: BesterGegner (ein zeiger für dein Gegnerobjekt), Letzte distanz. Letzte Distanz setzt du einfach auf zb 10000. (möglichst hoher wert)
3) Jeden gegner durchgehen. Dabei mit if Sgn(GegnerX - SpielerX) = richtung then ... bestimmen, ob der gegner in die gewünschte richtung liegt. (evtl mit den vorzeichen rumspielen, wenn mein hirn grade wieder spinnt Very Happy)
4) Wenn die richtung passt, das ergebnis von Abs(GegnerX-SpielerX) zwischenspeichern. Ist das ergebnis < "Letzte Distanz", wird Letzte Distanz auf Abs(GegnerX-SpielerX) gesetzt. Die variable BesterGegner wird ebenfalls auf den "aktuell geprüften" gegner gesetzt.
5) Am ende prüfst du noch, ob BesterGegner existiert und kannst ihm so schaden zufügen.

Das wäre so meine vorgehensweise. Programmiert wird aber schön selbst Smile

Nochmal zusammengefasst, was ich nutzten würde:

-Eine schleife, die alle gegner prüft.

-Eine durch vorzeichen geprüfte richtung, anhand der differenz von Spieler->Gegner (ist der gegner links, ist normalerweise sein X wert kleiner. Das heißt, GegnerX-SpielerX wird negativ!)

-Ein zwischenspeicher für gegner+distanz paare (distanz muss ABS sein, sonst gibts in die -links-richtung ein vorzeichen problem!)
 

Ronon_Dex

BeitragMo, Jan 23, 2012 22:12
Antworten mit Zitat
Benutzer-Profile anzeigen
danke ich werde mir das mal anschauen.
solange werde ich mal meinen Code posten um auch die letzten Missverständnisse aus zu räumen Very Happy

BlitzBasic: [AUSKLAPPEN]
Global max=800, min=600
Graphics max,min,32,0
SetBuffer BackBuffer()

Global hoch=200,runter=208,rechts=205,links=203,shift=42,leertaste=57,lookat$="w",pdown=209,esc=1
SeedRnd MilliSecs()


Type player
Field leben
Field px#
Field py#
Field geld
End Type

char.player = New player
char\leben=100
char\px=max/2
char\py=400
char\geld=0

Global ppx#=char\px, ppy#=char\py



Type monster
Field mx#
Field my#
Field typ
Field leben
Field speed#
End Type

For i=0 To 5

gegner.monster = New monster
gegner\mx=max
gegner\my=430
gegner\leben=100
gegner\typ=Rand(1,2)
gegner\speed=Rand(0.1,3)

Next


Global rep=0, kills=0

Repeat
Cls

If KeyDown(rechts) Then
If ppx < 740 Then
ppx=ppx+1
lookat="o"
Else ppx=739
EndIf
EndIf

If KeyDown(links) Then
If ppx > 0 Then
ppx=ppx-1
lookat="w"
Else ppx=1
EndIf
EndIf

Schuss(20,50)

Color 0,155,0
Rect ppx,ppy,60,90
Color 155,0,0

For gegner.monster = Each monster
If gegner\leben=0
Delete gegner.monster
kills=kills+1
Else
gegner\mx=gegner\mx-gegner\speed
Rect gegner\mx,gegner\my,60,60
Color 0,155,0
Text gegner\mx,gegner\my,gegner\leben
Color 155,0,0
EndIf
Next
Text 10,10,"Kills: "+kills


Flip
Until KeyHit(1)
End

Function Schuss(reload=5,dmg=1)

If KeyDown(leertaste) Then
rep = rep+1
End If

If rep = reload Then

For m.monster = Each monster
If lookat="o" And m\mx > ppx Then m\leben=m\leben-dmg
If lookat="w" And m\mx < ppx Then m\leben=m\leben-dmg
Next
rep = 0

End If

End Function



//Edit:
Ich komm nicht wirklich klar mit deiner Anleitung ist etwas unverständlich geschrieben Wink

Xeres

Moderator

BeitragMi, Jan 25, 2012 2:38
Antworten mit Zitat
Benutzer-Profile anzeigen
Die Blickrichtung mit einem String zu Prüfen funktioniert, ist aber keine hübsche Lösung. Integer werden schneller verarbeitet und Konstanten machen das ganze Lesbarer:
BlitzBasic: [AUSKLAPPEN]
Const Rechts%=0, Links%=1
Global LookAt%

;[...]

If LookAt = Rechts Then ;[...]

Deine Tasten-Variablen könnten entsprechend auch als Konstanten deklariert werden - es sei denn, du wolltest die Tastenbelegung einstellbar machen.

Du brauchst auch die Position nicht doppelt speichern, den Char Global zu machen, wäre da die bessere Lösung:
BlitzBasic: [AUSKLAPPEN]
char.player = New player
;[...]
Global ppx#=char\px, ppy#=char\py

;Besser:

Global char.player = New player

Und noch eins:
BlitzBasic: [AUSKLAPPEN]
If ppx < 740 Then
;[...]
Global gfx_max=800, gfx_min=600, Char_Size%=60
If ppx < (gfx_max-Char_Size) Then

Benutze von Anfang an Variablen und Konstanten, anstatt Werte "hardcoded" im Code zu benutzen - irgendwann willst du etwas ändern, und musst ein paar hundert Zeilen ändern, anstatt nur eine Zeile.

Zum Hauptteil: Um den Abstand zweier Punkte zu berechnen, wird üblicherweise der Satz des Pythagoras verwendet.
Etwas komplizierter wird es, das richtige Monster aus zu wählen: Ich würde eine Variable ZielMonster.monster und eine für den Abstand anlegen und in ZielMonster das Monster stecken, das einen kleineren Abstand hat als letzte.
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus
T
HERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld)
 

Ronon_Dex

BeitragMi, Jan 25, 2012 13:45
Antworten mit Zitat
Benutzer-Profile anzeigen
Zitat:
Ich würde eine Variable ZielMonster.monster und eine für den Abstand anlegen und in ZielMonster das Monster stecken, das einen kleineren Abstand hat als letzte.


genau da liegt das Problem Very Happy

Ich weis ja nicht wie ich die kleinste Distanz herraus bekommen soll...

Das erste erstellte Monster muss ja nicht zwangsläufig die kleinste Distanz zum Player haben,
es kann auch das 5. von 10 Monstern am nächsten am Player dran sein.
 

PhillipK

BeitragMi, Jan 25, 2012 13:59
Antworten mit Zitat
Benutzer-Profile anzeigen
Hast du dir meinen beitrag überhaupt durchgelesen? :<

Da hatte ich eigentlich die Logik geschildert ^^


Um die distanz zu bestimmen (auf einer achse, zb X) reicht es, wenn du mit ABS werte vergleichst.
Am besten rechnest du immer wie folgt die distanz aus: Monster-Spieler.

Sprich: Monster-koordinate-X MINUS Spieler-koordinate-X.

Dies mag einen negativen wert ergeben, aber das vorzeichen intressiert nicht. DH wir brauchen 'ABS' - eine funktion, welche dir eine zahl ohne Vorzeichen wiedergibt. Sprich: -2 wird zu 2, 4 wird zu 4.
Somit hast du die absolute (abs Wink ) entfernung zu deinem Ziel.

wenn du nun anfängt, mit 2 variablen, welche dir ein Monster und eine Distanz zwischenspeichern, und getrennt davon alle monster durchläufst (for-schleife), kannst du so jedes monster vergleichen.
Sollte die Absolute Distanz zum monster kleiner sein, als die zuletzt 'kleinste' (eine der Variablen -> Distanz) gehst du wie folgt vor:

1) Speichere die neueste, kleinste, absolute distanz in der variable (die, die VOR der for schleife erstellt wurde Wink )
2) Speichere das monster, welches die geringste distanz aufweißt, in der 2ten variable, dem zeiger auf dein monster. Hier ist der wert dir überlassne, obs nun ein Pointer auf eine Monster-instanz ist oder ein Index für einen array.

Nachdem die schleife durch ist, kontrollierst du, ob überhaupt ein monster gefunden wurde und ziehst diesem eventuell hp ab. Das geht ganz einfach, da du, wie in punkt 2) erwähnt, das monster zwischengespeichert hast.

Hmpf, nochmal mach ich mir nicht die mühe.

(ps: Dies ist nur eine von vielen möglichkeiten und wird mit zunehmender monsteranzahl langsamer. Wenn du allerdings nur ein paar tausend hast, dürfte das okay sein. Für alles andere musst du eh dein system ein wenig anders unterteilen (Sektoren, etc))

Xeres

Moderator

BeitragMi, Jan 25, 2012 14:20
Antworten mit Zitat
Benutzer-Profile anzeigen
Darum musst du eben alle Monster abarbeiten:
BlitzBasic: [AUSKLAPPEN]
Local m.monster, ziel.monster, minD%=-1
For m.monster = Each monster
;* Weitere Kriterien wie richtung nicht vergessen..
Local d = Distanz(...) ;* Abstand Spieler-Monster bestimmen
If d < minD Or minD=-1 Then ;Ist der Abstand kleiner (oder ist es die erste berechnung)?
minD = d ;* Neues Minimum
ziel = m ;* Ziel festhalten
EndIf
Next

If ziel<>Null Then
;* Ziel gefunden, hier reagieren.
EndIf
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus
T
HERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld)
 

PhillipK

BeitragMi, Jan 25, 2012 16:10
Antworten mit Zitat
Benutzer-Profile anzeigen
Da xeres meinen vorschlag nun code-technisch verfasst hat, erweiter ich das ganze noch Smile

BlitzBasic: [AUSKLAPPEN]
Function Distanz%(x1%,x2%)
Return Abs(x2-x1)
End Function

;----------------

[...]
Local d = Distanz(spieler\PositionX, m\PositionX) ;* Abstand Spieler-Monster bestimmen ;-> hoffentlich ist die BB syntax so richtig (type\field)


Anzumerken sei auch, das in
BlitzBasic: [AUSKLAPPEN]
minD%=-1

auch -1 durch eine "maximale" distanz ersetzt werden kann und die abfrage

BlitzBasic: [AUSKLAPPEN]
If d < minD Or minD=-1 Then ;

dann einfach
BlitzBasic: [AUSKLAPPEN]
If d < minD  Then

heißen kann.

Aber bedenke: Dein jetziges vorhaben wird auf jedenfall einen gegner finden, dh die kugel wird nicht "fliegen" - solltest du aber nach dem schießen noch die kugel fliegen lassen, kannst du das ganze auch nutzen:

Hierzu musst du statt der spieler position die kugel-position übergeben. (Distanz(kugel\positionX, m\PositionX) )
Der min-abstand sollte hier dann dem "radius" der kugel entsprechen - im besten fall noch ein wenig mehr, da die kugel wohl sehr schnell fliegen dürfte.
 

Ronon_Dex

BeitragSa, Jan 28, 2012 21:20
Antworten mit Zitat
Benutzer-Profile anzeigen
Also ich hab das jetz mal so gemacht:

BlitzBasic: [AUSKLAPPEN]
Function Schuss(reload=5,dmg=1)

rep = rep+1

If rep = reload Then

For m.monster = Each monster
Local d = Distanz(ppx, m\mx)
If d < minD Then
minD = d
If lookat=lrechts And ppx < m\mx Then m\leben=m\leben-dmg
If lookat=llinks And ppx > m\mx Then m\leben=m\leben-dmg
EndIf
Next

rep = 0

End If

End Function

Function Distanz%(x1%,x2%)
Return Abs(x2-x1)
End Function


nach rechts funktioniert es einigermaßen(d.h. manchmal greife ich auch den Mittleren an) jedoch nach links gar nicht.
 

PhillipK

BeitragSa, Jan 28, 2012 21:56
Antworten mit Zitat
Benutzer-Profile anzeigen
ich bin leider kein BB-crack, aber für mich sieht das noch nicht 100% richtig aus.

So wie es grade ausschaut, tust du jeden gegner angreifen, welcher zwischen dem ersten fund und dem spieler liegt.

Ich versuche grade mal ein wenig umzuformen, aber ich kann nicht garantieren, ob es so funktioniert^^

BlitzBasic: [AUSKLAPPEN]
Function Schuss(reload=5,dmg=1)

rep = rep+1

Local dist% = -1
Local target:monster = Null ;ka wie das in BB aussieht - halt eine variable für das Monster-obj bereitstellen.

If rep = reload Then

For m.monster = Each monster
If (lookat=lrechts And ppx < m\mx) Or (lookat = llinks And ppx > m\mx) Then ;der spieler schaut in monster-richtung
Local d = Distanz(ppx, m\mx)
If (dist = -1) Or (dist > d) Then ;es gibt keinen eintrag oder die neue distanz ist kleiner als die alte:
dist = d
target = m ;ebenfalls keine ahnung wie das in BB aussieht. Das monster 'merken' :)
EndIf
EndIf
Next

If target Then ;wenn ein Monster gefunden wurde (dh target <> null)
target\leben = target\leben-dmg
EndIf
rep = 0

End If

End Function

Function Distanz%(x1%,x2%)
Return Abs(x2-x1)
End Function


So oder so in der art sollte es funktionieren.
Vorraussetzungen hierfür sind, das der KoordinatenUrsprung von X auf der linken seite (vom bildschirm) liegt.
Aber, soweit ich das sehen kann, gibt es keinen logischen grund, warum monster auf der linken seite nicht angegriffen werden können. Bestenfalls stimmt was mit "lookat = llinks" nicht - vielleicht nimmt looktat niemals den wert von llinks an ?
 

Ronon_Dex

BeitragMo, Jan 30, 2012 18:17
Antworten mit Zitat
Benutzer-Profile anzeigen
Zitat:
If (lookat=lrechts And ppx < m\mx) Or (lookat = llinks And ppx > m\mx) Then ;der spieler schaut in monster-richtung


Ich weis nicht ob ich gerade was übersehen habe aber:
Greift er dann nicht den nächsten Gegner an auch wenn er in die falsche Richtung schaut ?


//Edit:
Ach nein stimmt doch Very Happy

Und dazu funktioniert es auch noch gut Wink

danke Phillipk

Neue Antwort erstellen


Übersicht BlitzBasic Beginners-Corner

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group