Skocz do zawartości
  • 👋 Witaj na MPCForum!

    Przeglądasz forum jako gość, co oznacza, że wiele świetnych funkcji jest jeszcze przed Tobą! 😎

    • Pełny dostęp do działów i ukrytych treści
    • Możliwość pisania i odpowiadania w tematach
    • System prywatnych wiadomości
    • Zbieranie reputacji i rozwijanie swojego profilu
    • Członkostwo w jednej z największych społeczności graczy

    👉 Dołączenie zajmie Ci mniej niż minutę – a zyskasz znacznie więcej!

    Zarejestruj się teraz

[Tutorial]Tworzymy Grę W Autoit


Rekomendowane odpowiedzi

Opublikowano

Siema!

Nie wiem dlaczego, ale mi się nudziło i postanowiłem napisać tutorial o pisaniu gier w AutoIt

Zostało to spowodowane małym zainteresowaniem konkursem zorganizowanym przez jackraymund'a. Mam nadzieję, że następny, o ile będzie, to będzie cieszył się większym zainteresowaniem ze strony działu. ZACZYNAMY!

 

I - GUI

Dobra, tutaj macie całe GUI:

 

$hGUI = GUICreate("Snake by hfaua", 500, 400)
GUISetState()

 

Wiem, dużo tego

Teraz może wytłumaczę? Yyy... no tak... jakby to tu... O! Już mam! To będzie nasza plansza gry. GUI o rozmiarach 500x400

Może dodam jeszcze includy i zmienne ;)

#include <GDIPlus.au3>
#include <WindowsConstants.au3>

Global $Snake[100][3];obrazek, X, Y
Global $Owoc[4] = [0, 0, 0, 0]; tym się zajmiemy później (są to współrzędne, obrazek owocu oraz informacja czy jest on na planszy)
Global $Course = 3; kierunek naszego snejka
Global $Length = 10; obezna długość węża
Global $speed = 10; prędkość gry

 

Jedziemy dalej!

 

II - GUIRegisterMsg

Hmm, długo się zastanawiałem, czy zrobić GUIRegisterMsg, czy jednak HotKey'e i guictrlcreatepic. Doszedłem do wniosku, że lepiej jak się nauczycie więcej za jednym razem. Jest świetny tutorial o GUIRegisterMsg by 4ggr35510n. Polecam zajrzeć i zaznajomić się z tematem.

Dobra teraz kodzik:

GUIRegisterMsg(0x0100, "KeyPress")
GUIRegisterMsg(0x000F, "WM_PAINT")

Jak widzicie użyłem tą funkcję dwa razy. Pierwszy raz po to aby wychwycić jaki klawisz przyciskamy (WM_KEYDOWN - F1 -> Appendix -> Windows Message Codes i szukamy), a drugi aby rysować naszego snejka i owoce

 

Ok, może zanim objawię wam zawartość tych niewątpliwie powodujących gęsią skórkę funkcji zaczniemy od czegoś przyjemnego

Tworzymy naszego Pytona!

 

III - Tworzymy snejka

Dobra, do roboty! Chociaż nie... Najpierw by się przydało napisać tutka o GDIPlus :P No ale skoro już zacząłem tego to kontynuujmy ;)

Tworzymy prostą funkcję 'start()' Stworzymy w niej grę i węża:

Func start()
_GDIPlus_Startup()
Global $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI)
Global $OwocBrush = _GDIPlus_BrushCreateSolid(0xFFFF0000)
Global $SnakeBrush = _GDIPlus_BrushCreateSolid(0xFF00FF00)

create_snake()
EndFunc   ;==>start

 

Ok, teraz tłumaczymy co od czego jest:

1. _GDIPlus_Startup() <- Przygotowujemy Windowsowe GDI+

2. _GDIPlus_GraphicsCreateFromHWND($hGUI) <- Tworzymy nowy obiekt graficzny

3. _GDIPlus_BrushCreateSolid() <- Tworzymy nowy pędzel

4. create_snake <- nasza nowa funkcja tworząca węża.

Zajmijmy się tą funkcją:

Func create_snake()
For $i = 0 To $Length - 1
	$Snake[$i][1] = 100 + $i * 10
	$Snake[$i][2] = 110
	$Snake[$i][0] = _GDIPlus_GraphicsFillRect($hGraphics, $Snake[$i][1], $Snake[$i][2], 10, 10, $SnakeBrush)
Next
EndFunc   ;==>create_snake

 

I tłumaczymy :D

