Hagyományos számológép használata
http://f-labor.mkt.bme.hu/~madas/index.php?rst=mp&rid=itpypr
(Szia! Ha még nem telepítetted volna föl a gépedre a Pythont és a Pygamet, akkor ugorj ide, az "előszó" részhez, hogy letöltsd és telepítsd, és készen állj a kezdésre.
1.1 Bevezetés
fig.trajectory
Az egyik legegyszerűbb dolog, amire a Python használható, az a csinos kis számológép funkciója. Várjunk csak, a számológép nem is játék. Mégis miért beszélünk róla? Uncsi...
Nos, ahhoz, hogy kiszámoljuk a tárgyak esését, a lövedék röppályáját, és a legjobb pontszámokat, ahhoz számológép kell. Plussz, bármely igazi kocka úgy tekint a számológépre, mint egy játékra. Inkább, mint egy kínzóeszközre. Szóval, kezdjük el a tanulást a számológéppel. Ne aggódj, a grafikát már az ötödik fejezetnél tárgyaljuk.
Egy egyszerű számológép program már használható arra, hogy a felhasználó infót kapjon unalmas dolgokról, mint amilyen az ingatlanhitel utalása, vagy mondjuk izgalmasabb dolgokról, mint például a röppályája egy sárgolyónak.
Ahogyan azt az első példa mutatja, mozgási energiát fogunk számolni, valami olyasmit, ami majd kell nekünk is a játék fizikai motorjába.
fig.kinetic_energy
Figure 1.1: Python használata mozgási energia kiszámolásához
A legjobb dolog a programozásban, hogy a bonyolultságot el tudjuk rejteni egy egyenletbe. A többi felhasználónak csak a szükséges információt kell megadni, és már meg is kapta a szükséges eredményt egy könnyen érthető formában. Bármilyen egyszerű, hagyományos számológép el tud futni egy okostelefonon, ami lehetőséget ad a felhasználónak, hogy bármikor elővegye, és számoljon.
1.2 Megjelenítés
1.2.1 Szöveg kiírása
Hogyan ír ki a programunk bármit is a képernyőre?
print("Hello World.")
fig.printing_calculator
Ez a program kiírja a képernyőre a "Hello World"("Helló Világ!") szöveget. Rajta, és írjuk be az IDLE készenléti jel(prompt) után! Lássuk, hogyan működik! Próbálj kiírni más szöveget és karaktereket is! A számítógép boldogan kiír bármit, amit szeretnél, akár igaz, akár nem.
Hogyan néz ki a "Hello World" program más számítógépes nyelveken? Nézzük meg a Wikipediában. Elég szép mennyiségű "Hello World" programot gyűjtöttek össze más nyelveken:
http://en.wikipedia.org/wiki/Hello_world_program_examples
Érdekes látni, hogy mennyi különböző nyelv létezik. Képet lehet alkotni arról, hogy milyen összetett egy másik nyelv, a "Hello World" programja alapján.
Videó: A print függvény
Emlékeztetőül: a Pythonban a képernyőre kiíratás könnyű, csak használd ezt a parancsot: print. A print parancs után tegyél zárójelet ( ). A zárójelbe írd bele, mit szeretnél viszontlátni a képernyőn. A zárójel használata az információ átadásra alapvető gyakorlat a matematikában és a számítógépes nyelvekben.
A matek hallgatók úgy tanulják, hogy a zárójelbe egy kifejezés értékadását tüntetjük fel. Például,. és függvények. Az adat a zárójeleken belülről jut el a függvényekhez. Ami a mi esetünkben másabb, az az, hogy mi szöveget íratunk ki.
Jegyezzük meg, hogy idézőjel van a szöveg elején és végén. Ha idézőjelbe tesszük, akkor a számítógép úgy jeleníti meg az adatot, ahogy leírtuk. Például, ez a program azt írja ki, hogy 2+3:
print("2 + 3")
1.2.2 Kifejezések eredményeinek kiíratása
A következő programban nincs idézőjel a kifejezés körül, és így a számítógép össze fogja adni, matematikai kifejezésként. Szóval 5-t fog kiírni és nem 2+3-t.
print(2 + 3)
Az alább látható kód viszont egy hibaüzenetet fog generálni, mivel a számítógép megpróbálja matematikai kifejezésként értelmezni a "Hello World" -t, és így nem igazán működik:
print(Hello World)
A fenti kód hatására egy hibaüzenetet kapunk. SyntaxError: invalid syntax, ami a számítógép nyelvén azt jelenti, hogy nem ismeri a "Hello" és a "World" jelentését.
Mostantól tartsd észben, hogy ez egy aposztrófjel (egyszeres-idézőjel): ', ez pedig egy idézőjel: ". Amikor dupla-idézőjelet kérnek, olyankor gyakori hiba, hogy ezt írják "", ami egy dupla dupla-idézőjel. (az angolban - a ford.)
1.2.3 Több elem kiírása
A print paranccsal több dolgot is kiírathatunk egyszerre, minden egyes elemet vesszővel választunk el. Például, az alábbi kód eredménye ez lesz: Your new score is 1040
print("Your new score is", 1030 + 10)
A következő egysoros kód eredménye ez lesz: Your new score is 1030+10. A számokat nem adja össze, mivel azok az idézőjel közt vannak. Bármi, ami idézőjelek közt van, a számítógép szövegnek értelmez. Bármi, ami azon kívül, az a számítógépnek egy matematikai művelet, vagy számítógépes kód.
print("Your new score is", "1030 + 10")
A vessző az idézőjelen belülre vagy kívülre kerüljön?
A következő példa nem működik rendesen. Ez azért van, mivel a vessző nem különíti el a két kifejezést. Ez pedig azért van, mert a vessző az idézőjelen belülre került. Ha vesszővel akarjuk elválasztani a megjeleníteni kívánt elemeket, akkor azt az idézőjelen kívülre kell írnunk. Ha a programozó a vessző ki akarja íratni, akkor persze az idézőjelen belülre írjuk:
print("Your new score is," 1030 + 10)
Ez a példa már működik, mivel a vessző a kifejezéseket különíti el. Az eredmény:
Your new score is, 1040
Megjegyzem, hogy csak egy vessző lett kiírva. Tehát a vesszők az idézőjelen kívül elkülönítik a kifejezéseket, míg azon belül kiíratásra kerülnek. Az első vessző meg lett jelenítve, a másodikkal elkülönítettük a kifejezéseket.
print("Your new score is,", 1030 + 10)
1.3 Escape kódok(Escape Codes)
Ha az idézőjel arra való, hogy megmondja a számítógépnek, hogy hol kezdődik és végződik egy szöveg, amit meg akarok jeleníteni, akkor hogyan fogja kinyomtatni a program az idézőjelet? Például:
print("I want to print a double quote " for some reason.")
Ez a kód nem működik. A számítógép a szöveg közepén lévő idézőjelet a szöveg befejezésének veszi. Azután nem sok ötlete van arra nézve, hogy mit kezdjen a for some reason paranccsal, és az idézőjellel a végén. Sikerült összezavarni a számítógépet.
Fontos elmondani a számítógépnek, hogy mi a középső idézőjelet szövegként akarjuk megjeleníteni, és nem befejezéseként az előző idézőjelnek. Ez egyszerű, csak tegyél egy fordított perjelet az idézőjel elé, és a számítógép így megérti, hogy ez a szöveg része, és nem egy karakter ami megszakítja a szöveget. Például:
print("I want to print a double quote \" for some reason.")
fig.escape_codes
Ez a kombinációja két kódnak: \", ezt nevezik kikerülő kódnak. Majdnem minden nyelvben léteznek ilyenek. De, mivel a fordított perjel egy escape kód, ezért a perjel nem lesz megjelenítve. Például ez a kód sem működik:
print("The file is stored in C:\new folder")
Miért? Mivel a \n is egy escape kód. Ahhoz, hogy kiírathassuk a perjelet, meg kell kerülnünk, valahogy így:
print("The file is stored in C:\\new folder")
Van még egy pár fontos escape kód, amit érdemes ismerni. Itt van egy táblázat a fontosabb kódokról:
Escape kód Leírás
\' Aposztróf, egyszeres idézőjel
\" idézőjel
\t Tabulátor
\r CR: Carriage Return (kocsi visszatérése, balra/sor elejére mozgatás)
\n LF: Linefeed (sornövelés, lefelé mozgatás)
Mi az a “Carriage Return” (kocsivisszatérés) és “Linefeed”(sornövelés)? Próbáld ki ezt a példát:
print("This\nis\nmy\nsample.")
A parancs kimenete:
This
is
my
sample.
A \n egy sornövelés. El fogja mozgatni a "kurzort" egy sorral lejjebb a nyomtatáshoz képest. A számítógép minden szöveget egy hatalmas, hosszú vonalban tárolja. Onnan tudja, hogy hol vannak a sorok, hogy felismeri a \n karaktert.
Hogy bonyolultabb legyen, a különböző operációs rendszereknek különböző standardjai vannak azt meghatározni, hogy a sor hol ér véget.
Escape kódok Leírás
\r\n CR+LF: Microsoft Windows
\n LF: UNIX alapú rendszerek, és újabb Mac.
\r CR: Régebbi Mac alapú rendszerek
Általában a szövegszerkesztő odafigyel erre helyetted. A MS notepad nem igazán mondjuk, és ha UNIX fájlt nyitunk meg notepadban, akkor borzalmasan néz ki, mivel a sorok vége nem látszik, vagy fekete dobozok láthatók ott.
1.4 Megjegyzések, kommentálás
A kommentálás fontos (mégha a számítógép nem is foglalkozik vele)
Néha a kód némi magyarázatra szorul, ha valaki más olvassa. Ezért adunk "kommentelést" a kódhoz. A megjegyzések az embereknek készülnek, nem a gépnek.
Kétféleképpen hozhatunk létre kommentet. Az egyik, hogy a # szimbólumot használjuk. A gép átugrik minden szöveget, ami a kettőskereszt után található. Például:
# This is a comment, it begins with a # sign
# and the computer will ignore it.
print("This is not a comment, the computer will")
print("run this and print it out.")
A kettőskereszt jel idézőjelek közt persze nem minősül kommentnek. Ha egy sor kódot nem akarunk figyelembe venni, akkor egész egyszerűen a sor elejére írjuk a kettőskeresztet. Lehetséges a sor végére tenni a kommentunket.
print("A # sign between quotes is not a comment.")
# print("This is a comment, even if it is computer code.")
print("Hi") # This is an end-of-line comment
Lehetséges továbbá több sornyi kódot is kommentelni, ehhez három aposztrófot kell egymás után beírnunk. delimit.
print("Hi")
'''
This is
a
multi
line
comment. Nothing
Will run in between these quotes.
print("There")
'''
print("Done")
A legtöbb profi Python programozó ezt a többsoros kommentelést fogja előnyben részesíteni, valami olyasmiért, amit úgy neveznek, hogy docstrings(szövegfüzér) A docstring megengedi, hogy a kód mellé írjuk a megjegyzéseinket, dokumentációnkat, és később akár automatikusan kinyomtathatjuk dokumentumba, weboldalra, vagy IDE-be. Az általános kommenteléshez a kettőskereszt a legjobb.
Mégha te is vagy az egyetlen, aki olvashatja a kódot, akkor is írj kommentet, hogy időt takaríthass meg később. Olyan kommenteket írni, mint "földönkívűliek bombájának a kezelése" segít később gyorsan emlékezni arra, hogy az a kódrész mire vonatkozik.
1.5 Értékadás műveletek
Videó: Az értékadás művelet
Hogyan tároljuk a pontszámokat a játékunkban? Vagy hogyan követjük nyomon az ellenség életerejét? Ami ehhez kell, az egy értékadás műveletek. (Ez egy olyanművelet, ami szimbólumokat tárol, mint pl. + vagy - ) Ez aztán eltárol egy értéket egy változóban, amit később használhatunk. Az alábbi kód például az x változóra a 10-t vonatkoztatja, és kiírja az eltárolt értéket.
Lásd a lenti példát. Click on the “Step” button to see how the code operates.
Értékadás és változók használata
1
2
3
4
5
6
7
8
9
10
11
12
# Create a variable x
# Store the value 10 into it.
x = 10
# This prints the value stored in x.
print(x)
# This prints the letter x, but not the value in x
print("x")
# This prints "x= 10"
print("x=",x)
Step
Variables:
x=
Output:
10
x
x= 10
Változók amik kívül kerülnek az idézőjelen:
Megjegyzés:A listázás fentebb bemutatta a különbséget aközött, amikor x idézőjelen belül van, és amikor x idézőjelen kívül van. Ha az x az idézőjelen belül van, akkor a számítógép azt írja ki, hogy x. Ha az x az idézőjelen kívül van, akkor a számítőgép az x értékét írja ki. Azok közt, akik először tanulnak programozást gyakori, hogy zavaró ez az idézőjelen kívül és idézőjelen belül dolog.
fig.pi
Egy értékadás művelet (olyan kódsor, ami használja az = műveletet.) különbözik az algebrai egyenlőségtől, amit matekból tanultál. Ne mosd össze a kettőt. Az értékadás műveletnél a bal oldalon csak egy változó lehet, semmi más.
A bal oldalán az egyenletnek műveleti jel/értékadás művelet lehet, ami egy kifejezés. Egy kifejezés bármi, ami egy értéket ad vissza értékadás által. Lásd az alábbi kódot.
x = x + 1
A fenti kód nyilván nem lehet algebrai egyenlet. De ez érvényes a számítógép számára, mivel ez egy értékadó állítás. A matematikai egyenletek különböznek az értékadó műveletektől, mégha van is bennük változó, szám, vagy egyenlőség jel.
A fenti kifejezés esetében a kód az x jelenlegi értékét adja meg, egyet hozzáad, és eltárolja az eredményt az x-ben.
A példánkat kiterjesztbe, a kifejezés lent kiírja a hatos számot.
x = 5
x = x + 1
print(x)
Részenként futnak az értékadások. A számítógép nem néz a jövőbe. A lenti kódban, a számítógép kiírja az 5-t a második sorban, és aztán a negyedik sorban kiírja a 6-t. Azért, mert a második sorban a kód, ami egyet adna az x-hez, még nem futott le.
1
2
3
4
x = 5
print(x) # Prints 5
x = x + 1
print(x) # Prints 6
A következő értékadás érvényes és futni is fog, de értelmetlen. A gép adni fog egyet x-hez, de se ki nem írja, se el nem tárolja.
x + 1
Az alábbi kód 5-t fog kiírni, és nem 6-t, mivel a programozó elfelejtette eltárolni azx + 1 eredményét az x változóban.
x = 5
x + 1
print(x)
Az állítás alább nem érvényes, mivel a bal oldal többet tartalmaz egy darab változónál.
x + 1 = x
A Pythonban van más típusú értékadási művelet is. Ezek lehetővé teszik, hogy a programozó könnyedén változtassa meg a változó értékét. Például:
x += 1
A fenti értékadás egyenlő az alábbival:
x = x + 1
Vannak még értékadó műveletek összeadáshoz, kivonáshoz, szorzáshoz, és osztáshoz.
1.6 Változók
A változók kisbetűvel kezdődnek:
A változóknak kisbetűvel kellene kezdődniük. A változók kezdődhetnek nagybetűvel, vagy aláhúzással, de ezek speciális esetek, és nem történhetnek meg normál esetekben. Az első kisbetű után a változó tartalmazhat nagybetűt, kisbetűt, számot, aláhúzást. A változók nem tartalmazhatnak space karaktert.
A változók betűtípusra érzékenyek. Ez összezavarhatja a programozót, aki nem készül erre fel. A lenti példában az eredmény 6 lesz és nem 5, mivel két különböző változót használunk, a x-t és a X-t.
x = 6
X = 5
print(x)
A hivatalos Python stílus kézikönyv (igen, a programozók tényleg írtak egy könyvet a stílusról) azt mondja, hogy a többszavas változónevek a Pythonban el kellene legyenek választva, aláhúzással. Például használjuk a hair_style és ne a hairStyle alakot. Személy szerint, ha te az én tanítványom vagy, akkor tudnod kell, hogy engem nem érdekel különösebben ez a szabály, mivel a következő nyelv, amit a Python után tanítunk, az a Java, és ott pont fordítva van. Megpróbáltam a Java stílusú szabályokat tanítani ezen a kurzuson, de akkor gyűlölködő leveleket kaptam a Python szerelmeseitől. Ezek az emberek meglátogatták a weboldalamat, és sokkot kaptak, sokkot kaptak, mondom, a szegényes stílusom miatt.
Joan Rivers-nek semmi köze ezekhez az emberekhez, szóval feladtam és megpróbáltam a helyes stílust követni immár.
Itt van néhány példának, hogy mi elfogadható és mi nem változónévként:
Elfogadható változónév Nem elfogadható változónév Elfogadható, de nem helyes
first_name first name FirstName
distance 9ds firstName
ds9 %correct X
Minden nagybetűs változónév, mint amilyen a MAX_SPEED megengedett, de csak akkor, ha a körülmények miatt a változó sosem változtatja meg az értékét. Azt a változót, ami nem változtatja meg az értékét állandónak/konstansnak hívjuk.
1.7 Műveletek
A bonyolultabb matematikai műveletekhez, a mindennapi matematikai műveletek elérhetők. Köztük néhány nem túl gyakorival:
műveleti jel művelet példa egyenlet példa kód
+ összeadás a = 3 + 2
- kivonás a = 3 - 2
* szorzás a = 3 * 2
/ osztás a = 10 / 2
// egész osztás N/A a = 10 // 3
** hatványozás a = 2 ** 3
% modulus/törtrész N/A a = 8 % 3
Videó: Műveletek
Az egész osztás mindig lefelé fogja kerekíteni az eredményt, a legközelebbi egész felé. Például a 11//2 egyenlő lesz 5-tel, és nem 5.5-tel, és 99//100 egyenlő 0.
Szorzás művelet műveleti jel nélkül nem működik a Python alatt. A következő két sornyi kód nem működik:
# This does not work
x = 5y
x = 5(3/2)
A szorzás műveleti jelét muszáj használni ezekben a sorokban, ha azt akarjuk, hogy működjenek:
# This does work
x = 5 * y
x = 5 * (3 / 2)
1.7.1 Műveletek elválasztása
Bármennyi space lehet a műveleti jelünk előtt és után, és a számítógép még akkor is meg fogja érteni. Például az alábbi 3 sor teljesen egyenértékű.
1
2
3
x=5*(3/2)
x = 5 * ( 3 / 2 )
x =5 *( 3/ 2)
A hivatalos Python stílus kézikönyv azt mondja, hogy lennie kell egy space-nek az operátor előtt és után is. (Majd meghaltatok, hogy megtudjátok, igaz? Oké, a hivatalos stílus kézikönyvnek az elérhetősége itt van: PEP-8.) A három fenti kód közül a legstílusosabb a második.
1.8 Műveletek sorrendje
A Python a kifejezéseknek úgy ad értéket, hogy követi a műveleti sorrendet, ahogyan azt egy alap matematikai kifejezésnél is találjuk. Például ez az egyenlet nem korrekt módon számolja ki az átlagot:
average = 90 + 86 + 71 + 100 + 98 / 5
Az első művelet, amit végrehajt az a 98/5. És így számol:
ahelyett, hogy a vágyott eredményt adná:
Zárójel használatával a probléma orvosolható:
average = (90 + 86 + 71 + 100 + 98) / 5
1.9 Trigonometrikus függvények
A trigonometrikus függvényeket arra használják, hogy velük szinuszt és koszinuszt számoljanak. Alapértelmezett állapotban a Python nem tudja a sin/cos függvényeket számolni, de ha a helyes könyvtárat importáljuk neki, akkor már igen. Az egységek radiánban lesznek megadva.
# Import the math library
# This line is done only once, and at the very top
# of the program.
from math import *
# Calculate x using sine and cosine
x = sin(0) + cos(0)
1.10 Szokványos egyenletek kiszámítása
Egy Python program kiszámolhatja fogyasztását egy autónak, ami 294 mérföldet tesz meg, 10.5 gallon gázolajjal.
m = 294 / 10.5
print(m)
Ez a program kicsit fejleszthető változók használatával. Ez lehetővé teszi, hogy az értékeket könnyedén megváltoztathassuk a kódban, anélkül, hogy az egyenlethez nyúlnánk.
m = 294
g = 10.5
m2 = m / g # This uses variables instead
print(m2)
A jó változó nevek fontosak.
Magától ezt a programot megérteni nehézkes.Az m és g változók nem jelentenek túl sokat önmagukban. A program megcsinálható úgy is, hogy könnyen érthető legyen a működése a változók alapján:
milesDriven = 294
gallonsUsed = 10.5
mpg = milesDriven / gallonsUsed
print(mpg)
Most már, ha egy nem-programozó ránéz a kódra, neki is lesz ötlete, hogy mit csinálhat a program. Egy másik példa a jó és a rossz változó elnevezésre:
# Hard to understand
ir = 0.12
b = 12123.34
i = ir * b
# Easy to understand
interestRate = 0.12
accountBalance = 12123.34
interestAmount = interestRate * accountBalance
Videó: Egy szokványos számoló program készítése
Az IDLE szerkesztőben lehetőség van arra, hogy szerkesszük az adott sort, annak újragépelése nélkül. Ezt úgy tehetjük meg, hogy a kurzort felvisszük a választott sorra, és ütünk egy entert. Ezzel másoljuk az adott sort.
A Python kódot bevinni a >>> prompttal lassú, és csak egy sort lehet egyszerre. Valamint nem lehetséges lementeni, hogy más is használhassa. Szerencsére, van egy sokkal egyszerúbb módja is a Python kód bevitelének.
A Python kódot bevihetjük script által is. A script Python kódsorok sorozata ami egyszerre lesz végrehajtva. Ahhoz, hogy egy scriptet készíthessünk, nyissunk egy új ablakot, ahogy az ábra mutatja 1.2.
fig.entering_a_script
Figure 1.2: Szkript bevitele
Vigyük be a gázolaj fogyasztást számoló programunkat, aztán mentsük el a fájlt. Elmenthetjük a fájlt flash drive-ra, network drive-ra, vagy bármilyen más helyre. A Python programok mindig .py kiterjesztésre végződnek. Lásd az ábrát: 1.3.
fig.saving_mpg_calculator
Figure 1.3: Szkript mentése
Futtassuk a programot, egyszerűen klikkeljünk a "Run" menüre és válasszuk a "Run Module" parancsot. Próbáljuk meg frissíteni a programot úgy, hogy új értékeket adunk a mérföldre, és gallonra.
Vigyázat, gyakori hiba!
Ettől a ponttól kezdve, szinte minden kódot vigyél be a script/modul-ba. Ne gépeld be a programodat az IDLE >>> prompton kívülre. Az ide beírt kód nem lesz elmentve. Ha ez történne, újra kell kezdeni. Ez az egyik leggyakoribb hibája a kezdő programozóknak.
Ez a program sokkal hasznosabb lenne, ha képes volna párbeszédre a felhasználókkal és megkérdezné a felhasználót a vezetett mérföldekről és a felhasznált gallonokról. Ez megtehető az input paranccsal. Lásd az alábbi kódot:
# This code almost works
milesDriven = input("Enter miles driven:")
gallonsUsed = input("Enter gallons used:")
mpg = milesDriven / gallonsUsed
print("Miles per gallon:", mpg)
Ennek a programnak a futtatása során a felhasználó meg lesz kérdezve a mérföldekről és a gallonokról, de egy furcsa hibát is generálunk, amit az alábbi ábrán láthatsz 1.4.
fig.mpg_program_error
Figure 1.4: Az MPG program futtatásakor megjelenő hiba
Ezt kijavítandó, kicsit módosítsuk a programunkat:
milesDriven = input("Enter miles driven:")
gallonsUsed = input("Enter gallons used:")
x = milesDriven + gallonsUsed
print("Sum of m+g:", x)
A fenti kódot futtatva ez lesz a kimeneti üzenet 1.5.
fig.mpg_incorrect_addition
Figure 1.5: Hibás összeadás
A program nem adja össze a két számot. Csak egymás után teszi őket. Ez azért történik, mert a program nem tudja, hogy itt két számot kértünk be. A felhasználó azt is beütheti, hogy Bob, vagy Mary. Ezek összege BobMary lenne. Elég érdekes.
Az adatbrvitelt számokká kell alakítanunk.
Ahhoz, hogy elmondjuk a számítógépnek, hogy ezek számok, szükséges az input funkciónkat kiegészíteni egy int( )-rel vagy egy float( )-tal. Az első esetben egész-, a másodikban törtszámokat várunk eredményül.
A végső, működő program:
calculate_miles_per_gallon.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Sample Python/Pygame Programs
# Simpson College Computer Science
# http://programarcadegames.com/
# http://simpson.edu/computer-science/
# Explanation video: http://youtu.be/JK5ht5_m6Mk
# Calculate Miles Per Gallon
print("This program calculates mpg.")
# Get miles driven from the user
miles_driven = input("Enter miles driven:")
# Convert text entered to a
# floating point number
miles_driven = float(miles_driven)
# Get gallons used from the user
gallons_used = input("Enter gallons used:")
# Convert text entered to a
# floating point number
gallons_used = float(gallons_used)
# Calculate and print the answer
mpg = miles_driven / gallons_used
print("Miles per gallon:", mpg)
Step
Variables:
milesDriven=
gallonsUsed=
mpg=
Output:
This program calculates mpg.
Enter miles driven:288
Enter gallons used:15
Miles per gallon: 19.2
És egy másik példa arra, hogyan számoljuk ki a mozgási energiáját egy tárgynak:
calculate_kinetic_energy.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Sample Python/Pygame Programs
# Simpson College Computer Science
# http://programarcadegames.com/
# http://simpson.edu/computer-science/
# Calculate Kinetic Energy
print("This program calculates the kinetic energy of a moving object.")
m_string = input("Enter the object's mass in kilograms: ")
m = float(m_string)
v_string = input("Enter the object's speed in meters per second: ")
v = float(v_string)
e = 0.5 * m * v * v
print("The object has " + str(e) + " joules of energy.")
Ha le akarjuk rövidíteni a programot, akkor egymásba ágyazhatjuk az input parancsunkat, és float utasítást. Példa erre:
milesDriven = input("Enter miles driven:")
milesDriven = float(milesDriven)
Ugyanazt fogja adni eredményül ez is:
milesDriven = float(input("Enter miles driven:"))
Ezesetben, a kimenete az input utasításnak közvetlenül van üsszekötve a float utasítással. Mindkettő működik, és a programozón múlik, hogy melyiket választja. Fontos, továbbá, hogy megértsük mindkét formát.
A játékok készítés komoly feladat több szempontból is. Először is a játékok intenzív interakciót követelnek meg a felhasználóval, hasonlóan a grafikus felületű szoftverekhez. A játék típusától és a játékmenettől függően megfelelően jól kell kinéznie, hogy közönséget kapjon, ezenkívül a játékoknak egy bizonyos szintű mesterséges intelligenciát kell nyújtania (gondoljunk akár egy szimpla amőbára). A játékoknak szórakoztatónak kell lenniük, mindamellett megfelelő kihívást kell nyújtania a játékosoknak. Ezek igen összetett követelményrendszert jelentenek.
A komoly és látványos játékok sosem egy ember munkájának az eredményei, hiszen a megalkotásukhoz szükséges szakmai ismeret annyira szerteágazó (nem beszélve az emberek saját adottságairól, tehetségéről), hogy azokat megfelelő szinten elsajátítani egy embernek egy életre szóló feladat - és akkor még semmit sem csinált. Ezeket a játékokat több emberből álló csapatok készítik (producer, designer, artist, coder, marketinges, webfejlesztő, és sok esetben PR-os is kell) igen nagy ráfordításokkal.
Ha valaki a játékiparban szeretne dolgozni, mindenképpen ki kell választania magának egy testhez álló szakirányt, majd keresnie vagy építenie kell egy csapatot. A játékfejlesztés kemény munka, ami lassan térül meg, hiszen néha egy játék fejlesztése több évig is eltart, addig finanszírozni kell a készítők bérét, és a fejlesztés infrastruktúráját.
Gondolom most kellőképpen sikerült mindenkit elijeszteni a témától, de nem eszik olyan forrón a kását, egy ember is készíthet jó, érdekes és jól kinéző játékokat, csak tudomásul kell venni, hogy ezek bonyolultsága és/vagy színvonala azért messze el fog maradni a fent említett komoly alkotásokétól :D A DRY (Don't Repeat Yourself) és DNRTW ( Do Not Reinvent The Wheel) elvet szem előtt tartva, a legokosabb ha valamilyen keretrendszert alkalmazunk a játékok készítése során (a komolyabb és összetettebb keretrendszereket már játékmotornak hívják). Ezek leveszik a terhet a vállunkról egy csomó olyan dologgal kapcsolatban, mint pl. képadatok tárolása, átalakítása, képernyőre rakása, hangok, zenék kezelése, stb.
Pythonhoz, az egyszerű gyalogbéka hobbiprogramozónak a pygame (ejtsd: pájgém), esetleg a pyglet (ejtsd: piglet) áll rendelkezésére, vagy komolyabb dolgokhoz az ogre, vagy a crystalspace. A pygame-en kívül a többinél konyitani kell valamennyire az opengl-hez, ha valaki nem foglalkozott vele, akkor mindenképpen a pygame-et ajánlanám kezdésnek.
Mi is ez a pygame? Nos létezik linuxon egy programkönyvtár (lib) amely elvben hasonló hozzáférést enged a gép video, hang és input elemeihez, mint a winen a directx. Simple Directmedia Layer a becsületes neve, de SDL-ként közismertebb. Ez egy C-ben írt lib, amit tud azt jól tudja, bár nem annyira sokrétű, mint a wines párja (egyébként elérhető win alatt is, így a pygame is).
Lelkes pythonosok megírták a pygame-et, ami tulajdonképpen pár általuk hozzáadott plusz dologtól eltekintve az SDL pythonos nyelvi kötése. Habár opengl mutatványokra is felhasználható, a pygame elsősorban 2D játékok készítésére készült. Ennyi unalmas bevezető után csapjunk a sűrűjébe, is próbáljunk meg valamit kezdeni a pygame-mel!
Természetesen fel kell telepíteni használat előtt, ubuntu, debian alatt van a repóban, sudo apt-get install python-pygame, más rendszereknél nézzétek meg a telepítési leírásokat. Használatához be kell importálnunk a pygame modult a programunkba. Mindjárt két importot is érdemes elvégezni, ezzel egy csomó gépeléstől kímélhetjük meg magunkat (pl. pygame.QUIT helyett elegendő QUIT-et írni), majd inicializálni kell a pygame összetevőket:
import pygame
from pygame.locals import *
pygame.init()
Az inicializálás során a pygame felkészíti az SDL réteget a működésre, ami egyben a hardverek inicializálását is magában foglalja. Ha ezt elmulasztjuk, a programunk működésképtelen lesz.
Ahhoz, hogy legyen egy ablakunk, ahol a játék grafikáját, elemeit megjelenítjük, meg kell kérnünk az SDL-t, hogy készítsen nekünk egyet. És itt jön a pygame és az SDL első korlátja, mert meg kell adni neki, hogy mekkorát készítsen. Ezzel nincs semmi baj, a baj azzal van, hogy ezen utána nem tudunk változtatni :(
Ezért már a játék kezdetekor ki kell találni, hogy mekkora ablakban fogunk dolgozni.
Most egy 800x600-as ablakot hozunk létre, ez elfér manapság szinte minden képernyőn, ahol a pygame elfut (a telefonokat most hagyjuk ki ebből).
screen = pygame.display.set_mode((800,600))
A screen változóban egy pygame.surface objektum tárolódik el. Mi is ez a surface? A szó maga felületet jelent, a pygame-ben egy kicsit többet, de a lényeg az a mi szempontunkból, hogy egy olyan felület, amire rajzolni tudunk.
Nosza rajzoljunk rá! Csinálunk egy pattogó labdát. Nem egy hasznos dolog, és semmiképpen nem játék még, de kezdetnek jó lesz :) Itt a forráskód, és átbeszéljük.
#!/usr/bin/env python
# -*- coding:utf8 -*-
import sys,pygame
from pygame.locals import *
# pygame inicializálása
pygame.init()
# ablak megjelenítése és a játékadatok beállítás
SCREEN_SIZE = (800,600) # ablak mérete
screen = pygame.display.set_mode(SCREEN_SIZE) # ablak "surface"
BGCOLOR = (0,0,0) # háttérszín
BALLCOLOR = (255,0,0) # labda színe
d = 30 # labda átmérője
dh = d/2 # átmérő fele
x,y = dh,dh # labda kezdőpontja (középpont)
vx,vy = 12,18 # függőleges és vízszintes sebessége a labdának
fps = 30 # képkocka / másodperc
# ezek adják meg hol kell a labdának visszapattannia
xlimits = (dh,SCREEN_SIZE[0]-dh)
ylimits = (dh,SCREEN_SIZE[1]-dh)
def rajzol(x,y):
"""rajzol(x,y):
letörli a képernyőt, és felrajzolja a labdát az x,y pozícióba"""
screen.fill(BGCOLOR)
pygame.draw.circle(screen,BALLCOLOR,(x,y),dh,0)
def mozgat(x,y,vx,vy):
"""mozgat(x,y,vx,vy):
kiszámolja a labda következő pozícióját.
megfordítja a labda mozgását az ablak szélénél"""
x = x + vx
y = y + vy
if x < xlimits[0]:
x = xlimits[0]
vx = -vx
if x > xlimits[1]:
x = xlimits[1]
vx = -vx
if y < ylimits[0]:
y = ylimits[0]
vy = -vy
if y > ylimits[1]:
y = ylimits[1]
vy = -vy
return x,y,vx,vy
def kilep():
"""kilep():
Megnézi, hogy megnyomták-e az ESC gombot
vagy megpróbálták bezárni az ablakot"""
for event in pygame.event.get():
if event.type==QUIT:
return True
elif (event.type==KEYDOWN and event.key==K_ESCAPE):
return True
return False
# ezzel az objektummal tudjuk szabályozni a játék sebességét
clock = pygame.time.Clock()
# fő ciklus
# ismétlődik amíg ki nem lépünk
while True:
# kirajzoljuk a játékunkat
# és elvégezzük a mozgatását a labdának
rajzol(x,y)
x,y,vx,vy = mozgat(x,y,vx,vy)
# ki akart lépni a felhasználó?
if kilep():
pygame.quit()
sys.exit()
# kirakjuk az ablak tartalmát a képernyőre
pygame.display.flip()
# szabályozzuk a futási sebességet
clock.tick(fps)
# infóként kinyomjuk a labda adatait a konzolra
print x,y,vx,vy
Az 1-25 sorok magától értetődőek, de azért elláttam kommentekkel is a biztonság kedvéért. Mielőtt a rajzol és mozgat függvényeket megnéznénk, inkább foglalkozzunk a kód végén látható végtelenített ciklussal, a 67-87 sorokban.
Ez a programunk fő ciklusa. Mit is csinál? Kirajzolja az ablak tartalmát a rajzol() függvénnyel, kiszámolja a labda következő koordinátáját a mozgat() függvénnyel, megnézi, hogy kapott-e kilépési parancsot - ha igen, akkor kilép - , logolja a labda koordinátáit és sebességét a konzolra, és kezdődik minden előlről.
Van itt viszont egy fontos parancs, amiről fontos szót ejteni: pygame.display.flip()
Az SDL dupla pufferelést alkalmaz, minden rajzolási műveletet a képernyő egy másolatán végez a memóriában. Ahhoz, hogy ezt lássuk is, meg kell jeleníteni a képernyőn. Ezzel a paranccsal a puffer tartalmát villámgyorsan kiteszi a videomemóriába, így az számunkra is láthatóvá válik.
A clock.tick(fps) paranccsal a játék futásának sebességét állítjuk be, így minden hardveren azonos sebességel fog futni a ciklusunk, nevezetesen egy másodperc alatt fps alkalommal.
Ejtsünk szót még a rajzol() függvényünkről!
A függvény elején letöröljük a képernyőt, azaz kitöltjük a BGCOLOR színnel, majd a kapott x,y koordinátákra kirajzolunk egy BALLCOLOR színű kört. Ha nem törölnénk le a képernyőt, csak a kört rajzolnánk ki, akkor a labdánk gyakorlatilag csíkot húzna a képernyőre. Ebből is látható, hogy minden képkockán elő kell állítani a teljes képet. Ez bonyolult játékoknál elég időigényes feladat lehet, ezért mindenféle praktikához kell folyamodni a megfelelő teljesítmény elérése érdekében.
A mozgat() függvényünk egyszerű, "csak" számítási feladatot végez, a kapott x,y és vx,vy sebességadatok alapján kiszámolja hova kerül a labda. Ha a képernyőn kívülre kerülne, akkor visszateszi a képernyőre, és megfordítja a vízszintes vagy függőleges (vagy mindkettő) mozgási irányát.
A Python programozási nyelv
Pygame
A Pygame játékok fejlesztését segítő python modulok gyűjteménye. A platformfüggetlen SDL könyvtárra épül. Ez az oka annak, hogy a pygame programok szinte minden platformon és operációs rendszeren futtathatók.
A Pygame egy ingyenes bővítése a nyelvnek. Részleteket ld. az LGPL licensz leírásában.
A következőkben megpróbálom egyszerű példákkal bemutatni a pygame használatát, működését. Ezt a tutoriált Pete Shinners: Line By Line Chimp című munkája alapján készítettem. Többnyire annak fordítása, ill. saját tapasztalatokkal való kiegészítése.
Szükséges modulok
A következő kódrészlet tartalmazza a szükséges modulokat. Egyben példát láthatunk arra, hogyan ellenőrizhetjük egyes, opcionális modulok jelenlétét a futtató környezetben.
import os, sys
import pygame
from pygame.locals import *
if not pygame.font: print 'Warning, fonts disabled'
if not pygame.mixer: print 'Warning, sound disabled'
Először importáljuk az "os" és "sys" python modulokat. Ezek sok mindenre használhatók, például lehetővé teszik platform független fájl-útvonalak megadását. A következő sorban importáljuk a pygame csomagot. Ezzel az összes pygame modult importáltuk. Van néhány opcionális modul is, melyek None értéket vesznek fel, ha nem sikerült őket beimportálni. Ezt ellenőrizzük az utolsó két sorban.
A "locals" egy speciális pygame csomag. Ez olyan gyakran használható konstansokat és függvényeket tartalmaz, melyeket célszerű a program globális névterébe elhelyezni. Ez a modul tartalmazza többek között a Rect függvényt, mellyel téglalap objektumokat hozhatunk létre, vagy olyan konstansokat, mint a 'QUIT, HWSURFACE', melyeket a pygame más részeivel való interakciókhoz használjuk. Természetesen nem kötelező ezt importálni. Ekkor a pygame modulon keresztül is elérhetjük.
Végül példát láthatunk arra, hogyan írassunk ki hibajelzéseket, ha egy adott modul pl. a font vagy a sound nem elérhető.
Erőforrások betöltése
Két függvényt adunk képek és hangok betöltésére.
Kép betöltése
def load_image(name, colorkey=None):
fullname = os.path.join('data', name)
try:
image = pygame.image.load(fullname)
except pygame.error, message:
print 'Cannot load image:', name
raise SystemExit, message
image = image.convert()
if colorkey is not None:
if colorkey is -1:
colorkey = image.get_at((0,0))
image.set_colorkey(colorkey, RLEACCEL)
return image, image.get_rect()
Az első paramétere a betöltendő kép nevét tartalmazza. A függvény rendelkezik egy második, opcionális paraméterrel is. Ezt a kép "színkulcsának" beállításához használhatjuk. A "színkulcsot" az átlátszó színek reprezentálására használjuk.
A függvény első sorában elkészítjük a fájlhoz tartozó teljes útvonalat. Ebben a példában az összes erőforrás a "data" alkönyvtárban van. Az os.path.join használatával olyan fájl-útvonalakat gyárthatunk, melyek bármilyen platformon használhatók.
A következő lépésben a pygame.image.load függvénnyel betöltjük a képet. Ezt a függvényhívást egy kivételkezelő részbe ágyaztuk, így a betöltés során fellépő hibákat könnyen lekezelhetjük. A betöltés után fontos a convert() függvény meghívása. Ez egy új másolatot készít az objektumról és a képernyőhöz igazítja a kép színformátumát és színmélységét. Ez azért kell, hogy a képernyőre való kirajzolás a lehető leggyorsabban menjen.
Végül beállítjuk a "színkulcsot" a képhez. Ha a felhasználó megadta a colorkey paramétert, akkor ez lesz a képhez rendelve. Általában ez egy szín RGB értéke, pl. a (255,255,255) tuple a fehér színt jelenti. Ezenkívül megadhatunk -1-et is színkulcsként. Ebben az esetben a kép bal-felső pixelének színe lesz a színkulcs.
Hang betöltése
def load_sound(name):
class NoneSound:
def play(self): pass
if not pygame.mixer:
return NoneSound()
fullname = os.path.join('data', name)
try:
sound = pygame.mixer.Sound(fullname)
except pygame.error, message:
print 'Cannot load sound:', wav
raise SystemExit, message
return sound
Ezzel a függvénnyel egy hangfájlt tudunk betölteni. Az első dolog annak ellenőrzése, hogy sikerült-e rendesen importálnunk a pygame.mixer modult. Sikertelen esetben egy speciális osztálypéldányt adunk vissza, mely rendelkezik egy állejátszó metódussal. Ez az objektum ugyanúgy viselkedik és használható, mint egy normális Sound objektum azzal a kivétellel, hogy nem ad hangot. Ezáltal nincs is szükségünk további hiba ellenőrzésre.
A fenti két függvény nagyon hasonlít egymásra. Itt is először definiálunk egy teljes útvonalat a hangfájlhoz, majd a try-except részben betöltjük. Végül egy Sound objektumot adunk vissza.
Játék osztályok
A következőkben egy játék két lehetséges objektumait mutatjuk be. A játék "logikáját" ez a két osztály tartalmazza.
class Fist(pygame.sprite.Sprite):
"""moves a clenched fist on the screen, following the mouse"""
def __init__(self):
pygame.sprite.Sprite.__init__(self) #call Sprite initializer
self.image, self.rect = load_image('fist.bmp', -1)
self.punching = 0
def update(self):
"move the fist based on the mouse position"
pos = pygame.mouse.get_pos()
self.rect.midtop = pos
if self.punching:
self.rect.move_ip(5, 10)
def punch(self, target):
"returns true if the fist collides with the target"
if not self.punching:
self.punching = 1
hitbox = self.rect.inflate(-5, -5)
return hitbox.colliderect(target.rect)
def unpunch(self):
"called to pull the fist back"
self.punching = 0
A fenti osztály reprezentálja a játékos öklét. Ezt a pygame.sprite modul Sprite osztályából származtattuk. Az __init__ függvény új példány létrehozásakor hívódik meg. Ebben a függvényben először a bázisosztály __init__ függvényét hívjuk. A játékunkban a sprite-ok kirajzolásához Group osztályokat használunk. Ezen osztályok olyan sprite-ok megjelenítésére használhatók, amelyek rendelkeznek image és rect attribútumokkal. Ezen attribútumok módosításával érhetjük el, hogy a megjelenítő egy adott képet egy adott helyre rajzoljon ki.
Minden sprite rendelkezik egy update() metódussal. Ezt a függvény általában képkockánként egyszer hívjuk. Ebbe helyezhetünk olyan kódokat, melyekkel mozgathatjuk és frissíthetjük a sprite változóit. Jelen esetben az update() metódus az öklöt az egér kurzor helyére mozgatja. Eltolást is alkalmaz, ha az objektum "punching" állapotban van.
A punch() és az unpunch() metódusokkal a "punching" állapot kapcsolható be és ki. A punch() függvény igaz értéket ad vissza, ha az ököl eltalálta a célt, azaz a két sprite ütközött.
class Chimp(pygame.sprite.Sprite):
"""moves a monkey critter across the screen. it can spin the
monkey when it is punched."""
def __init__(self):
pygame.sprite.Sprite.__init__(self) #call Sprite intializer
self.image, self.rect = load_image('chimp.bmp', -1)
screen = pygame.display.get_surface()
self.area = screen.get_rect()
self.rect.topleft = 10, 10
self.move = 9
self.dizzy = 0
def update(self):
"walk or spin, depending on the monkeys state"
if self.dizzy:
self._spin()
else:
self._walk()
def _walk(self):
"move the monkey across the screen, and turn at the ends"
newpos = self.rect.move((self.move, 0))
if not self.area.contains(newpos):
if self.rect.left < self.area.left or \
self.rect.right > self.area.right:
self.move = -self.move
newpos = self.rect.move((self.move, 0))
self.image = pygame.transform.flip(self.image, 1, 0)
self.rect = newpos
def _spin(self):
"spin the monkey image"
center = self.rect.center
self.dizzy += 12
if self.dizzy >= 360:
self.dizzy = 0
self.image = self.original
else:
rotate = pygame.transform.rotate
self.image = rotate(self.original, self.dizzy)
self.rect = self.image.get_rect(center=center)
def punched(self):
"this will cause the monkey to start spinning"
if not self.dizzy:
self.dizzy = 1
self.original = self.image
A chimp osztálynak egy kicsit több feladata van, mint a Fist-nek, de semmivel sem bonyolultabb annál. Az osztály feladata a csimpánz mozgatása a képernyőn, és ha eltaláljuk a majmot, akkor elkezd forogni. Ezt az osztályt is a Sprite osztályból származtatjuk, és a Fisthez hasonlóan inicializáljuk. Az inicializálás során az area attribútumot a képernyő méretéhez igazítjuk.
Az update függvény tevékenysége a csimpánz "dizzy" állapotától függ. Ez akkor igaz, ha eltalálták a majmot és éppen forog. Ennek függvényében vagy a _spin vagy a _walk metódusokat hívja. Az aláhuzás prefix a python függvények nevében azt jelenti, hogy ezt csak a tartalmazó osztály használhatja. Ez csupán egy konvenció, azaz nem nyelvi szintű deklarátum.
A walk metódus egy adott értékkel eltolja a csimpánz képét. Ha az új pozíció érinti a kép szélét, akkor az eltolás irányát megfordítjuk. Ezen kívül a csimpánz képét is tükrözzük a pygame.transform.flip függvénnyel. Ezzel elértük, hogy a csimpánz mindig testtel előrefelé mozogjon.
A spin metódust, akkor használjuk, amikor eltalálták a makit, és épp szédül, azaz a "dizzy" változó nem nulla (logikai értéke igaz). Ebben az attribútumban tároljuk a aktuális forgatás mértékét (0-360 fokig). Miután teljesen körbeforgattuk, ismét az eredeti, forgatás nélküli képet rajzoljuk a csimpi helyére. A pygame.transform.rotate hívása helyett, először egy referenciát állítunk erre a függvényre. Ez a rotate változó. Később - a rövidebb forma miatt - ezen keresztül végezzük a forgatást. Ezt nem kötelező így csinálnunk, de adunk erre is példát. Mindig az eredeti képet fogjuk forgatni. Erre azért van szűkség, mert a forgatás során romlik a kép minősége. Így egy forgatás sorozat jelentősen rontana a képminőségen. Ezen kívül a forgatással a kép mérete is változhat. A rotate függvény első paramétere a forgatandó kép, a második pedig a forgatás mértéke fokokban. A rotáció után a forgatás középpontja, a keletkezett kép középpontja kell, hogy legyen. Ezzel elérhetjük, hogy ne lépjen fel elmozdulás.
Végül nézzük meg a punched() metódust. Ennek meghívásával lép a sprite a forgó, szédült állapotba. Az aktuális képről készít egy másolatot az original attribútumba. Ez a kép lesz a forgatás alapja.
Inicializáljunk mindent
Mielőtt bármit is tennénk a pygame-mel, meg kell bizonyosodnunk, hogy minden szükséges modul inicializálva lett. Ha ez teljesült, akkor létrehozhatunk egy egyszerű grafikus ablakot. A következőket a main() függvénybe fogjuk elhelyezni.
pygame.init()
screen = pygame.display.set_mode((468, 60))
pygame.display.set_caption('Monkey Fever')
pygame.mouse.set_visible(0)
Az első sorral inicializáljuk a pygame-et. Ellenőrzi az importált pygame modulokat, és inicializálja azokat. Lehetőségünk van saját kezűleg is inicializálni és ellenőrizni a modulokat, de erre most nem térünk ki.
A következő lépésben a képernyőt állítjuk be. Jegyezzük meg, hogy a képernyő beállításokért a pygame.display modul felelős. Ezen keresztül tudjuk azokat módosítani, stb. Jelen esetben egy üres, 468x60-as felbontású ablakot készítünk. A képernyő módok beállításának témája meghaladná ennek a tutoriálnak a kereteit. A fenti esetben ezt a feladatot a pygame elvégzi helyettünk. Végül beállítjuk az ablak címét, és eltüntetjük az egérkurzort az ablak felett. Ezzel a módszerrel egy fekete ablakhoz jutottunk.
Csináljunk hátteret
A programunk hátterében különböző szöveges üzeneteket szeretnénk megjeleníteni. Jó lenne egy egyszerű felületet készíteni, ami a programunk hátterét reprezentálná, és a továbbiakban ezt használni. Készítsük el ezt a felületet!
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((250, 250, 250))
Ezzel egy új felületet hoztunk létre, melynek mérete egyezik a képernyőével. Itt is szűkség van a convert() hívásra. Az argumentum nélküli convert függvénnyel a képernyő formátumával megegyező lesz a háttér. Ezzel a programunk hatékonyságát növeljük.
Végül fehérre színezzük a hátteret. A fill művelet egy RGB hármast, egy tuple-t vár paraméternek.
Szöveg elhelyezése a háttéren
Tehát rendelkezünk egy felülettel, és ezen szeretnénk szöveget megjeleníteni. Ezt csak akkor tehetjük meg, ha a pygame.font modult megfelelően importáltuk. Ha nem, akkor átugorjuk ezt a részt.
if pygame.font:
font = pygame.font.Font(None, 36)
text = font.render("Pummel The Chimp, And Win $$$", 1, (10, 10, 10))
textpos = text.get_rect(centerx=background.get_width()/2)
background.blit(text, textpos)
Látható, hogy egy egyszerű szöveg megjelenítéséhez is több lépésre van szükség. Először létrehozunk a font objektumot és megjelenítjük azt egy új felületen. Eztán megkeressük ennek a felületnek a középpontját, majd beillesztjük a háttérbe.
Font-ot a font modul Font() konstruktorával hozhatunk létre. Paramétereiben megadhatod egy truetype fontfájl nevét. None-nal jelezhetjük az alapértelmezett betűtípus használatát. A Font konstruktorának még meg kell adni a használni kívánt font méretét.
A render függvény egy új felületet hoz létre, mely megfelelő méretű a megjelenítendő szövegnek. A paraméterekben megadjuk, hogy antialiased, sötét szürke színű szöveget akarunk kirakni.
Eztán megkeressük a szöveg középpontját. Létrehozunk egy - a szöveg dimeziónak megfelelő - Rect objektumot, ami már egyszerűen felrakható a képernyő közepére.
Végül a blit művelettel feltesszük a háttérre.
Háttér megjelenítése
Mutassuk meg a hátteret, amíg a többi erőforrás betöltésére várunk.
screen.blit(background, (0, 0))
pygame.display.flip()
Ezzel a kódrészlettel a teljes hátteret megjelenítettük a képernyőn. A blit kiteszi a screen objektumra, míg a flip a screen objektum tartalmát jeleníti meg fizikailag az ablakban/képernyőn.
A pygame-ben nem közvetlenül a fizikai képernyőre rajzolunk, hanem egy screen objektumra. Ha mindent, amit meg akarunk jeleníteni feltettünk erre, akkor egy pillanat alatt ki tudjuk rajzolni a fizikai képernyőre.
Játékobjektumok elkészítése
Elkészítjük mindazokat az objektumokat, melyek a játék futtatásához szükségesek.
whiff_sound = load_sound('whiff.wav')
punch_sound = load_sound('punch.wav')
chimp = Chimp()
fist = Fist()
allsprites = pygame.sprite.RenderPlain((fist, chimp))
clock = pygame.time.Clock()
Először betöltünk két hang effektust a load_sound függvény segítségével. Eztán létrehozunk egy-egy példányt a sprite osztályainkból. Végül a spritejainkat elhelyezzük egy Group objektumba. Ez egy tároló, amivel egyszerűbbé válik a spriteok kezelése.
Egy speciális sprite Group-ot használunk, nevezetesen egy RenderPlain-t. Ez az összes benne elhelyezett spritot meg tudja jeleníteni. Vannak ennél sokkal összetettebb Render Groupok is. A mi kis játékunkban csak a megjelenítést kell elvégeznie. A Group objektumunkra hivatkozik az allsprites referencia.
A clock objektummal szabályozhatjuk a programunk framerátáját, azaz azt, hogy legfeljebb hány képkockát jelenítsen meg a program másodpercenként. Ezt majd a főciklusban fogjuk használni.
A fő ciklus
A főciklus egy végtelen ciklus lesz.
while 1:
clock.tick(60)
Minden játék egy hasonló ciklusban fut. A clock.tick(60)-nal garantáljuk, hogy a programunk legfeljebb 60 képkocka per másodperces sebességgel fog futni/megjeleníteni.
Események kezelése
Az eseménysor nagyon egyszerű kezelésére mutatunk példát.
for event in pygame.event.get():
if event.type == QUIT:
return
elif event.type == KEYDOWN and event.key == K_ESCAPE:
return
elif event.type == MOUSEBUTTONDOWN:
if fist.punch(chimp):
punch_sound.play() #punch
chimp.punched()
else:
whiff_sound.play() #miss
elif event.type == MOUSEBUTTONUP:
fist.unpunch()
Először elkérjük a pygame-től a rendelkezésre álló eseményeket. Ez szerepel a ciklus fejlécében. Az elágazás első két ágában két egyszerű eseményt kezelünk. Az első: a felhasználó kilépett a programból. A második: lenyomták az esc billentyűt. Ezekben az esetekben kilépünk a programból.
Eztán ellenőrizzük, hogy az egér gombja le lett-e nyomva, vagy fel lett-e engedve. Ha lenyomták a gombot, akkor megkérdezzük a fist objektumot, hogy ütközik-e a chimp objektummal. Eztán lejátsszuk a megfelelő hangeffektet, és ha eltalálta a majmot, akkor hívjuk a chimp punched metódusát. (Erre ő bepörög.)
Spriteok frissítése
allsprites.update()
A sprite csoportoknak van egy update metódusa, melynek hívására az összes tartalmazott sprite update metódusát meghívja. Ennek hatására minden frissül, ahogy azt a játék objektumoknál leírtuk.
Rajzoljunk ki mindent
A következő utasításokkal kirajzolhatjuk az objektumainkat.
screen.blit(background, (0, 0))
allsprites.draw(screen)
pygame.display.flip()
Először kirakjuk a hátteret a screen objektumra. Ezt követően a allsprites csoportnak hívjuk a draw metódusát. Ezzel az összes benne tárolt objektumot kitesszük a screen objektumra. Végül a flip függvénnyel mindent megjelenítünk a fizikai képernyőn.
http://f-labor.mkt.bme.hu/~madas/index.php?rst=mp&rid=itpypr
(Szia! Ha még nem telepítetted volna föl a gépedre a Pythont és a Pygamet, akkor ugorj ide, az "előszó" részhez, hogy letöltsd és telepítsd, és készen állj a kezdésre.
1.1 Bevezetés
fig.trajectory
Az egyik legegyszerűbb dolog, amire a Python használható, az a csinos kis számológép funkciója. Várjunk csak, a számológép nem is játék. Mégis miért beszélünk róla? Uncsi...
Nos, ahhoz, hogy kiszámoljuk a tárgyak esését, a lövedék röppályáját, és a legjobb pontszámokat, ahhoz számológép kell. Plussz, bármely igazi kocka úgy tekint a számológépre, mint egy játékra. Inkább, mint egy kínzóeszközre. Szóval, kezdjük el a tanulást a számológéppel. Ne aggódj, a grafikát már az ötödik fejezetnél tárgyaljuk.
Egy egyszerű számológép program már használható arra, hogy a felhasználó infót kapjon unalmas dolgokról, mint amilyen az ingatlanhitel utalása, vagy mondjuk izgalmasabb dolgokról, mint például a röppályája egy sárgolyónak.
Ahogyan azt az első példa mutatja, mozgási energiát fogunk számolni, valami olyasmit, ami majd kell nekünk is a játék fizikai motorjába.
fig.kinetic_energy
Figure 1.1: Python használata mozgási energia kiszámolásához
A legjobb dolog a programozásban, hogy a bonyolultságot el tudjuk rejteni egy egyenletbe. A többi felhasználónak csak a szükséges információt kell megadni, és már meg is kapta a szükséges eredményt egy könnyen érthető formában. Bármilyen egyszerű, hagyományos számológép el tud futni egy okostelefonon, ami lehetőséget ad a felhasználónak, hogy bármikor elővegye, és számoljon.
1.2 Megjelenítés
1.2.1 Szöveg kiírása
Hogyan ír ki a programunk bármit is a képernyőre?
print("Hello World.")
fig.printing_calculator
Ez a program kiírja a képernyőre a "Hello World"("Helló Világ!") szöveget. Rajta, és írjuk be az IDLE készenléti jel(prompt) után! Lássuk, hogyan működik! Próbálj kiírni más szöveget és karaktereket is! A számítógép boldogan kiír bármit, amit szeretnél, akár igaz, akár nem.
Hogyan néz ki a "Hello World" program más számítógépes nyelveken? Nézzük meg a Wikipediában. Elég szép mennyiségű "Hello World" programot gyűjtöttek össze más nyelveken:
http://en.wikipedia.org/wiki/Hello_world_program_examples
Érdekes látni, hogy mennyi különböző nyelv létezik. Képet lehet alkotni arról, hogy milyen összetett egy másik nyelv, a "Hello World" programja alapján.
Videó: A print függvény
Emlékeztetőül: a Pythonban a képernyőre kiíratás könnyű, csak használd ezt a parancsot: print. A print parancs után tegyél zárójelet ( ). A zárójelbe írd bele, mit szeretnél viszontlátni a képernyőn. A zárójel használata az információ átadásra alapvető gyakorlat a matematikában és a számítógépes nyelvekben.
A matek hallgatók úgy tanulják, hogy a zárójelbe egy kifejezés értékadását tüntetjük fel. Például,. és függvények. Az adat a zárójeleken belülről jut el a függvényekhez. Ami a mi esetünkben másabb, az az, hogy mi szöveget íratunk ki.
Jegyezzük meg, hogy idézőjel van a szöveg elején és végén. Ha idézőjelbe tesszük, akkor a számítógép úgy jeleníti meg az adatot, ahogy leírtuk. Például, ez a program azt írja ki, hogy 2+3:
print("2 + 3")
1.2.2 Kifejezések eredményeinek kiíratása
A következő programban nincs idézőjel a kifejezés körül, és így a számítógép össze fogja adni, matematikai kifejezésként. Szóval 5-t fog kiírni és nem 2+3-t.
print(2 + 3)
Az alább látható kód viszont egy hibaüzenetet fog generálni, mivel a számítógép megpróbálja matematikai kifejezésként értelmezni a "Hello World" -t, és így nem igazán működik:
print(Hello World)
A fenti kód hatására egy hibaüzenetet kapunk. SyntaxError: invalid syntax, ami a számítógép nyelvén azt jelenti, hogy nem ismeri a "Hello" és a "World" jelentését.
Mostantól tartsd észben, hogy ez egy aposztrófjel (egyszeres-idézőjel): ', ez pedig egy idézőjel: ". Amikor dupla-idézőjelet kérnek, olyankor gyakori hiba, hogy ezt írják "", ami egy dupla dupla-idézőjel. (az angolban - a ford.)
1.2.3 Több elem kiírása
A print paranccsal több dolgot is kiírathatunk egyszerre, minden egyes elemet vesszővel választunk el. Például, az alábbi kód eredménye ez lesz: Your new score is 1040
print("Your new score is", 1030 + 10)
A következő egysoros kód eredménye ez lesz: Your new score is 1030+10. A számokat nem adja össze, mivel azok az idézőjel közt vannak. Bármi, ami idézőjelek közt van, a számítógép szövegnek értelmez. Bármi, ami azon kívül, az a számítógépnek egy matematikai művelet, vagy számítógépes kód.
print("Your new score is", "1030 + 10")
A vessző az idézőjelen belülre vagy kívülre kerüljön?
A következő példa nem működik rendesen. Ez azért van, mivel a vessző nem különíti el a két kifejezést. Ez pedig azért van, mert a vessző az idézőjelen belülre került. Ha vesszővel akarjuk elválasztani a megjeleníteni kívánt elemeket, akkor azt az idézőjelen kívülre kell írnunk. Ha a programozó a vessző ki akarja íratni, akkor persze az idézőjelen belülre írjuk:
print("Your new score is," 1030 + 10)
Ez a példa már működik, mivel a vessző a kifejezéseket különíti el. Az eredmény:
Your new score is, 1040
Megjegyzem, hogy csak egy vessző lett kiírva. Tehát a vesszők az idézőjelen kívül elkülönítik a kifejezéseket, míg azon belül kiíratásra kerülnek. Az első vessző meg lett jelenítve, a másodikkal elkülönítettük a kifejezéseket.
print("Your new score is,", 1030 + 10)
1.3 Escape kódok(Escape Codes)
Ha az idézőjel arra való, hogy megmondja a számítógépnek, hogy hol kezdődik és végződik egy szöveg, amit meg akarok jeleníteni, akkor hogyan fogja kinyomtatni a program az idézőjelet? Például:
print("I want to print a double quote " for some reason.")
Ez a kód nem működik. A számítógép a szöveg közepén lévő idézőjelet a szöveg befejezésének veszi. Azután nem sok ötlete van arra nézve, hogy mit kezdjen a for some reason paranccsal, és az idézőjellel a végén. Sikerült összezavarni a számítógépet.
Fontos elmondani a számítógépnek, hogy mi a középső idézőjelet szövegként akarjuk megjeleníteni, és nem befejezéseként az előző idézőjelnek. Ez egyszerű, csak tegyél egy fordított perjelet az idézőjel elé, és a számítógép így megérti, hogy ez a szöveg része, és nem egy karakter ami megszakítja a szöveget. Például:
print("I want to print a double quote \" for some reason.")
fig.escape_codes
Ez a kombinációja két kódnak: \", ezt nevezik kikerülő kódnak. Majdnem minden nyelvben léteznek ilyenek. De, mivel a fordított perjel egy escape kód, ezért a perjel nem lesz megjelenítve. Például ez a kód sem működik:
print("The file is stored in C:\new folder")
Miért? Mivel a \n is egy escape kód. Ahhoz, hogy kiírathassuk a perjelet, meg kell kerülnünk, valahogy így:
print("The file is stored in C:\\new folder")
Van még egy pár fontos escape kód, amit érdemes ismerni. Itt van egy táblázat a fontosabb kódokról:
Escape kód Leírás
\' Aposztróf, egyszeres idézőjel
\" idézőjel
\t Tabulátor
\r CR: Carriage Return (kocsi visszatérése, balra/sor elejére mozgatás)
\n LF: Linefeed (sornövelés, lefelé mozgatás)
Mi az a “Carriage Return” (kocsivisszatérés) és “Linefeed”(sornövelés)? Próbáld ki ezt a példát:
print("This\nis\nmy\nsample.")
A parancs kimenete:
This
is
my
sample.
A \n egy sornövelés. El fogja mozgatni a "kurzort" egy sorral lejjebb a nyomtatáshoz képest. A számítógép minden szöveget egy hatalmas, hosszú vonalban tárolja. Onnan tudja, hogy hol vannak a sorok, hogy felismeri a \n karaktert.
Hogy bonyolultabb legyen, a különböző operációs rendszereknek különböző standardjai vannak azt meghatározni, hogy a sor hol ér véget.
Escape kódok Leírás
\r\n CR+LF: Microsoft Windows
\n LF: UNIX alapú rendszerek, és újabb Mac.
\r CR: Régebbi Mac alapú rendszerek
Általában a szövegszerkesztő odafigyel erre helyetted. A MS notepad nem igazán mondjuk, és ha UNIX fájlt nyitunk meg notepadban, akkor borzalmasan néz ki, mivel a sorok vége nem látszik, vagy fekete dobozok láthatók ott.
1.4 Megjegyzések, kommentálás
A kommentálás fontos (mégha a számítógép nem is foglalkozik vele)
Néha a kód némi magyarázatra szorul, ha valaki más olvassa. Ezért adunk "kommentelést" a kódhoz. A megjegyzések az embereknek készülnek, nem a gépnek.
Kétféleképpen hozhatunk létre kommentet. Az egyik, hogy a # szimbólumot használjuk. A gép átugrik minden szöveget, ami a kettőskereszt után található. Például:
# This is a comment, it begins with a # sign
# and the computer will ignore it.
print("This is not a comment, the computer will")
print("run this and print it out.")
A kettőskereszt jel idézőjelek közt persze nem minősül kommentnek. Ha egy sor kódot nem akarunk figyelembe venni, akkor egész egyszerűen a sor elejére írjuk a kettőskeresztet. Lehetséges a sor végére tenni a kommentunket.
print("A # sign between quotes is not a comment.")
# print("This is a comment, even if it is computer code.")
print("Hi") # This is an end-of-line comment
Lehetséges továbbá több sornyi kódot is kommentelni, ehhez három aposztrófot kell egymás után beírnunk. delimit.
print("Hi")
'''
This is
a
multi
line
comment. Nothing
Will run in between these quotes.
print("There")
'''
print("Done")
A legtöbb profi Python programozó ezt a többsoros kommentelést fogja előnyben részesíteni, valami olyasmiért, amit úgy neveznek, hogy docstrings(szövegfüzér) A docstring megengedi, hogy a kód mellé írjuk a megjegyzéseinket, dokumentációnkat, és később akár automatikusan kinyomtathatjuk dokumentumba, weboldalra, vagy IDE-be. Az általános kommenteléshez a kettőskereszt a legjobb.
Mégha te is vagy az egyetlen, aki olvashatja a kódot, akkor is írj kommentet, hogy időt takaríthass meg később. Olyan kommenteket írni, mint "földönkívűliek bombájának a kezelése" segít később gyorsan emlékezni arra, hogy az a kódrész mire vonatkozik.
1.5 Értékadás műveletek
Videó: Az értékadás művelet
Hogyan tároljuk a pontszámokat a játékunkban? Vagy hogyan követjük nyomon az ellenség életerejét? Ami ehhez kell, az egy értékadás műveletek. (Ez egy olyanművelet, ami szimbólumokat tárol, mint pl. + vagy - ) Ez aztán eltárol egy értéket egy változóban, amit később használhatunk. Az alábbi kód például az x változóra a 10-t vonatkoztatja, és kiírja az eltárolt értéket.
Lásd a lenti példát. Click on the “Step” button to see how the code operates.
Értékadás és változók használata
1
2
3
4
5
6
7
8
9
10
11
12
# Create a variable x
# Store the value 10 into it.
x = 10
# This prints the value stored in x.
print(x)
# This prints the letter x, but not the value in x
print("x")
# This prints "x= 10"
print("x=",x)
Step
Variables:
x=
Output:
10
x
x= 10
Változók amik kívül kerülnek az idézőjelen:
Megjegyzés:A listázás fentebb bemutatta a különbséget aközött, amikor x idézőjelen belül van, és amikor x idézőjelen kívül van. Ha az x az idézőjelen belül van, akkor a számítógép azt írja ki, hogy x. Ha az x az idézőjelen kívül van, akkor a számítőgép az x értékét írja ki. Azok közt, akik először tanulnak programozást gyakori, hogy zavaró ez az idézőjelen kívül és idézőjelen belül dolog.
fig.pi
Egy értékadás művelet (olyan kódsor, ami használja az = műveletet.) különbözik az algebrai egyenlőségtől, amit matekból tanultál. Ne mosd össze a kettőt. Az értékadás műveletnél a bal oldalon csak egy változó lehet, semmi más.
A bal oldalán az egyenletnek műveleti jel/értékadás művelet lehet, ami egy kifejezés. Egy kifejezés bármi, ami egy értéket ad vissza értékadás által. Lásd az alábbi kódot.
x = x + 1
A fenti kód nyilván nem lehet algebrai egyenlet. De ez érvényes a számítógép számára, mivel ez egy értékadó állítás. A matematikai egyenletek különböznek az értékadó műveletektől, mégha van is bennük változó, szám, vagy egyenlőség jel.
A fenti kifejezés esetében a kód az x jelenlegi értékét adja meg, egyet hozzáad, és eltárolja az eredményt az x-ben.
A példánkat kiterjesztbe, a kifejezés lent kiírja a hatos számot.
x = 5
x = x + 1
print(x)
Részenként futnak az értékadások. A számítógép nem néz a jövőbe. A lenti kódban, a számítógép kiírja az 5-t a második sorban, és aztán a negyedik sorban kiírja a 6-t. Azért, mert a második sorban a kód, ami egyet adna az x-hez, még nem futott le.
1
2
3
4
x = 5
print(x) # Prints 5
x = x + 1
print(x) # Prints 6
A következő értékadás érvényes és futni is fog, de értelmetlen. A gép adni fog egyet x-hez, de se ki nem írja, se el nem tárolja.
x + 1
Az alábbi kód 5-t fog kiírni, és nem 6-t, mivel a programozó elfelejtette eltárolni azx + 1 eredményét az x változóban.
x = 5
x + 1
print(x)
Az állítás alább nem érvényes, mivel a bal oldal többet tartalmaz egy darab változónál.
x + 1 = x
A Pythonban van más típusú értékadási művelet is. Ezek lehetővé teszik, hogy a programozó könnyedén változtassa meg a változó értékét. Például:
x += 1
A fenti értékadás egyenlő az alábbival:
x = x + 1
Vannak még értékadó műveletek összeadáshoz, kivonáshoz, szorzáshoz, és osztáshoz.
1.6 Változók
A változók kisbetűvel kezdődnek:
A változóknak kisbetűvel kellene kezdődniük. A változók kezdődhetnek nagybetűvel, vagy aláhúzással, de ezek speciális esetek, és nem történhetnek meg normál esetekben. Az első kisbetű után a változó tartalmazhat nagybetűt, kisbetűt, számot, aláhúzást. A változók nem tartalmazhatnak space karaktert.
A változók betűtípusra érzékenyek. Ez összezavarhatja a programozót, aki nem készül erre fel. A lenti példában az eredmény 6 lesz és nem 5, mivel két különböző változót használunk, a x-t és a X-t.
x = 6
X = 5
print(x)
A hivatalos Python stílus kézikönyv (igen, a programozók tényleg írtak egy könyvet a stílusról) azt mondja, hogy a többszavas változónevek a Pythonban el kellene legyenek választva, aláhúzással. Például használjuk a hair_style és ne a hairStyle alakot. Személy szerint, ha te az én tanítványom vagy, akkor tudnod kell, hogy engem nem érdekel különösebben ez a szabály, mivel a következő nyelv, amit a Python után tanítunk, az a Java, és ott pont fordítva van. Megpróbáltam a Java stílusú szabályokat tanítani ezen a kurzuson, de akkor gyűlölködő leveleket kaptam a Python szerelmeseitől. Ezek az emberek meglátogatták a weboldalamat, és sokkot kaptak, sokkot kaptak, mondom, a szegényes stílusom miatt.
Joan Rivers-nek semmi köze ezekhez az emberekhez, szóval feladtam és megpróbáltam a helyes stílust követni immár.
Itt van néhány példának, hogy mi elfogadható és mi nem változónévként:
Elfogadható változónév Nem elfogadható változónév Elfogadható, de nem helyes
first_name first name FirstName
distance 9ds firstName
ds9 %correct X
Minden nagybetűs változónév, mint amilyen a MAX_SPEED megengedett, de csak akkor, ha a körülmények miatt a változó sosem változtatja meg az értékét. Azt a változót, ami nem változtatja meg az értékét állandónak/konstansnak hívjuk.
1.7 Műveletek
A bonyolultabb matematikai műveletekhez, a mindennapi matematikai műveletek elérhetők. Köztük néhány nem túl gyakorival:
műveleti jel művelet példa egyenlet példa kód
+ összeadás a = 3 + 2
- kivonás a = 3 - 2
* szorzás a = 3 * 2
/ osztás a = 10 / 2
// egész osztás N/A a = 10 // 3
** hatványozás a = 2 ** 3
% modulus/törtrész N/A a = 8 % 3
Videó: Műveletek
Az egész osztás mindig lefelé fogja kerekíteni az eredményt, a legközelebbi egész felé. Például a 11//2 egyenlő lesz 5-tel, és nem 5.5-tel, és 99//100 egyenlő 0.
Szorzás művelet műveleti jel nélkül nem működik a Python alatt. A következő két sornyi kód nem működik:
# This does not work
x = 5y
x = 5(3/2)
A szorzás műveleti jelét muszáj használni ezekben a sorokban, ha azt akarjuk, hogy működjenek:
# This does work
x = 5 * y
x = 5 * (3 / 2)
1.7.1 Műveletek elválasztása
Bármennyi space lehet a műveleti jelünk előtt és után, és a számítógép még akkor is meg fogja érteni. Például az alábbi 3 sor teljesen egyenértékű.
1
2
3
x=5*(3/2)
x = 5 * ( 3 / 2 )
x =5 *( 3/ 2)
A hivatalos Python stílus kézikönyv azt mondja, hogy lennie kell egy space-nek az operátor előtt és után is. (Majd meghaltatok, hogy megtudjátok, igaz? Oké, a hivatalos stílus kézikönyvnek az elérhetősége itt van: PEP-8.) A három fenti kód közül a legstílusosabb a második.
1.8 Műveletek sorrendje
A Python a kifejezéseknek úgy ad értéket, hogy követi a műveleti sorrendet, ahogyan azt egy alap matematikai kifejezésnél is találjuk. Például ez az egyenlet nem korrekt módon számolja ki az átlagot:
average = 90 + 86 + 71 + 100 + 98 / 5
Az első művelet, amit végrehajt az a 98/5. És így számol:
ahelyett, hogy a vágyott eredményt adná:
Zárójel használatával a probléma orvosolható:
average = (90 + 86 + 71 + 100 + 98) / 5
1.9 Trigonometrikus függvények
A trigonometrikus függvényeket arra használják, hogy velük szinuszt és koszinuszt számoljanak. Alapértelmezett állapotban a Python nem tudja a sin/cos függvényeket számolni, de ha a helyes könyvtárat importáljuk neki, akkor már igen. Az egységek radiánban lesznek megadva.
# Import the math library
# This line is done only once, and at the very top
# of the program.
from math import *
# Calculate x using sine and cosine
x = sin(0) + cos(0)
1.10 Szokványos egyenletek kiszámítása
Egy Python program kiszámolhatja fogyasztását egy autónak, ami 294 mérföldet tesz meg, 10.5 gallon gázolajjal.
m = 294 / 10.5
print(m)
Ez a program kicsit fejleszthető változók használatával. Ez lehetővé teszi, hogy az értékeket könnyedén megváltoztathassuk a kódban, anélkül, hogy az egyenlethez nyúlnánk.
m = 294
g = 10.5
m2 = m / g # This uses variables instead
print(m2)
A jó változó nevek fontosak.
Magától ezt a programot megérteni nehézkes.Az m és g változók nem jelentenek túl sokat önmagukban. A program megcsinálható úgy is, hogy könnyen érthető legyen a működése a változók alapján:
milesDriven = 294
gallonsUsed = 10.5
mpg = milesDriven / gallonsUsed
print(mpg)
Most már, ha egy nem-programozó ránéz a kódra, neki is lesz ötlete, hogy mit csinálhat a program. Egy másik példa a jó és a rossz változó elnevezésre:
# Hard to understand
ir = 0.12
b = 12123.34
i = ir * b
# Easy to understand
interestRate = 0.12
accountBalance = 12123.34
interestAmount = interestRate * accountBalance
Videó: Egy szokványos számoló program készítése
Az IDLE szerkesztőben lehetőség van arra, hogy szerkesszük az adott sort, annak újragépelése nélkül. Ezt úgy tehetjük meg, hogy a kurzort felvisszük a választott sorra, és ütünk egy entert. Ezzel másoljuk az adott sort.
A Python kódot bevinni a >>> prompttal lassú, és csak egy sort lehet egyszerre. Valamint nem lehetséges lementeni, hogy más is használhassa. Szerencsére, van egy sokkal egyszerúbb módja is a Python kód bevitelének.
A Python kódot bevihetjük script által is. A script Python kódsorok sorozata ami egyszerre lesz végrehajtva. Ahhoz, hogy egy scriptet készíthessünk, nyissunk egy új ablakot, ahogy az ábra mutatja 1.2.
fig.entering_a_script
Figure 1.2: Szkript bevitele
Vigyük be a gázolaj fogyasztást számoló programunkat, aztán mentsük el a fájlt. Elmenthetjük a fájlt flash drive-ra, network drive-ra, vagy bármilyen más helyre. A Python programok mindig .py kiterjesztésre végződnek. Lásd az ábrát: 1.3.
fig.saving_mpg_calculator
Figure 1.3: Szkript mentése
Futtassuk a programot, egyszerűen klikkeljünk a "Run" menüre és válasszuk a "Run Module" parancsot. Próbáljuk meg frissíteni a programot úgy, hogy új értékeket adunk a mérföldre, és gallonra.
Vigyázat, gyakori hiba!
Ettől a ponttól kezdve, szinte minden kódot vigyél be a script/modul-ba. Ne gépeld be a programodat az IDLE >>> prompton kívülre. Az ide beírt kód nem lesz elmentve. Ha ez történne, újra kell kezdeni. Ez az egyik leggyakoribb hibája a kezdő programozóknak.
Ez a program sokkal hasznosabb lenne, ha képes volna párbeszédre a felhasználókkal és megkérdezné a felhasználót a vezetett mérföldekről és a felhasznált gallonokról. Ez megtehető az input paranccsal. Lásd az alábbi kódot:
# This code almost works
milesDriven = input("Enter miles driven:")
gallonsUsed = input("Enter gallons used:")
mpg = milesDriven / gallonsUsed
print("Miles per gallon:", mpg)
Ennek a programnak a futtatása során a felhasználó meg lesz kérdezve a mérföldekről és a gallonokról, de egy furcsa hibát is generálunk, amit az alábbi ábrán láthatsz 1.4.
fig.mpg_program_error
Figure 1.4: Az MPG program futtatásakor megjelenő hiba
Ezt kijavítandó, kicsit módosítsuk a programunkat:
milesDriven = input("Enter miles driven:")
gallonsUsed = input("Enter gallons used:")
x = milesDriven + gallonsUsed
print("Sum of m+g:", x)
A fenti kódot futtatva ez lesz a kimeneti üzenet 1.5.
fig.mpg_incorrect_addition
Figure 1.5: Hibás összeadás
A program nem adja össze a két számot. Csak egymás után teszi őket. Ez azért történik, mert a program nem tudja, hogy itt két számot kértünk be. A felhasználó azt is beütheti, hogy Bob, vagy Mary. Ezek összege BobMary lenne. Elég érdekes.
Az adatbrvitelt számokká kell alakítanunk.
Ahhoz, hogy elmondjuk a számítógépnek, hogy ezek számok, szükséges az input funkciónkat kiegészíteni egy int( )-rel vagy egy float( )-tal. Az első esetben egész-, a másodikban törtszámokat várunk eredményül.
A végső, működő program:
calculate_miles_per_gallon.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Sample Python/Pygame Programs
# Simpson College Computer Science
# http://programarcadegames.com/
# http://simpson.edu/computer-science/
# Explanation video: http://youtu.be/JK5ht5_m6Mk
# Calculate Miles Per Gallon
print("This program calculates mpg.")
# Get miles driven from the user
miles_driven = input("Enter miles driven:")
# Convert text entered to a
# floating point number
miles_driven = float(miles_driven)
# Get gallons used from the user
gallons_used = input("Enter gallons used:")
# Convert text entered to a
# floating point number
gallons_used = float(gallons_used)
# Calculate and print the answer
mpg = miles_driven / gallons_used
print("Miles per gallon:", mpg)
Step
Variables:
milesDriven=
gallonsUsed=
mpg=
Output:
This program calculates mpg.
Enter miles driven:288
Enter gallons used:15
Miles per gallon: 19.2
És egy másik példa arra, hogyan számoljuk ki a mozgási energiáját egy tárgynak:
calculate_kinetic_energy.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Sample Python/Pygame Programs
# Simpson College Computer Science
# http://programarcadegames.com/
# http://simpson.edu/computer-science/
# Calculate Kinetic Energy
print("This program calculates the kinetic energy of a moving object.")
m_string = input("Enter the object's mass in kilograms: ")
m = float(m_string)
v_string = input("Enter the object's speed in meters per second: ")
v = float(v_string)
e = 0.5 * m * v * v
print("The object has " + str(e) + " joules of energy.")
Ha le akarjuk rövidíteni a programot, akkor egymásba ágyazhatjuk az input parancsunkat, és float utasítást. Példa erre:
milesDriven = input("Enter miles driven:")
milesDriven = float(milesDriven)
Ugyanazt fogja adni eredményül ez is:
milesDriven = float(input("Enter miles driven:"))
Ezesetben, a kimenete az input utasításnak közvetlenül van üsszekötve a float utasítással. Mindkettő működik, és a programozón múlik, hogy melyiket választja. Fontos, továbbá, hogy megértsük mindkét formát.
A játékok készítés komoly feladat több szempontból is. Először is a játékok intenzív interakciót követelnek meg a felhasználóval, hasonlóan a grafikus felületű szoftverekhez. A játék típusától és a játékmenettől függően megfelelően jól kell kinéznie, hogy közönséget kapjon, ezenkívül a játékoknak egy bizonyos szintű mesterséges intelligenciát kell nyújtania (gondoljunk akár egy szimpla amőbára). A játékoknak szórakoztatónak kell lenniük, mindamellett megfelelő kihívást kell nyújtania a játékosoknak. Ezek igen összetett követelményrendszert jelentenek.
A komoly és látványos játékok sosem egy ember munkájának az eredményei, hiszen a megalkotásukhoz szükséges szakmai ismeret annyira szerteágazó (nem beszélve az emberek saját adottságairól, tehetségéről), hogy azokat megfelelő szinten elsajátítani egy embernek egy életre szóló feladat - és akkor még semmit sem csinált. Ezeket a játékokat több emberből álló csapatok készítik (producer, designer, artist, coder, marketinges, webfejlesztő, és sok esetben PR-os is kell) igen nagy ráfordításokkal.
Ha valaki a játékiparban szeretne dolgozni, mindenképpen ki kell választania magának egy testhez álló szakirányt, majd keresnie vagy építenie kell egy csapatot. A játékfejlesztés kemény munka, ami lassan térül meg, hiszen néha egy játék fejlesztése több évig is eltart, addig finanszírozni kell a készítők bérét, és a fejlesztés infrastruktúráját.
Gondolom most kellőképpen sikerült mindenkit elijeszteni a témától, de nem eszik olyan forrón a kását, egy ember is készíthet jó, érdekes és jól kinéző játékokat, csak tudomásul kell venni, hogy ezek bonyolultsága és/vagy színvonala azért messze el fog maradni a fent említett komoly alkotásokétól :D A DRY (Don't Repeat Yourself) és DNRTW ( Do Not Reinvent The Wheel) elvet szem előtt tartva, a legokosabb ha valamilyen keretrendszert alkalmazunk a játékok készítése során (a komolyabb és összetettebb keretrendszereket már játékmotornak hívják). Ezek leveszik a terhet a vállunkról egy csomó olyan dologgal kapcsolatban, mint pl. képadatok tárolása, átalakítása, képernyőre rakása, hangok, zenék kezelése, stb.
Pythonhoz, az egyszerű gyalogbéka hobbiprogramozónak a pygame (ejtsd: pájgém), esetleg a pyglet (ejtsd: piglet) áll rendelkezésére, vagy komolyabb dolgokhoz az ogre, vagy a crystalspace. A pygame-en kívül a többinél konyitani kell valamennyire az opengl-hez, ha valaki nem foglalkozott vele, akkor mindenképpen a pygame-et ajánlanám kezdésnek.
Mi is ez a pygame? Nos létezik linuxon egy programkönyvtár (lib) amely elvben hasonló hozzáférést enged a gép video, hang és input elemeihez, mint a winen a directx. Simple Directmedia Layer a becsületes neve, de SDL-ként közismertebb. Ez egy C-ben írt lib, amit tud azt jól tudja, bár nem annyira sokrétű, mint a wines párja (egyébként elérhető win alatt is, így a pygame is).
Lelkes pythonosok megírták a pygame-et, ami tulajdonképpen pár általuk hozzáadott plusz dologtól eltekintve az SDL pythonos nyelvi kötése. Habár opengl mutatványokra is felhasználható, a pygame elsősorban 2D játékok készítésére készült. Ennyi unalmas bevezető után csapjunk a sűrűjébe, is próbáljunk meg valamit kezdeni a pygame-mel!
Természetesen fel kell telepíteni használat előtt, ubuntu, debian alatt van a repóban, sudo apt-get install python-pygame, más rendszereknél nézzétek meg a telepítési leírásokat. Használatához be kell importálnunk a pygame modult a programunkba. Mindjárt két importot is érdemes elvégezni, ezzel egy csomó gépeléstől kímélhetjük meg magunkat (pl. pygame.QUIT helyett elegendő QUIT-et írni), majd inicializálni kell a pygame összetevőket:
import pygame
from pygame.locals import *
pygame.init()
Az inicializálás során a pygame felkészíti az SDL réteget a működésre, ami egyben a hardverek inicializálását is magában foglalja. Ha ezt elmulasztjuk, a programunk működésképtelen lesz.
Ahhoz, hogy legyen egy ablakunk, ahol a játék grafikáját, elemeit megjelenítjük, meg kell kérnünk az SDL-t, hogy készítsen nekünk egyet. És itt jön a pygame és az SDL első korlátja, mert meg kell adni neki, hogy mekkorát készítsen. Ezzel nincs semmi baj, a baj azzal van, hogy ezen utána nem tudunk változtatni :(
Ezért már a játék kezdetekor ki kell találni, hogy mekkora ablakban fogunk dolgozni.
Most egy 800x600-as ablakot hozunk létre, ez elfér manapság szinte minden képernyőn, ahol a pygame elfut (a telefonokat most hagyjuk ki ebből).
screen = pygame.display.set_mode((800,600))
A screen változóban egy pygame.surface objektum tárolódik el. Mi is ez a surface? A szó maga felületet jelent, a pygame-ben egy kicsit többet, de a lényeg az a mi szempontunkból, hogy egy olyan felület, amire rajzolni tudunk.
Nosza rajzoljunk rá! Csinálunk egy pattogó labdát. Nem egy hasznos dolog, és semmiképpen nem játék még, de kezdetnek jó lesz :) Itt a forráskód, és átbeszéljük.
#!/usr/bin/env python
# -*- coding:utf8 -*-
import sys,pygame
from pygame.locals import *
# pygame inicializálása
pygame.init()
# ablak megjelenítése és a játékadatok beállítás
SCREEN_SIZE = (800,600) # ablak mérete
screen = pygame.display.set_mode(SCREEN_SIZE) # ablak "surface"
BGCOLOR = (0,0,0) # háttérszín
BALLCOLOR = (255,0,0) # labda színe
d = 30 # labda átmérője
dh = d/2 # átmérő fele
x,y = dh,dh # labda kezdőpontja (középpont)
vx,vy = 12,18 # függőleges és vízszintes sebessége a labdának
fps = 30 # képkocka / másodperc
# ezek adják meg hol kell a labdának visszapattannia
xlimits = (dh,SCREEN_SIZE[0]-dh)
ylimits = (dh,SCREEN_SIZE[1]-dh)
def rajzol(x,y):
"""rajzol(x,y):
letörli a képernyőt, és felrajzolja a labdát az x,y pozícióba"""
screen.fill(BGCOLOR)
pygame.draw.circle(screen,BALLCOLOR,(x,y),dh,0)
def mozgat(x,y,vx,vy):
"""mozgat(x,y,vx,vy):
kiszámolja a labda következő pozícióját.
megfordítja a labda mozgását az ablak szélénél"""
x = x + vx
y = y + vy
if x < xlimits[0]:
x = xlimits[0]
vx = -vx
if x > xlimits[1]:
x = xlimits[1]
vx = -vx
if y < ylimits[0]:
y = ylimits[0]
vy = -vy
if y > ylimits[1]:
y = ylimits[1]
vy = -vy
return x,y,vx,vy
def kilep():
"""kilep():
Megnézi, hogy megnyomták-e az ESC gombot
vagy megpróbálták bezárni az ablakot"""
for event in pygame.event.get():
if event.type==QUIT:
return True
elif (event.type==KEYDOWN and event.key==K_ESCAPE):
return True
return False
# ezzel az objektummal tudjuk szabályozni a játék sebességét
clock = pygame.time.Clock()
# fő ciklus
# ismétlődik amíg ki nem lépünk
while True:
# kirajzoljuk a játékunkat
# és elvégezzük a mozgatását a labdának
rajzol(x,y)
x,y,vx,vy = mozgat(x,y,vx,vy)
# ki akart lépni a felhasználó?
if kilep():
pygame.quit()
sys.exit()
# kirakjuk az ablak tartalmát a képernyőre
pygame.display.flip()
# szabályozzuk a futási sebességet
clock.tick(fps)
# infóként kinyomjuk a labda adatait a konzolra
print x,y,vx,vy
Az 1-25 sorok magától értetődőek, de azért elláttam kommentekkel is a biztonság kedvéért. Mielőtt a rajzol és mozgat függvényeket megnéznénk, inkább foglalkozzunk a kód végén látható végtelenített ciklussal, a 67-87 sorokban.
Ez a programunk fő ciklusa. Mit is csinál? Kirajzolja az ablak tartalmát a rajzol() függvénnyel, kiszámolja a labda következő koordinátáját a mozgat() függvénnyel, megnézi, hogy kapott-e kilépési parancsot - ha igen, akkor kilép - , logolja a labda koordinátáit és sebességét a konzolra, és kezdődik minden előlről.
Van itt viszont egy fontos parancs, amiről fontos szót ejteni: pygame.display.flip()
Az SDL dupla pufferelést alkalmaz, minden rajzolási műveletet a képernyő egy másolatán végez a memóriában. Ahhoz, hogy ezt lássuk is, meg kell jeleníteni a képernyőn. Ezzel a paranccsal a puffer tartalmát villámgyorsan kiteszi a videomemóriába, így az számunkra is láthatóvá válik.
A clock.tick(fps) paranccsal a játék futásának sebességét állítjuk be, így minden hardveren azonos sebességel fog futni a ciklusunk, nevezetesen egy másodperc alatt fps alkalommal.
Ejtsünk szót még a rajzol() függvényünkről!
A függvény elején letöröljük a képernyőt, azaz kitöltjük a BGCOLOR színnel, majd a kapott x,y koordinátákra kirajzolunk egy BALLCOLOR színű kört. Ha nem törölnénk le a képernyőt, csak a kört rajzolnánk ki, akkor a labdánk gyakorlatilag csíkot húzna a képernyőre. Ebből is látható, hogy minden képkockán elő kell állítani a teljes képet. Ez bonyolult játékoknál elég időigényes feladat lehet, ezért mindenféle praktikához kell folyamodni a megfelelő teljesítmény elérése érdekében.
A mozgat() függvényünk egyszerű, "csak" számítási feladatot végez, a kapott x,y és vx,vy sebességadatok alapján kiszámolja hova kerül a labda. Ha a képernyőn kívülre kerülne, akkor visszateszi a képernyőre, és megfordítja a vízszintes vagy függőleges (vagy mindkettő) mozgási irányát.
A Python programozási nyelv
Pygame
A Pygame játékok fejlesztését segítő python modulok gyűjteménye. A platformfüggetlen SDL könyvtárra épül. Ez az oka annak, hogy a pygame programok szinte minden platformon és operációs rendszeren futtathatók.
A Pygame egy ingyenes bővítése a nyelvnek. Részleteket ld. az LGPL licensz leírásában.
A következőkben megpróbálom egyszerű példákkal bemutatni a pygame használatát, működését. Ezt a tutoriált Pete Shinners: Line By Line Chimp című munkája alapján készítettem. Többnyire annak fordítása, ill. saját tapasztalatokkal való kiegészítése.
Szükséges modulok
A következő kódrészlet tartalmazza a szükséges modulokat. Egyben példát láthatunk arra, hogyan ellenőrizhetjük egyes, opcionális modulok jelenlétét a futtató környezetben.
import os, sys
import pygame
from pygame.locals import *
if not pygame.font: print 'Warning, fonts disabled'
if not pygame.mixer: print 'Warning, sound disabled'
Először importáljuk az "os" és "sys" python modulokat. Ezek sok mindenre használhatók, például lehetővé teszik platform független fájl-útvonalak megadását. A következő sorban importáljuk a pygame csomagot. Ezzel az összes pygame modult importáltuk. Van néhány opcionális modul is, melyek None értéket vesznek fel, ha nem sikerült őket beimportálni. Ezt ellenőrizzük az utolsó két sorban.
A "locals" egy speciális pygame csomag. Ez olyan gyakran használható konstansokat és függvényeket tartalmaz, melyeket célszerű a program globális névterébe elhelyezni. Ez a modul tartalmazza többek között a Rect függvényt, mellyel téglalap objektumokat hozhatunk létre, vagy olyan konstansokat, mint a 'QUIT, HWSURFACE', melyeket a pygame más részeivel való interakciókhoz használjuk. Természetesen nem kötelező ezt importálni. Ekkor a pygame modulon keresztül is elérhetjük.
Végül példát láthatunk arra, hogyan írassunk ki hibajelzéseket, ha egy adott modul pl. a font vagy a sound nem elérhető.
Erőforrások betöltése
Két függvényt adunk képek és hangok betöltésére.
Kép betöltése
def load_image(name, colorkey=None):
fullname = os.path.join('data', name)
try:
image = pygame.image.load(fullname)
except pygame.error, message:
print 'Cannot load image:', name
raise SystemExit, message
image = image.convert()
if colorkey is not None:
if colorkey is -1:
colorkey = image.get_at((0,0))
image.set_colorkey(colorkey, RLEACCEL)
return image, image.get_rect()
Az első paramétere a betöltendő kép nevét tartalmazza. A függvény rendelkezik egy második, opcionális paraméterrel is. Ezt a kép "színkulcsának" beállításához használhatjuk. A "színkulcsot" az átlátszó színek reprezentálására használjuk.
A függvény első sorában elkészítjük a fájlhoz tartozó teljes útvonalat. Ebben a példában az összes erőforrás a "data" alkönyvtárban van. Az os.path.join használatával olyan fájl-útvonalakat gyárthatunk, melyek bármilyen platformon használhatók.
A következő lépésben a pygame.image.load függvénnyel betöltjük a képet. Ezt a függvényhívást egy kivételkezelő részbe ágyaztuk, így a betöltés során fellépő hibákat könnyen lekezelhetjük. A betöltés után fontos a convert() függvény meghívása. Ez egy új másolatot készít az objektumról és a képernyőhöz igazítja a kép színformátumát és színmélységét. Ez azért kell, hogy a képernyőre való kirajzolás a lehető leggyorsabban menjen.
Végül beállítjuk a "színkulcsot" a képhez. Ha a felhasználó megadta a colorkey paramétert, akkor ez lesz a képhez rendelve. Általában ez egy szín RGB értéke, pl. a (255,255,255) tuple a fehér színt jelenti. Ezenkívül megadhatunk -1-et is színkulcsként. Ebben az esetben a kép bal-felső pixelének színe lesz a színkulcs.
Hang betöltése
def load_sound(name):
class NoneSound:
def play(self): pass
if not pygame.mixer:
return NoneSound()
fullname = os.path.join('data', name)
try:
sound = pygame.mixer.Sound(fullname)
except pygame.error, message:
print 'Cannot load sound:', wav
raise SystemExit, message
return sound
Ezzel a függvénnyel egy hangfájlt tudunk betölteni. Az első dolog annak ellenőrzése, hogy sikerült-e rendesen importálnunk a pygame.mixer modult. Sikertelen esetben egy speciális osztálypéldányt adunk vissza, mely rendelkezik egy állejátszó metódussal. Ez az objektum ugyanúgy viselkedik és használható, mint egy normális Sound objektum azzal a kivétellel, hogy nem ad hangot. Ezáltal nincs is szükségünk további hiba ellenőrzésre.
A fenti két függvény nagyon hasonlít egymásra. Itt is először definiálunk egy teljes útvonalat a hangfájlhoz, majd a try-except részben betöltjük. Végül egy Sound objektumot adunk vissza.
Játék osztályok
A következőkben egy játék két lehetséges objektumait mutatjuk be. A játék "logikáját" ez a két osztály tartalmazza.
class Fist(pygame.sprite.Sprite):
"""moves a clenched fist on the screen, following the mouse"""
def __init__(self):
pygame.sprite.Sprite.__init__(self) #call Sprite initializer
self.image, self.rect = load_image('fist.bmp', -1)
self.punching = 0
def update(self):
"move the fist based on the mouse position"
pos = pygame.mouse.get_pos()
self.rect.midtop = pos
if self.punching:
self.rect.move_ip(5, 10)
def punch(self, target):
"returns true if the fist collides with the target"
if not self.punching:
self.punching = 1
hitbox = self.rect.inflate(-5, -5)
return hitbox.colliderect(target.rect)
def unpunch(self):
"called to pull the fist back"
self.punching = 0
A fenti osztály reprezentálja a játékos öklét. Ezt a pygame.sprite modul Sprite osztályából származtattuk. Az __init__ függvény új példány létrehozásakor hívódik meg. Ebben a függvényben először a bázisosztály __init__ függvényét hívjuk. A játékunkban a sprite-ok kirajzolásához Group osztályokat használunk. Ezen osztályok olyan sprite-ok megjelenítésére használhatók, amelyek rendelkeznek image és rect attribútumokkal. Ezen attribútumok módosításával érhetjük el, hogy a megjelenítő egy adott képet egy adott helyre rajzoljon ki.
Minden sprite rendelkezik egy update() metódussal. Ezt a függvény általában képkockánként egyszer hívjuk. Ebbe helyezhetünk olyan kódokat, melyekkel mozgathatjuk és frissíthetjük a sprite változóit. Jelen esetben az update() metódus az öklöt az egér kurzor helyére mozgatja. Eltolást is alkalmaz, ha az objektum "punching" állapotban van.
A punch() és az unpunch() metódusokkal a "punching" állapot kapcsolható be és ki. A punch() függvény igaz értéket ad vissza, ha az ököl eltalálta a célt, azaz a két sprite ütközött.
class Chimp(pygame.sprite.Sprite):
"""moves a monkey critter across the screen. it can spin the
monkey when it is punched."""
def __init__(self):
pygame.sprite.Sprite.__init__(self) #call Sprite intializer
self.image, self.rect = load_image('chimp.bmp', -1)
screen = pygame.display.get_surface()
self.area = screen.get_rect()
self.rect.topleft = 10, 10
self.move = 9
self.dizzy = 0
def update(self):
"walk or spin, depending on the monkeys state"
if self.dizzy:
self._spin()
else:
self._walk()
def _walk(self):
"move the monkey across the screen, and turn at the ends"
newpos = self.rect.move((self.move, 0))
if not self.area.contains(newpos):
if self.rect.left < self.area.left or \
self.rect.right > self.area.right:
self.move = -self.move
newpos = self.rect.move((self.move, 0))
self.image = pygame.transform.flip(self.image, 1, 0)
self.rect = newpos
def _spin(self):
"spin the monkey image"
center = self.rect.center
self.dizzy += 12
if self.dizzy >= 360:
self.dizzy = 0
self.image = self.original
else:
rotate = pygame.transform.rotate
self.image = rotate(self.original, self.dizzy)
self.rect = self.image.get_rect(center=center)
def punched(self):
"this will cause the monkey to start spinning"
if not self.dizzy:
self.dizzy = 1
self.original = self.image
A chimp osztálynak egy kicsit több feladata van, mint a Fist-nek, de semmivel sem bonyolultabb annál. Az osztály feladata a csimpánz mozgatása a képernyőn, és ha eltaláljuk a majmot, akkor elkezd forogni. Ezt az osztályt is a Sprite osztályból származtatjuk, és a Fisthez hasonlóan inicializáljuk. Az inicializálás során az area attribútumot a képernyő méretéhez igazítjuk.
Az update függvény tevékenysége a csimpánz "dizzy" állapotától függ. Ez akkor igaz, ha eltalálták a majmot és éppen forog. Ennek függvényében vagy a _spin vagy a _walk metódusokat hívja. Az aláhuzás prefix a python függvények nevében azt jelenti, hogy ezt csak a tartalmazó osztály használhatja. Ez csupán egy konvenció, azaz nem nyelvi szintű deklarátum.
A walk metódus egy adott értékkel eltolja a csimpánz képét. Ha az új pozíció érinti a kép szélét, akkor az eltolás irányát megfordítjuk. Ezen kívül a csimpánz képét is tükrözzük a pygame.transform.flip függvénnyel. Ezzel elértük, hogy a csimpánz mindig testtel előrefelé mozogjon.
A spin metódust, akkor használjuk, amikor eltalálták a makit, és épp szédül, azaz a "dizzy" változó nem nulla (logikai értéke igaz). Ebben az attribútumban tároljuk a aktuális forgatás mértékét (0-360 fokig). Miután teljesen körbeforgattuk, ismét az eredeti, forgatás nélküli képet rajzoljuk a csimpi helyére. A pygame.transform.rotate hívása helyett, először egy referenciát állítunk erre a függvényre. Ez a rotate változó. Később - a rövidebb forma miatt - ezen keresztül végezzük a forgatást. Ezt nem kötelező így csinálnunk, de adunk erre is példát. Mindig az eredeti képet fogjuk forgatni. Erre azért van szűkség, mert a forgatás során romlik a kép minősége. Így egy forgatás sorozat jelentősen rontana a képminőségen. Ezen kívül a forgatással a kép mérete is változhat. A rotate függvény első paramétere a forgatandó kép, a második pedig a forgatás mértéke fokokban. A rotáció után a forgatás középpontja, a keletkezett kép középpontja kell, hogy legyen. Ezzel elérhetjük, hogy ne lépjen fel elmozdulás.
Végül nézzük meg a punched() metódust. Ennek meghívásával lép a sprite a forgó, szédült állapotba. Az aktuális képről készít egy másolatot az original attribútumba. Ez a kép lesz a forgatás alapja.
Inicializáljunk mindent
Mielőtt bármit is tennénk a pygame-mel, meg kell bizonyosodnunk, hogy minden szükséges modul inicializálva lett. Ha ez teljesült, akkor létrehozhatunk egy egyszerű grafikus ablakot. A következőket a main() függvénybe fogjuk elhelyezni.
pygame.init()
screen = pygame.display.set_mode((468, 60))
pygame.display.set_caption('Monkey Fever')
pygame.mouse.set_visible(0)
Az első sorral inicializáljuk a pygame-et. Ellenőrzi az importált pygame modulokat, és inicializálja azokat. Lehetőségünk van saját kezűleg is inicializálni és ellenőrizni a modulokat, de erre most nem térünk ki.
A következő lépésben a képernyőt állítjuk be. Jegyezzük meg, hogy a képernyő beállításokért a pygame.display modul felelős. Ezen keresztül tudjuk azokat módosítani, stb. Jelen esetben egy üres, 468x60-as felbontású ablakot készítünk. A képernyő módok beállításának témája meghaladná ennek a tutoriálnak a kereteit. A fenti esetben ezt a feladatot a pygame elvégzi helyettünk. Végül beállítjuk az ablak címét, és eltüntetjük az egérkurzort az ablak felett. Ezzel a módszerrel egy fekete ablakhoz jutottunk.
Csináljunk hátteret
A programunk hátterében különböző szöveges üzeneteket szeretnénk megjeleníteni. Jó lenne egy egyszerű felületet készíteni, ami a programunk hátterét reprezentálná, és a továbbiakban ezt használni. Készítsük el ezt a felületet!
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((250, 250, 250))
Ezzel egy új felületet hoztunk létre, melynek mérete egyezik a képernyőével. Itt is szűkség van a convert() hívásra. Az argumentum nélküli convert függvénnyel a képernyő formátumával megegyező lesz a háttér. Ezzel a programunk hatékonyságát növeljük.
Végül fehérre színezzük a hátteret. A fill művelet egy RGB hármast, egy tuple-t vár paraméternek.
Szöveg elhelyezése a háttéren
Tehát rendelkezünk egy felülettel, és ezen szeretnénk szöveget megjeleníteni. Ezt csak akkor tehetjük meg, ha a pygame.font modult megfelelően importáltuk. Ha nem, akkor átugorjuk ezt a részt.
if pygame.font:
font = pygame.font.Font(None, 36)
text = font.render("Pummel The Chimp, And Win $$$", 1, (10, 10, 10))
textpos = text.get_rect(centerx=background.get_width()/2)
background.blit(text, textpos)
Látható, hogy egy egyszerű szöveg megjelenítéséhez is több lépésre van szükség. Először létrehozunk a font objektumot és megjelenítjük azt egy új felületen. Eztán megkeressük ennek a felületnek a középpontját, majd beillesztjük a háttérbe.
Font-ot a font modul Font() konstruktorával hozhatunk létre. Paramétereiben megadhatod egy truetype fontfájl nevét. None-nal jelezhetjük az alapértelmezett betűtípus használatát. A Font konstruktorának még meg kell adni a használni kívánt font méretét.
A render függvény egy új felületet hoz létre, mely megfelelő méretű a megjelenítendő szövegnek. A paraméterekben megadjuk, hogy antialiased, sötét szürke színű szöveget akarunk kirakni.
Eztán megkeressük a szöveg középpontját. Létrehozunk egy - a szöveg dimeziónak megfelelő - Rect objektumot, ami már egyszerűen felrakható a képernyő közepére.
Végül a blit művelettel feltesszük a háttérre.
Háttér megjelenítése
Mutassuk meg a hátteret, amíg a többi erőforrás betöltésére várunk.
screen.blit(background, (0, 0))
pygame.display.flip()
Ezzel a kódrészlettel a teljes hátteret megjelenítettük a képernyőn. A blit kiteszi a screen objektumra, míg a flip a screen objektum tartalmát jeleníti meg fizikailag az ablakban/képernyőn.
A pygame-ben nem közvetlenül a fizikai képernyőre rajzolunk, hanem egy screen objektumra. Ha mindent, amit meg akarunk jeleníteni feltettünk erre, akkor egy pillanat alatt ki tudjuk rajzolni a fizikai képernyőre.
Játékobjektumok elkészítése
Elkészítjük mindazokat az objektumokat, melyek a játék futtatásához szükségesek.
whiff_sound = load_sound('whiff.wav')
punch_sound = load_sound('punch.wav')
chimp = Chimp()
fist = Fist()
allsprites = pygame.sprite.RenderPlain((fist, chimp))
clock = pygame.time.Clock()
Először betöltünk két hang effektust a load_sound függvény segítségével. Eztán létrehozunk egy-egy példányt a sprite osztályainkból. Végül a spritejainkat elhelyezzük egy Group objektumba. Ez egy tároló, amivel egyszerűbbé válik a spriteok kezelése.
Egy speciális sprite Group-ot használunk, nevezetesen egy RenderPlain-t. Ez az összes benne elhelyezett spritot meg tudja jeleníteni. Vannak ennél sokkal összetettebb Render Groupok is. A mi kis játékunkban csak a megjelenítést kell elvégeznie. A Group objektumunkra hivatkozik az allsprites referencia.
A clock objektummal szabályozhatjuk a programunk framerátáját, azaz azt, hogy legfeljebb hány képkockát jelenítsen meg a program másodpercenként. Ezt majd a főciklusban fogjuk használni.
A fő ciklus
A főciklus egy végtelen ciklus lesz.
while 1:
clock.tick(60)
Minden játék egy hasonló ciklusban fut. A clock.tick(60)-nal garantáljuk, hogy a programunk legfeljebb 60 képkocka per másodperces sebességgel fog futni/megjeleníteni.
Események kezelése
Az eseménysor nagyon egyszerű kezelésére mutatunk példát.
for event in pygame.event.get():
if event.type == QUIT:
return
elif event.type == KEYDOWN and event.key == K_ESCAPE:
return
elif event.type == MOUSEBUTTONDOWN:
if fist.punch(chimp):
punch_sound.play() #punch
chimp.punched()
else:
whiff_sound.play() #miss
elif event.type == MOUSEBUTTONUP:
fist.unpunch()
Először elkérjük a pygame-től a rendelkezésre álló eseményeket. Ez szerepel a ciklus fejlécében. Az elágazás első két ágában két egyszerű eseményt kezelünk. Az első: a felhasználó kilépett a programból. A második: lenyomták az esc billentyűt. Ezekben az esetekben kilépünk a programból.
Eztán ellenőrizzük, hogy az egér gombja le lett-e nyomva, vagy fel lett-e engedve. Ha lenyomták a gombot, akkor megkérdezzük a fist objektumot, hogy ütközik-e a chimp objektummal. Eztán lejátsszuk a megfelelő hangeffektet, és ha eltalálta a majmot, akkor hívjuk a chimp punched metódusát. (Erre ő bepörög.)
Spriteok frissítése
allsprites.update()
A sprite csoportoknak van egy update metódusa, melynek hívására az összes tartalmazott sprite update metódusát meghívja. Ennek hatására minden frissül, ahogy azt a játék objektumoknál leírtuk.
Rajzoljunk ki mindent
A következő utasításokkal kirajzolhatjuk az objektumainkat.
screen.blit(background, (0, 0))
allsprites.draw(screen)
pygame.display.flip()
Először kirakjuk a hátteret a screen objektumra. Ezt követően a allsprites csoportnak hívjuk a draw metódusát. Ezzel az összes benne tárolt objektumot kitesszük a screen objektumra. Végül a flip függvénnyel mindent megjelenítünk a fizikai képernyőn.
Nincsenek megjegyzések:
Megjegyzés küldése