[Python Gaming Programming Studies] 7. Basis of Cocos2D. Input.

Alegruz
2017-10-03
조회수 1070

Before we create some games using Cocos2D, let's create some basis for a 2d platform game. You know, stereotypical 2d kinds of stuff. Remember, we are making games back in the 70's.

Basic things we need is rendering, which is about Sprites, input, and physics. It's a bit weird compared to the first series because collision wasn't the first thing we have discussed. Put that in mind that Cocos2D is all about making games.


Let's talk about inputs first. When we were studying tkinter, we used bind method to bind a key to an event. This time, we don't need to bind anything. All we have to check is whether a key is being pressed or released. This kind of input handling is called event handling. In order to activate event handling, we have to tell the layer that the events are being handled through is_event_handler = True.


import cocos


class MainLayer(cocos.layer.Layer):
    is_event_handler = True


This time, instead of labeling, we will load some graphical data. We have drawn shapes through methods in tkinter. This time, no more drawing, but loading. Download the 'ball.png' and put them in the exact folder where you've saved your python file.


Now, we will assign this image to the sprite object.


def __init__(self):
    super(MainLayer, self).__init__()
    self.player = cocos.sprite.Sprite('ball.png')
    self.player.color = (0, 0, 255)
    self.player.position = (320, 240)
    self.add(self.player)


Then we will assign two methods called on_key_press and on_key_release. These two methods are ready-made. The first parameter is a key parameter. The second parameter is a modifier. We are not going to discuss what is a modifier. Let's check if the method works well or not by printing the key being pressed.


def on_key_press(self, k, m):
    print('Pressed', k)

def on_key_release(self, k, m):
    print('Released', k)


Let's run the program and check whether the key input is going alright.


import cocos

class MainLayer(cocos.layer.Layer):

    is_event_handler = True

    def __init__(self):
        super(MainLayer, self).__init__()
        self.player = cocos.sprite.Sprite('ball.png')
        self.player.color = (0, 0, 255)
        self.player.position = (320, 240)
        self.add(self.player)

    def on_key_press(self, k, m):
        print('Pressed', k)

    def on_key_release(self, k, m):
        print('Released', k)

if __name__ == '__main__':
    cocos.director.director.init(caption = 'Hello, World!')
    layer = MainLayer()
    scene = cocos.scene.Scene(layer)
    cocos.director.director.run(scene)


You can see that some numbers are indicated on the shell. These codes are pyglet key constants. You can check them out at this link. 

http://pythonhosted.org/pyglet/api/pyglet.window.key-module.html


Now, we want to visually see which key is being pressed. So we will import key from the pyglet.window module.


from pyglet.window import key


We want to convert the constants, the symbols into the string format. We are going to use key.symbol_string method.


def on_key_press(self, k, m):
    print('Pressed', key.symbol_string(k))

def on_key_release(self, k, m):
    print('Released', key.symbol_string(k))


Now we will make the ball move through these methods. The logic is as follows.

  1. for right side is x positive and left is x negative, x = right - left.
  2. Make a new variable new_x and new_y in new update method in order to update the x and y coordinate of the specific object.
  3. Set the velocity of the object.
  4. new_x = x + v * key_input_check * dt (dt is the differential of time. The basic dt of cocos2d is 60 fps)
  5. if on_key_press is activated, key_input_check is True, which means that the value of the variable is 1
  6. if on_key_release is activated, key_input_check is False, which means that the value of the variable is 0


Let's code these.


class MainLayer(cocos.layer.Layer):

    is_event_handler = True

    def __init__(self):
        super(MainLayer, self).__init__()
        self.player = cocos.sprite.Sprite('ball.png')
        self.player.color = (0, 0, 255)
        self.player.position = (320, 240)
        self.add(self.player)
        self.speed = 100.0
        self.pressed = {}
        self.schedule(self.update)

    def on_key_press(self, k, m):
        self.pressed[k] = 1

    def on_key_release(self, k, m):
        self.pressed[k] = 0

    def update(self, dt):
        x = self.pressed[key.RIGHT] - self.pressed[key.LEFT]
        y = self.pressed[key.UP] - self.pressed[key.DOWN]
        if x != 0 or y != 0:
            pos = self.player.position
            new_x = pos[0] + self.speed * x * dt
            new_y = pos[1] + self.speed * y * dt
            self.player.position = (new_x, new_y)


But there's one problem. We don't press right or left at the same time the program starts. Which means that in the update method, the x and y variables are asking for a value of a key that doesn't exist. In order to solve this, we are going to use a special dictionary from an external method called collections. From this module, we will import defaultdict. This dictionary stores default 0 value for the absent keys.

 

from collections import defaultdict

class MainLayer(cocos.layer.Layer):

    is_event_handler = True

    def __init__(self):
        super(MainLayer, self).__init__()
        self.player = cocos.sprite.Sprite('ball.png')
        self.player.color = (0, 0, 255)
        self.player.position = (320, 240)
        self.add(self.player)
        self.speed = 100.0
        self.pressed = defaultdict(int)
        self.schedule(self.update)

    def on_key_press(self, k, m):
        self.pressed[k] = 1

    def on_key_release(self, k, m):
        self.pressed[k] = 0

    def update(self, dt):
        x = self.pressed[key.RIGHT] - self.pressed[key.LEFT]
        y = self.pressed[key.UP] - self.pressed[key.DOWN]
        if x != 0 or y != 0:
            pos = self.player.position
            new_x = pos[0] + self.speed * x * dt
            new_y = pos[1] + self.speed * y * dt
            self.player.position = (new_x, new_y)


When you run the final output, you will be surprised that the key input, the movement of the ball is smoother than the one of tkinter's.

In next episode, we will discuss the collision, the basic physics of the game.


import cocos
from collections import defaultdict
from pyglet.window import key

class MainLayer(cocos.layer.Layer):

    is_event_handler = True

    def __init__(self):
        super(MainLayer, self).__init__()
        self.player = cocos.sprite.Sprite('ball.png')
        self.player.color = (0, 0, 255)
        self.player.position = (320, 240)
        self.add(self.player)
        self.speed = 100.0
        self.pressed = defaultdict(int)
        self.schedule(self.update)

    def on_key_press(self, k, m):
        self.pressed[k] = 1

    def on_key_release(self, k, m):
        self.pressed[k] = 0

    def update(self, dt):
        x = self.pressed[key.RIGHT] - self.pressed[key.LEFT]
        y = self.pressed[key.UP] - self.pressed[key.DOWN]
        if x != 0 or y != 0:
            pos = self.player.position
            new_x = pos[0] + self.speed * x * dt
            new_y = pos[1] + self.speed * y * dt
            self.player.position = (new_x, new_y)

if __name__ == '__main__':
    cocos.director.director.init(caption='Hello, World!')
    layer = MainLayer()
    scene = cocos.scene.Scene(layer)
    cocos.director.director.run(scene)

0 0