2015/05/21
Slides powered by Reveal.js
Story + Graphics + Music/effects + Mechanics
Release: 2000-10 / Stable: 1.9.1 (2009-08)
Alpha Release: 2007-06 / Stable: 1.1.4 (2010-01), 1.2.2 (2015-03)
Release: 2008-02 / Stable: 0.6.3 (2015-04)
Release: 2012-09 / Stable: 1.9.0 (2015-04)
Release: 2000 / Stable: 2.74 (2015-03)
Python 3
Low learning curve
Pyglet API access
Development based on Nodes, Scenes and Layers
Actions and transformations effects
Basic Collision engine
...
Node: Base class that exposes Cocos2d core characteristics and functionalites:
Director: Singleton object that manages the main window and scenes workflow
import cocos
# structured style
def create_layer():
a_layer = cocos.layer.Layer()
a_label = cocos.text.Label('structured')
a_label.position = 320, 240 # x, y
a_layer.add(a_label)
return a_layer
# object oriented style
class MyLayer(cocos.layer.Layer):
def __init__(self):
super(MyLayer, self).__init__()
a_label = cocos.text.Label('Object oriented')
a_label.position = 320, 100 # x, y
self.add(a_label)
if __name__ == '__main__':
cocos.director.director.init(width=640, height=480)
a_scene = cocos.scene.Scene()
a_scene.add(create_layer(), z = 1)
a_scene.add(myLayer(), z = 0)
cocos.director.director.run(a_scene)
Actions are grouped orders received by a node resulting in a specific attribute transformation (positional, rotational, scale, visibility).
One action can be composed within an other action:
We can apply modifiers to the actions:
#...
label.do(Repeat(JumpTo(label.position, height=100, duration=2)))
#...
label2.do(Repeat(ScaleBy(1.1, 0.2) + Reverse(ScaleBy(1.1, 0.2))))
#...
label3.do(Repeat(FadeTo(0, 1) + FadeTo(255, 1)))
#...
sprite = cocos.sprite.Sprite('sunglasses.png')
sprite.do(JumpTo((window_width*0.4, window_height*0.6), duration=1) +
Repeat(RotateBy(10, 0.6) + Reverse(RotateBy(10, 0.6))))
Pyglet events fallback on Cocos2D layer
import cocos
class MyLayer(cocos.layer.Layer):
is_event_handler = True
#...
def on_key_press(self, key, modifiers):
pass
def on_key_release(self, key, modifiers):
pass
def on_key_press(self, key, modifiers):
pass
def on_mouse_motion(self, x, y, dx, dy):
pass
#...
Pyglet key events fallback on Cocos2D's window handlers
from pyglet.window import key
from cocos import director
kb = key.KeyStateHandler()
director.window.push_handlers(kb)
[Snipped based on a JPWright blog's entry]
kb is an dictionary that saves keyboard keys states.
# scheduled update handler for sprite position management
self.schedule(self.__update__)
# ...
def __update__(self, dt):
turbo = (4 * kb[key.LSHIFT]) | 1
new_x = self.sprite.position[0] +
(dt * 200 * turbo * kb[key.RIGHT] - kb[key.LEFT])
new_y = self.sprite.position[1] +
(dt * 200 * turbo * kb[key.UP] - kb[key.DOWN])
self.sprite.position = new_x, new_y
Based on spritesheet images (row x columns)
[Side Scroller Sprite Base Animation by Wind astella | CC-By 3.0 License]
from pyglet import image
img = image.load('/path/to/the/image') # Image load
# We build a matrix were each element is a sprite sheet partition
img_grid = image.ImageGrid(img, rows, columns,
item_height, item_width,
column_padding, row_padding)
# We make a texture grid from the image grid for memory optimization
texture_grid = image.TextureGrid(img_grid)
# Animation building from a set of elements of the grid
animation_01 = image.Animation.
from_image_sequence(sequence=texture_grid[begin:end]
period=animation_rate,
Loop=True|False)
By default we can play uncompressed "RIFF/WAV" files without any extra dependencies.
To play MP3/AU/OGG files, we must install AVBin.
music = pyglet.resource.media('/path/to/the/file')
# Using Player wrapper
player = pyglet.media.Player()
player.queue(music)
player.volume = 0.2
player.play()
# playing directly from source
sound_media_src = pyglet.media.load('/path/to/the/file')
sound_media_src = pyglet.media.StaticSource(sound_media)
sound_media_src.play().volume = 0.5
Cocos2d have a module for simple collision and proximity checking, based on geometrical distance and overlapping calculations.
A collidable object must have a "cshape" property (CircleShape or AARectShape).
Collisions and distance checking are handled by the collision manager.
Collisions (II)
Collisions (III)
import cocos.collision_model as cm
# ...
collision_mgr = cm.CollisionManagerGrid(xmin, xmax,
ymin, ymax,
cell_width,
cell_height)
# ...
for item in collision_mgr.iter_colliding(target):
# react to the collision
# ...
near_list = collision_mgr.objs_near(obj, near_distance)
# ...
check_a_b_collision = collision_mgr.they_collide(a, b)
# ...
items_in_zone = collision_mgr.objs_into_box(minx, maxx, miny, maxy)
import cocos.collision_model as cm
import cocos.euclid as eu
#...
obj_center = eu.Vector2(cx, cy)
obj.cshape = cm.AARectShape(center=obj_center, half_width, half_height)
collision_mgr.add(obj, name)
class Entity(cocos.sprite.Sprite):
def __init__(self, image, x=0.0, y=0.0):
# ...
def draw(self):
if self.x + self.center[0] < self.boundaries[0] or \
self.x - self.center[0] > self.boundaries[2]:
self.parent.remove(self)
return
if self.y + self.center[1] < self.boundaries[1] or \
self.y - self.center[1] > self.boundaries[3]:
self.parent.remove(self)
return
super(Entity, self).draw()
import random as rnd
# ...
class SpawnerLayer(cocos.layer.ColorLayer):
def __init__(self, image):
super(SpawnerLayer, self).__init__(r=255, g=255, b=255, a=255)
self.schedule_interval(callback=self.__spawn__, interval=1)
self.image = image
def __spawn__(self, _):
y = rnd.uniform(10, 400)
spawned = Entity(self.image, -100, y)
spawned.scale = rnd.uniform(0.5, 1.5)
spawned.do(MoveTo((800, y), rnd.randint(1, 8)))
self.add(spawned)
Complete code examples used in the slides
RunnerBase: A Cocos2d based runner skeleton that eases the building of simple runner games.
Twitter: @adoankim
Github: adoankim
E-Mail: dkc.adam [at] gmail [dot] com