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
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.