1 of 30

Python in Game Development

Denis Kovalev

Software Developer at DataArt

2 of 30

About me

  • 6+ years in IT
  • started as C developer
  • 3+ years Python
  • Linux, bash, Perl, Java
  • DataArt (http://www.dataart.com)
  • http://about.me/denis.kovalev

3 of 30

Why Python?

  • Python
  • maintenance
  • libraries
  • learn

4 of 30

Existing “Python” games

  • Battlefield 2 & Battlefield 2142
  • Eve Online
  • Mount & Blade
  • Civilization IV
  • Severance: Blade of Darkness
  • Greyhawk: Temple of Elemental Evil

5 of 30

GUI

  • Tkinter, PyGTK, PyQt
  • PyGame
  • Kivy
  • Pyggel (Python Graphical Game Engine + Libraries)
  • Panda3D
  • Pyglet + Cocos2d

2D

3D

6 of 30

Pygame

+ SDL (Simple Directmedia Layer) library

+ Stable and well-documented

+ Examples and tutorials

- Not pythonic

+ Easy & powerful

7 of 30

Pygame Drawing Concept

8 of 30

Create window

  1. import pygame
  2. pygame.init()
  3. screen = pygame.display.set_mode((640, 480))
  4. while 1:
  5. for event in pygame.event.get():
  6. if event.type == pygame.QUIT:
  7. raise SystemExit("QUIT")

9 of 30

Pygame “Hello, World!”

  1. import pygame
  2. pygame.init()
  3. WHITE = pygame.Color(255, 255, 255)
  4. width, height = (640, 480)
  5. screen = pygame.display.set_mode((width, height))
  6. font = pygame.font.Font(None, 50)
  7. text = font.render("Hello, World!", True, WHITE)
  8. # Draw text on screen
  9. screen.blit(text, text.get_rect(centerx=width/2., centery=height/2.))
  10. pygame.display.update()
  11. while 1:
  12. for event in pygame.event.get():
  13. if event.type == pygame.QUIT:
  14. raise SystemExit("QUIT")

10 of 30

Pygame key press

  1. def get_text(msg="Hello, World!"):
  2. font = pygame.font.Font(None, 50)
  3. text = font.render(msg, True, WHITE)
  4. return text
  5. delta_x, delta_y = (0, 0)
  6. step = 20
  7. while 1:
  8. screen.fill(BLACK)
  9. for event in pygame.event.get():
  10. if event.type == pygame.QUIT:
  11. raise SystemExit("QUIT")
  12. elif event.type == pygame.KEYDOWN and event.key == pygame.K_DOWN:
  13. delta_y += step
  14. elif event.type == pygame.KEYDOWN and event.key == pygame.K_UP:
  15. delta_y -= step
  16. elif event.type == pygame.KEYDOWN and event.key == pygame.K_r:
  17. delta_x, delta_y = (0, 0)
  18. text = get_text()
  19. screen.blit(text, text.get_rect(centerx=width/2. + delta_x, centery=height/2. + delta_y))
  20. pygame.display.update()

11 of 30

Pygame surfaces

  1. yellow_surface = pygame.Surface((width, height))
  2. yellow_surface.fill(YELLOW)
  3. green_surface = pygame.Surface((width/2, height/2))
  4. green_surface.fill(GREEN)
  5. def draw_circle(pos, radius=width/8):
  6. pygame.draw.circle(yellow_surface, GREEN, pos, radius)
  7. pygame.draw.circle(green_surface, YELLOW, pos, radius)
  8. while 1:
  9. for event in pygame.event.get():
  10. if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
  11. move = True
  12. elif event.type == pygame.MOUSEBUTTONUP and event.button == 1:
  13. move = False
  14. if move:
  15. yellow_surface.fill(YELLOW)
  16. green_surface.fill(GREEN)
  17. pos = pygame.mouse.get_pos()
  18. draw_circle(pos)
  19. screen.blit(yellow_surface, (0, 0))
  20. screen.blit(green_surface, (0, 0))
  21. pygame.display.update()

12 of 30

Pygame objects collision

  1. static_rect = pygame.Rect((width/3, height/3), (width/3, height/3))
  2. moving_rect = pygame.Rect((width*2/3, height*2/3), (width/6, height/6))
  3. def draw_rects(pos):
  4. moving_rect.centerx, moving_rect.centery = pos
  5. pygame.draw.rect(yellow_surface, GREEN, moving_rect)
  6. if moving_rect.colliderect(static_rect):
  7. pygame.draw.rect(yellow_surface, PURPLE, static_rect)
  8. else:
  9. pygame.draw.rect(yellow_surface, BLUE, static_rect)
  10. pos = (0, 0)
  11. move = False
  12. while 1:
  13. for event in pygame.event.get():
  14. ...
  15. if move:
  16. yellow_surface.fill(YELLOW)
  17. pos = pygame.mouse.get_pos()
  18. draw_rects(pos)
  19. screen.blit(yellow_surface, (0, 0))
  20. pygame.display.update()

13 of 30

Pygame Sprites - create

  1. class Ball(pygame.sprite.Sprite):
  2. radius = 25
  3. groups = []
  4. acceleration = 1
  5. def __init__(self, pos):
  6. pygame.sprite.Sprite.__init__(self, self.groups)
  7. self.image = pygame.Surface((Ball.radius * 2, Ball.radius * 2))
  8. self.image.fill(YELLOW)
  9. self.image.convert_alpha()
  10. self.rect = self.image.get_rect()
  11. self.radius = Ball.radius
  12. self.velocity = 0
  13. pygame.draw.circle(self.image, BLUE, self.rect.center, self.radius, 0)
  14. self.rect.center = pos

14 of 30

Pygame Sprites - move

  1. class Ball(pygame.sprite.Sprite):
  2. ….
  3. def update(self):
  4. if self.rect.top < height: # inside the screen?
  5. self.rect.move_ip(0, self.velocity)
  6. bricks = pygame.sprite.spritecollide(self, static, False)
  7. if bricks:
  8. brick = bricks[0]
  9. self.rect.bottom = brick.rect.top # place the ball on top of the brick
  10. self.velocity *= -0.9 # bounce with speed loss
  11. if 0 > self.velocity > -0.1: # prevent infinite bounce
  12. self.velocity = 0
  13. else:
  14. self.velocity += Ball.acceleration

15 of 30

Pygame Sprites

  1. allsprites = pygame.sprite.Group()
  2. Ball.groups = allsprites
  3. static = pygame.sprite.Group()
  4. Brick.groups = allsprites, static
  5. timer = pygame.time.Clock()
  6. screen.blit(yellow_surface, (0, 0))
  7. while 1:
  8. timer.tick(60)
  9. for event in pygame.event.get():
  10. if event.type == pygame.QUIT:
  11. raise SystemExit("QUIT")
  12. elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
  13. Ball(event.pos)
  14. elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 3:
  15. Brick(event.pos)
  16. elif event.type == pygame.KEYDOWN and event.key == pygame.K_r:
  17. allsprites.empty()
  18. static.empty()
  19. allsprites.clear(screen, yellow_surface)
  20. allsprites.update()
  21. allsprites.draw(screen)
  22. pygame.display.update()

16 of 30

Python Physics Engines

PyODE (Python bindings for The Open Dynamics Engine)

pyBox2D

Panda3D

17 of 30

Pymunk Physics Engine

  • Based on Chipmunk2D
  • Force & impulse
  • Collisions
  • Constraints
  • Pygame & Pyglet modules

18 of 30

Pymunk basics

  1. import pymunk as pm
  2. space = pm.Space()
  3. space.gravity = (0, -900.0)
  4. class Ball(pm.Body):
  5. def __init__(self, pos, mass=10, radius=25):
  6. inertia = pm.moment_for_circle(mass, 0, radius, (0,0))
  7. pm.Body.__init__(self, mass, inertia)
  8. self.position = pos
  9. self.radius = radius
  10. def get_shape(self, elasticity=0.9):
  11. shape = pm.Circle(self, self.radius, (0,0))
  12. shape.elasticity = elasticity
  13. return shape

19 of 30

Pygame + Pymunk

  1. while 1:
  2. for event in pygame.event.get():
  3. if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
  4. body = Ball(to_pygame(event.pos))
  5. shape = body.get_shape()
  6. space.add(body, shape)
  7. balls.append(shape)
  8. elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 3:
  9. brick = Brick(to_pygame(event.pos))
  10. space.add(brick)
  11. bricks.append(brick)
  12. ### Draw stuff here
  13. ### Update physics
  14. fps = 60.0
  15. space.step(1./fps)
  16. pygame.display.flip()
  17. clock.tick(fps)

20 of 30

Pyglet

Cocos2d

+ No dependencies

+ Pythonic

+ Images, audio, video in any format

- Not for games

+ Pyglet-based

+ For games, apps, GUI interaction

- Poor API docs

- Google does not help

+ OpenGL interface

+ Layers and scenes

21 of 30

Pygame vs Pyglet

  1. import pygame
  2. pygame.init()
  3. screen = pygame.display.set_mode((640,480))
  4. while 1:
  5. for event in pygame.event.get():
  6. if event.type == pygame.QUIT:
  7. raise SystemExit("QUIT")
  1. import pyglet
  2. screen = pyglet.window.Window(640,480)
  3. pyglet.app.run()

22 of 30

Pygame vs Pyglet

  1. import pygame
  2. pygame.init()
  3. screen = pygame.display.set_mode((640,480))
  4. while 1:
  5. timer.tick(60)
  6. for event in pygame.event.get():
  7. if event.type == pygame.KEYDOWN and event.key == pygame.K_a:
  8. print 'You pressed A'
  9. #update objects here
  10. pygame.display.update()

  1. import pyglet
  2. from pyglet.window import key
  3. screen = pyglet.window.Window(640,480)
  4. @screen.event
  5. def on_key_press(symbol, modifiers):
  6. if symbol == key.A:
  7. print 'You pressed A'
  8. def update(dt):
  9. #update objects here
  10. pyglet.clock.schedule_interval(update, 1/60.0)
  11. pyglet.app.run()

23 of 30

Showtime!

24 of 30

Prerequisites

Python 2.6, 2.7, 3.3+

pip install --upgrade http://pyglet.googlecode.com/archive/tip.zip

pip install cocos2d

Download images from http://bit.ly/pycon_game

25 of 30

Map editors

26 of 30

+ PyTMX

27 of 30

“Unknown Horizons”

“Zero-Projekt”

28 of 30

Examples and games

pyvolley (cocos2d, pymunk) -

https://github.com/aikikode/pyvolley

Minecraft in Python (pyglet, OpenGL) -

https://github.com/boskee/Minecraft

“Nautili” (PyGame, Tiled)

https://github.com/aikikode/nautili

pyhammerfight (cocos2d, pymunk) -

https://github.com/aikikode/pyhammerfight

Presentation examples - https://bitbucket.org/aikikode/pygame_examples

29 of 30

Thanks to

  • Cody Lovett for Pygame examples

  • QR Code Generator - http://goqr.me/

  • Syntax Highlighter - http://highlight.hohli.com/

30 of 30

Thanks for your attention!

  • skype: aikikode
  • email: aikikode@gmail.com
  • http://about.me/denis.kovalev

Questions?