×

Podstawy GDScript – część 4 – operatory logiczne i instrukcje warunkowe (Godot tutorial po polsku)

Podstawy GDScript – część 4 – operatory logiczne i instrukcje warunkowe (Godot tutorial po polsku)

Wiemy już jak narysować sprite, jak nim poruszać i obracać. Wiemy jak wykonywać obliczenia. A co gdybyśmy chcieli na ich podstawie podejmować jakieś decyzje? Do tego przydadzą nam się instrukcje warunkowe, ale najpierw dokończmy zaczęty wcześniej temat operatorów logicznych wspomnianych przy okazji typu bool (od algebry Boole’a).

Dla niecierpliwych film, a dla dociekliwych artykuł pod nim.

Operacje porównania oraz logiczne

Operatory logiczne służą w programowaniu gier przede wszystkim do porównywania różnych wartości bądź stanów w jakich znajduje się obiekt. Na przykład:

  • czy gracz ma jeszcze wystarczającą ilość żyć?
  • kto komu zadał więcej obrażeń?
  • czy dana broń została już odblokowana, a jeśli tak, to czy gracz ma do niej amunicję?
  • czy gracz odnalazł wszystkie klucze potrzebne do przejścia do następnej planszy?
  • czy wybrał odpowiednie kwestie dialogowe w trakcie rozmowy z NPC?

Operatory porównania

Operatory porównania to działania, które możemy wykonywać na liczbach, a których wynikiem jest prawda (true) lub fałsz (false).

OperatorOpisPrzykład
<Porównanie: mniejsze niża < b
>Porównanie: większe niżb > a
==Równea == b
!=Różne oda != b
<=Mniejsze lub równea <= b
>=Większe lub równea >= b

Sprawdzimy jak to działa w praktyce – dla wyjaśnienia jednak dodam nieużywaną do tej pory opcję funkcji print. Otóż możemy jej podać kilka parametrów oddzielonych przecinkami, a zostaną one zamienione w jeden łańcuch znaków. Jeżeli znajdą się tam jakieś obliczenia lub porównania – w ich miejscu zostanie wstawiony wynik. Uruchom poniższy kod, żeby zobaczyć jak to działa i jakie są wyniki działania powyższych operatorów:

extends Node

var a: int = 5
var b: int = 10

func _ready() -> void:
	print("a = ", a)
	print("b = ", b)
	print("a > b: ", a > b)
	print("a < b: ", a < b)
	print("a == b: ", a == b)
	print("a != b: ", a != b)
	print("a <= b: ", a <= b)
	print("a >= b: ", a >= b)

Wynik:

a = 5
b = 10
a > b: false
a < b: true
a == b: false
a != b: true
a <= b: true
a >= b: false

Następnie zmień a = 10 i b = 5, a później a = 5 i b = 5. Porównaj sobie wyniki.

Operatory logiczne

W przypadku operatorów logicznych działamy na wartościach logicznych. Tutaj też wynikiem jest zawsze wartość logiczna true lub false.

OperatorOpisPrzykład
|| (alternatywny zapis: or)Logiczne lub (dwa znaki pipe na klawiaturze, zazwyczaj obok entera)a || b
&& (alternatywny zapis: and)Logiczne ia && b
! (alternatywny zapis: not)Negacja!a

Stosuję tutaj pewne uproszczenia – fachowo && to koniunkcja, || to alternatywa, itd. – dociekliwym polecam rozpiskę na Wikipedii.

Wyniki powyższych operacji najłatwiej pokazać w matrycy logicznej – takiej tabeli prawdy😉

Dla || (or) będzie to:

ABA || B (A or B)
falsefalsefalse
truefalsetrue
falsetruetrue
truetruetrue

Jak widać wystarczy żeby choć jeden parametr był prawdziwy i wynik też jest prawdziwy.

Dla && (and) będzie to:

ABA && B (A and B)
falsefalsefalse
truefalsefalse
falsetruefalse
truetruetrue

W tym przypadku oba parametry muszą być prawdziwe, żeby wynik był prawdziwy.

Dla ! (negacji) podajemy tylko jeden parametr – jest to po prostu odwrócenie wartości logicznej na przeciwną:

A!A
falsetrue
truefalse

Przykładowy kod pokazujący działanie operatorów logicznych

extends Node

var a: bool
var b: bool

func _ready() -> void:
	print("Przyklad 1:")
	a = false
	b = true
	print("a || b = ", a || b)
	print("a && b = ", a && b)
	print("!a = ", !a)
	
	print("Przyklad 2:")	
	a = true
	b = true
	print("a || b = ", a || b)
	print("a && b = ", a && b)
	print("!a = ", !a)

Wynik:

Przyklad 1:
a || b = true
a && b = false
!a = true
Przyklad 2:
a || b = true
a && b = true
!a = false

Instrukcje porównania (if/else)

Tym sposobem doszliśmy do wisienki na torcie tej części tutoriala. Znając porównania i operatory logiczne możemy wziąć się za instrukcje porównania. Dzięki nim możemy „sterować przepływem” programu na podstawie obliczeń i wartości zmiennych.

Porównanie zaczynamy od słowa kluczowego if – następnie podajemy warunek do spełnienia i dwukropek. W następnej linii i po wcięciu instrukcje do wykonania:

