In this part we will add some moving blocks to the game which we’ll call opponents, because we can’t touch them.

Also, when going through the code, I realized that I should move some methods to different classes so it makes more sense, and I should also rewrite some methods.

Refactoring

Method PivotGame.got_point() which detected when we hit the score ball wasn’t really that nice and it probably wasn’t correct. I think it is better to mvoe it to PivotBall class. To make that method more general, I’ll pass argument to method which will represent other objects so we can use to detect when the ball is in collision with score ball or with opponent square.

def is_touching(self, other_object):
    dist = sqrt((self.center[0] - other_object.center[0]) ** 2 +
                (self.center[1] - other_object.center[1]) ** 2)
    touch_dist_x = self.size[0] / 2 + other_object.size[0] / 2
    touch_dist_y = self.size[1] / 2 + other_object.size[1] / 2

    if (dist < touch_dist_x or dist < touch_dist_y):
        return True

Another method that should be moved is PivotGame.move_target(). Since we are moving target, it would only make sense to actually move it to target class and call it on the object.

Adding opponents

Opponents will be squares moving in window from left to right. So first I will create new widget in pivot.kv file. But I will not add that widget to <PivotGame>, I want to add them later on during the game.

<PivotOpponent>:

    canvas:
        Color:
            rgb: 0,1,0
        Rectangle:
            pos: self.x, self.y
            size: 50,50

There is another little thing I needed to add to pivot.kv file, and that is color property to all items. That’s because when I add opponents from Python code, they will be on drawn on top of everything else. There is option to specify index with method add_widget(). It seems that higher the number, lower the widget will be. Problem was that all other widgets were using the color from the first widget. So I explicitly specified color for other items in pivot.kv.

After that we can create PivotOpponent class in Python code and add move() method to it. As I mentioned before, we want it to move from left to right. I also want it to randomly change y location once it goes through the window.

Here is the result:

class PivotOpponent(Widget):

    speed = NumericProperty(5)

    def move(self):
        if (self.x - self.size[0] > self.parent.width or
            self.x + self.size[0] < 0):
            self.x -= self.speed
            self.speed *= -1
            self.y = randint(0,self.parent.height)

        self.x += self.speed

So now, I just need to create opponents and call move() method from update(). But where do I create them ? At first I though of doing it in update(), but I don’t want to create them the moment I start the game.

I decided to create another Clock.schedul_interval(), and run it every 5 seconds with method update_opponent() which will add opponents when playing.

def update_opponent(self, dt):
    if self.state == "started":
        pass
    elif self.state == "playing":
        if len(self.opponents) < self.number_of_opponents[self.level]:
            p = (-50,randint(0,self.parent.height))
            temp_op = PivotOpponent(pos=p, size=(50,50))
            self.add_widget(temp_op,9999)
            self.opponents.append(temp_op)
    elif self.state == "killed":
        pass

As you can see I am creating new opponents with random y location and I am also adding them to the list of opponents. I need to do that so I can move them all later on in update(). The addition of opponents is little bit limited. Apart from the fact that opponents are added every 5 seconds, the amount of them is limited. In variable self.level I keep the track of current level. Each time user get 5 points, the level goes up.

Here is code that increases the level:

if self.ball.is_touching(self.target):
    self.target.move()
    self.score += 1
    if self.score % 5 == 0:
        self.level += 1

In the list self.number_of_opponents, I have list of numbers in ascending order. So higher the level, more opponents you should see.

So now we should have green squares moving around, out ball collecting other balls and increasing the score. It all works fine until we hit the wall or opponent and start again. Problem is that all opponents are still there. All opponent objects are still stored in memory and on the screen.

To sort this out, we remove all widgets when player is in killed state and we also empty the opponents list. To remove widgets we use remove_widget().

elif self.state == "killed":
    self.menu.canvas.opacity = 1
    self.ball.canvas.opacity = 0
    self.set_score(self.score)
    self.score_label.canvas.opacity = 1
    self.target.canvas.opacity = 0
    self.target.move()

    # removing all opponents
    for o in self.opponents:
        self.remove_widget(o)
    self.opponents = []

Result

You can find source code for game in PivotGame repository.

Pivot Game at the end of 1st iteration