1. For $i = 0 to $Length -1 <- $Length to obecna długość naszego pytona

2. $Snake[$i][1] = 100 + $i * 10 <- Zapisujemy pozycję X elementu węża

3. $Snake[$i][2] = 110 <- zapisujemy pozycję Y części węża

4. $Snake[$i][0] = _GDIPlus_GraphicsFillRect($hGraphics, $Snake[$i][1], $Snake[$i][2], 10, 10, $SnakeBrush) <- Ta funkcja rysuje wypełniony kwadrat, za pomocą pędzla $SnakeBrush, który stworzyliśmy wcześniej.

Zapomniałem napisać wcześniej, ale nasz wąż będzie się składał z klocków 10x10. Będą one ustawione jeden za drugim (stąd to 100 + $i * 10). Będzie to wyglądało mniej więcej tak: [0][1][2][3][4][5] Element 0 jest to pysk (?) węża, a 5 to jego ogon

Myślę, że na razie wszystko jest jasne.

Teraz czas na sterowanie!

 

IV - Sterowanie

Przykro mi, ale musimy zająć się teraz owym, mrocznym GUIRegisterMsg. Jeśli cierpisz na padaczkę lub fenyloketonurię zaleca się pominąć ten rozdział i przejść do następnego.

Ok, więc piszemy funkcję 'KeyPress':

Func KeyPress($hWnd, $msg, $wParam, $lParam); na pewno jest to dobrze wytłumaczone w tutorialu by 4ggr35510n
$key = Dec(Hex($wParam)); zmieniamy kod przycisku na liczbę dziesiętną

Switch $key; switch przyciśniętego przycisku (masło maślane)
	Case 87; W
		$Course = 0; kierunek góra

	Case 68; D
		$Course = 1; kierunek prawo

	Case 83; S
		$Course = 2; kierunek dół

	Case 65; A
		$Course = 3; kierunek lewo

	Case 35; END
		Exit; koniec gry

EndSwitch
EndFunc   ;==>KeyPress

Wszystko jasne, nie? Nie? o.O No dobra...

1. $wParam < -zawiera kod przycisku który nacisnęliśmy

2. $key = Dec(Hex($wParam)) <- zmienna $key zawiera ten kod w postaci dziesiętnej

3. Switch $key <- sprawdzamy czy $key to nasze przyciski sterowania

Lepiej wytłumaczone macie to w tutku 4ggr35510n'a, do którego odsyłam was chyba piąty raz

Sprawdzamy czy działa! Hehe, oczywiście, że nie. To tylko powoduje zmianę kierunku w którym przemieszcza się nasz pyton.

Musimy stworzyć funkcję poruszająca węża!

 

V - Poruszania węża do przodu

Teoretycznie musimy narysować te same obrazki tylko na innych pozycjach. Tylko jak? Ja zwykle piszę sobie funkcję refresh() i używam ją, jeśli muszę zaktualizować GUI programu. Nasza funkcja refresh, będzie wyglądała tak:

Func refresh()
_GDIPlus_GraphicsClear($hGraphics, 0xFFFFFFFF)

For $i = 0 To $Length - 1
	$Snake[$i][0] = _GDIPlus_GraphicsFillRect($hGraphics, $Snake[$i][1], $Snake[$i][2], 10, 10, $SnakeBrush)
Next
EndFunc   ;==>refresh

 

Teraz tłumaczymy:

1. _GDIPlus_GraphicsClear($hGraphics, 0xFFFFFFFF) <- Czyścimy naszą planszę i nadajemy jej biały kolor

2. For $i = 0 To $Length - 1 ... <- Rysujemy na nowo naszego snejka

To na razie tyle w tej funkcji

Teraz musimy jakoś ruszyć węża

Najlepiej będzie wykorzystać do tego pętelkę While.

Kodzik:

While True
Sleep($speed * 10); przerwa, żeby można było regulować prędkość gry
turn(); ruch węża
check_owoce(); narazie sobie tym nie zaprzątajcie głowy
check_snake(); tym tez
check_map(); i tym
refresh(); nasza funkcja odświeżająca planszę
WEnd

Kilka słów wyjaśnienia:

1. Sleep($speed * 10) <- Ile mamy czekać między ruchami snejka (im większe speed tym więcej czekamy)

2. turn() <- funkcja ruszająca węża do przodu

3. check_owoce _snake _map <- to na razie nas nie dotyczy, o tym później

4. refresh() <- odświeżamy plansze, aby zobaczyć wyniki naszej pracy

