So morgen Leute,
Ich hab mir gedacht ich probier auch mal was in GDI+ und dabei ist dann das rausgekommen:
Spoiler anzeigen
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Compression=4
#AutoIt3Wrapper_UseUpx=n
#AutoIt3Wrapper_UseX64=n
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#cs ----------------------------------------------------------------------------
AutoIt Version: 3.3.6.1
Author: oetzn (autoit.de)
Script Function:
Snake Mini-Game
TO-DO:
* Items einbauen CHECK
* Level einbauen
* Verhältnis Normale Items | Special Items in Ini-Speichern (If Abfrage Random Wert)
#ce ----------------------------------------------------------------------------
[/autoit] [autoit][/autoit] [autoit]#include <GDIPlus.au3>
#include <GUIConstants.au3>
#include <Misc.au3>
#include <WinAPI.au3>
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
Opt("GuiCloseOnEsc", 0)
Opt("GuiOnEventMode", 1)
Opt("TrayOnEventMode", 1)
Opt("TrayMenuMode", 1)
Opt("MustDeclareVars", 1)
; STRINGS
Global Const $sTitle = "GDI+ SNAKE"
Global Const $sIniPath = @ScriptDir & "\" & $sTitle & ".ini"
Global Const $sString = "PRESS 'UP', 'DOWN', 'RIGHT' OR 'LEFT' TO BEGIN!"
; ARRAYS
Global $aC[1][3]
Global $aI[1][3]
Global $aP[1][3]
Global $aW[5][80][60] ; 5 Welten mit jeweils einer Größe von 80x60
Global $aITyp[4][2] = [["FASTER", 0xFF0000FF],["SLOWER", 0xFFFFFF00],["DOUBLE", 0xFFFF0000],["HALF", 0xFF00FF00]]
; WORLD 0 (CROSS)
For $i = 5 To 54
$aW[0][40][$i] = 1
Next
For $i = 4 To 74
$aW[0][$i][29] = 1
Next
; GUI
Global $GUIWidth = 320 * 3
Global $GUIHeight = 240 * 3
Local $hGUI, $hHelpGui, $hBitmap, $hBitmapWorld, $hGraphics, $hBuffer, $bBufferWorld, $hPenRed, $hPenGrey, $hPenBlue, $hPenGreen, $hPenYellow, $ButtonOK
[/autoit] [autoit][/autoit] [autoit]; INTEGER
Global $iSpeed
Global $iDefSpeed
Global $iDefParts
Global $iParts
Global $iSize
Global $iMovement
Global $iScaleFactor
Global $iLevel
Global $iGrowOnFeed
Global $iTimerFaster
Global $iTimerSlower
Global $iSpeedFactor
Global $iCornerStart = 0
Local $iXTemp
Local $iYTemp
Local $i, $j
; BOOLEAN
Global $bRunning = False
Global $bPaused = False
Global $bRestart = False
Global $bFaster = False
Global $bSlower = False
; FLOAT
Global $PlayTimer
Global $SpeedTimer
; INTERNAL USE
Global $bTimerDebug = False
Global $bElseDebug = True
Global $bDebugParts = False
Global $Timer
; READ INI
$iDefSpeed = IniRead($sIniPath, "Values", "Speed", 10)
$iDefParts = IniRead($sIniPath, "Values", "DefaultParts", 10)
$iScaleFactor = IniRead($sTitle, "Values", "ScaleFactor", 1)
$iGrowOnFeed = IniRead($sIniPath, "Values", "GrowOnFeed", 2)
$iTimerFaster = IniRead($sIniPath, "Values", "TimeFaster", 10)
$iTimerSlower = IniRead($sIniPath, "Values", "TimeSlower", 10)
$iSpeedFactor = IniRead($sIniPath, "Values", "Speedfactor", 5)
If $CmdLine[0] > 0 Then
If Not IsNumber($CmdLine[1]) Then
MsgBox(16, $sTitle, "ERROR!" & @CRLF & "Falscher Startparameter!")
Exit
ElseIf $CmdLine[1] > 5 Then
MsgBox(16, $sTitle, "ERROR!" & @CRLF & "Maximale Levelanzahl: 5!")
Exit
Else
$iLevel = $CmdLine[1]
EndIf
EndIf
If Not IsNumber($iLevel) Then $iLevel = 0
[/autoit] [autoit][/autoit] [autoit]$iSpeed = $iDefSpeed
$GUIWidth *= $iScaleFactor
$GUIHeight *= $iScaleFactor
$iSize = $GUIWidth / 80
$iParts = $iDefParts
$iMovement = $iSize
$aP[0][0] = $iSize
$aP[0][1] = $iSize
_GDIPlus_Startup()
[/autoit] [autoit][/autoit] [autoit]$hGUI = GUICreate($sTitle, $GUIWidth, $GUIHeight)
GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit", $hGUI)
$hHelpGui = GUICreate($sTitle & " Hilfe", 368, 288, 200, 117)
GUICtrlCreateGroup("Kommandozeilenparameter ", 8, 8, 353, 121)
GUICtrlCreateLabel("Gültige Parameter sind natürliche Zahlen zwischen 0 und 5.", 16, 32, 284, 17)
GUICtrlCreateLabel("Zum Beispiel:", 16, 56, 67, 17)
GUICtrlCreateLabel("GDI+ Snake.exe 3", 88, 56, 92, 17)
GUICtrlCreateLabel("GDI+ Snake.exe 0", 200, 56, 92, 17)
GUICtrlCreateLabel("Kein Parameter entspricht dem Parameter 0.", 16, 80, 211, 17)
GUICtrlCreateLabel("Der Parameter gibt die Welt an, die zu Spielbeginn geladen werden soll. ", 16, 104, 344, 17)
GUICtrlCreateGroup("", -99, -99, 1, 1)
GUICtrlCreateGroup("Itemlegende ", 8, 136, 353, 113)
GUICtrlCreateLabel("Ein rotes Item verdoppelt die Länge der Schlagen.", 16, 152, 240, 17)
GUICtrlCreateLabel("Ein grünes Item halbiert die Länge der Schlagen.", 16, 176, 233, 17)
GUICtrlCreateLabel("Ein blaues Item lässt die Schlange kurzzeitig schneller werden.", 16, 200, 298, 17)
GUICtrlCreateLabel("Ein gelbes Item lässt die Schlange kurzzeitig langsamer werden.", 16, 224, 304, 17)
GUICtrlCreateGroup("", -99, -99, 1, 1)
$ButtonOK = GUICtrlCreateButton("OK", 136, 256, 75, 25, $WS_GROUP)
GUICtrlSetOnEvent($ButtonOK, "_Help")
$hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI)
[/autoit] [autoit][/autoit] [autoit]$hBitmap = _GDIPlus_BitmapCreateFromGraphics($GUIWidth, $GUIHeight, $hGraphics)
$hBuffer = _GDIPlus_ImageGetGraphicsContext($hBitmap)
$hBitmapWorld = _GDIPlus_BitmapCreateFromGraphics($GUIWidth, $GUIHeight, $hGraphics)
$bBufferWorld = _GDIPlus_ImageGetGraphicsContext($hBitmapWorld)
$hPenGrey = _GDIPlus_PenCreate(0xFF808080)
$hPenBlue = _GDIPlus_PenCreate($aITyp[0][1])
$hPenYellow = _GDIPlus_PenCreate($aITyp[1][1])
$hPenRed = _GDIPlus_PenCreate($aITyp[2][1])
$hPenGreen = _GDIPlus_PenCreate($aITyp[3][1])
For $i = 0 To 79
For $j = 0 To 59
If $aW[$iLevel][$i][$j] == 1 Then
_GDIPlus_GraphicsDrawRect($bBufferWorld, $i * $iSize, $j * $iSize, $iSize, $iSize, $hPenGrey)
EndIf
Next
Next
HotKeySet("p", "_Pause")
HotKeySet("{F1}", "_Help")
HotKeySet("{F2}","_PlaceItem")
TrayTip($sTitle, $sString, 1)
[/autoit] [autoit][/autoit] [autoit]GUISetState(@SW_SHOW, $hGUI)
[/autoit] [autoit][/autoit] [autoit]While Not $bRunning
Sleep(10)
If _IsPressed(25) Or _IsPressed(26) Or _IsPressed(27) Or _IsPressed(28) Then $bRunning = True
WEnd
_PlaceItem()
[/autoit] [autoit][/autoit] [autoit]AdlibRegister("_CheckInput", 10)
[/autoit] [autoit][/autoit] [autoit]While 1
[/autoit] [autoit][/autoit] [autoit]If $bTimerDebug Then $Timer = TimerInit()
_CheckCollision()
_CheckTimer()
If $bTimerDebug Then ConsoleWrite("COLLISION & TIMER CHECKING: " & TimerDiff($Timer) & @CRLF)
If $bTimerDebug Then $Timer = TimerInit()
[/autoit] [autoit][/autoit] [autoit]For $i = 0 To UBound($aP, 1) - 1
[/autoit] [autoit][/autoit] [autoit]If $i == UBound($aP, 1) - 1 And $iParts > 0 Then
$iXTemp = $aP[$i][0]
$iYTemp = $aP[$i][1]
EndIf
Switch $aP[$i][2]
Case "LEFT"
$aP[$i][0] -= $iMovement
Case "UP"
$aP[$i][1] -= $iMovement
Case "RIGHT"
$aP[$i][0] += $iMovement
Case "DOWN"
$aP[$i][1] += $iMovement
EndSwitch
If $i == UBound($aP, 1) - 1 And $iParts > 0 Then
ReDim $aP[UBound($aP, 1) + 1][3]
$aP[UBound($aP, 1) - 1][0] = $iXTemp
$aP[UBound($aP, 1) - 1][1] = $iYTemp
$aP[UBound($aP, 1) - 1][2] = $aP[UBound($aP, 1) - 2][2]
$iParts -= 1
EndIf
For $j = $iCornerStart To UBound($aC, 1) - 1
Select
Case $aC[$j][2] = ""
ContinueLoop
Case $aP[$i][0] == $aC[$j][0] And $aP[$i][1] == $aC[$j][1]
$aP[$i][2] = $aC[$j][2]
Select
Case $i == UBound($aP, 1) - 1
$iCornerStart = $j
EndSelect
EndSelect
Next
Next
[/autoit] [autoit][/autoit] [autoit]If $bTimerDebug Then ConsoleWrite("MOVING & CORNER & ADDING: " & TimerDiff($Timer) & @CRLF)
[/autoit] [autoit][/autoit] [autoit]If $bTimerDebug Then $Timer = TimerInit()
[/autoit] [autoit][/autoit] [autoit]_GDIPlus_GraphicsClear($hBuffer, 0xFFFFFFFF)
[/autoit] [autoit][/autoit] [autoit]For $i = 0 To UBound($aP, 1) - 1
_GDIPlus_GraphicsDrawRect($hBuffer, $aP[$i][0], $aP[$i][1], $iSize, $iSize, 0)
Next
_DisplayItem()
[/autoit] [autoit][/autoit] [autoit]_GDIPlus_GraphicsDrawImageRect($hBuffer, $hBitmapWorld, 0, 0, $GUIWidth, $GUIHeight)
_GDIPlus_GraphicsDrawImageRect($hGraphics, $hBitmap, 0, 0, $GUIWidth, $GUIHeight)
If $bTimerDebug Then ConsoleWrite("DRAWING EVERYTHING: " & TimerDiff($Timer) & @CRLF)
If $bDebugParts Then ConsoleWrite("PARTS: " & UBound($aP,1) -1 & @TAB & "ECKEN: " & UBound($aC, 1) -1 & @CRLF & @CRLF)
Sleep(1000 / $iSpeed)
WEnd
Func _Pause()
If Not WinActive($sTitle) Then
HotKeySet("p")
Send("p")
HotKeySet("p", "_Pause")
Return
EndIf
$bPaused = Not $bPaused
While $bPaused
Sleep(100)
WEnd
EndFunc ;==>_Pause
Func _CheckInput()
If $bPaused Then Return
Local $bPressed = True
Select
Case _IsPressed(25) = 1
If $aP[0][2] <> "RIGHT" Then $aP[0][2] = "LEFT"
Case _IsPressed(26) = 1
If $aP[0][2] <> "DOWN" Then $aP[0][2] = "UP"
Case _IsPressed(27) = 1
If $aP[0][2] <> "LEFT" Then $aP[0][2] = "RIGHT"
Case _IsPressed(28) = 1
If $aP[0][2] <> "UP" Then $aP[0][2] = "DOWN"
Case Else
$bPressed = False
EndSelect
If $bPressed = False Then Return
[/autoit] [autoit][/autoit] [autoit]If $bElseDebug Then ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : UBound($aC, 1) - 1 = ' & UBound($aC, 1) - 1 & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
ReDim $aC[UBound($aC, 1) + 1][3]
If $bElseDebug Then ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : UBound($aC, 1) - 1 = ' & UBound($aC, 1) - 1 & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
$aC[UBound($aC, 1) - 1][0] = $aP[0][0]
;~ ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $aC[UBound($aC, 1) - 1][0] = ' & $aC[UBound($aC, 1) - 1][0] & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
$aC[UBound($aC, 1) - 1][1] = $aP[0][1]
;~ ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $aC[UBound($aC, 1) - 1][1] = ' & $aC[UBound($aC, 1) - 1][1] & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
$aC[UBound($aC, 1) - 1][2] = $aP[0][2]
;~ ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $aC[UBound($aC, 1) - 1][2] = ' & $aC[UBound($aC, 1) - 1][2] & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
EndFunc ;==>_CheckInput
Func _CheckCollision()
If $aP[0][0] < 0 Or $aP[0][0] > $GUIWidth Or $aP[0][1] < 0 Or $aP[0][1] > $GUIHeight Then _GameOver()
If Not $iParts > 0 Then
For $i = 1 To UBound($aP, 1) - 1
If $aP[0][0] = $aP[$i][0] And $aP[0][1] = $aP[$i][1] Then _GameOver()
Next
EndIf
For $i = 0 To 79
For $j = 0 To 59
If $aW[$iLevel][$i][$j] == 1 Then
If $aW[$iLevel][$i][$j] == 1 And $aP[0][0] == $i * $iSize And $aP[0][1] == $j * $iSize Then _GameOver()
EndIf
Next
Next
If $aP[0][0] = $aI[0][0] And $aP[0][1] = $aI[0][1] Then
Switch $aI[0][2]
Case "NORMAL"
$iParts += $iGrowOnFeed
Case $aITyp[0][0]
$iSpeed *= $iSpeedFactor
$bFaster = True
$SpeedTimer = TimerInit()
Case $aITyp[1][0]
$iSpeed /= $iSpeedFactor
$bSlower = True
$SpeedTimer = TimerInit()
Case $aITyp[2][0]
$iParts += (UBound($aP, 1) - 1)
Case $aITyp[3][0]
ReDim $aP[(UBound($aP, 1) - 1) / 2][3]
EndSwitch
_PlaceItem()
EndIf
EndFunc ;==>_CheckCollision
Func _CheckTimer()
If $bFaster Then
If TimerDiff($SpeedTimer) > $iTimerFaster * 1000 Then
$iSpeed /= $iSpeedFactor
$bFaster = False
EndIf
EndIf
If $bSlower Then
If TimerDiff($SpeedTimer) > $iTimerSlower * 1000 Then
$iSpeed *= $iSpeedFactor
$bSlower = False
EndIf
EndIf
EndFunc ;==>_CheckTimer
Func _PlaceItem()
Local $iRandom = Random(0, 10, 1)
;~ Local $iRandom = 8
Local $iX
Local $iY
Local $bDisplay = False
Local $bValid = False
Do
[/autoit] [autoit][/autoit] [autoit]$iX = Random(5, 75, 1)
$iY = Random(5, 55, 1)
For $i = 0 To UBound($aP, 1) - 1
If $aP[$i][0] <> $iX * $iSize And $aP[$i][1] <> $iY * $iSize And $aW[$iLevel][$iX][$iY] <> 1 Then
$bDisplay = True
ExitLoop
EndIf
Next
Until $bDisplay = True
[/autoit] [autoit][/autoit] [autoit]$aI[0][0] = $iX * $iSize
$aI[0][1] = $iY * $iSize
If $iRandom < 7 Then
$aI[0][2] = "NORMAL"
Else
Do
$iRandom = Random(0, 3, 1)
;~ $iRandom = 2
Switch $bFaster
Case True
If $iRandom <> 0 Then $bValid = True
Case False
$bValid = True
EndSwitch
Switch $bSlower
Case True
If $iRandom <> 1 Then $bValid = True
Case False
$bValid = True
EndSwitch
If $iRandom = 3 And UBound($aP, 1) - 1 = 1 Then $bValid = False
[/autoit] [autoit][/autoit] [autoit]Until $bValid = True
[/autoit] [autoit][/autoit] [autoit]$aI[0][2] = $aITyp[$iRandom][0]
EndIf
EndFunc ;==>_PlaceItem
Func _DisplayItem()
Switch $aI[0][2]
Case "NORMAL"
_GDIPlus_GraphicsFillRect($hBuffer, $aI[0][0], $aI[0][1], $iSize, $iSize)
Case $aITyp[0][0]
_GDIPlus_GraphicsFillRect($hBuffer, $aI[0][0], $aI[0][1], $iSize, $iSize, $hPenBlue)
Case $aITyp[1][0]
_GDIPlus_GraphicsFillRect($hBuffer, $aI[0][0], $aI[0][1], $iSize, $iSize, $hPenRed)
Case $aITyp[2][0]
_GDIPlus_GraphicsFillRect($hBuffer, $aI[0][0], $aI[0][1], $iSize, $iSize, $hPenYellow)
Case $aITyp[3][0]
_GDIPlus_GraphicsFillRect($hBuffer, $aI[0][0], $aI[0][1], $iSize, $iSize, $hPenGreen)
EndSwitch
EndFunc ;==>_DisplayItem
Func _Help()
If Not WinActive($sTitle) Then
HotKeySet("{F1}")
Send("{F1}")
HotKeySet("{F1}", "_Help")
Return
EndIf
Switch _WinAPI_IsWindowVisible($hHelpGui)
Case True
GUISetState(@SW_HIDE, $hHelpGui)
Case False
GUISetState(@SW_SHOW, $hHelpGui)
EndSwitch
EndFunc ;==>_Help
Func _GameOver()
If MsgBox(4, $sTitle, "GAME OVER" & @CR & "TRY AGAIN?") = 6 Then $bRestart = True
_Exit()
EndFunc ;==>_GameOver
Func _Exit()
_GDIPlus_GraphicsDispose($hBuffer)
_GDIPlus_BitmapDispose($hBitmap)
_GDIPlus_GraphicsDispose($hGraphics)
_GDIPlus_Shutdown()
IniWrite($sIniPath, "Values", "Speed", $iDefSpeed)
IniWrite($sIniPath, "Values", "DefaultParts", $iDefParts)
IniWrite($sIniPath, "Values", "ScaleFactor", $iScaleFactor)
IniWrite($sIniPath, "Values", "GrowOnFeed", $iGrowOnFeed)
IniWrite($sIniPath, "Values", "TimeFaster", $iTimerFaster)
IniWrite($sIniPath, "Values", "TimeSlower", $iTimerSlower)
IniWrite($sIniPath, "Values", "Speedfactor", $iSpeedFactor)
If $bRestart Then ShellExecute(@ScriptFullPath)
Exit
EndFunc ;==>_Exit
Es funktioniert auch schon ganz gut, nur die Performance ist das Problem. Sobald die Schlange länger als 20 - 30 Teile ist, braucht das Skript ewig (3-5 ms) um EINEN Part auf eine ECKE zu überprüfen.
Vielleicht kann sich ja das mal jemand ansehen und mir Optimierungsmöglickeiten vorschlagen. Wie gesagt, das Hauptproblem ist die Überprüfung, ob ein Teil (Part) der Schlange grade bei einer Ecke ist und somit abbiegen muss.
kleine Erklärung:
$aP = Array mit den Parts
$aW = Array mit der Welt
$aI = Array mit den Items
$aC = Array mit den Ecken
$aITyp = Array mit den Itemtypen
$aP, $aC sind so aufgebaut, dass im 1. Element (Index 0) der 2. Dimension ( also [0][0] zB) die x-Koordinate steht und im 2. Element (Index 1) die y-Koordinate. Im dritten Element (Index 2) steht entweder "LEFT, RIGHT, UP oder DOWN".
Beim Array der Teile gibt dies die Richtung an, in die sich ein Teil bewegt. Bei den Ecken gibt dieser Teil an, in welche Richtung sich ein Teil weiterbewegen muss, wenn er zu einer Ecke kommt.
Ich hoffe das erleichtert das Verständnis ein bisschen.
Noch eine Frage zum Schluss, hat jemand eine bessere Idee, wie ich die Welt noch zeichnen könnte? (So wie es jetzt ist, dauert es 25 ms pro Durchlauf)
Danke schon mal im Vorraus.
mfg oetzn
TO-DO:
* Mehrere Welten einbauen
* Punktezähler einbauen
EDIT: 20. Juni 12:14:
Ausgebesserte Version hochgeladen. Bug gefixt, dass die Schlange eine Länge von 0 erreichen kann.
EDIT: 20. Juni 12:59:
Dateianhang hinzugefügt.
EDIT: 20. Juni 13:31:
Hinzugefügt: Bei F2 wird das Item neu gezeichnet, da es vorkommen kann, dass kein Item erscheint.
Verbessert: Eigene Bitmap für die Welt ( name22, meintest du das so, wie ich es jetzt realisiert habe?)
Dateianhang upgedatet!
EDIT: 20. Juni 14:11:
Performance verbessert. Hatte den Ecken-Array noch auf 999 Elemente definiert, wodurch die Eckenüberprüfung lange dauerte.
EDIT: 20. Juni 14:28:
Geschwindigkeit des Spiels ist nun (fast) unabhängig von der Anzahl der Elemente. Diese Version würde ich nun als Alpha bezeichnen