Game Programming LCA 2010 Richard Jones
The Basics • Displaying something • Controlling animation • User input • Gameplay mechanics • Playing sound effects and music • Further stuff
Displaying Something • Opening a window • Reading images • Displaying images
Controlling Animation • Image position on screen • Updates over time • Accounting for frame rate
User Input • Getting events • Distinct keyboard events vs. keyboard state
Gameplay Mechanics • Interaction of game objects • Detecting important events (game won or game over)
Detecting Collisions • Pixel-Perfect • Axis-Aligned Bounding Box • Circle-Circle • Hash Map
Sound • Reading sound files • Playing sounds and background music
Opening a Window import pyglet w = pyglet.window.Window() pyglet.app.run()
Clearing the Window import pyglet w = pyglet.window.Window() @w.event def on_draw(): w.clear() pyglet.app.run()
Drawing import pyglet w = pyglet.window.Window() ship_image = pyglet.image.load('data/ship.png') @w.event def on_draw(): w.clear() ship_image.blit(100, 100) pyglet.app.run()
Better Drawing import pyglet w = pyglet.window.Window() ship_image = pyglet.image.load('data/ship.png') ship = pyglet.sprite.Sprite(ship_image) ship.position = (100, 100) @w.event def on_draw(): w.clear() ship_image.blit(100, 100) ship.draw() pyglet.app.run()
Animation ... w.clear() ship.draw() def update(dt): ship.x += 1 pyglet.clock.schedule_interval(update, 1./30) pyglet.app.run()
Better Animation ... w.clear() ship.draw() def update(dt): ship.x += 1 ship.x += 100 * dt pyglet.clock.schedule_interval(update, 1./30) pyglet.app.run()
Adding Asteroids import random import pyglet w = pyglet.window.Window() def center_anchor(img): img.anchor_x = img.width / 2 img.anchor_y = img.height / 2 ...
Adding Asteroids ... ship_image = pyglet.image.load('data/ship.png') center_anchor(ship_image) ship = pyglet.sprite.Sprite(ship_image) ship.position = (100, 100) big_asteroid_image = pyglet.image.load('data/big_asteroid.png') center_anchor(big_asteroid_image) asteroids = [] for i in range(3): x = random.randint(0, w.width) y = random.randint(0, w.height) s = pyglet.sprite.Sprite(big_asteroid_image, x, y) s.dx = random.randint(-100, 100) s.dy = random.randint(-100, 100) asteroids.append(s) @w.event ...
Adding Asteroids ... @w.event def on_draw(): w.clear() for asteroid in asteroids: asteroid.draw() ship.draw() ...
Adding Asteroids ... def update(dt): ship.x += 100 * dt for asteroid in asteroids: asteroid.x += asteroid.dx*dt asteroid.y += asteroid.dy*dt ...
A Little Refactoring ... ship = pyglet.sprite.Sprite(ship_image) ship.position = (100, 100) ship.dx = 100 ship.dy = 0 ...
Screen Wrapping ... def update(dt): ship.x += 100 * dt for asteroid in asteroids: asteroid.x += asteroid.dx*dt asteroid.y += asteroid.dy*dt for a in asteroids + [ship]: a.x += a.dx*dt a.y += a.dy*dt if a.x - a.width/2 > w.width: a.x -= w.width + a.width elif a.x + a.width/2 < 0: a.x += w.width + a.width if a.y - a.height/2 > w.height: a.y -= w.height + a.height elif a.y + a.height/2 < 0: a.y += w.height + a.height ...
Control import math import random import pyglet w = pyglet.window.Window() ...
Control ... keys = pyglet.window.key.KeyStateHandler() w.push_handlers(keys) def update(dt): if keys[pyglet.window.key.LEFT]: ship.rotation -= 360*dt if keys[pyglet.window.key.RIGHT]: ship.rotation += 360*dt rotation = math.radians(ship.rotation) rotation_x = math.cos(-rotation) rotation_y = math.sin(-rotation) if keys[pyglet.window.key.UP]: ship.dx += 200 * rotation_x * dt ship.dy += 200 * rotation_y * dt for a in asteroids + [ship]: ...
Rotation ... ship = pyglet.sprite.Sprite(ship_image) ship.position = (100, 100) ship.dx = 100 ship.dy = 0 ship.position = (w.width/2, w.height/2) ship.dx = ship.dy = ship.dr = 0 ...
Rotation ... 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) asteroids.append(s) ...
Rotation ... def update(dt): if keys[pyglet.window.key.LEFT]: ship.rotation -= 360*dt if keys[pyglet.window.key.RIGHT]: ship.rotation += 360*dt ship.dr = (keys[pyglet.window.key.RIGHT] - keys[pyglet.window.key.LEFT]) * 360 rotation = math.pi * ship.rotation / 180.0 ... for a in asteroids + [ship]: a.x += a.dx*dt a.y += a.dy*dt a.rotation += a.dr * dt if a.x - a.width/2 > w.width: a.x -= w.width + a.width
Collision Detection
Collision Detection
Collision Detection
Collision Detection
Collision Detection distance
Collision Detection import sys import math import random import pyglet w = pyglet.window.Window() ...
Collision Detection ... w.push_handlers(keys) def distance(a, b): return math.sqrt((a.x-b.x)**2 + (a.y-b.y)**2) def update(dt): ...
Collision Detection ... elif a.y + a.height/2 < 0: a.y += w.height + a.height for a in asteroids: if distance(a, ship) < (a.width/2 + ship.width/2): sys.exit('GAME OVER') pyglet.clock.schedule_interval(update, 1./30) ...
Shooting ship.position = (w.width/2, w.height/2) ship.dx = ship.dy = ship.dr = 0 ship.gun_cooldown = 0 bullet_image = pyglet.image.load('data/bullet.png') center_anchor(bullet_image) bullets = [] ...
... Shooting ship.dy += 200 * rotation_y * dt if ship.gun_cooldown: ship.gun_cooldown = max(0, ship.gun_cooldown - dt) elif keys[pyglet.window.key.SPACE] and len(bullets) < 2: b = pyglet.sprite.Sprite(bullet_image, ship.x, ship.y) b.dx = rotation_x * 500 b.dy = rotation_y * 500 b.dr = 0 b.life = 1 bullets.append(b) ship.gun_cooldown = .5 for b in list(bullets): b.life -= dt if b.life < 0: bullets.remove(b) for a in asteroids + [ship]: for a in asteroids + [ship] + bullets: a.x += a.dx*dt ...
Shooting ... @w.event def on_draw(): w.clear() for asteroid in asteroids: asteroid.draw() for s in asteroids + bullets: s.draw() ship.draw() ...
Shooting ... and Hitting ... def distance(a, b): return math.sqrt((a.x-b.x)**2 + (a.y-b.y)**2) def collide(a, b): return distance(a, b) < (a.width/2 + b.width/2) ...
Shooting ... and Hitting ... elif a.y + a.height/2 < 0: a.y += w.height + a.height for a in asteroids: if distance(a, ship) < (a.width/2 + ship.width/2): sys.exit('GAME OVER') for a in list(asteroids): if collide(a, ship): sys.exit('GAME OVER') for b in list(bullets): if collide(a, b): bullets.remove(b) asteroids.remove(a) if not asteroids: sys.exit('YOU WIN') pyglet.clock.schedule_interval(update, 1./30) ...
Chunks ... center_anchor(bullet_image) bullets = [] 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) ...
... Chunks for b in list(bullets): if collide(a, b): bullets.remove(b) asteroids.remove(a) if a.image is big_asteroid_image.texture: for i in range(2): s = pyglet.sprite.Sprite(medium_asteroid_image, a.x, a.y) s.dx = a.dx + random.randint(-50, 50) s.dy = a.dy + random.randint(-50, 50) s.dr = a.dr + random.randint(-50, 50) asteroids.append(s) elif a.image is medium_asteroid_image.texture: for i in range(2): s = pyglet.sprite.Sprite(small_asteroid_image, a.x, a.y) s.dx = a.dx + random.randint(-50, 50) s.dy = a.dy + random.randint(-50, 50) s.dr = a.dr + random.randint(-50, 50) asteroids.append(s) if not asteroids: sys.exit('YOU WIN') ...
Sound Effects ... asteroids.append(s) explosion_sound = pyglet.media.load('data/explosion.wav', streaming=False) bullet_sound = pyglet.media.load('data/bullet.wav', streaming=False) @w.event def on_draw(): ...
Sound Effects ... bullets.append(b) ship.gun_cooldown = .5 bullet_sound.play() for b in list(bullets): ...
Sound Effects ... bullets.remove(b) asteroids.remove(a) explosion_sound.play() if a.image is big_asteroid_image.texture:
Further Stuff • Opening screen • Options menu • Game won / game over screen • Special effects
Other screen / menu • Use libraries like Cocos2d (Scenes, Layers, Sprites, Animations)
Special Effects • Simple image animations • Use libraries like lepton
Where To From Here? • http://pyglet.org • http://pygame.org • http://los-cocos.org • http://inventwithpython.com/ • http://pyweek.org