Teraz czas na funkcję turn()

 

Func turn()
For $i = $Length - 1 To 1 Step -1
	$Snake[$i][1] = $Snake[$i - 1][1]
	$Snake[$i][2] = $Snake[$i - 1][2]
Next

Switch $Course
	Case 0
		$Snake[0][2] -= 10

	Case 1
		$Snake[0][1] += 10

	Case 2
		$Snake[0][2] += 10

	Case 3
		$Snake[0][1] -= 10

EndSwitch
EndFunc   ;==>turn

 

Widzicie? Nie wygląda tak strasznie.

Dobra, teraz muszę napisać 'O co w tym kurwa chodzi?' :]

1. For $i = $Length - 1 To 1 Step -1.... <- Przesuwamy, zaczynając od ostatniego, wszystkie elementy za pozycję poprzednich

2. Switch $Course <- Teraz sprawdzamy w jakim kierunku ma się poruszać nasz wąż

3. $Snake[0][2] -= 10, += 10 itd. <- Poruszamy pysk naszego snejka w odpowiednim kierunku

Myślę, że do te pory wszystko jasne.

Może teraz zrobimy owoce?

 

VI - Owoce

W tym klasyczny snejku owoce pokazywały się pojedynczo, więc aby nie przeładować wasze mózgi informacjami zrobimy podobnie

Zastanówmy się, co ile mają się pokazywać owoce? Ja by proponował co 10 sek. Czemu? Nie wiem, tak jakoś.. Poza tym każdy będzie sobie mógł to zmienić.

Najlepiej użyć do tego funkcji AdLibRegister (można też Timer'ów, ale ja wolę to bo mniej pisania i łatwiej załapać). Musimy wstawić do funkcji start Adlib'a. Będzie ona wyglądała mniej więcej tak:

Func start()
_GDIPlus_Startup()
Global $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI)
Global $OwocBrush = _GDIPlus_BrushCreateSolid(0xFFFF0000)
Global $SnakeBrush = _GDIPlus_BrushCreateSolid(0xFF00FF00)

create_snake()
owoce()
AdlibRegister("owoce", 10000)
EndFunc   ;==>start

 

Czemu dałem funkcję owoce() przed adlibem?, chciałem, żebyśmy mieli owocki już od początku gry :]

Teraz zawartość funkcji owoce():

Func owoce()
If Not $Owoc[1] Then
	$Owoc[1] = 1
	$Owoc[2] = Random(0, 49, 1) * 10
	$Owoc[3] = Random(0, 39, 1) * 10
	$Owoc[0] = _GDIPlus_GraphicsFillRect($hGraphics, $Owoc[2], $Owoc[3], 10, 10, $OwocBrush)
EndIf
EndFunc   ;==>owoce

 

No tak... Już wyjaśniam:

1. If Not $Owoc[1] Then <- ten element tablicy $Owoc zawiera informacje o tym czy owoc jest na planszy, czy jest już zebrany (zapobiega kilku owocom na mapie)

2. $Owoc[1] = 1 <- Owoc jest na mapie

3. $Owoc[2] = Random(0, 49, 1) * 10 <- losowa pozycja X owocu (wielokrotność 10)

4. $Owoc[3] = Random(0, 39, 1) * 10 <- losowa pozycja Y owocu (wielokrotność 10)

5. $Owoc[0] = $Owoc[0] = _GDIPlus_GraphicsFillRect($hGraphics, $Owoc[2], $Owoc[3], 10, 10, $OwocBrush) <- kwadracik narysowany na pozycji owocu za pomocą pędzla $OwocBrush.

Chyba wszystko jasne?

Owocki się tworzą, wszystko jest super, ale nie możemy ich zbierać

Pamiętacie jak pisałem, że te funkcje w While'u nas na razie nie dotyczą? Teraz się nimi zainteresujemy, a przynajmniej jedną. Chodzi mi o funkcję check_owoce().

Zawartość funkcji:

Func check_owoce()
If ($Snake[0][1] = $Owoc[2]) And ($Snake[0][2] = $Owoc[3]) Then
	$Owoc[1] = 0
	$Length += 1
EndIf
EndFunc   ;==>check_owoce

 

Standardowo tłumaczymy:

1. If ($Snake[0][1] = $Owoc[2]) And ($Snake[0][2] = $Owoc[3]) Then <- jeśli współrzędne pyska węża i owocu są równe to go zbiera