if warunek:
    instrukcja1
    instrukcja2

Czyli – jeżeli warunek jest spełniony, to wykonujemy instrukcje pod nim. Jeżeli nie jest spełniony – nic nie robimy, program leci dalej. Wynikiem warunku powinna być wartość logiczna prawda lub fałsz (true lub false) albo 1 lub 0 (które też przekładają się na prawda/fałsz).

Jeżeli jednak chcemy wyświetlić gdy nie jest spełniony, używamy instrukcji else i po dwukropku i wcięciu podajemy instrukcje.

if warunek:
    instrukcja1
    instrukcja2
else:
    instrukcja3
    instrukcja4

Tutaj taki konkretniejszy przykład, skopiuj i uruchom:

extends Node

var zycia: int = 0

func _ready() -> void:
	if zycia > 0:
		print("Gracz żyje")
	else:
		print("Gracz nie żyje")

Sprawdzamy, czy życia > 0 – jeżeli więcej, to wyświetlamy Gracz żyje, jeżeli mniej – Gracz nie żyje. Zamień teraz na początku kodu życia na 5 i uruchom ponownie.

Jeszcze precyzyjniejsze porównywanie (if/else/elif)

Gdy rozważamy kilka różnych opcji, możemy dodać dodatkowe warunki do takiego porównania, jeżeli mamy do sprawdzenia jakieś progi. Np. załóżmy, że oprócz punktów chcemy opisać stan gracza na podstawie ilości jego żyć (albo zmienić kolor paska życia). Uruchom poniższy kod:

extends Node

var zycia: int = 1

func _ready() -> void:
	if zycia == 5:
		print("Gracz ma pełne życie")
	elif zycia > 1 and zycia < 5:
		print("Gracz oberwał, ale żyje")
	elif zycia == 1:
		print("Gracz ledwie żyje")
	else:
		print("Gracz nie żyje")

Jak wyglądał przebieg tego porównania?

if zycia == 5
czy zmienna zycia była równa 5? Nie, lecimy dalej.

elif zycia > 1 and zycia < 5
czy zmienna zycia była większa od 1 i mniejsza od 5? Nie, lecimy dalej.

elif zycia == 1:
czy zmienna zycia była równa 1? Tak, wyświetlamy komunikat i kończymy porównywanie.

else:
program nawet tutaj nie doszedł. Bo został spełniony warunek wcześniej.

A teraz poeksperymentuj – ustaw zmienną życia kolejno na 5, 3 i 0 uruchamiając za każdym razem i odczytując komunikat jaki program wyświetli.

Kręcimy sprajta po raz kolejny

Ok, tekst tekstem, teraz coś bardziej efektownego – pokażę jak za pomocą instrukcji warunkowych sprawić, żeby sprite obracał się raz w prawo, raz w lewo. Zmiana kierunku będzie następowała po obrocie o 360 stopni.

Co będzie nam potrzebne?

Na pewno kierunek, w którym kręcimy sprite – zacznijmy od obrotu w prawo. Zmienną nazwę krec_w_prawo, będzie ona typu bool i jej wartość, to true.

W funkcji _ready() ustawię pozycję sprite na 100, 100 tak jak w poprzednich częściach kursu (żeby sprite nie był w rogu okna).

W funkcji _process() zrobimy logikę i obrót, taki pseudo kod wyglądałby tak:

Jeżeli sprite ma się kręcić w prawo to:
zwiększ jego obrót 
Jeżeli nie:
zmniejsz jego obrót (kręć w lewo)

Jeżeli obrót jest większy od lub równy 360 (czyli dokonał się pełny obrót sprite)
nie kręć już w prawo 
Jeżeli obrót jest mniejszy od lub równy 0 (czyli wrócił na początkową pozycję)
kręć w prawo

Tak właśnie można sobie rozpisywać „na brudno” programy przed napisaniem właściwego kodu:) Przekładając to na prawdziwy kod otrzymamy coś takiego – dodałem jeszcze prędkość, żeby szybciej zobaczyć efekty:

extends Sprite2D

var krec_w_prawo: bool = true
var predkosc: float = 150

func _ready() -> void:
	position.x = 100
	position.y = 100


func _process(delta: float) -> void:
	if krec_w_prawo == true:
		rotation_degrees += delta * predkosc
	else:
		rotation_degrees -= delta * predkosc
	
	if rotation_degrees >= 360:
		krec_w_prawo = false
	elif rotation_degrees <= 0:
		krec_w_prawo = true

Skopiuj kod do skryptu przypiętego do Sprite2D (na pewno już wiesz jak, a jeżeli nie – pisałem o tym tutaj)

Jeżeli wszystko poszło jak należy – sprite obróci się o 360 stopni w prawo i zacznie obracać się w lewo. Jak dojdzie do początkowego obrotu (zero), to znowu zacznie kręcić się w prawo itd.

Zakończenie

Sporo tego, ale mam nadzieję, że się przyda – zwłaszcza w następnych częściach mojego Godot tutoriala;) Jak zwykle wersja wideo pojawi się wkrótce – link do umieszczę w tym wpisie.

Projekt w GodotEngine 4.5 do pobrania tutaj.

Opublikuj komentarz