Seite 1 von 1

Testaufruf >> Sichtfeld -> Gegner - Spieler

Verfasst: 12.09.2004 19:40
von Ynnus
Hallöchen,

ich hab eine kleine Bitte an euch. Für eines meiner Projekte hab ich ein Sichtfeld geschrieben welches den Spieler im Sichtbereich von 90° sehen soll, allerdings nicht durch Hindernisse und Mauern durch. Also hab ich mir ein kleines Script geschrieben, das es nun zu testen gilt. Die Frage ist, ob man die Sache mit dem Sichtfeld auch besser lösen könnte. Derzeit läuft es so, dass ich den Winkel zwischen Spieler und Gegner errechne, dann einen Strahl (Line()) vom Gegner zum Spieler laufen lasse, und wenn diese durch kein Objekt (die Gelben Blöcke) gestört wird, ist er sichtbar. Wenn allerdings ein Block dazwischen liegt, wird er nicht gesehen. Der Strahl wird später natürlich unsichtbar gemacht. ;)

Ich bitte euch also, wer Ahnung von sowas hat, oder sowas schonmal gemacht hat, meine Methode zu testen, und diese zu bewerten. Ob man es besser machen könnte, ob die Genauigkeit so ausreicht und so. Vielleicht habt ihr ja eine ganz einfachere Möglichkeit die besser ist als die meine? Daher bitte meinen Code mal testen obs so in Ordnung geht. (ein Theorieforum wäre hier angebracht... Schade dass es abgeschafft wurde).


Dies ist also der Code: (ist nicht optimiert, also seltsame Variablenname und co. Ist nur testweise obs so gehen könnte) :

Code: Alles auswählen

InitSprite() And InitKeyboard()

Enumeration
#block
#enemy
#blocking
EndEnumeration

#PI = 3.14159

viewfield = 45

Structure map_point_struc
  lastpos_x.w
  lastpos_y.w
  image_x.b
  image_y.b
  state.b
EndStructure

Dim map_point.map_point_struc(200, 200, 10)