2. $Owoc[1] = 0 <- Owocu już nie ma na planszy

3. $Length += 1 <- Powiększamy długość węża o 1

Zbiera się? No ba! Mój kod by nie zbierał... Tylko by spróbował B)

Teraz napiszemy ograniczenia w grze!

 

VII - Ograniczenia

No i tak. Graliście już w stworzoną przez nas wersję gry? Nie?? No tak, najlepiej ściągnąć gotowca i się nic nie nauczyć...

Ale ja już to umiem, więc to wasz problem. Mniejsza z tym ;) Problem -> możemy wyjechać snejkiem z planszy

Trzeba napisać ograniczenia.

Najpierw zastanówmy się gdzie je dać? No tak do While. Najlepiej zaraz po ruchu, abyśmy mogli wyeliminować pomyłkę zaraz po jej zaistnieniu.

My już mamy to w While'u, więc piszemy od razu funkcję:

Func check_map()
If ($Snake[0][1] > 490) Or ($Snake[0][1] < 0) Or ($Snake[0][2] > 390) Or ($Snake[0][2] < 0) Then
	Exit
EndIf
EndFunc   ;==>check_map

 

Wyjaśnienie:

1. If $Snake[0][1] > 490.... <- jeśli pysk snejka przekroczy wymiary mapki to wyłączamy grę. Wy możecie (a nawet powinniście) napisać jakieś komunikaty i powrót do menu.

Dobra, ale co jeśli najedziemy wężem na samego siebie? o.O Będziemy nim po sobie jeździli? NIE! Jeszcze się biedaczek zapląta i będzie trzeba przerwać grę, aby ktoś go wyprostował. Aby zapobiec takim mankamentom napiszemy prostą funkcję, która będzie sprawdzała czy jakiś element snejka nachodzi na inny.

Funkcja:

Func check_snake()
For $i = 0 To $Length - 1
	For $x = 0 To $Length - 1
		If Not ($i = $x) Then
			If ($Snake[$i][1] = $Snake[$x][1]) And ($Snake[$i][2] = $Snake[$x][2]) Then
				Exit
			EndIf
		EndIf
	Next
Next
EndFunc   ;==>check_snake

 

1. For $i / $x <- Sprawdzamy po kolei każdy element z każdym

2. If Not ($i = $x) Then <- Jeśli to nie jest ten sam element

3. If ($Snake[$i][1] = $Snake[$x][1]) And ($Snake[$i][2] = $Snake[$x][2]) Then <- Jeśli na siebie nachodzą to koniec gry :]

Gra już jest prawie ukończona

 

VIII - WM_PAINT

Ciekawe czy ktoś zauważył, że nie wykorzystaliśmy takiej funkcji jak WM_PAINT? A przecież pisałem, że się przyda :]

No tak... Spróbujcie zwinąć i ponownie rozwinąć grę. No tak jest refresh(), który się wykonuje co chwilkę. Jeśli by go nie było (spróbujcie zakomentować) to byłoby puste GUI o.O Do tego służy WM_PAINT. Myślałem w ogóle napisać o GDI+ nowy tutorial, ale to się jeszcze zobaczy.

Piszemy WM_PAINT:

Func WM_PAINT($hWnd, $msg, $wParam, $lParam)
refresh()
EndFunc   ;==>WM_PAINT

 

WTF? No tak, po co pisać to 2 razy, skoro możemy wywołać funkcję refresh?

Tu chyba nie ma nic do tłumaczenia.

 

No to by było na tyle :]

Jeszcze tylko pełny kod:

#include <GDIPlus.au3>
#include <WindowsConstants.au3>

Global $Snake[100][3];obrazek, X, Y
Global $Owoc[4] = [0, 0, 0, 0]
Global $Course = 3
Global $Length = 10
Global $speed = 10

$hGUI = GUICreate("Snake by hfaua", 500, 400)
GUISetState()

GUIRegisterMsg(0x0100, "KeyPress")
GUIRegisterMsg(0x000F, "WM_PAINT")

start()

While True
Sleep($speed * 10)
turn()
check_owoce()
check_snake()
check_map()
refresh()
WEnd

Func check_snake()
For $i = 0 To $Length - 1
	For $x = 0 To $Length - 1
		If Not ($i = $x) Then
			If ($Snake[$i][1] = $Snake[$x][1]) And ($Snake[$i][2] = $Snake[$x][2]) Then
				Exit
			EndIf
		EndIf
	Next
Next
EndFunc   ;==>check_snake

