Drawing the Cannon Bullet
We want to create a new cannon bullet everytime we press the space bar. Since we can have more than one bullet at a time, we'll use a list to hold all our bullets. Start by creating an empty list...
bullets = 
Next, in update(), check if the space key is pressed and add a bullet if it is.
if keyboard.space: bullet = Actor('bulletblue2') bullet.angle = tank.angle bullet.x = tank.x bullet.y = tank.y bullets.append(bullet)
We set the bullet angle to be the same as the tank so that they'll face the same direction. We also set the x and y of the bullet to be the same as the tank, so that the bullet will start from the tank.
Don't forget to draw the bullets in the draw() function...
for bullet in bullets: bullet.draw()
When you try out the program, you'll see a bullet created each time you press the space bar. But the bullet just stays there and don't do anything, so next, we'll make the bullet fly.
Moving the Bullet
In update, we can move the bullet by changing x or y. To decide which direction to move towards, we can look at the bullet's angle.
|Angle||Direction||x or y|
We should move the bullet in the update() function. Using a for loop.
for bullet in bullets: if bullet.angle == 0: bullet.x = bullet.x + 5 elif bullet.angle == 90: bullet.y = bullet.y - 5 elif bullet.angle == 180: bullet.x = bullet.x - 5 elif bullet.angle == 270: bullet.y = bullet.y + 5
Now our bullet looks more like a laser! That's because when we press the space bar, it creates a LOT of bullets very rapidly. We should add a hold-off. This is some code that stops the tank for shooting for a while after each bullet. We'll start by creating a new variable.
bullet_holdoff = 0
Then modify our shoot code...
if bullet_holdoff == 0: if keyboard.space: bullet = Actor('bulletblue2') bullet.angle = tank.angle bullet.x = tank.x bullet.y = tank.y bullets.append(bullet) bullet_holdoff = 100 else: bullet_holdoff = bullet_holdoff - 1
If you try to run the code now, you'll get an error. Do you know why? Look at the Score section in Gem Catcher and see if you can figure out what's missing! (Answer is at the bottom of this page, but try to figure it out on your own!)
What the above code does is...
if bullet_holdoff == 0: Only allow firing if bullet_holdoff is 0.
bullet_holdoff = 100 Set the bullet_holdoff to 100. This will prevent firing since it is no longer zero. You can try changing this value and see what effects it has.
else: bullet_holdoff = bullet_holdoff - 1
If the bullet_holdoff is not zero, we'll decrease it by one. This will gradually reduce it until it reaches zero again.
Your code should now look like this...
import pgzrun import random WIDTH=800 HEIGHT=600 tank = Actor('tank_blue') tank.y = 575 tank.x = 400 tank.angle = 90 background = Actor('grass') walls =  for x in range(16): for y in range(10): if random.randint(0, 100) < 50: wall = Actor('wall') wall.x = x * 50 + 25 wall.y = y * 50 + 25 + 50 walls.append(wall) bullets =  bullet_holdoff = 0 def update(): global bullet_holdoff # This part is for the tank original_x = tank.x original_y = tank.y if keyboard.left: tank.x = tank.x - 2 tank.angle = 180 elif keyboard.right: tank.x = tank.x + 2 tank.angle = 0 elif keyboard.up: tank.y = tank.y - 2 tank.angle = 90 elif keyboard.down: tank.y = tank.y + 2 tank.angle = 270 if tank.collidelist(walls) != -1: tank.x = original_x tank.y = original_y if tank.x < 0 or tank.x > 800 or tank.y < 0 or tank.y > 600: tank.x = original_x tank.y = original_y # This part is for the bullet if bullet_holdoff == 0: if keyboard.space: bullet = Actor('bulletblue2') bullet.angle = tank.angle bullet.x = tank.x bullet.y = tank.y bullets.append(bullet) bullet_holdoff = 100 else: bullet_holdoff = bullet_holdoff - 1 for bullet in bullets: if bullet.angle == 0: bullet.x = bullet.x + 5 elif bullet.angle == 90: bullet.y = bullet.y - 5 elif bullet.angle == 180: bullet.x = bullet.x - 5 elif bullet.angle == 270: bullet.y = bullet.y + 5 def draw(): screen.fill((0,0,0)) background.draw() tank.draw() for bullet in bullets: bullet.draw() for wall in walls: wall.draw() pgzrun.go() # Must be last line
We need to add
The bullet_holdoff variable is declared outside of the update() function, but we are trying to write it from inside the update() function. In Python, we can read variables that are outside a function (...these are called global variables), but cannot write to them unless we declare them as global inside the function.