Hnefa Tafl...

Fragen zu Grafik- & Soundproblemen und zur Spieleprogrammierung haben hier ihren Platz.
Benutzeravatar
Farodin
Beiträge: 35
Registriert: 16.05.2006 18:49
Wohnort: bei mir zuhause
Kontaktdaten:

Hnefa Tafl...

Beitrag von Farodin »

..so heißt das altnordische Brettspiel,welches ich momentan Umsetzen möchte. Auswählen und Bewegen von Einheiten funktioniert bereits, jedoch hänge ich jetzt am nächsten Problem und zwar funktioniert eine Abfrage zum 'Umzingeltsein' einer Einheit nicht so wirklich und ich habe keine ahnung wieso :(

hier mal der Code des gesamten Spiels bis jetzt:

Code: Alles auswählen

InitSprite()
InitMouse()
InitKeyboard()


;- Structures
Structure Unitcoords
  x.l  
  y.l  
  Selected.l
  color.l
  defeated.l
EndStructure


Global NewList Units.Unitcoords()

Structure Players
  number.l
  turn.l
  move.l
EndStructure

NewList Game.Players()

For a = 0 To 1
  AddElement(Game())
    Game()\number +1
Next


;-Proc's
Procedure Drawframe(x.l,y.l)
  Line(x-20,y+20,40,0,0)
  Line(x-20,y-20,40,0,0)
  Line(x+20,y-20,0,40,0)
  Line(x-20,y-20,0,40,0)
EndProcedure

Procedure Unit(x.l,y.l,colortype.l,direction1.l,direction2.l)
  If colortype = 1
    color = $00FFFF
    If direction1 = 1
      If direction2 = 1
        For a = 0 To 4
          AddElement(Units()) 
          Units()\x = x 
          Units()\y = y
          Units()\color = color
          y + (600/12)
        Next
        x+(800/12)
        y-((600/12)*3)
        AddElement(Units()) 
        Units()\x = x 
        Units()\y = y
        Units()\color = color
      Else
        For a = 0 To 4
          AddElement(Units()) 
          Units()\x = x 
          Units()\y = y
          Units()\color = color
          x + (800/12)
        Next
        x-((800/12)*3)
        y-(600/12)
        AddElement(Units()) 
        Units()\x = x 
        Units()\y = y
        Units()\color = color
      EndIf
    Else
      If direction2 = 1
        For a = 0 To 4
          AddElement(Units()) 
          Units()\x = x 
          Units()\y = y
          Units()\color = color
          y + (600/12)
        Next
        x-(800/12)
        y-((600/12)*3)
        AddElement(Units()) 
        Units()\x = x 
        Units()\y = y
        Units()\color = color
      Else
        For a = 0 To 4
          AddElement(Units()) 
          Units()\x = x 
          Units()\y = y
          Units()\color = color
          x + (800/12)
        Next
        x-((800/12)*3)
        y+(600/12)
        AddElement(Units()) 
        Units()\x = x 
        Units()\y = y
        Units()\color = color
      EndIf
    EndIf
  Else
    color = $FF0000
    If direction2 = 1
      For a = 0 To 2
        AddElement(Units()) 
        Units()\x = x 
        Units()\y = y
        Units()\color = color
        y + (600/12)
      Next
    Else
      For a = 0 To 2
        AddElement(Units()) 
        Units()\x = x 
        Units()\y = y
        Units()\color = color
        x + (800/12)
      Next
    EndIf
  EndIf
EndProcedure

Procedure King(x.l,y.l)
  color = $FFFF00
  AddElement(Units()) 
  Units()\x = x 
  Units()\y = y
  Units()\color = color
EndProcedure

Procedure Check()
  ForEach Units()
    *Unit = @Units()
    positionX = Units()\x
    positionY = Units()\y
    unitcolor = Units()\color
    counter = 0
    
    ForEach Units()
      If (Units()\x >= positionX - (800/12) - 1 And Units()\x <= positionX + (800/12) + 1) And Units()\y - positionY > (600/12) Or Units()\y - positionY > -(600/12)
        If Units()\color <> unitcolor
          counter + 1
        EndIf
      EndIf
    Next
    
    ChangeCurrentElement(Units(),*Unit)
    
    If counter = 2
      DeleteElement(Units())
    EndIf
  Next
EndProcedure 


;- Main Program
OpenWindow(0,0,0,910,710,"Hnefa-Tafl",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
  OpenWindowedScreen(WindowID(0),8.5,5,893,701,0,0,0)

x = 50
y = 50
  
Unit(x,y+200,1,1,1)
Unit(x+792,y+200,1,0,1)
Unit(x+264,y+600,1,1,0)
Unit(x+264,y,1,0,0)
Unit(x+396,y+350,0,1,1)
Unit(x+396,y+149,0,0,1)
Unit(x+197,y+300,0,1,0)
Unit(x+462,y+300,0,0,0)
King(446,350)

Repeat
  EventID = WaitWindowEvent(10000)
  ClearScreen($FFFFFF)
  ExamineKeyboard()
  StartDrawing(ScreenOutput())
  ExamineMouse()
  x = 50
  y = 50
  For a = 0 To 12
    Line(x,50,0,600,0)
    x + (800/12)
  Next
  x = 50
  y = 50
  For a = 0 To 12
    Line(50,y,793,0,0)
    y + (600/12)
  Next
  x = 50
  y = 50
  Box(51,51,(793/12)-1,(601/12)-1,$0000FF)
  Box(777,51,(793/12)-1,(601/12)-1,$0000FF)
  Box(51,601,(793/12)-1,(601/12)-1,$0000FF)
  Box(777,601,(793/12)-1,(601/12)-1,$0000FF)
  ;- Enemy Forces
  ForEach Units()
    Circle(Units()\x,Units()\y,20,Units()\color)
  Next
  ;- Own Troops
  ForEach Units()
    Circle(Units()\x,Units()\y,20,Units()\color)
  Next
  

  StopDrawing()
  ForEach Game()
    If Game()\number = 0
      StartDrawing(ScreenOutput())
        Circle(MouseX(),MouseY(),10,$FF0000)
      StopDrawing()
    Else
      StartDrawing(ScreenOutput())
        Circle(MouseX(),MouseY(),10, $00FFFF)
      StopDrawing()
    EndIf
  Next
  
  ForEach Units()
    If Units()\selected
      StartDrawing(ScreenOutput())
        Drawframe(Units()\x,Units()\y)
      StopDrawing()
    EndIf
  Next
    
  FlipBuffers()
  
  
  If EventID =  #WM_LBUTTONDOWN
    Game()\move =0
    

    ForEach Units()
      If MouseX() <= Units()\x + 20 And MouseX() >= Units()\x - 20
        If MouseY() <= Units()\y + 20 And MouseY() >= Units()\y - 20
          *Unit = @Units()
          ForEach Units()
            Units()\selected = 0
          Next
          ChangeCurrentElement(Units(), *Unit)
    
          Units()\selected = 1
          Game()\move = 1
          Break
        EndIf
      EndIf
    Next
    
    If Game()\move =0
      ForEach Units()
        If Units()\selected
          If Abs(Units()\x - MouseX()) > Abs(Units()\y - MouseY())
            If MouseX() > Units()\x
              Units()\x + (800/12)
            Else
              Units()\x - (800/12)
            EndIf
          Else
            If MouseY() > Units()\y
              Units()\y + (600/12)
            Else
              Units()\y - (600/12)
            EndIf
          EndIf
          
          Break
        EndIf
      Next
    EndIf
    
    Check()
  EndIf
    
  ForEach Units()
    If Units()\color = $FFFF00
      If (Units()\x <= 51 And Units()\y <= 51) Or (Units()\x > 777 And Units()\y <= 51) Or (Units()\x <= 51 And Units()\y > 601) Or (Units()\x > 777 And Units()\y > 601)
          MessageRequester("SIEG","Spieler 1 gewinnt!",16)
          End
      EndIf
    EndIf
  Next
Until EventID = #PB_Event_CloseWindow Or KeyboardPushed(#PB_Key_Escape)
und hier die Prozedur um die sichs im speziellen dreht:

Code: Alles auswählen

Procedure Check()
  ForEach Units()
    *Unit = @Units()
    positionX = Units()\x
    positionY = Units()\y
    unitcolor = Units()\color
    counter = 0
    
    ForEach Units()
      If (Units()\x >= positionX - (800/12) - 1 And Units()\x <= positionX + (800/12) + 1) And Units()\y - positionY > (600/12) Or Units()\y - positionY > -(600/12)
        If Units()\color <> unitcolor
          counter + 1
        EndIf
      EndIf
    Next
    
    ChangeCurrentElement(Units(),*Unit)
    
    If counter = 2
      DeleteElement(Units())
    EndIf
  Next
EndProcedure 
wenn ich die Sache so angehe verschwinden nämlich Einheiten,die garnicht umzingelt sind.
Ich hoffe ihr könnt mir da weiterhelfen :)
Warning! Exception Error in Life.exe
Task will be shut down.

verwende version 4.10 unter Windows
Rokur
Beiträge: 167
Registriert: 29.12.2005 09:58
Computerausstattung: Intel Core2 Quad (4x2,4 GHz), 4096 MB RAM, GForce 8800GTX 786 MB
Windows XP 32 Bit, PureBasic 4.40 (x86)

Beitrag von Rokur »

Du solltest die Abfrage nur in Bezug auf den gerade bewegten Stein machen und nicht auf alle, da Steine die freiwillig zwischen zwei Gegner ziehen nicht entfernt werden dürfen.

Könnte z.B. so aussehen (Pseudo-Code):

Code: Alles auswählen

x = GeradeBewegterStein\x
y = GeradeBewegterStein\y
color = GeradeBewegterStein\color

Durchlaufe AlleSteine() als Stein
  ;liegt der Stein links vom Bewegten und ist feindlich?
  Wenn Stein\x = x - 1 und Stein\y = y und Stein\color <> color dann
    Durchlaufe AlleSteine() als Stein2
      Wenn Stein2\x = Stein\x - 1 und Stein2\y = Stein\y und Stein2\color <> Stein\color dann
        EntferneStein(Stein)
        VerlasseSchleife ;wegen Performance, wir haben ja was wir wollten
      EndeWenn
    Nächster Stein2
  EndeWenn
  ;das musst du natürlich für alle 4 Richtungen wiederholen
  ;...
Nächster Stein

Die Abfrage wäre etwas leichter wenn du alle Steine in einem zweidimensionalen Array hättest, das braucht zwar etwas mehr Speicher, aber du könntest dann über den Array-Index direkt die Steine rings rum abfragen, ohne jedesmal alle durchlaufen zu müssen.

Da die Ecksteine als Verteidiger zählen musst du die in die Abfrage mit einbauen, das habe ich jetzt oben weggelassen, aber das bekommst du schon hin. :wink:

Falls du mit der Regel spielst das der König nur von 4 Gegnern gefangen genommen werden kann, dann musst du noch den SteinTyp abfragen...

P.S.
Schön das es noch Hnefatafl-Spieler gibt. :D
Antworten