25. Anchoring
import cocos
from cocos.director import director
director.init()
scene = cocos.scene.Scene()
sprite = cocos.sprite.Sprite('kitten.jpg', anchor=(0,0))
scene.add(sprite)
director.run(scene)
26. Using a Layer
import cocos
from cocos.director import director
director.init()
scene = cocos.scene.Scene()
layer = cocos.layer.Layer()
scene.add(layer)
sprite = cocos.sprite.Sprite('kitten.jpg', anchor=(0,0))
layer.add(sprite)
director.run(scene)
27. Animation
import cocos
from cocos import actions
from cocos.director import director
...
scene = cocos.scene.Scene()
layer = cocos.layer.Layer()
scene.add(layer)
sprite = cocos.sprite.Sprite('kitten.jpg', anchor=(0,0))
layer.add(sprite)
sprite.do(actions.MoveBy((100, 0)))
director.run(scene)
28. Getting Organised
import cocos
from cocos import actions
from cocos.director import director
class AsteroidsGame(cocos.scene.Scene):
def __init__(self):
super(AsteroidsGame, self).__init__()
self.player = cocos.layer.Layer()
self.add(self.player)
self.ship = cocos.sprite.Sprite('data/ship.png', (width/2, height/2))
velocity = (100, 0)
self.ship.do(actions.MoveBy(velocity))
self.player.add(self.ship)
director.init()
width, height = director.get_window_size()
director.run(AsteroidsGame())
29. Adding Asteroids
import random
import cocos
from cocos import actions
from cocos.director import director
def create_asteroid(layer, size, position, speed):
'''Create an asteroid of a certain size and speed.
'''
s = cocos.sprite.Sprite('data/%s_asteroid.png' % size, position)
s.size = size
layer.add(s)
velocity = (random.randint(-speed, speed), random.randint(-speed, speed))
dr = random.randint(-speed, speed)
s.do(actions.Repeat(actions.MoveBy(velocity, 1) | actions.RotateBy(dr, 1)))
...
30. Adding Asteroids
...
super(AsteroidsGame, self).__init__()
# place the asteroids in a layer by themselves
self.asteroids = cocos.layer.Layer()
self.add(self.asteroids)
for i in range(3):
# place asteroids at random positions around the screen
position = (random.randint(0, width), random.randint(0, height))
create_asteroid(self.asteroids, 'big', position, 100)
# place the player ship in another layer
...
36. Gameplay Mechanics
• Player Controls
• Timed rules (when objects appear; moving
the play field)
• Interaction of game objects
37. Gameplay Mechanics
• Player Controls
• Timed rules (when objects appear; moving
the play field)
• Interaction of game objects
• Detecting important events (game won or
game over)
42. Control
y = speed x sin(rotation)
ng)
ho oti
rs
n, o
er atio
l
a cce
d (or
s pee
rotation
x = speed x cos(rotation)
43. Control
x = speed x cos(rotation)
y = speed x sin(-rotation)
rotation
spe
ed
(or
acc
ele
rat
ion
, or
sho
oti
ng)
44. Control
class MoveShip(actions.WrappedMove):
def step(self, dt):
super(MoveShip, self).step(dt)
# set the rotation using the left and right arrow keys
self.target.dr = (keys[key.RIGHT] - keys[key.LEFT]) * 360
# figure the x and y heading components from the rotation
rotation = math.radians(self.target.rotation)
rotation_x = math.cos(rotation)
rotation_y = math.sin(-rotation)
# accelerate along the heading
acc = keys[key.UP] * 200
self.target.acceleration = (acc * rotation_x, acc * rotation_y)
46. Control
...
# open the window, get dimensions, watch the keyboard and run our scene
director.init()
width, height = director.get_window_size()
keys = key.KeyStateHandler()
director.window.push_handlers(keys)
director.run(AsteriodsGame())
66. ...
Collision
self.target.acceleration = (acc * rotation_x, acc * rotation_y)
def collide(a, b):
'''Determine whether two objects with a center point and width
(diameter) are colliding.'''
distance = math.sqrt((a.x-b.x)**2 + (a.y-b.y)**2)
return distance < (a.width/2 + b.width/2)
class MoveAsteroid(actions.WrappedMove):
def step(self, dt):
super(MoveAsteroid, self).step(dt)
# detect collision between this asteroid and the ship
if collide(self.target, director.scene.ship):
quit('GAME OVER')
def create_asteroid(layer, size, position, speed):
...
67. Collision
def create_asteroid(layer, size, position, speed):
'''Create an asteroid of a certain size and speed.
'''
s = cocos.sprite.Sprite('data/%s_asteroid.png' % size, position)
s.size = size
layer.add(s)
s.velocity = (random.randint(-speed, speed), random.randint(-speed, speed))
s.dr = random.randint(-speed, speed)
s.do(MoveAsteroid(width, height))
...
68. Shooting
...
self.target.acceleration = (acc * rotation_x, acc * rotation_y)
if self.target.gun_cooldown:
# still limiting the gun rate of fire
self.target.gun_cooldown = max(0, self.target.gun_cooldown - dt)
elif keys[key.SPACE]:
# fire a bullet from the ship
b = cocos.sprite.Sprite('data/bullet.png', (self.target.x,
self.target.y))
# send it in the same heading as the ship
b.velocity = (rotation_x * 400, rotation_y * 400)
# the bullet has a lifespan of 1 second
b.life = 1
director.scene.player.add(b)
# move the bullet with its custom action
b.do(MoveBullet(width, height))
# ship may only shoot twice per second
self.target.gun_cooldown = .5
...
69. Shooting
class MoveBullet(actions.WrappedMove):
def step(self, dt):
super(MoveBullet, self).step(dt)
# age the bullet
self.target.life -= dt
if self.target.life < 0:
# remove from play if it's too old
self.target.kill()
return
# see if the bullet hits any asteroids
for asteroid in director.scene.asteroids.get_children():
if collide(self.target, asteroid):
# remove the bullet and asteroid
self.target.kill()
asteroid.kill()
return
70. ... and winning
...
super(MoveShip, self).step(dt)
# if there's no asteroids left then the player has won
if not director.scene.asteroids.children:
quit('YOU WIN')
# set the rotation using the left and right arrow keys
self.target.dr = (keys[key.RIGHT] - keys[key.LEFT]) * 360
...
71. Creating chunks
def create_asteroid(layer, size, position, velocity, rotation, speed):
'''Create an asteroid of a certain size, possibly inheriting its
parent's velocity and rotation.
'''
s = cocos.sprite.Sprite('data/%s_asteroid.png' % size, position)
s.size = size
dx, dy = velocity
s.velocity = (dx + random.randint(-speed, speed),
dy + random.randint(-speed, speed))
s.dr = rotation + random.randint(-speed, speed)
layer.add(s)
s.do(MoveAsteroid(width, height))
72. Creating chunks
for asteroid in director.scene.asteroids.get_children():
if collide(self.target, asteroid):
# remove the bullet and asteroid, create new smaller
# asteroid
self.target.kill()
create_smaller_asteroids(asteroid)
asteroid.kill()
return
73. Creating chunks
...
position = (random.randint(0, width), random.randint(0, height))
create_asteroid(self.asteroids, 'big', position, (0, 0), 0, 100)
def create_smaller_asteroids(asteroid):
asteroids = director.scene.asteroids
if asteroid.size == 'big':
# if it's a big asteroid then make two medium asteroids in
# its place
for i in range(2):
create_asteroid(asteroids, 'medium', asteroid.position,
asteroid.velocity, asteroid.dr, 50)
elif asteroid.size == 'medium':
# if it's a medium asteroid then make two small asteroids in
# its place
for i in range(2):
create_asteroid(asteroids, 'small', asteroid.position,
asteroid.velocity, asteroid.dr, 50)
88. Lives
self.ship.set_invulnerable()
self.player.add(self.ship)
# another layer for the "HUD" or front informational display
self.hud = cocos.layer.Layer()
self.add(self.hud)
self.lives = cocos.text.Label('Lives: 3', font_size=20, y=height, anchor_y='top')
self.lives.counter = 3
self.hud.add(self.lives)
89. Lives
# detect collision between this asteroid and the ship
if collide(self.target, director.scene.ship):
lives = director.scene.lives
lives.counter -= 1
director.scene.ship.set_invulnerable()
if not lives.counter:
quit('GAME OVER')
else:
lives.element.text = 'Lives: %d' % lives.counter
91. Scenes
# if there's no asteroids left then the player has won
if not director.scene.asteroids.children:
director.replace(MessageScene('You Win'))
# set the rotation using the left and right arrow keys
self.target.dr = (keys[key.RIGHT] - keys[key.LEFT]) * 360
...
lives.counter -= 1
director.scene.ship.set_invulnerable()
if not lives.counter:
director.replace(MessageScene('Game Over'))
else:
lives.element.text = 'Lives: %d' % lives.counter
92. Menu
class MenuScene(cocos.scene.Scene):
def __init__(self):
super(MenuScene, self).__init__()
# opening menu
menu = cocos.menu.Menu("Asteroids!!!!")
menu.create_menu([
cocos.menu.MenuItem('Play', lambda: director.push(AsteroidsGame())),
cocos.menu.MenuItem('Quit', pyglet.app.exit),
])
menu.on_quit = pyglet.app.exit
self.add(menu)
# open the window, get dimensions, watch the keyboard and run our scene
director.init()
width, height = director.get_window_size()
keys = key.KeyStateHandler()
director.window.push_handlers(keys)
director.run(MenuScene())
112. Where To From Here?
• http://los-cocos.org
• http://pyglet.org
• http://pygame.org
• http://inventwithpython.com/
• http://pyweek.org
Editor's Notes
A Sprite is an image that knows how to draw itself on the screen.
The default anchor point in cocos2d is the center of the sprite image.
Unfortunately cocos2d rotates clockwise around Z, whereas pyglet (and basic trigenometry) rotates anti-clockwise, so we must negate the rotation to determine the correct y value.
Make life easier for yourself - make all your animation frames the same size!
Make life easier for yourself - make all your animation frames the same size!
pyglet will sequence a grid of images from the bottom left corner taking each row, and then each cell in turn