Als gamedeveloper, wil ik dat mijn speler, kogels en vijanden zichzelf besturen via methodes met parameters en returnwaarden, zodat de engine alleen nog de methodes hoeft aan te roepen.
Een spelengine schrijf je niet zelf. Hij roept methodes aan die jij levert. In deze taak leer je dat contract kennen en schrijf je de methodes voor je vijand.
In een programma zit vaak een deel dat je niet zelf schrijft: een engine, een bibliotheek, een raamwerk. Dat deel kent jouw class niet. Het kent alleen de namen van de methodes die het wil aanroepen. Die afspraak heet een contract.
def run(things, ticks): # dit stuk schrijft iemand anders
for tick in range(ticks):
for thing in things:
thing.update() # het contract: elk ding heeft update()
class Plant:
def __init__(self, height):
self.height = height
def update(self): # jouw deel van het contract
self.height += 1
class Candle:
def __init__(self, length):
self.length = length
def update(self):
self.length -= 1
run([Plant(10), Candle(8)], 3)
run weet niet of een ding een plant of een kaars is. Het roept alleen update() aan.
Elke class beslist zelf wat update() doet.
updat() of Update()?
Dan krijg je een AttributeError. De foutmelding noemt precies de naam die ontbreekt.
Laat een functie run jouw objecten aansturen, en kijk wat er misgaat zonder update().
plant = Plant(10)candle = Candle(8)things = [plant, candle] โ een lijst met beide objecten.run(things, 3) โ de engine draait 3 rondes.plant.height โ wat is er gebeurd?candle.length โ en hier?rock = Rock() โ een ding zonder update().run([rock], 1) โ lees de foutmelding goed.Je maakt een vijand die de minimotor hieronder kan aansturen. De motor krijg je kant-en-klaar; die pas je niet aan.
Enemy met __init__(self, x, y, speed) en de attributen x, y, speed, width = 30, height = 30 en color = (220, 60, 60).update(self). De vijand valt een stap: self.y wordt groter met self.speed.respawn(self, width). De vijand gaat terug naar boven: self.y = -40, en self.x wordt een willekeurig getal tussen 0 en width - self.width (gebruik random.randint).y = 600 met snelheden 3, 4 en 5. Start met run_ticks(enemies, 12, 480) en kijk naar de uitvoer.Kopieer de motor naar je script, boven je eigen code:
import random
def run_ticks(enemies, ticks, width):
for tick in range(1, ticks + 1):
for enemy in enemies:
enemy.update()
if enemy.y > 640: # onder het scherm
enemy.respawn(width)
print("tick", tick, [(e.x, e.y) for e in enemies])
Acceptatiecriteria
Enemy(100, 0, 3).update() zet y op 3.respawn(480) is y < 0 en ligt x tussen 0 en 450.run_ticks draait ongewijzigd met jouw vijanden en print per tick de posities.640 komt, weer bovenaan begint.