7.1 OBJECTS EVERYWHERE

 

 

INTRODUCTION

 

In daily life, you are surrounded by a multitude of different objects. Since software often builds of models of reality, it is straightforward to also introduce objects in computer science. This is called object-oriented programming (OOP). For more than decades, the concept of OOP has proved to be groundbreaking in computer science to the extent that it is applied in virtually all developed software systems today [more...A distinction is made between programming languages such as Java, with which one can only object-oriented programming
and those that can also be used object-free (hybrid languages). These include Python and C ++
]. In the following chapter you will learn the main concepts of OOP so that you can participate in the hype.

You have already gotten to know the turtle as an object. A turtle has properties (it has a certain color, is located at a certain position, and has a specific viewing direction) and skills (it can move forward, rotate, etc.). In OOP, objects with similar properties and skills are grouped in classes. The turtle objects belong to the Turtle class, we also say that they are instances of the Turtle class. In order to create an object, you must first define a class or use a predefined class such as with the turtles.

When programming, the properties are also called attributes or instance variables, and the skills are also called operations or methods. These are variables and functions, except for the fact that they belong to a certain class and are thus "encapsulated" in this class. In order to use them outside of the class, you have to prefix a class instance and the dot operator.

PROGRAMMING CONCEPTS:
Class, object (instance), property, ability,
attribute/instance variable, method, inheritance, base/super class, constructor

 

 

AN ADAPTIVE GAME WINDOW

 

It is not possible to create a computer game with reasonable effort without OOP, since the game performers and other objects of the game board are obviously objects. The game board is a rectangular screen window and it is modeled by the class GameGrid from the game library JGameGrid. TigerJython provides you with an instance when calling makeGameGrid() and displays the window with show(). Here you can customize the look of the game window with parameter values. With makeGameGrid(10, 10, 60, Color.red, "sprites/town.jpg", False)

a square game window is displayed, the size of which is 10 horizontal by 10 vertical cells of the size 60 pixels. You will see red grid lines and a background image town.jpg. (The last parameter causes the navigation bar to be disabled, which is not needed in this case.)

 

from gamegrid import *

makeGameGrid(10, 10, 60, Color.red, "sprites/town.jpg", False)
show()
Highlight program code (Ctrl+C to copy, Ctrl+V to paste)

 

 

MEMO

 

The methods of the class GameGrid are available to you as functions using makeGameGrid(). However, you can also generate an instance yourself and call the methods using the dot operator.

from gamegrid import *

gg = GameGrid(10, 10, 60, Color.red, "sprites/town.jpg", False)
gg.show()

The game window is constructed of square cells, and as specified above, each cell is 60 pixels in size with 10 horizontal and 10 vertical cells. This means that when the right and bottom gridline is displayed, the window has a size of 601 x 601 pixels. This corresponds to the (minimum) size of the background image.

The last Boolean parameter determines whether a navigation bar appears.

 

 

DEFINING A CLASS WITH DERIVATION

 

When defining a class, you can decide whether your new class is fully independent, or derived from a previously existing class. All the properties and skills of the parent class (also called base class or superclass) are available to you in the derived class. Simply said, the derived class (or subclass) inherits properties and skills.

In the game library JGameGrid, game characters are called actors and are instances of the predefined class actor. If you need your own performer, define a class that is derived from an actor.

Your class definition should begin with the keyword class. This is followed by any selected class name and a pair of parentheses. In the parentheses, you write down the name of one or several classes from which you derived your class. Since you want to derive your character from Actor, you provide that class name.

The class definition contains the definition of the methods that are defined like regular functions, with the difference that they mandatorily must have the parameter self as the first parameter. With this parameter you can access other methods and instance variables of your class and its base class.

The list of method definitions usually begins with the definition of a special method named  __init__ (with two leading and trailing underlines). This is called a constructor (in Python also named initializer) and it is automatically called when an object of the class is created. In our case, you call the constructor of the base class Actor in the constructor of Alien, to which you deliver the path to the sprite image.

Next, you define the method act() which plays a central role in game animation, as it is called automatically by the game manager in each simulation cycle. This is a particularly smart trick so that you do not have to worry about animation in a looping structure.

You can define what the game character should do in each simulation cycle with act(). As a demonstration, you only move it to the next cell with move() in this example. Since move() is a method of the base class Actor, you have to call it with prefixed self.

Once you have defined your class Alien, you create an alien object by calling the class name and assigning a variable to it. Typical of OOP, you can create as many aliens as you would like. As in everyday life, they each have their own individuality, therefore they "know" how they should move from their act() method.

To add the created aliens to the game board you use addActor(), where you have to specify the cell coordinates with Location() (the cell with the coordinates (0,0) is at the top left, x increases to the right, y increases going down). To finally start the simulation cycle, call doRun().
 