Func check_owoce()
If ($Snake[0][1] = $Owoc[2]) And ($Snake[0][2] = $Owoc[3]) Then
	$Owoc[1] = 0
	$Length += 1
EndIf
EndFunc   ;==>check_owoce

Func check_map()
If ($Snake[0][1] > 490) Or ($Snake[0][1] < 0) Or ($Snake[0][2] > 390) Or ($Snake[0][2] < 0) Then
	Exit
EndIf
EndFunc   ;==>check_map

Func create_snake()
For $i = 0 To $Length - 1
	$Snake[$i][1] = 100 + $i * 10
	$Snake[$i][2] = 110
	$Snake[$i][0] = _GDIPlus_GraphicsFillRect($hGraphics, $Snake[$i][1], $Snake[$i][2], 10, 10, $SnakeBrush)
Next
EndFunc   ;==>create_snake

Func KeyPress($hWnd, $msg, $wParam, $lParam)
$key = Dec(Hex($wParam))

Switch $key
	Case 87
		$Course = 0

	Case 68
		$Course = 1

	Case 83
		$Course = 2

	Case 65
		$Course = 3

	Case 35
		Exit

EndSwitch
EndFunc   ;==>KeyPress

Func turn()
For $i = $Length - 1 To 1 Step -1
	$Snake[$i][1] = $Snake[$i - 1][1]
	$Snake[$i][2] = $Snake[$i - 1][2]
Next

Switch $Course
	Case 0
		$Snake[0][2] -= 10

	Case 1
		$Snake[0][1] += 10

	Case 2
		$Snake[0][2] += 10

	Case 3
		$Snake[0][1] -= 10

EndSwitch
EndFunc   ;==>turn

Func start()
_GDIPlus_Startup()
Global $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI)
Global $OwocBrush = _GDIPlus_BrushCreateSolid(0xFFFF0000)
Global $SnakeBrush = _GDIPlus_BrushCreateSolid(0xFF00FF00)

create_snake()
owoce()
AdlibRegister("owoce", 10000)
EndFunc   ;==>start

Func owoce()
If Not $Owoc[1] Then
	$Owoc[1] = 1
	$Owoc[2] = Random(0, 49, 1) * 10
	$Owoc[3] = Random(0, 39, 1) * 10
	$Owoc[0] = _GDIPlus_GraphicsFillRect($hGraphics, $Owoc[2], $Owoc[3], 10, 10, $OwocBrush)
EndIf
EndFunc   ;==>owoce

Func WM_PAINT($hWnd, $msg, $wParam, $lParam)
refresh()
EndFunc   ;==>WM_PAINT

Func refresh()
_GDIPlus_GraphicsClear($hGraphics, 0xFFFFFFFF)

For $i = 0 To $Length - 1
	$Snake[$i][0] = _GDIPlus_GraphicsFillRect($hGraphics, $Snake[$i][1], $Snake[$i][2], 10, 10, $SnakeBrush)
Next

If $Owoc[1] Then
	$Owoc[0] = _GDIPlus_GraphicsFillRect($hGraphics, $Owoc[2], $Owoc[3], 10, 10, $OwocBrush)
EndIf
EndFunc   ;==>refresh

 

GRA JEST GOTOWA!!!

I możemy zacząć pisać własną gierkę :D Jeśli ktoś coś napisze to niech da na forum to ocenimy. :]

Żeby was nie zniechęcić poziomem mojej 'Pr0 elo elo gry' to napiszę, że moje pierwsze gry były naprawdę (jak to mówili prehistoryczni australijscy eskimosi) cieńkie jak sik wynża :P Więc klawiatury w dłoń i do roboty!

 

PS. Ło kurwa! Ale to długie wyszło :D

PPS. Pewnie zapomniałem o połowie rzeczy więc piszcie.

PPPS. Jeśli nie rozumiecie (nie dziwie się wam) to piszcie również, postaram się wytłumaczyć dokładnej.

 

Pozdrawiam, hfaua B)

Opublikowano

Przyjemnie się czytało..:)

 

PS.

 

 

 

Fakt,sporo czytania.

 

PS2.

 

Dostałeś już Versje VIP 123 H,że powstał owy TuT?

 

 

Niech szlag,151 errorow mi wyskoczylo...

Opublikowano
Dobra, tutaj macie całe GUI:

$hGUI = GUICreate("Snake by hfaua", 500, 400)
GUISetState()

Wiem, dużo tego

 

ROFL :D

 

- - -

 

