- apply learnt knowledge to create a new object
- apply learnt knowledge to plan code using an IPO table
- learn how to initiate movement when objects are created
- learn how to negate numbers (use `* -1` to swap between positve and negative numbers)
Our boss for this game is called Zork, who is an evil alien. Most of the creation of Zork follows the same processes as creating the ship so we will race through those steps, then we will plan and implement the differences.
In the Objects
directory make a new file and call it Zork.py
. Then add the following code which creates the Zork class and adds its image:
:linenos:
from GameFrame import RoomObject
class Zork(RoomObject):
"""
A class for the game's antagoist
"""
def __init__(self, room, x, y):
"""
Initialise the Boss object
"""
# include attributes and methods from RoomObject
RoomObject.__init__(self, room, x, y)
# set image
image = self.load_image("Zork.png")
self.set_image(image,135,165)
Save the Zork.py
file.
In the Objects
directory open the __init__.py
file. Then add the following highlighted code:
:linenos:
:emphasize-lines: 3
from Objects.Title import Title
from Objects.Ship import Ship
from Objects.Zork import Zork
Save and close the __init__.py
file.
In the Rooms
folder, open the GamePlay.py
file. Then add the highlighted code below:
:linenos:
:emphasize-lines: 3, 14
from GameFrame import Level
from Objects.Ship import Ship
from Objects.Zork import Zork
class GamePlay(Level):
def __init__(self, screen, joysticks):
Level.__init__(self, screen, joysticks)
# set background image
self.set_background_image("Background.png")
# add objects
self.add_room_object(Ship(self, 25, 50))
self.add_room_object(Zork(self,1120, 50))
Save and close the GamePlay.py
file, then use the MainController.py
to run and test the code.
If everything tests ok, you should now have our boss on the screen. Now it is time to think about it's unique features.
Since Zork is run by the computer we will have to animate it's movement. Just like our spaceship, Zork will only move up and down. Unlike our spaceship, this will not be in response to a keystroke.
There are two aspects of Zork's movement we need to automate:
- starting Zork moving when the game begins
- changing the direction of Zork's direction when it reaches the top or bottom of the screen
Let's use an IPO table to plan out the initial Zork movement.
- Output → we want Zork to move either up or down
- Input → we want this to start when Zork is created
- Process → we can randomly set Zork's
y_speed
to either-10
(up) or10
(down)
So our IPO table would look as such:
:class: note
Remember classes are like blueprints that we use to create object instances. The term **object** refers to all the objects created from the same class (ie. Zork object), while the term instance refers to each individual object.
When we create an **instance** of an **object** from a **class**, this is called **instantiation**.
When Zork hits the top or bottom of the screen, we don't want it to stop, but rather to change direction (ie. y_speed
from -10
to 10
or vice versa).
Let's think about this in IPO terms:
- Output → Zork moves in the opposite direction
- Input → Zork touches top or bottom of the screen
- Process → negate the value of Zork's
y_speed
(ie.-10
becomes10
or10
becomes-10
)
So our IPO table would be something like this:
Now we have conceptualised how we will make these happen, let's get to the coding.
Return the the Objects/Zork.py
file to add the code for the initial movement. According to our IPO plan the event that triggers the movement is the instantiation of the Zork object. We know that when instantiate an object the __init__
method gets called, so that would be the logical place to put it.
We also know that we can use random.choice
to choose a random item from a list. So if we have a list consisting of -10
and 10
, random.choice
can choose one. So let's make these changes to the the Zork
class by adding the highlighted code below:
:linenos:
:emphasize-lines: 2, 19-20
from GameFrame import RoomObject
import random
class Zork(RoomObject):
"""
A class for the game's antagoist
"""
def __init__(self, room, x, y):
"""
Initialise the Boss object
"""
# include attributes and methods from RoomObject
RoomObject.__init__(self, room, x, y)
# set image
image = self.load_image("Zork.png")
self.set_image(image,135,165)
# set inital movement
self.y_speed = random.choice([-10,10])
Unpacking this:
- line 2 → importing random so we can use choice
- line 20 → randomly choose between
-10
and10
and set that as Zork'sy_speed
Now save Zork.py
and run MainController.py
to test our code. Zork should either move up or down until it is off the screen.
To reverse Zork's direction we will use a similar process that we used to stop the ship from moving off screen. This will involve using step()
to test if Zork is off screen. The only difference will be in the keep_in_room
method where we will just reverse Zork's y_speed
.
Go back to Objects/Zork.py
and add the highlighted code below:
:linenos:
:emphasize-lines: 1, 22-
from GameFrame import RoomObject, Globals
import random
class Zork(RoomObject):
"""
A class for the game's antagoist
"""
def __init__(self, room, x, y):
"""
Initialise the Boss object
"""
# include attributes and methods from RoomObject
RoomObject.__init__(self, room, x, y)
# set image
image = self.load_image("Zork.png")
self.set_image(image,135,165)
# set inital movement
self.y_speed = random.choice([-10,10])
def keep_in_room(self):
"""
Keeps the Zork inside the top and bottom room limits
"""
if self.y < 0 or self.y > Globals.SCREEN_HEIGHT - self.height:
self.y_speed *= -1
def step(self):
"""
Determine what happens to the Dragon on each tick of the game clock
"""
self.keep_in_room()
We really only need to look at two lines here:
- line 26 → checks if Zork has touched either the top or the bottom of the screen
- line 27
- negate a number (change its sign) → multiply it by
-1
*=
is similar to+=
, it means take the value stored iny_speed
multiply it by-1
, then store it back iny_speed
- negate a number (change its sign) → multiply it by
Save Zork.py
then run MainController.py
to test that our code works.
We have finished and tested another section of code so we should make a Git commit.
To do this:
- In GitHub Desktop go to the bottom left-hand box and write into the summary Added Zork.
- Click on Commit to main
- Click on Push origin
Now the work from this lesson is committed and synced with the online repo.
Below are all the files we used in this lesson in their finished state. Use this to check if your code is correct.
:linenos:
from GameFrame import RoomObject, Globals
import random
class Zork(RoomObject):
"""
A class for the game's antagoist
"""
def __init__(self, room, x, y):
"""
Initialise the Boss object
"""
# include attributes and methods from RoomObject
RoomObject.__init__(self, room, x, y)
# set image
image = self.load_image("Zork.png")
self.set_image(image,135,165)
# set inital movement
self.y_speed = random.choice([-10,10])
def keep_in_room(self):
"""
Keeps the Zork inside the top and bottom room limits
"""
if self.y < 0 or self.y > Globals.SCREEN_HEIGHT - self.height:
self.y_speed *= -1
def step(self):
"""
Determine what happens to the Dragon on each tick of the game clock
"""
self.keep_in_room()
:linenos:
from Objects.Title import Title
from Objects.Ship import Ship
from Objects.Zork import Zork
:linenos:
from GameFrame import Level
from Objects.Ship import Ship
from Objects.Zork import Zork
class GamePlay(Level):
def __init__(self, screen, joysticks):
Level.__init__(self, screen, joysticks)
# set background image
self.set_background_image("Background.png")
# add objects
self.add_room_object(Ship(self, 25, 50))
self.add_room_object(Zork(self,1120, 50))