Introduction to Game Programming Tutorial

  • 1.
    Game Programming LCA 2010 Richard Jones
  • 2.
    The Basics • Displayingsomething • Controlling animation • User input • Gameplay mechanics • Playing sound effects and music • Further stuff
  • 3.
    Displaying Something • Openinga window • Reading images • Displaying images
  • 4.
    Controlling Animation • Imageposition on screen • Updates over time • Accounting for frame rate
  • 5.
    User Input • Gettingevents • Distinct keyboard events vs. keyboard state
  • 6.
    Gameplay Mechanics • Interactionof game objects • Detecting important events (game won or game over)
  • 7.
    Detecting Collisions • Pixel-Perfect •Axis-Aligned Bounding Box • Circle-Circle • Hash Map
  • 8.
    Sound • Reading soundfiles • Playing sounds and background music
  • 9.
    Opening a Window import pyglet w = pyglet.window.Window() pyglet.app.run()
  • 10.
    Clearing the Window import pyglet w = pyglet.window.Window() @w.event def on_draw(): w.clear() pyglet.app.run()
  • 11.
    Drawing import pyglet w =pyglet.window.Window() ship_image = pyglet.image.load('data/ship.png') @w.event def on_draw(): w.clear() ship_image.blit(100, 100) pyglet.app.run()
  • 12.
    Better Drawing import pyglet w= pyglet.window.Window() ship_image = pyglet.image.load('data/ship.png') ship = pyglet.sprite.Sprite(ship_image) ship.position = (100, 100) @w.event def on_draw(): w.clear() ship_image.blit(100, 100) ship.draw() pyglet.app.run()
  • 13.
    Animation ... w.clear() ship.draw() def update(dt): ship.x += 1 pyglet.clock.schedule_interval(update, 1./30) pyglet.app.run()
  • 14.
    Better Animation ... w.clear() ship.draw() def update(dt): ship.x += 1 ship.x += 100 * dt pyglet.clock.schedule_interval(update, 1./30) pyglet.app.run()
  • 15.
    Adding Asteroids importrandom import pyglet w = pyglet.window.Window() def center_anchor(img): img.anchor_x = img.width / 2 img.anchor_y = img.height / 2 ...
  • 16.
    Adding Asteroids ... ship_image =pyglet.image.load('data/ship.png') center_anchor(ship_image) ship = pyglet.sprite.Sprite(ship_image) ship.position = (100, 100) big_asteroid_image = pyglet.image.load('data/big_asteroid.png') center_anchor(big_asteroid_image) asteroids = [] for i in range(3): x = random.randint(0, w.width) y = random.randint(0, w.height) s = pyglet.sprite.Sprite(big_asteroid_image, x, y) s.dx = random.randint(-100, 100) s.dy = random.randint(-100, 100) asteroids.append(s) @w.event ...
  • 17.
    Adding Asteroids ... @w.event def on_draw(): w.clear() for asteroid in asteroids: asteroid.draw() ship.draw() ...
  • 18.
    Adding Asteroids ... def update(dt): ship.x += 100 * dt for asteroid in asteroids: asteroid.x += asteroid.dx*dt asteroid.y += asteroid.dy*dt ...
  • 19.
    A Little Refactoring ... ship = pyglet.sprite.Sprite(ship_image) ship.position = (100, 100) ship.dx = 100 ship.dy = 0 ...
  • 20.
    Screen Wrapping ... def update(dt): ship.x += 100 * dt for asteroid in asteroids: asteroid.x += asteroid.dx*dt asteroid.y += asteroid.dy*dt for a in asteroids + [ship]: a.x += a.dx*dt a.y += a.dy*dt if a.x - a.width/2 > w.width: a.x -= w.width + a.width elif a.x + a.width/2 < 0: a.x += w.width + a.width if a.y - a.height/2 > w.height: a.y -= w.height + a.height elif a.y + a.height/2 < 0: a.y += w.height + a.height ...
  • 21.
    Control import math import random importpyglet w = pyglet.window.Window() ...
  • 22.
    Control ... keys = pyglet.window.key.KeyStateHandler() w.push_handlers(keys) defupdate(dt): if keys[pyglet.window.key.LEFT]: ship.rotation -= 360*dt if keys[pyglet.window.key.RIGHT]: ship.rotation += 360*dt rotation = math.radians(ship.rotation) rotation_x = math.cos(-rotation) rotation_y = math.sin(-rotation) if keys[pyglet.window.key.UP]: ship.dx += 200 * rotation_x * dt ship.dy += 200 * rotation_y * dt for a in asteroids + [ship]: ...
  • 23.
    Rotation ... ship = pyglet.sprite.Sprite(ship_image) ship.position= (100, 100) ship.dx = 100 ship.dy = 0 ship.position = (w.width/2, w.height/2) ship.dx = ship.dy = ship.dr = 0 ...
  • 24.
    Rotation ... 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) asteroids.append(s) ...
  • 25.
    Rotation ... def update(dt): if keys[pyglet.window.key.LEFT]: ship.rotation -= 360*dt if keys[pyglet.window.key.RIGHT]: ship.rotation += 360*dt ship.dr = (keys[pyglet.window.key.RIGHT] - keys[pyglet.window.key.LEFT]) * 360 rotation = math.pi * ship.rotation / 180.0 ... for a in asteroids + [ship]: a.x += a.dx*dt a.y += a.dy*dt a.rotation += a.dr * dt if a.x - a.width/2 > w.width: a.x -= w.width + a.width
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
    Collision Detection import sys import math import random import pyglet w = pyglet.window.Window() ...
  • 32.
    Collision Detection ... w.push_handlers(keys) def distance(a, b): return math.sqrt((a.x-b.x)**2 + (a.y-b.y)**2) def update(dt): ...
  • 33.
    Collision Detection ... elif a.y + a.height/2 < 0: a.y += w.height + a.height for a in asteroids: if distance(a, ship) < (a.width/2 + ship.width/2): sys.exit('GAME OVER') pyglet.clock.schedule_interval(update, 1./30) ...
  • 34.
    Shooting ship.position = (w.width/2,w.height/2) ship.dx = ship.dy = ship.dr = 0 ship.gun_cooldown = 0 bullet_image = pyglet.image.load('data/bullet.png') center_anchor(bullet_image) bullets = [] ...
  • 35.
    ... Shooting ship.dy += 200 * rotation_y * dt if ship.gun_cooldown: ship.gun_cooldown = max(0, ship.gun_cooldown - dt) elif keys[pyglet.window.key.SPACE] and len(bullets) < 2: b = pyglet.sprite.Sprite(bullet_image, ship.x, ship.y) b.dx = rotation_x * 500 b.dy = rotation_y * 500 b.dr = 0 b.life = 1 bullets.append(b) ship.gun_cooldown = .5 for b in list(bullets): b.life -= dt if b.life < 0: bullets.remove(b) for a in asteroids + [ship]: for a in asteroids + [ship] + bullets: a.x += a.dx*dt ...
  • 36.
    Shooting ... @w.event def on_draw(): w.clear() for asteroid in asteroids: asteroid.draw() for s in asteroids + bullets: s.draw() ship.draw() ...
  • 37.
    Shooting ... andHitting ... def distance(a, b): return math.sqrt((a.x-b.x)**2 + (a.y-b.y)**2) def collide(a, b): return distance(a, b) < (a.width/2 + b.width/2) ...
  • 38.
    Shooting ... andHitting ... elif a.y + a.height/2 < 0: a.y += w.height + a.height for a in asteroids: if distance(a, ship) < (a.width/2 + ship.width/2): sys.exit('GAME OVER') for a in list(asteroids): if collide(a, ship): sys.exit('GAME OVER') for b in list(bullets): if collide(a, b): bullets.remove(b) asteroids.remove(a) if not asteroids: sys.exit('YOU WIN') pyglet.clock.schedule_interval(update, 1./30) ...
  • 39.
    Chunks ... center_anchor(bullet_image) bullets = [] 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) ...
  • 40.
    ... Chunks for b in list(bullets): if collide(a, b): bullets.remove(b) asteroids.remove(a) if a.image is big_asteroid_image.texture: for i in range(2): s = pyglet.sprite.Sprite(medium_asteroid_image, a.x, a.y) s.dx = a.dx + random.randint(-50, 50) s.dy = a.dy + random.randint(-50, 50) s.dr = a.dr + random.randint(-50, 50) asteroids.append(s) elif a.image is medium_asteroid_image.texture: for i in range(2): s = pyglet.sprite.Sprite(small_asteroid_image, a.x, a.y) s.dx = a.dx + random.randint(-50, 50) s.dy = a.dy + random.randint(-50, 50) s.dr = a.dr + random.randint(-50, 50) asteroids.append(s) if not asteroids: sys.exit('YOU WIN') ...
  • 41.
    Sound Effects ... asteroids.append(s) explosion_sound = pyglet.media.load('data/explosion.wav', streaming=False) bullet_sound = pyglet.media.load('data/bullet.wav', streaming=False) @w.event def on_draw(): ...
  • 42.
    Sound Effects ... bullets.append(b) ship.gun_cooldown = .5 bullet_sound.play() for b in list(bullets): ...
  • 43.
  • 44.
    Further Stuff • Openingscreen • Options menu • Game won / game over screen • Special effects
  • 45.
    Other screen /menu • Use libraries like Cocos2d (Scenes, Layers, Sprites, Animations)
  • 46.
    Special Effects • Simpleimage animations • Use libraries like lepton
  • 47.
    Where To FromHere? • http://pyglet.org • http://pygame.org • http://los-cocos.org • http://inventwithpython.com/ • http://pyweek.org

Editor's Notes