Dobra, a teraz wytykamy błędy:

 

#include <WinAPI.au3>
#include <GDIPlus.au3>

 

GDIPlus sam includuje WinAPi, więc ta linijka niepotrzebna.

 

Dalej nie doszedłem, ponieważ gra wywala się, gdy tylko wąż dotrze do krawędzi ekranu.

 

 

@Edit:

 

Ahaa, że niby ginie?

 

No dobra. Więc jeszcze w sprawie mechanizmów:

Po 'pójściu' w stronę swojego tyłka również ginie. Jak długo grałem na Nokii 3310, tak długo taki ruch był ignorowany :P

 

 

 

No a teraz na poważnie: (w sensie bardziej niż ostatnio)

 

Jeśli dobrze rozumiem, to co pętlę pozycja całego węża jest przesuwana.

Czy ktoś mógłby mi wytłumaczyć dlaczego, skoro jedyna co trzeba zrobić, to przestawić ostatnią "część tłowia" (klocek/kwadrat) na sam przód, przed głowę (pierwszy klocek)?

Z tego powodu mamy do czynienia z potwornym mruganiem.

 

 

 

Jeszcze Ci mało ?

 

Nie rozumiem też, po co refresh() w WM_PAIN'cie, skoro dokonuje się on co kilka(naście) milisekund w głównej pętli.

 

Jeśli by go nie było (spróbujcie zakomentować)

 

Yes, we dare!

 

 

#include <WinAPI.au3>
#include <GDIPlus.au3>
#include <WindowsConstants.au3>

Global $Snake[100][3];obrazek, X, Y
Global $Owoc[4] = [0, 0, 0, 0]
Global $Course = 2 ;dw
Global $Length = 10
Global $speed = 10

$hGUI = GUICreate("Snake by hfaua", 500, 400)
GUISetState()

GUIRegisterMsg(0x0100, "KeyPress")
GUIRegisterMsg(0x000F, "WM_PAINT")

start()

While True
       Sleep($speed * 10)
       turn()
       check_owoce()
       check_snake()
       check_map()
       refresh()
WEnd

Func check_snake()
       For $i = 0 To $Length - 1
               For $x = 0 To $Length - 1
                       If Not ($i = $x) Then
                               If ($Snake[$i][1] = $Snake[$x][1]) And ($Snake[$i][2] = $Snake[$x][2]) Then
                                       Exit
                               EndIf
                       EndIf
               Next
       Next
EndFunc   ;==>check_snake

Func check_owoce()
       If ($Snake[0][1] = $Owoc[2]) And ($Snake[0][2] = $Owoc[3]) Then
               $Owoc[1] = 0
               $Length += 1
       EndIf
EndFunc   ;==>check_owoce

Func check_map()
       If ($Snake[0][1] > 490) Or ($Snake[0][1] < 0) Or ($Snake[0][2] > 390) Or ($Snake[0][2] < 0) Then
               Exit
       EndIf
EndFunc   ;==>check_map

Func create_snake()
       For $i = 0 To $Length - 1
               $Snake[$i][1] = 100 + $i * 10
               $Snake[$i][2] = 110
               $Snake[$i][0] = _GDIPlus_GraphicsFillRect($hGraphics, $Snake[$i][1], $Snake[$i][2], 10, 10, $SnakeBrush)
       Next
EndFunc   ;==>create_snake

Func KeyPress($hWnd, $msg, $wParam, $lParam)
       $key = Dec(Hex($wParam))

       Switch $key
               Case 87
                       $Course = 0

               Case 68
                       $Course = 1

               Case 83
                       $Course = 2

               Case 65
                       $Course = 3

               Case 35
                       Exit

       EndSwitch
EndFunc   ;==>KeyPress

Func turn()
       For $i = $Length - 1 To 1 Step -1
               $Snake[$i][1] = $Snake[$i - 1][1]
               $Snake[$i][2] = $Snake[$i - 1][2]
       Next

       Switch $Course
               Case 0
                       $Snake[0][2] -= 10

               Case 1
                       $Snake[0][1] += 10

               Case 2
                       $Snake[0][2] += 10

               Case 3
                       $Snake[0][1] -= 10

       EndSwitch
EndFunc   ;==>turn

Func start()
       _GDIPlus_Startup()
       Global $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI)
       Global $OwocBrush = _GDIPlus_BrushCreateSolid(0xFFFF0000)
       Global $SnakeBrush = _GDIPlus_BrushCreateSolid(0xFF00FF00)

       create_snake()
       owoce()
       AdlibRegister("owoce", 10)
