The following is a version of the asteroids.py code with additional cocos2d features added.
import sys
import mathimport sys
import math
import random
import pyglet
import cocos
from cocos.director import director
from cocos.menu import *
from cocos.actions import *
from pyglet.gl import *
def center_anchor(img):
'''Center the anchor of the given image.'''
img.anchor_x = img.width // 2
img.anchor_y = img.height // 2
def distance(a, b):
'''Determine the distance between two points.'''
return math.sqrt((a.x-b.x)**2 + (a.y-b.y)**2)
def collide(a, b):
'''Determine whether two objects with a center point and width
(diameter) are colliding.'''
return distance(a, b) < (a.width/2 + b.width/2)
# load the ship image, center the anchor
ship_image = pyglet.image.load('data/ship.png')
center_anchor(ship_image)
# load the bullet image for later sprites, center anchored
bullet_image = pyglet.image.load('data/bullet.png')
center_anchor(bullet_image)
# load the three sizes of asteroid image and center their anchors
small_asteroid_image = pyglet.image.load('data/small_asteroid.png')
center_anchor(small_asteroid_image)
medium_asteroid_image = pyglet.image.load('data/medium_asteroid.png')
center_anchor(medium_asteroid_image)
big_asteroid_image = pyglet.image.load('data/big_asteroid.png')
center_anchor(big_asteroid_image)
# load up our sound effects
explosion_sound = pyglet.media.load('data/explosion.wav', streaming=False)
bullet_sound = pyglet.media.load('data/bullet.wav', streaming=False)
class Level(cocos.layer.Layer):
is_event_handler = True
def on_enter(self):
# create a sprite with that image, intial position in the center of the
# screen and not moving or rotating
self.ship = pyglet.sprite.Sprite(ship_image)
self.ship.position = (director.window.width/2, director.window.height/2)
self.ship.dx = self.ship.dy = self.ship.dr = 0
self.ship.gun_cooldown = 0
# keep track of the currently-active bullet sprites
self.bullets = []
# keep track of the currently-active asteroid sprites
self.asteroids = []
# create 4 starting big asteroids with random positioning, speed and
# rotation
for i in range(3):
x = random.randint(0, director.window.width)
y = random.randint(0, director.window.height)
s = pyglet.sprite.Sprite(big_asteroid_image, x, y)
s.dx = random.randint(-100, 100)
s.dy = random.randint(-100, 100)
s.dr = random.randint(-100, 100)
self.asteroids.append(s)
# use the standard pyglet keyboard state event handler
self.keys = pyglet.window.key.KeyStateHandler()
director.window.push_handlers(self.keys)
pyglet.clock.schedule_interval(self.update, 1/60.)
def on_exit(self):
self.bullets = []
self.asteroids = []
pyglet.clock.unschedule(self.update)
director.window.pop_handlers()
# set up the game's drawing event handler
def visit(self):
director.window.clear()
for s in self.asteroids + self.bullets:
s.draw()
self.ship.draw()
def update(self, dt):
'''Update the game for the "dt" seconds that have passed.'''
# update the ship's speed of rotation based on the combination of
# left/right arrow being held down
self.ship.dr = (self.keys[pyglet.window.key.RIGHT] - self.keys[pyglet.window.key.LEFT]) * 360
# determine the radian angle of rotation and thereby the X and Y
# components of the ship's heading
rotation = math.pi * self.ship.rotation / 180.0
rotation_x = math.cos(-rotation)
rotation_y = math.sin(-rotation)
# if the thrust (up) key is pressed then accelerate in the current
# heading by increasing the ship's dx/dy
if self.keys[pyglet.window.key.UP]:
self.ship.dx += 200 * rotation_x * dt
self.ship.dy += 200 * rotation_y * dt
# if the ship's gun has recently been fired then cool it down,
# otherwise fire a new bulled if the fire (space) key has been pressed
if self.ship.gun_cooldown:
self.ship.gun_cooldown = max(0, self.ship.gun_cooldown - dt)
elif self.keys[pyglet.window.key.SPACE] and len(self.bullets) < 2:
# the gun is firing so create a new bullet over the ship with a
# speed of roughly 500 pixels per second in the same heading as the
# ship.
b = pyglet.sprite.Sprite(bullet_image, self.ship.x,
self.ship.y)
b.dx = rotation_x * 500
b.dy = rotation_y * 500
b.dr = 0
# set the bullet to live for 1 second
b.life = 1
# retain the bullet in our bullet sprites list
self.bullets.append(b)
# set the cooldown to 2 shots per second
self.ship.gun_cooldown = .5
# play a nice sound effect
bullet_sound.play()
# kill off any old bullets
for b in list(self.bullets):
b.life -= dt
if b.life < 0:
self.bullets.remove(b)
# update the position and rotation of all our sprites based on their
# dx, dy and dr attributes
for a in self.asteroids + [self.ship] + self.bullets:
a.x += a.dx*dt
a.y += a.dy*dt
a.rotation += a.dr * dt
# wrap all sprites once they're off the screen
if a.x - a.width/2 > director.window.width:
a.x -= director.window.width + a.width
elif a.x + a.width/2 < 0:
a.x += director.window.width + a.width
if a.y - a.height/2 > director.window.height:
a.y -= director.window.height + a.height
elif a.y + a.height/2 < 0:
a.y += director.window.height + a.height
# check collisions with the asteroids
for a in list(self.asteroids):
# if the ship collides then it's GAME OVER
if collide(a, self.ship):
l = cocos.layer.Layer()
l.add(cocos.text.Label('GAME OVER', font_size=64,
color=(255, 0, 0, 255), anchor_x='center',
anchor_y='center', position=(320, 240)))
l.do(boom())
director.replace(cocos.scene.Scene(l))
# if any bullet collides then the asteroid is damaged/destroyed
for b in list(self.bullets):
if collide(a, b):
self.bullets.remove(b)
self.asteroids.remove(a)
explosion_sound.play()
if a.image is big_asteroid_image.texture:
# if it's a big asteroid then make two medium asteroids in
# its place
for i in range(2):
s = pyglet.sprite.Sprite(medium_asteroid_image, a.x, a.y)
# modify the parent speed/rotation by some random
# amount
s.dx = a.dx + random.randint(-50, 50)
s.dy = a.dy + random.randint(-50, 50)
s.dr = a.dr + random.randint(-50, 50)
self.asteroids.append(s)
elif a.image is medium_asteroid_image.texture:
# if it's a medium asteroid then make two small asteroids in
# its place
for i in range(2):
s = pyglet.sprite.Sprite(small_asteroid_image, a.x, a.y)
# modify the parent speed/rotation by some random
# amount
s.dx = a.dx + random.randint(-50, 50)
s.dy = a.dy + random.randint(-50, 50)
s.dr = a.dr + random.randint(-50, 50)
self.asteroids.append(s)
break
# if there's no more asteroids then the player has won!
if not self.asteroids:
l = cocos.layer.Layer()
l.add(cocos.text.Label('YOU WIN', font_size=64,
color=(255, 255, 0, 255), anchor_x='center',
anchor_y='center', position=(320, 240)))
l.do(boom())
director.replace(cocos.scene.Scene(l))
director.init(width=640, height=480)
director.window.set_mouse_visible(False)
glClearColor(0, 0, 0, 1)
glDisable(GL_DEPTH_TEST)
def boom():
angle = 3
duration = .05
rot = Accelerate(RotateBy( angle, duration ))
rot2 = Accelerate(RotateBy( -angle*2, duration))
return ScaleBy(1.2, .5) | (rot + (rot2 + Reverse(rot2)) * 4 + Reverse(rot))
def play():
director.push(cocos.scene.Scene(Level()))
menu = Menu("Asteroids!!!!")
menu.create_menu([
MenuItem('Play', play),
MenuItem('Quit', quit),
])
menu.on_quit = pyglet.app.exit
director.run(cocos.scene.Scene(menu))