Procedure get_angle(start_x, start_y, end_x, end_y)
 Protected angle.l
 Protected delta_x.w
 Protected delta_y.w

  delta_x = start_x - end_x
  delta_y = start_y - end_y
  angle = (ATan(delta_y / delta_x) * 180 / #PI) * (-1)        ;Der Winkel zum Object
  
  If angle < 0
    angle = 180 + angle
  EndIf
  If start_y < end_y       ;Negativer Winkel - also 180 dazu damit es volle 360 Grad werden!
    angle = 180 + angle
  EndIf
  If angle = 0 And start_x > end_x
    angle = 180
  EndIf

  ProcedureReturn angle
EndProcedure


Structure blocking_struc
  pos_x.w
  pos_y.w
EndStructure

Dim blocking.blocking_struc(10)

blocking(0)\pos_x = Round(100 / 32,0) * 32
blocking(0)\pos_y = Round(200 / 32,0) * 32
blocking(1)\pos_x = Round(400 / 32,0) * 32
blocking(1)\pos_y = Round(100 / 32,0) * 32
blocking(2)\pos_x = Round(140 / 32,0) * 32
blocking(2)\pos_y = Round(140 / 32,0) * 32
blocking(3)\pos_x = Round(250 / 32,0) * 32
blocking(3)\pos_y = Round(300 / 32,0) * 32
blocking(4)\pos_x = Round(100 / 32,0) * 32
blocking(4)\pos_y = Round(600 / 32,0) * 32
blocking(5)\pos_x = Round(400 / 32,0) * 32
blocking(5)\pos_y = Round(500 / 32,0) * 32
blocking(6)\pos_x = Round(140 / 32,0) * 32
blocking(6)\pos_y = Round(340 / 32,0) * 32
blocking(7)\pos_x = Round(128 / 32,0) * 32
blocking(7)\pos_y = Round(500 / 32,0) * 32

For x = 0 To 7
  map_point(Int(Round(blocking(x)\pos_x / 32, 0)), Int(Round(blocking(x)\pos_y / 32, 0)), 0)\state = 1
Next x


pos2_x = Round(500 / 32, 0) * 32
pos2_y = Round(400 / 32, 0) * 32

OpenScreen(1024, 768, 32, "")

CreateSprite(#block, 32, 32)
StartDrawing(SpriteOutput(#block))
  Box(0, 0, 32, 32, RGB($DE,$D9,$3))
StopDrawing()
CreateSprite(#enemy, 32, 32)
StartDrawing(SpriteOutput(#enemy))
  Box(0, 0, 32, 32, RGB($DE,$D9,$3))
StopDrawing()
CreateSprite(#blocking, 32, 32)
StartDrawing(SpriteOutput(#blocking))
  Box(0, 0, 32, 32, RGB($DE,$D9,$3))
StopDrawing()
Repeat

  ClearScreen($95,$F4,$79)
  
  DisplaySprite(#block, pos_x - 16, pos_y - 16)
  DisplaySprite(#enemy, pos2_x - 16, pos2_y - 16)
  
  For x = 0 To 10
    DisplaySprite(#blocking, blocking(x)\pos_x, blocking(x)\pos_y)
  Next x
  
  StartDrawing(ScreenOutput())
    For x = 0 To 1024 Step 32
      Line(x, 0, 0, 768, RGB($BC,$BC,$BC))
    Next x
    For y = 0 To 768 Step 32
      Line(0, y, 1024, 0, RGB($BC,$BC,$BC))
    Next y

    Line(pos2_x, pos2_y, -500, -500, RGB(0,0,0))
    Line(pos2_x, pos2_y, -500, 500, RGB(0,0,0))
  
    Locate(10, 10)
    DrawText("Sichtbar?: " + collision.s)
    Locate(10, 30)
    DrawText("Angle: " + Str(angle))
  StopDrawing()


  angle = get_angle(pos2_x, pos2_y, pos_x, pos_y)
  delta_x.f = pos2_x - pos_x
  delta_y.f = pos2_y - pos_y
  abstand.f = Sqr(Pow(delta_x, 2) + Pow(delta_y, 2))
  delta_y = 4 * Sin(2 * #PI * angle / 360)
  If delta_y <> 0
    delta_x = delta_y / Tan(2 * #PI * angle / 360)
  Else
    delta_x = 4
    delta_y = 0
  EndIf

  
  time = ElapsedMilliseconds()
  StartDrawing(ScreenOutput())
    temp = 0
    For x = 0 To abstand / 4
      Line(pos2_x + x * (delta_x), pos2_y + x * (-delta_y), delta_x, -delta_y)
      xxx = (Round((pos2_x + x * (delta_x) + (delta_x)) / 32, 0))
      yyy = (Round((pos2_y + x * (-delta_y) + (-delta_y)) / 32, 0))
      If yyy >= 0 And xxx >= 0
        If map_point(xxx, yyy, 0)\state = 1
          temp = 1
        EndIf
      EndIf
    Next x
    Locate(10, 50)
    DrawText("Angle: " + Str(angle))
    Locate(10, 70)
    DrawText("x: " + Str(xxx))
    Locate(10, 90)
    DrawText("y: " + Str(yyy))
    Locate(10, 110)
    DrawText("time: " + Str(time_))
    Locate(10, 130)
    DrawText("Delta_X: " + StrF(delta_x))
    Locate(10, 150)
    DrawText("Delta_Y: " + StrF(delta_y))
  StopDrawing()


  angle = get_angle(pos2_x, pos2_y, pos_x, pos_y)

  If temp = 0
    If (angle >= 180 - viewfield And angle <= 180 + viewfield)
      collision.s = "JA"
      StartDrawing(ScreenOutput())
        delta_x.f = pos2_x - pos_x
        delta_y.f = pos2_y - pos_y
        If line = 1
          Line(pos2_x, pos2_y, -delta_x, -delta_y, RGB(255, 0, 0))
        EndIf
      StopDrawing()
    Else
      collision.s = "NEIN"
    EndIf
  Else
    collision.s = "NEIN"
  EndIf
  time_ = ElapsedMilliseconds() - time

  FlipBuffers()

   
  ExamineKeyboard()
  
  If KeyboardPushed(#PB_Key_Right)
    pos_x = pos_x + 2
  EndIf
  If KeyboardPushed(#PB_Key_Left)
    pos_x = pos_x - 2
  EndIf
  If KeyboardPushed(#PB_Key_Down)
    pos_y = pos_y + 2
  EndIf
  If KeyboardPushed(#PB_Key_Up)
    pos_y = pos_y - 2
  EndIf  
  If KeyboardPushed(#PB_Key_Escape)
    quit = #True
  EndIf
  If KeyboardPushed(#PB_Key_1)
    line = 1
  EndIf
  If KeyboardPushed(#PB_Key_2)
    line = 0
  EndIf  

Until quit = #True
Mit den Cursortasten bewegt man den gelben Block, den Spieler. Eure Aufgabe wäre, bewegt den Block durch das Sichtfeld des Gegners und bewertet, ob das SIchtfeldverhalten so ok ist.
Oben links seht ihr, ob Sichtkontakt besteht oder nicht.

Dinge wie, "Drawingoperationen mehrmals in der Hauptschleife sind unnötig und belasten unnötig, könnte man optimieren" sind mir klar, ist wie gesagt nur ein Testcode. Dabei gehts eben nur um die Methode bei der herausgefunden wird, ob der Spieler sichbar ist oder nicht.

Verfasst: 14.09.2004 23:53
von Ynnus
Bitte, gibt es hier denn niemanden der mir was dazu sagen kann? Ob die Präzision ausreichend ist, wie es denn überhaupt so ist, oder einfach nur, was für einen Tag er heute hatte? :freak:

Ich bin gerade dabei dass in mein Spiel einzubinden, da wäre es schon hilfreich wenn ich vorher wüsste, obs irgendwo Probleme gibt oder ob alles so läuft wie es soll. Ohne grobe Schnitzer in der Sichtfeld-Eerkennung.

Verfasst: 15.09.2004 00:44
von RaVeN99
Moin!

Also ich habs grade mal getestet, und bei mir liefs eigtl ziemlich gut, mir wären so auf den ersten blick keine abnormitäten aufgefallen, die präzision sollte ausreichen, wird sich aber denke ich noch ingame herausstellen, wenn der gelbe block einen dann verfolgt...
Ansonsten würde ich für den moment sagen: Klasse :)
Zumindest von meiner warte aus - hab davon jetz persönlich recht wenig ahnung ;)


Ahja, mein Tag war klasse - hab nen absolut genialen Stundenplan *g* ;)


Mfg
RaVeN

Verfasst: 15.09.2004 00:51
von Andre
@Sunny: ja, aus meiner Sicht auch absolut in Ordnung. Sichtbarkeit ja/nein geht ja m.E. immer von der Mitte des gelben Quadrats aus, und von daher einwandfrei... :)

Verfasst: 15.09.2004 16:27
von Lars
Da ich deinen Code nicht ganz blicke auf den ersten Blick und auch keinen
Nerv habe, mich da einzuarbeiten, sage ich dir einfach mal, wie ich es
machen würde:

Da du ja nur nach einem Objekt suchst, brauchst du ja nicht ein ganzes
Sichtfeld zu simulieren. Du berechnest also den Winkel, wo das gesuchte
Objekt ist und checkst dann nur diese eine Linie.

Verfasst: 15.09.2004 16:49
von Ynnus
Naja, so läuft es ja auch ab. :D
Also, ich errechne vom Gegner zum Spieler den Winkel. Ist dieser innerhalb des Sichtfeldes, also innerhalb der 90 Grad, so wird eine Linie vom Gegner zum Spieler gezogen und prüft ob eine Kollision stattfindet. Im Code oben wird zwar immer eine Linie gezeichnet, diese dient aber nur zur Verdeutlichung. Diese Linie gibt es ja später nicht mehr.

Verfasst: 15.09.2004 16:51
von Lars
Na denne <)

Verfasst: 16.09.2004 22:19
von KTX82
2 super-winzig-und-kaum-zu-bemerken-optimierungen:

in deiner Winkelberechnung kannst du das "180 / #PI" schon am anfang von Programm in einer Konstante Speichrn und statt der berechnung die Konstante einfügen. Wäre schon mal ein Rechenschritt weniger.

und die ganzen 2 * #PI können auch von anfang in eine Konstante gepackt werden das es nicht ständig neu berechnet werden müssen.

Wie ich gesehen hab sind es so 3 Rechenoperationen die du einsparen kannst. Da die Kontrolle im entgültigem Programm warscheinlich eh sehr kompakt ausfallen wird, wäre das doch schon mal ein Anfang :mrgreen:

*SchonMalInDeckungGeh*