EndFunc   ;==>start

Func owoce()
       If Not $Owoc[1] Then
               $Owoc[1] = 1
               $Owoc[2] = Random(0, 49, 1) * 10
               $Owoc[3] = Random(0, 39, 1) * 10
               $Owoc[0] = _GDIPlus_GraphicsFillRect($hGraphics, $Owoc[2], $Owoc[3], 10, 10, $OwocBrush)
       EndIf
EndFunc   ;==>owoce

Func WM_PAINT($hWnd, $msg, $wParam, $lParam)
       ; refresh()
EndFunc   ;==>WM_PAINT

Func refresh()
       _GDIPlus_GraphicsClear($hGraphics, 0xFFFFFFFF)

       For $i = 0 To $Length - 1
               $Snake[$i][0] = _GDIPlus_GraphicsFillRect($hGraphics, $Snake[$i][1], $Snake[$i][2], 10, 10, $SnakeBrush)
       Next

       If $Owoc[1] Then
               $Owoc[0] = _GDIPlus_GraphicsFillRect($hGraphics, $Owoc[2], $Owoc[3], 10, 10, $OwocBrush)
       EndIf
EndFunc   ;==>refresh

 

Powyższy fragment jest identyczny z ostatecznym kodem, z jedną różnicą -> wykomentowanie linii refresh() w WM_PAINC'ie.

(w zasadzie to z dwoma różnica, bo wkurzało mnie to zabijanie się o ścianę)

 

Ale tak napradę wycinanie refresha() z WM_PAINT'a do niczego nie prowadzi. W zasadzie jest błędem ( wycinanie jest błędem, w sensie refresh() powinien tam być ).

 

Natomiast, właśnie w głównej pętli, refresha być nie powinno w takiej postaci w jakiej jest teraz:

Oprócz wspomnianego już przerysowywanie węża w całości (zamiast zamiany koloru dwóch pól) funkcja refresh() odświeża całe okno i przerysowywuje całego węża ==> mruganie.

 

Rysowanie całego węża jest akceptowalne tylko w WM_PAINC'ie, więc tak naprawdę potrzebne nam są dwie zupełnie różne funkcje. W żadnej jednak nie będziemy używać 'graphicsClear()'. Nie rozumiem zupełnie, co tam funkcja tam robi?!!! Czyż nie łatwiej i optymalniej byłoby po prostu stworzyć białe GUI ? GUISetBKColor(0xFFFFFF) i nie musimy niczego czyścić.

 

Podobnie, co każdą pętle wykonuje się przerysowywanie owocu... Po co? Przecież zjadamy go stosunkowo rzadko...

 

 

 

 

Coś czuję, że zamotałem.

Dlatego nie piszę tutoriali, tylko narzekam na istniejące :P

 

@Edit2:

 

A, no tak, plus.

Ta sygnatura jest pusta.

Opublikowano

A no tak masz rację :P Nie pomyślałem :] grę pisałem w czasie pisania tutorialu, wiec starałem się ją napisać tak żeby wszyscy (a przynajmniej większość) zrozumieli ;) Co do includa to masz rację, już usuwam ;) Jeśli chodzi o to chodzenie to nie chciało mi się już z tym robić, bo mnie już oczka bolą od monitora :P

 

Mam nadzieję, że kiedyś coś napiszę tak, że nie będziesz miał się do czego przyczepić :D

 

BTW

Motywacja została po poprzednich azjatkach :D

Opublikowano

Hah,czyli bylo aż tak dobrze?

 

NoNo....

 

 

No co jest,nie moge tym Snejkiem ruszac ........................!

Opublikowano

Po następne!

 

Wklej to zamiast dotychczasowej funkcji WM_PAINT

 

Func WM_PAINT($hWnd, $msg, $wParam, $lParam)
Local $left, $top, $right, $bottom
DllCall('user32.dll', 'bool', 'GetUpdateRect', 'hwnd', $hGUI, 'uint', $tPointer, 'bool', 'false')

$left = DllStructGetData($tRectStruct, 1)
$top = DllStructGetData($tRectStruct, 2)
$right = DllStructGetData($tRectStruct, 3)
$bottom = DllStructGetData($tRectStruct, 4)

ConsoleWrite($left & @CRLF)
ConsoleWrite($top & @CRLF)
ConsoleWrite($right & @CRLF)
ConsoleWrite($bottom & @CRLF)
ConsoleWrite('! ==========' & @CRLF)

 

