GDI+ Spiel : Snake

  • Hallo,
    Da ich gestern beim Vorstellungsgespräch nach Codebeispielen gefragt wurde, die ich schicken könnte, habe ich mir überlegt noch schnell einen Snake-Klon zu schreiben.

    Nichts weltbewegendes, aber er macht schonmal Spaß.
    Steuerung und Spielprinzip sollten eigentlich klar sein, aber ich erklär es nochmal:

    Pfeiltasten benutzen um der Schlange eine neue richtung zuzuweisen.
    Ziel ist es, so lange durchzuhalten wie möglich, und so viel Beute wie möglich aufzusammeln.

    Viel Spaß damit

    (Mein Rekord : 194941 - hab aber nicht exessiv gespielt)

    Spoiler anzeigen
    [autoit]

    #include <GDIPlus.au3>
    #include <GUIConstantsEx.au3>
    #include <Misc.au3>
    #include <Timers.au3>
    #include <WinAPI.au3>
    #include <WindowsConstants.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Opt("GUIOnEventMode", 1)
    OnAutoItExitRegister("__GDIPlus_Shutdown")

    [/autoit] [autoit][/autoit] [autoit]

    ;General GDI+ Vars
    Global $SCALE = 1.75

    [/autoit] [autoit][/autoit] [autoit]

    Global $hGUI, $iWidth = 200 * $SCALE, $iHeight = 200 * $SCALE
    Global $GUI_Back_Color = 0xFFF0F0F0
    Global $hBackbuffer, $hBrush, $hBrushFood, $hGraphic, $hBitmap
    ;Game Vars
    Global $PL_THICKNESS = $iWidth / 20, $PL_SPEED = 2
    Global $aTimers[2], _ ; [timers] -> 0: movement | 1: Full Playtime
    $PL_MOV_CUR, $PL_JUST_CHANGED_DIR, _
    $aPL_POSITIONS[3][2]
    Global Enum _
    $PL_MOV_NONE, _
    $PL_MOV_UP, _
    $PL_MOV_LEFT, _
    $PL_MOV_DOWN, _
    $PL_MOV_RIGHT

    [/autoit] [autoit][/autoit] [autoit]

    Global $FOOD_ISACTIVE, $FOOD_COORD[2]

    [/autoit] [autoit][/autoit] [autoit]

    $hDLL = DllOpen("user32.dll")
    _GDI_StartUp()
    While 1
    _NewDirection()
    _GDIPlus_GraphicsClear($hBackbuffer, $GUI_Back_Color)
    _DrawTimerHandler()
    _WinAPI_RedrawWindow($hGUI, 0, 0, $RDW_INTERNALPAINT)
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    #region - Essential GDI+ Functions
    Func _GDI_StartUp()

    [/autoit] [autoit][/autoit] [autoit]

    ;Create GUI as background.
    $hGUI = GUICreate("GDI+ Snake [SEuBo]", $iWidth, $iHeight)
    GUISetOnEvent(-3, "OnEvent_Eventhandler")
    GUIRegisterMsg($WM_PAINT, "WM_PAINT")

    [/autoit] [autoit][/autoit] [autoit]

    ;Startup GDI+ Engine
    _GDIPlus_Startup()
    $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    $hBrush = _GDIPlus_BrushCreateSolid()
    $hBrushFood = _GDIPlus_BrushCreateSolid(0xFFFF3535)
    $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iWidth, $iHeight, $hGraphic)
    $hBackbuffer = _GDIPlus_ImageGetGraphicsContext($hBitmap)

    [/autoit] [autoit][/autoit] [autoit]

    ;Set Timers for Movement/Special/Boni
    For $i = 0 To UBound($aTimers) - 1
    $aTimers[$i] = TimerInit()
    Next
    For $i = 0 To UBound($aPL_POSITIONS) - 1
    $aPL_POSITIONS[$i][0] = Floor($iWidth) / 2 - Mod($iWidth / 2, $PL_THICKNESS) - $PL_THICKNESS
    $aPL_POSITIONS[$i][1] = Floor($iHeight) / 2 - Mod($iHeight / 2, $PL_THICKNESS) - $PL_THICKNESS
    Next
    GUISetState()
    EndFunc ;==>_GDI_StartUp

    [/autoit] [autoit][/autoit] [autoit]

    Func WM_PAINT()
    _WinAPI_RedrawWindow($hGUI, 0, 0, $RDW_UPDATENOW)
    _GDIPlus_GraphicsDrawImageRect($hGraphic, $hBitmap, 0, 0, $iWidth, $iHeight)
    _WinAPI_RedrawWindow($hGUI, 0, 0, $RDW_VALIDATE)
    Return $GUI_RUNDEFMSG
    EndFunc ;==>WM_PAINT

    [/autoit] [autoit][/autoit] [autoit]

    Func __GDIPlus_Shutdown()
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_GraphicsDispose($hGraphic)
    _GDIPlus_BitmapDispose($hBitmap)
    _GDIPlus_Shutdown()
    EndFunc ;==>__GDIPlus_Shutdown
    #endregion - Essential GDI+ Functions

    [/autoit] [autoit][/autoit] [autoit]

    #region - Game Funktions
    Func _DrawTimerHandler()

    [/autoit] [autoit][/autoit] [autoit]

    ;Draw Player
    If TimerDiff($aTimers[0]) > 500 / $PL_SPEED + 25 Then
    _DrawPlayer(1)
    $aTimers[0] = TimerInit()
    Else
    _DrawPlayer(0)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;Draw Food
    _DrawFood($FOOD_ISACTIVE = False)

    [/autoit] [autoit][/autoit] [autoit]

    ;Draw More stuff
    ;...

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc ;==>_DrawTimerHandler

    [/autoit] [autoit][/autoit] [autoit]

    Func _DrawPlayer($iFlag)
    Local $iUB = UBound($aPL_POSITIONS)

    [/autoit] [autoit][/autoit] [autoit]

    If $iFlag Then
    For $i = $iUB - 1 To 1 Step -1
    $aPL_POSITIONS[$i][0] = $aPL_POSITIONS[$i - 1][0]
    $aPL_POSITIONS[$i][1] = $aPL_POSITIONS[$i - 1][1]
    Next

    [/autoit] [autoit][/autoit] [autoit]

    $aPL_POSITIONS[0][0] = $aPL_POSITIONS[0][0] + (($PL_MOV_CUR = $PL_MOV_RIGHT) * $PL_THICKNESS) - (($PL_MOV_CUR = $PL_MOV_LEFT) * $PL_THICKNESS)
    $aPL_POSITIONS[0][1] = $aPL_POSITIONS[0][1] + (($PL_MOV_CUR = $PL_MOV_DOWN) * $PL_THICKNESS) - (($PL_MOV_CUR = $PL_MOV_UP) * $PL_THICKNESS)

    [/autoit] [autoit][/autoit] [autoit]

    If $aPL_POSITIONS[0][0] >= $iWidth Then $aPL_POSITIONS[0][0] = 0
    If $aPL_POSITIONS[0][0] < 0 Then $aPL_POSITIONS[0][0] = $iWidth - $PL_THICKNESS

    [/autoit] [autoit][/autoit] [autoit]

    If $aPL_POSITIONS[0][1] >= $iHeight Then $aPL_POSITIONS[0][1] = 0
    If $aPL_POSITIONS[0][1] < 0 Then $aPL_POSITIONS[0][1] = $iHeight - $PL_THICKNESS

    [/autoit] [autoit][/autoit] [autoit]

    $PL_JUST_CHANGED_DIR = False

    [/autoit] [autoit][/autoit] [autoit]

    _PlayerAteFood(($aPL_POSITIONS[0][0] = $FOOD_COORD[0]) And ($aPL_POSITIONS[0][1] = $FOOD_COORD[1]))

    [/autoit] [autoit][/autoit] [autoit]

    If _CoordsAlreadyUsedByPlayer($aPL_POSITIONS[0][0], $aPL_POSITIONS[0][1], 1) Then Exit MsgBox(64, "Game over!", "Herzlichen Glückwunsch, du hast " & Floor(TimerDiff($aTimers[1]) / 100 * UBound($aPL_POSITIONS)) & " Punkte erreicht!" & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    EndIf
    For $i = 0 To $iUB - 1
    _GDIPlus_GraphicsFillRect($hBackbuffer, $aPL_POSITIONS[$i][0], $aPL_POSITIONS[$i][1], $PL_THICKNESS, $PL_THICKNESS, $hBrush)
    Next
    EndFunc ;==>_DrawPlayer

    [/autoit] [autoit][/autoit] [autoit]

    Func _DrawFood($iFlag)
    If $iFlag Then
    Do
    $FOOD_COORD[0] = Random(0, $iWidth - $PL_THICKNESS)
    $FOOD_COORD[1] = Random(0, $iHeight - $PL_THICKNESS)
    $FOOD_COORD[0] -= Mod($FOOD_COORD[0], $PL_THICKNESS)
    $FOOD_COORD[1] -= Mod($FOOD_COORD[1], $PL_THICKNESS)
    Until Not _CoordsAlreadyUsedByPlayer($FOOD_COORD[0], $FOOD_COORD[1])
    $FOOD_ISACTIVE = True
    EndIf
    _GDIPlus_GraphicsFillRect($hBackbuffer, $FOOD_COORD[0], $FOOD_COORD[1], $PL_THICKNESS, $PL_THICKNESS, $hBrushFood)
    EndFunc ;==>_DrawFood

    [/autoit] [autoit][/autoit] [autoit]

    Func _PlayerAteFood($fBool)
    Local Static $iFoodQueue
    If $fBool Then
    Local $iUB = UBound($aPL_POSITIONS)
    ReDim $aPL_POSITIONS[$iUB + 1][2]
    $aPL_POSITIONS[$iUB][0] = $aPL_POSITIONS[$iUB - 1][0]
    $aPL_POSITIONS[$iUB][1] = $aPL_POSITIONS[$iUB - 1][1]
    $FOOD_ISACTIVE = False
    $iFoodQueue += 1
    If $iFoodQueue = 5 Then
    $PL_SPEED += 0.5
    $iFoodQueue = 0
    EndIf
    EndIf
    EndFunc ;==>_PlayerAteFood

    [/autoit] [autoit][/autoit] [autoit]

    Func _CoordsAlreadyUsedByPlayer($iX, $iY, $iStart = 0)
    If $PL_MOV_CUR = $PL_MOV_NONE Then Return False
    For $i = $iStart To UBound($aPL_POSITIONS) - 1
    If $iX = $aPL_POSITIONS[$i][0] And $iY = $aPL_POSITIONS[$i][1] Then Return True
    Next
    Return False
    EndFunc ;==>_CoordsAlreadyUsedByPlayer
    #endregion - Game Funktions

    [/autoit] [autoit][/autoit] [autoit]

    Func OnEvent_Eventhandler()
    Switch @GUI_CtrlId
    Case -3
    Exit
    EndSwitch
    EndFunc ;==>OnEvent_Eventhandler

    [/autoit] [autoit][/autoit] [autoit]

    Func _NewDirection()

    [/autoit] [autoit][/autoit] [autoit]

    If _IsPressed(26, $hDLL) Then
    If $PL_MOV_CUR <> $PL_MOV_DOWN And $PL_MOV_CUR <> $PL_MOV_UP Then __NewDirection($PL_MOV_UP)
    EndIf
    If _IsPressed(25, $hDLL) Then ; left
    If $PL_MOV_CUR <> $PL_MOV_RIGHT And $PL_MOV_CUR <> $PL_MOV_LEFT Then __NewDirection($PL_MOV_LEFT)
    EndIf
    If _IsPressed(28, $hDLL) Then ; down
    If $PL_MOV_CUR <> $PL_MOV_UP And $PL_MOV_CUR <> $PL_MOV_DOWN Then __NewDirection($PL_MOV_DOWN)
    EndIf
    If _IsPressed(27, $hDLL) Then ; right
    If $PL_MOV_CUR <> $PL_MOV_LEFT And $PL_MOV_CUR <> $PL_MOV_RIGHT Then __NewDirection($PL_MOV_RIGHT)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc ;==>_NewDirection

    [/autoit] [autoit][/autoit] [autoit]

    Func __NewDirection($PL_NEW_DIRECTION = -1) ;Internal
    Local Static $KEY_BUFFER, $KEY_BUFFERTIMER
    If $PL_JUST_CHANGED_DIR Then
    $KEY_BUFFER = $PL_NEW_DIRECTION
    _Timer_KillTimer($hGUI, $KEY_BUFFERTIMER)
    Return
    EndIf
    If $PL_NEW_DIRECTION = -1 Then
    $PL_MOV_CUR = $KEY_BUFFER
    $KEY_BUFFERTIMER = _Timer_SetTimer($hGUI, 500 / $PL_SPEED * 0.75, "__NewDirection")
    Return
    EndIf
    $PL_MOV_CUR = $PL_NEW_DIRECTION
    $PL_JUST_CHANGED_DIR = True
    EndFunc ;==>__NewDirection

    [/autoit]
  • Der speed wird automatisch höher gestellt. Alle 5 "Beutetiere" erhöt sich der Speed um 0.5 (Zeile 154). Ich wollte den Schwierigkeitsgrad nicht zu schwer machen - Bei den Testläufen war es zwar lustig, wie schnell man reagieren musste (als der Speed noch anders berechnet wurde), aber bestimmte Altersgruppen und grobmotoriker haben dann ja doch nur noch Frust als Spielerlebnis.

    Außerdem bin ich mir nicht sicher ob meine hoffentlich zukünftigen Chefs zu den Zockern gehören :P