Testaufruf >> Sichtfeld -> Gegner - Spieler

Für allgemeine Fragen zur Programmierung mit PureBasic.
Benutzeravatar
Ynnus
Beiträge: 855
Registriert: 29.08.2004 01:37
Kontaktdaten:

Testaufruf >> Sichtfeld -> Gegner - Spieler

Beitrag 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.
Benutzeravatar
Ynnus
Beiträge: 855
Registriert: 29.08.2004 01:37
Kontaktdaten:

Beitrag 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.
RaVeN99
Beiträge: 310
Registriert: 29.08.2004 15:26
Wohnort: Weiden i.d.OPF
Kontaktdaten:

Beitrag 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
AMD Athlon64 3000+, 1024MB DDR-RAM, Geforce 8600GT, WinXP SP2, DirectX 9.0c, PureBasic 3.94
Benutzeravatar
Andre
PureBasic Team
Beiträge: 1755
Registriert: 11.09.2004 16:35
Computerausstattung: MacBook Core2Duo mit MacOS 10.6.8
Lenovo Y50 i7 mit Windows 10
Wohnort: Saxony / Deutscheinsiedel
Kontaktdaten:

Beitrag 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... :)
Bye,
...André
(PureBasicTeam::Docs - PureArea.net | Bestellen:: PureBasic | PureVisionXP)
Benutzeravatar
Lars
Beiträge: 347
Registriert: 31.08.2004 23:53
Wohnort: Shanghai
Kontaktdaten:

Beitrag 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.
Lars
The only problem with troubleshooting is, that sometimes the trouble shoots back.
P4 2,6Ghz, 512MB RAM, GeForce 6200, WinXP Pro SP2, PB V3.94
Benutzeravatar
Ynnus
Beiträge: 855
Registriert: 29.08.2004 01:37
Kontaktdaten:

Beitrag 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.
Benutzeravatar
Lars
Beiträge: 347
Registriert: 31.08.2004 23:53
Wohnort: Shanghai
Kontaktdaten:

Beitrag von Lars »

Na denne <)
Lars
The only problem with troubleshooting is, that sometimes the trouble shoots back.
P4 2,6Ghz, 512MB RAM, GeForce 6200, WinXP Pro SP2, PB V3.94
KTX82
Beiträge: 95
Registriert: 31.08.2004 00:11
Wohnort: Mannheim
Kontaktdaten:

Beitrag 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*
Pharmacie populaire www.viagrasansordonnancefr.com aide aux malades
Antworten