Some time passed and second part is here 🙂 This time we will arm our enemy. Lets give him bombs and ability to drop them !
Bomb will drop vertically. One bomb or more ? We will control this with variable, we will also implement drop rate.
Download source code
First create a starting bomb class:
import item class Bomb(item.Item): """Bomb""" def __init__(self, x, y): """init bomb""" self.pos_x = x self.pos_y = y self.sprite = "@" def tick(self): """action in tick""" self.pos_y += 1 def get_position(self): """enemy position""" return self.pos_x, self.pos_y def get_sprite(self): """get sprite""" return self.sprite
Next lets change enemy class.
We need few extra parameters in it, for keeping current number of bombs and max no of bombs. We will also keep percentage chance of dropping bomb.
Modify __init__ , add self.bombs_current = 0, self.bombs_max = 1 and self.bomb_chance = 20.
Next we need to add drop action. But first enemy needs to have ability to add new object to objects dict. But this dict is available only in main loop, so need to pass it. Modify constructor by adding another parameter objects to __init__.
def __init__(self, x, y, max_x, objects): """init enemy""" self.pos_x = x self.pos_y = y self.max_x = max_x self.sprite = "<*>" self.bombs_current = 0 self.bombs_max = 1 self.objects = objects self.bomb_chance = 200
and new call (in Game class):
self.objects.append(enemy.Enemy(2, 0, self.width, self.objects))
Change enemy AI by adding drop chance in function tick.
if self.bombs_max > self.bombs_current and random.randint(1, 100) < self.bomb_chance: self.bombs_current += 1 self.objects.append(bomb.Bomb(self.pos_x + 1, self.pos_y))
Run game now. Our DMO will drop bomb, it will reach bottom of screen and script will crash.
Second screen and bomb discard
Problem is in draw function in main Piader class. We are using only one screen, time to fix this. Case is simple, if y is in <0, 3> draw on first screen. If <4, 5> draw on second. But there is one catch, top screen is wider than bottom one. So if x in <0, 1> or <17, 19> discard object. And of course when y > 5 discard it too.
Our new draw function will look like this:
def draw(self, item): """draw sprite on screen""" lcd_no = 0 (x, y) = item.get_position() if y > 5: self.objects.remove(item) return if y > 3: x -= 2 if x < 0 or x > 15: self.objects.remove(item) return lcd_no = 1 y -= 4 lcd = self.lcds[lcd_no] lcd.write(item.get_sprite(), x, y) lcd.flush()
We also need to add buffer_clear() and flush() in game tick function.
There is one more catch. Bomb is connected with DMO, so when bombs is discarder, DMO must know about it. We will do it by passing caller reference to bomb class. We need to add some event handler, open Item class and add new abstract function:
def event_discard(self): """called when onject is discarded""" raise NotImplementedError("event_discard not implemented")
Now implement it in Bomb class:
def event_discard(self): """discard bomb, decrease DMO bomb counter""" self.dmo.bombs_current -= 1
Finally go back to draw function in Game class and change:
Now when you run script it should work. Enemy will drop one bomb. Only after bomb is discarded another will be dropped.
Stop! Jenkins time !
We have some stable source of another part of our game. Its good idea to run Jenkins test.
This time thing that I messed up were:
– variable names – x and y, too short
– too many attributes in enemy class – unfixed, not important problem for now
In part 2 we have:
– add bomb
– add second screen
– fixed drawing
– add discard event to abstract Item class
– implement bomb discard event
– DMO now can drop a bomb
Download source code.