Add Asteroid Object

In the game the Zork will hurl asteroids back at the player’s ship, which the player will the need to dodge. To create an asteroid RoomObject we will need to go through many of the steps we also used for the Ship and Zork.

Create Asteroid Object

First we need to create the Asteroid RoomObject. The code for this should be very familiar by now.

Objects/Asteroid.py

Create a new file in the Objects folder called Asteroid.py, then add the code below to it.

 1from GameFrame import RoomObject
 2
 3class Asteroid(RoomObject):
 4    """
 5    A class for Zorks danerous obstacles
 6    """
 7    
 8    def __init__(self, room, x, y):
 9        """
10        Initialise the Asteroid object
11        """
12        # include attributes and methods from RoomObject
13        RoomObject.__init__(self, room, x, y)
14
15        # set image
16        image = self.load_image("asteroid.png")
17        self.set_image(image,50,49)

We won’t unpack this since it is the same as the Ship and Zork Objects. Save the file.

Objects/__init__.py

Open the Objects/__init__.py file and add the highlighted code:

1from Objects.Title import Title
2from Objects.Ship import Ship
3from Objects.Zork import Zork
4from Objects.Asteroid import Asteroid

Save and close Objects/__init__.py.

Testing

Run the code using MainController.py. There should be no changes, but this just checks that we haven’t made a mistake.

Spawn Asteroid Object

Now we have an Asteroid Object we need to:

  1. make it spawn

  2. make it move in a random direction across the screen when it spawns

  3. bounce the asteroid off the top and bottom of the screen

  4. de-spawn the asteroid once if exits the left of screen

Let’s do that in order.

Spawn asteroids

Planning

We should do some planning for the spawning process. Some considerations:

  • we want the asteroids to spawn at Zork’s location.

  • we want the asteroids to spawn at random intervals - regular intervals are too predictable and therefore less fun.

Spawning at Zork’s location is fairly simple, since we know it’s location is Zork.x and Zork.y.

Spawning at a random time is a bit trickier. If we looks that the Room/Levels Methods docs we can see a method called set_timer. It starts a timer that will call a function when it’s countdown reaches 0. This would be a good thing to use.

So we now have the mechanisms, but where do we put them? Since Zork will be spawning the asteroids the method for spawning the asteroids should go in the Zork class.

Lets put this all together in a IPO table.

asteroid spawn IPO

You can see that there are two separate step to this process.

  1. When Zork is instantiated, we need to set a timer to a random value.

  2. When the time reaches 0 it will call a function that will spawn the asteroid and then set the timer again.

Let’s put that into code.

Coding

Objects/Zork.py

Open Objects/Zork.py and the ASteroid import to the top.

1from GameFrame import RoomObject, Globals
2from Objects.Asteroid import Asteroid
3import random

We now need to add the code that will start the spawn timer. Since this needs to happen when Zork is instantiated, it has to go into the __init__ method. So add the highlighted code below to your __init__.

 1from GameFrame import RoomObject, Globals
 2from Objects.Asteroid import Asteroid
 3import random
 4
 5class Zork(RoomObject):
 6    """
 7    A class for the game's antagoist
 8    """
 9    def __init__(self, room, x, y):
10        """
11        Initialise the Boss object
12        """
13        # include attributes and methods from RoomObject
14        RoomObject.__init__(self, room, x, y)
15        
16        # set image
17        image = self.load_image("Zork.png")
18        self.set_image(image,135,165)
19        
20        # set inital movement
21        self.y_speed = random.choice([-10,10])
22        
23        # start asteroid timer
24        asteroid_spawn_time = random.randint(15,150)
25        self.set_timer(asteroid_spawn_time, self.spawn_asteroid)

Let’s break that code down:

  • line 25 - creates a random timer number between 15 ticks and 150 ticks.

  • line 26 - sets timer and declares self.spawn_asteroid as the method to call when the timer is 0.

Calling methods from method

When we pass a method as an argument (like in the timer), the argument method just uses it’s name. The () after the name is dropped.

If you include the () after the method name, it will be automatically called rather then waiting for the trigger.

We currently have the timer calling the self.spawn_asteroid method, which does not exist, so we need to create that. Go to the bottom of the Zork.py file and add the code below:

40    def spawn_asteroid(self):
41        """
42        Randomly spawns a new Asteroid
43        """
44        # spawn Asteroid and add to room
45        new_asteroid = Asteroid(self.room, self.x, self.y + self.height/2)
46        self.room.add_room_object(new_asteroid)
47        
48        # reset time for next Asteroid spawn
49        asteroid_spawn_time = random.randint(15, 150)
50        self.set_timer(asteroid_spawn_time, self.spawn_asteroid)

Save Zork.py and then run the program using MainController.py

Zork should move up and down, spawning asteroids, much like below:

Zork spawning asteroids

Obviously the next thing we need to do is make the asteroids move. We’ll do that in the next lesson.

Commit and Push

We have finished and tested another section of code so we should make a Git commit.

To do this:

  1. In GitHub Desktop go to the bottom left-hand box and write into the summary Added asteroids.

  2. Click on Commit to main

  3. Click on Push origin

Now the work from this lesson is committed and synced with the online repo.

Completed File States

Below are all the files we used in this lesson in their finished state. Use this to check if your code is correct.

Objects/Asteroid.py

 1from GameFrame import RoomObject
 2
 3class Asteroid(RoomObject):
 4    """
 5    A class for Zorks danerous obstacles
 6    """
 7    
 8    def __init__(self, room, x, y):
 9        """
10        Initialise the Asteroid object
11        """
12        # include attributes and methods from RoomObject
13        RoomObject.__init__(self,room, x, y)
14        
15        # set image
16        image = self.load_image("asteroid.png")
17        self.set_image(image,50,49)

Objects/__init__.py

1from Objects.Title import Title
2from Objects.Ship import Ship
3from Objects.Zork import Zork
4from Objects.Asteroid import Asteroid

Objects/Zork.py

 1from GameFrame import RoomObject, Globals
 2from Objects.Asteroid import Asteroid
 3import random
 4
 5class Zork(RoomObject):
 6    """
 7    A class for the game's antagoist
 8    """
 9    def __init__(self, room, x, y):
10        """
11        Initialise the Boss object
12        """
13        # include attributes and methods from RoomObject
14        RoomObject.__init__(self, room, x, y)
15        
16        # set image
17        image = self.load_image("Zork.png")
18        self.set_image(image,135,165)
19        
20        # set inital movement
21        self.y_speed = random.choice([-10,10])
22        
23        # start asteroid timer
24        asteroid_spawn_time = random.randint(15,150)
25        self.set_timer(asteroid_spawn_time, self.spawn_asteroid)
26        
27    def keep_in_room(self):
28        """
29        Keeps the Zork inside the top and bottom room limits
30        """
31        if self.y < 0 or self.y > Globals.SCREEN_HEIGHT - self.height:
32            self.y_speed *= -1
33            
34    def step(self):
35        """
36        Determine what happens to the Dragon on each tick of the game clock
37        """
38        self.keep_in_room()
39        
40    def spawn_asteroid(self):
41        """
42        Randomly spawns a new Asteroid
43        """
44        # spawn Asteroid and add to room
45        new_asteroid = Asteroid(self.room, self.x, self.y + self.height/2)
46        self.room.add_room_object(new_asteroid)
47        
48        # reset time for next Asteroid spawn
49        asteroid_spawn_time = random.randint(15, 150)
50        self.set_timer(asteroid_spawn_time, self.spawn_asteroid)