from gamegrid import *

# ---------------- class Alien ----------------
class Alien(Actor):
    def __init__(self):
        Actor.__init__(self, "sprites/alien.png")
    
    def act(self):
        self.move()

makeGameGrid(10, 10, 60, Color.red, "sprites/town.jpg", False)
spin = Alien() # object creation, many instances can be created
urix = Alien()
addActor(spin, Location(2, 0), 90)
addActor(urix, Location(5, 0), 90)
show()
doRun()
Highlight program code (Ctrl+C to copy, Ctrl+V to paste)

 

 

MEMO

 

A class definition begins with the keyword class and encapsulates the methods and instance variables of the class. The constructor with the name __init__ is called automatically when an object is created. To create an object (an instance), write the corresponding class name and pass it the parameter values that __init__ asks for.

All game characters are derived from the class Actor. You define what the game character should do in each simulation cycle in the method act().

With addActor() you can add a game character to the game board. You must indicate its starting position (Location) and its starting direction (in degrees) (0 goes east, positive is clockwise).

 

 

ATTACK OF THE ALIENS

 

You notice the strengths and benefits of the object-oriented programming paradigm when you see how easily you are able to populate the game board with many aliens falling from the sky by using just a few lines of code.

Using a repeating loop in the main part, design an alien figure so that every 0.2 seconds a new alien is placed at a random location somewhere in the top grid line.
 
from gamegrid import *
from random import randint

# ---------------- class Alien ----------------
class Alien(Actor):
    def __init__(self):
        Actor.__init__(self, "sprites/alien.png")
    
    def act(self):
        self.move()

makeGameGrid(10, 10, 60, Color.red, "sprites/town.jpg", False)
show()
doRun()

while not isDisposed():
    alien = Alien()
    addActor(alien, Location(randint(0, 9), 0), 90)
    delay(200)
Highlight program code (Ctrl+C to copy, Ctrl+V to paste)

 

 

MEMO

 

An endless loop in the main part of the program should test using isDisposed() whether the game window was closed, so that the program is able to end correctly.

Note: Sometimes it is necessary to close TigerJython and reopen it, so that sprites and background images with the same name but changed content are reloaded.

 

 

SPACE INVADERS LIGHT

 

In your first self-written computer game, the player should try to fight off an alien invasion by removing the invading aliens with a mouse click. Each alien landed in the city subtracts one point.

To get mouse support in the program, you have to add a mouse callback with the name pressCallback and register it as the named parameter mousePressed. In the callback, you first fetch the cell position of the mouse click from the event parameter e. If there is an Actor located in that cell you will get it with getOneActorAt(). If the cell is empty, None will be returned. removeActor() removes the actor from the game board.

from gamegrid import *
from random import randint

# ---------------- class Alien ----------------
class Alien(Actor):
    def __init__(self):
        Actor.__init__(self, "sprites/alien.png")
    
    def act(self):
        self.move()

def pressCallback(e):
    location = toLocationInGrid(e.getX(), e.getY())
    actor = getOneActorAt(location)
    if actor != None:
        removeActor(actor)
    refresh()

makeGameGrid(10, 10, 60, Color.red, "sprites/town.jpg", False, 
             mousePressed = pressCallback)
setSimulationPeriod(800)
show()
doRun()

while not isDisposed():
    alien = Alien()
    addActor(alien, Location(randint(0, 9), 0), 90)
    delay(1000)
Highlight program code (Ctrl+C to copy, Ctrl+V to paste)

 

 

MEMO

 

Since act() is called once in every simulation cycle, the period is responsible for the execution speed of the game. The default value of the simulation period is 200 ms. It can be set to a different value using setSimulationPeriod().

The game board is rebuilt in each simulation cycle (rendered), and therefore a change in the game situation is only visible at this moment. If you want to immediately display the new situation at a mouse click, you can manually execute the rendering with refresh().

 

 

EXERCISES

 

1.


Create your own background image with an image editor. Add it to the directory sprites, in the same directory where your program is located (or in <userhome>/gamegrid/sprites) or specify the fully qualified file path.

2.

Add a 30 pixel high status bar with addStatusBar(30) and write the number of aliens that were able to land in the city (despite the defense system) into it using setStatusText().


3.

The landed aliens should not simply disappear, rather they should be transformed into a different form at the landing spot ("sprites/alien_1.png" or your own image) and remain there.

(Hint: with removeSelf() you can remove an old alien and with addActor() you can generate a new actor in the same place.)

4*.

The landed aliens report back to the attacking alien where they have landed so that new aliens can jump into the “open” columns. Once all the columns are occupied, the game ends and displays "Game Over" ("sprites/gameover.gif").

(Hint: the game manager can be stopped using doPause())
 
5*. Expand the game with some of your own ideas