Oraz! gdzieś na samym początku skryptu:

 

$tRectStruct = DllStructCreate($tagRECT)
$tPointer = DllStructGetPtr($tRectStruct)

 

Jak wyraźnie widać, zmienne $left, $top, $right i $bottom zawierają teraz relatywne wymiary regionu okna, który należy odświeżyć.

 

Jeśli musi być odświeżony lewy dolny róg -> wiesz, że wystarczy odświeżyć lewy dolny róg. I tak dalej. Nie musisz odświeżać całego węża. Najczęściej nawet w ogóle nie musisz odświeżać ;)

 

 

Mam nadzieję, że kiedyś coś napiszę tak, że nie będziesz miał się do czego przyczepić

 

Wielu już próbowało xD

Ta sygnatura jest pusta.

Opublikowano

Zostawię jak jest :P

To nie jest gra na konkurs, albo do oceny ;)

Taki przykład, żeby się ktoś nauczył pisać gierki :]

Jakbym dodał Twój kod to by nikt (z osób dla których jest ten tutek) nic nie zrozumiał :)

 

#EDIT

Właśnie przeczytałem Twojego edita :P

Nie pisałem, żeby było jak najoptymalniej :)

Więc już się tak nie przyczepiaj :P To jest tylko przykład na którym tłumaczę jak takie coś napisać :) Jeśli ktoś to zakapuje i będzie chciał napisać jakąś grę to będzie już wiedział jak zacząć ;)

 

BTW.

I mnie zniechęciłeś do pisania tutka o GDI+ :P

Opublikowano

Wczoraj wpadłem na pomysł i zacząłem pisać snejka, ale doszedłem do wniosku, że jednak napiszę go od nowa i od razu wytłumaczę co i jak ;)

Opublikowano

Ale błędny przykład.

 

Po co ludzi uczyć błędnych rozwiązań?

 

I mnie zniechęciłeś do pisania tutka o GDI+

Cała przyjemność po mojej stronie!

 

Raz jeszcze jednobiegunowo afektywne nastawienie Shopenhauerskiego pesymizmu zwyciężyło nad naiwnym zapałem niedoświadczonych entuzjastów!

Ta sygnatura jest pusta.

Opublikowano

Czemu błędnych? :] Może gorszy, ale łatwiejszych do zrozumienia ;)

Jakbym dał Twój kod i go przerobił tak jak piszesz to by 3/4 nie zrozumiało :]

Wierz mi napisałbym lepszego ;) Tego pisałem (razem z tutkiem) 3h i wyszedł jak chciałem ;) Nie jest jakiś super rozbudowany, bo wtedy tutek by musiał być 3x dłuższy :P PROSTA gierka pokazująca jak napisać PROSTE poruszanie się po mapce i PROSTE zbieranie owoców ;)

  • 2 miesiące temu...
Opublikowano

Bardzo fajny i przydatny poradnik :> Od razu widać o co gdzie chodzi. Na podstawie tego można zrobić pełno innych gier, m.in Ponga :D

 

Masz tam błąd:

Func refresh()
       _GDIPlus_GraphicsClear($hGraphics, 0xFFFFFFFF)

       For $i = 0 To $Length - 1
               $Snake[$i][0] = _GDIPlus_GraphicsFillRect($hGraphics, $Snake[$i][1], $Snake[$i][2], 10, 10, $SnakeBrush)
       Next
EndFunc   ;==>refresh

 

Brakuje malowania owoców.

//Zakaz gifów-Dektored

Opublikowano

Faktycznie :P Musiałem podczas łączenia kodu wziąć ten kawałek sprzed zrobienia owocków :)

Myślałem napisać jeszcze tutka o GDI+, ale może ktoś się na to pokusi? (4ggr :D )

Wtedy by już było wszystko potrzebne do zrobienia gry, na konkurs, który rusza za niedługo ;>

  • 2 tygodnie później...
  • 6 miesięcy temu...
Opublikowano

Cześc, za pierwszym razem miałem tylko 1 error, potem poprawiłem ale snake skręca tylko w dół i w lewy bok "A", "S".

Co zrobić aby chodził dobrze. ?

1z3uffc.png

Sygnatura by around i av.

Uczę Się Programować !

  • 10 miesięcy temu...

Zarchiwizowany

Ten temat przebywa obecnie w archiwum. Dodawanie nowych odpowiedzi zostało zablokowane.

×
×
  • Dodaj nową pozycję...