├── bpwpapcode ├── AppendixA │ └── readme.txt ├── Chapter01 │ └── readme.txt ├── AppendixB │ ├── dist.bat │ ├── ant.png │ ├── leaf.png │ ├── spider.png │ ├── setup.py │ ├── ants.iss │ └── antsstatemachine.py ├── Chapter06 │ ├── cat.jpg │ ├── fugu.png │ ├── sushiplate.jpg │ ├── keydemo.py │ ├── hatscroll.py │ ├── joystickevents.py │ ├── keymovement.py │ ├── diagonalmovement.py │ ├── simplekeyboardmovement.py │ ├── analoguehatscroll.py │ ├── keyrotatemovement.py │ ├── mouserotatemovement.py │ ├── joystickmovement.py │ └── joystickdemo.py ├── Chapter07 │ ├── ant.png │ ├── leaf.png │ ├── spider.png │ ├── smallfugu.png │ ├── ants.py │ └── antsstatemachine.py ├── Chapter09 │ ├── map.png │ ├── rotation3d.py │ └── firstopengl.py ├── Chapter10 │ ├── bar.png │ ├── ball.png │ ├── bounce.wav │ ├── cross.png │ ├── next.png │ ├── pause.png │ ├── play.png │ ├── prev.png │ ├── stop.png │ ├── mousecursor.png │ ├── music │ │ └── please put some ogg files in the music folder.ogg │ ├── bouncesound.py │ └── jukebox.py ├── Chapter03 │ ├── fugu.png │ ├── name.png │ ├── sushiplate.jpg │ ├── events.py │ ├── fullscreentest.py │ ├── helloworld.py │ ├── resize.py │ └── scrolly.py ├── Chapter05 │ ├── fugu.png │ ├── sushiplate.jpg │ ├── gotest.py │ ├── vecmagniture.py │ ├── simplemove.py │ ├── timebasedmovement.py │ ├── vectormovement.py │ ├── frameratecompare.py │ ├── simplevec.py │ └── diagonalmovement.py ├── Chapter08 │ ├── ball.png │ ├── vectordroid.py │ ├── vector3test.py │ ├── parallaxstars.py │ ├── simple3d.py │ └── rotation3d.py ├── Chapter12 │ ├── fugu.png │ ├── bodytex.jpg │ ├── booktex.png │ ├── model3d.pyc │ ├── background.png │ ├── mytanktex.jpg │ ├── tanksky │ │ ├── bk.png │ │ ├── dn.png │ │ ├── ft.png │ │ ├── lt.png │ │ ├── rt.png │ │ ├── up.png │ │ ├── skybox.mtl │ │ └── skybox.obj │ ├── mytank.mtl │ ├── fogdemo.py │ ├── skybox.py │ ├── blenddemo.py │ └── model3d.py ├── Chapter11 │ ├── bodytex.jpg │ ├── booktex.png │ ├── sushitex.png │ ├── mytanktex.jpg │ ├── mytank.mtl │ ├── tankdemo.py │ ├── opengltex.py │ ├── opengltextiled.py │ └── model3d.py ├── README.txt ├── Chapter04 │ ├── allcolors.py │ ├── ellipsetest.py │ ├── arctest.py │ ├── circletest.py │ ├── polytest.py │ ├── colrects.py │ ├── multiplelines.py │ ├── drawinglines.py │ └── colortest.py └── Chapter02 │ ├── tankgame.py │ └── tank.py ├── 3767.pdf ├── 3781.pdf ├── LICENSE.txt ├── 9781590598726.jpg ├── README.md └── contributing.md /bpwpapcode/AppendixA/readme.txt: -------------------------------------------------------------------------------- 1 | No code for Appendix A -------------------------------------------------------------------------------- /bpwpapcode/Chapter01/readme.txt: -------------------------------------------------------------------------------- 1 | No code for chapter 1 -------------------------------------------------------------------------------- /bpwpapcode/AppendixB/dist.bat: -------------------------------------------------------------------------------- 1 | python setup.py py2exe 2 | pause -------------------------------------------------------------------------------- /3767.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/3767.pdf -------------------------------------------------------------------------------- /3781.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/3781.pdf -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/LICENSE.txt -------------------------------------------------------------------------------- /9781590598726.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/9781590598726.jpg -------------------------------------------------------------------------------- /bpwpapcode/AppendixB/ant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/AppendixB/ant.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter06/cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter06/cat.jpg -------------------------------------------------------------------------------- /bpwpapcode/Chapter07/ant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter07/ant.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter09/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter09/map.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter10/bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter10/bar.png -------------------------------------------------------------------------------- /bpwpapcode/AppendixB/leaf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/AppendixB/leaf.png -------------------------------------------------------------------------------- /bpwpapcode/AppendixB/spider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/AppendixB/spider.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter03/fugu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter03/fugu.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter03/name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter03/name.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter05/fugu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter05/fugu.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter06/fugu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter06/fugu.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter07/leaf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter07/leaf.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter07/spider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter07/spider.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter08/ball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter08/ball.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter10/ball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter10/ball.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter10/bounce.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter10/bounce.wav -------------------------------------------------------------------------------- /bpwpapcode/Chapter10/cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter10/cross.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter10/next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter10/next.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter10/pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter10/pause.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter10/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter10/play.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter10/prev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter10/prev.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter10/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter10/stop.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter12/fugu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter12/fugu.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter11/bodytex.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter11/bodytex.jpg -------------------------------------------------------------------------------- /bpwpapcode/Chapter11/booktex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter11/booktex.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter11/sushitex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter11/sushitex.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter12/bodytex.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter12/bodytex.jpg -------------------------------------------------------------------------------- /bpwpapcode/Chapter12/booktex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter12/booktex.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter12/model3d.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter12/model3d.pyc -------------------------------------------------------------------------------- /bpwpapcode/Chapter03/sushiplate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter03/sushiplate.jpg -------------------------------------------------------------------------------- /bpwpapcode/Chapter05/sushiplate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter05/sushiplate.jpg -------------------------------------------------------------------------------- /bpwpapcode/Chapter06/sushiplate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter06/sushiplate.jpg -------------------------------------------------------------------------------- /bpwpapcode/Chapter07/smallfugu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter07/smallfugu.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter10/mousecursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter10/mousecursor.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter11/mytanktex.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter11/mytanktex.jpg -------------------------------------------------------------------------------- /bpwpapcode/Chapter12/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter12/background.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter12/mytanktex.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter12/mytanktex.jpg -------------------------------------------------------------------------------- /bpwpapcode/Chapter12/tanksky/bk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter12/tanksky/bk.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter12/tanksky/dn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter12/tanksky/dn.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter12/tanksky/ft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter12/tanksky/ft.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter12/tanksky/lt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter12/tanksky/lt.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter12/tanksky/rt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter12/tanksky/rt.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter12/tanksky/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter12/tanksky/up.png -------------------------------------------------------------------------------- /bpwpapcode/Chapter10/music/please put some ogg files in the music folder.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-game-dev-w-python-pygame/HEAD/bpwpapcode/Chapter10/music/please put some ogg files in the music folder.ogg -------------------------------------------------------------------------------- /bpwpapcode/README.txt: -------------------------------------------------------------------------------- 1 | Some of the sample code require the Game Objects library (http://www.willmcgugan.com/game-objects/). Chapters 8, 9, 11 and 12 also require PyOpenGL. 2 | 3 | You can download both with the following commands. 4 | 5 | easy_install gameobjects 6 | easy_install pyopengl 7 | 8 | Need help? Email will@willmcgugan.com -------------------------------------------------------------------------------- /bpwpapcode/AppendixB/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | import py2exe 3 | 4 | setup( 5 | #version = "1.0", 6 | #description = "Ant State machine from Chapter7", 7 | #name = "antsstatemachine", 8 | windows = [{"script":"antsstatemachine.py"}], 9 | data_files = [ (".", ["ant.png", "leaf.png", "spider.png"]) ] 10 | ) 11 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter05/gotest.py: -------------------------------------------------------------------------------- 1 | from gameobjects.vector2 import * 2 | 3 | A = (10.0, 20.0) 4 | B = (30.0, 35.0) 5 | AB = Vector2.from_points(A, B) 6 | print "Vector AB is", AB 7 | print "AB * 2 is", AB * 2 8 | print "AB / 2 is", AB / 2 9 | print "AB + (-10, 5) is", AB + (-10, 5) 10 | print "Magnitude of AB is", AB.get_magnitude() 11 | print "AB normalized is", AB.get_normalized() -------------------------------------------------------------------------------- /bpwpapcode/Chapter11/mytank.mtl: -------------------------------------------------------------------------------- 1 | newmtl acmat_0 2 | Kd 1 1 1 3 | Ka 0.2 0.2 0.2 4 | Ks 0.2 0.2 0.2 5 | Ns 128 6 | Tr 0 7 | map_Kd booktex.png 8 | newmtl acmat_1 9 | Kd 1 1 1 10 | Ka 0.2 0.2 0.2 11 | Ks 0.2 0.2 0.2 12 | Ns 128 13 | Tr 0 14 | map_Kd bodytex.jpg 15 | newmtl acmat_2 16 | Kd 1 1 1 17 | Ka 0.2 0.2 0.2 18 | Ks 0.2 0.2 0.2 19 | Ns 128 20 | Tr 0 21 | map_Kd mytanktex.jpg 22 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter12/mytank.mtl: -------------------------------------------------------------------------------- 1 | newmtl acmat_0 2 | Kd 1 1 1 3 | Ka 0.2 0.2 0.2 4 | Ks 0.2 0.2 0.2 5 | Ns 128 6 | Tr 0 7 | map_Kd booktex.png 8 | newmtl acmat_1 9 | Kd 1 1 1 10 | Ka 0.2 0.2 0.2 11 | Ks 0.2 0.2 0.2 12 | Ns 128 13 | Tr 0 14 | map_Kd bodytex.jpg 15 | newmtl acmat_2 16 | Kd 1 1 1 17 | Ka 0.2 0.2 0.2 18 | Ks 0.2 0.2 0.2 19 | Ns 128 20 | Tr 0 21 | map_Kd mytanktex.jpg 22 | -------------------------------------------------------------------------------- /bpwpapcode/AppendixB/ants.iss: -------------------------------------------------------------------------------- 1 | [Setup] 2 | SolidCompression=true 3 | AppName=Ant State Machine 4 | AppVerName=Ant State Machine 1.0 5 | DefaultDirName={pf}\ant state machine 6 | DefaultGroupName=ant state machine 7 | ShowLanguageDialog=yes 8 | [Files] 9 | Source: dist\*.*; DestDir: {app} 10 | [Icons] 11 | Name: {group}\Launch Ants; Filename: {app}\antsstatemachine.exe; WorkingDir: {app} 12 | Name: {group}\Uninstall Ants; Filename: {uninstallexe} 13 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter04/allcolors.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | pygame.init() 3 | 4 | screen = pygame.display.set_mode((640, 480)) 5 | 6 | all_colors = pygame.Surface((4096,4096), depth=24) 7 | 8 | for r in xrange(256): 9 | print r+1, "out of 256" 10 | x = (r&15)*256 11 | y = (r>>4)*256 12 | for g in xrange(256): 13 | for b in xrange(256): 14 | all_colors.set_at((x+g, y+b), (r, g, b)) 15 | 16 | pygame.image.save(all_colors, "allcolors.bmp") -------------------------------------------------------------------------------- /bpwpapcode/Chapter05/vecmagniture.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | A = (10.0, 20.0) 4 | B = (30.0, 35.0) 5 | AB = (B[0]-A[0], B[1]-A[1]) 6 | 7 | print "AB is", AB 8 | 9 | def vector_magnitude(vec): 10 | return math.sqrt(vec[0] * vec[0] + vec[1] * vec[1]) 11 | 12 | print "Magnitude of AB is", vector_magnitude(AB) 13 | 14 | def unit_vector(vec): 15 | magnitude = vector_magnitude(vec) 16 | return (vec[0] / magnitude, vec[1] / magnitude) 17 | 18 | print "Unit vector of AB is (%s, %s)" % unit_vector(AB) 19 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter04/ellipsetest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import pygame 4 | from pygame.locals import * 5 | from sys import exit 6 | 7 | from random import * 8 | 9 | pygame.init() 10 | screen = pygame.display.set_mode((640, 480), 0, 32) 11 | 12 | while True: 13 | 14 | for event in pygame.event.get(): 15 | if event.type == QUIT: 16 | exit() 17 | 18 | x, y = pygame.mouse.get_pos() 19 | screen.fill((255,255,255)) 20 | pygame.draw.ellipse(screen, (0,255,0), (0,0,x,y)) 21 | 22 | pygame.display.update() 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Apress Source Code 2 | 3 | This repository accompanies [*Beginning Game Development with Python and Pygame*](http://www.apress.com/9781590598726) by Will McGugan (Apress, 2007). 4 | 5 | ![Cover image](9781590598726.jpg) 6 | 7 | Download the files as a zip using the green button, or clone the repository to your machine using Git. 8 | 9 | ## Releases 10 | 11 | Release v1.0 corresponds to the code in the published book, without corrections or updates. 12 | 13 | ## Contributions 14 | 15 | See the file Contributing.md for more information on how you can contribute to this repository. 16 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter08/vectordroid.py: -------------------------------------------------------------------------------- 1 | from gameobjects.vector3 import * 2 | 3 | A = (-6, 2, 2) 4 | B = (7, 5, 10) 5 | plasma_speed = 100. # meters per second 6 | 7 | AB = Vector3.from_points(A, B) 8 | print "Vector to droid is", AB 9 | 10 | distance_to_target = AB.get_magnitude() 11 | print "Distance to droid is", distance_to_target, "meters" 12 | 13 | plasma_heading = AB.get_normalized() 14 | print "Heading is", plasma_heading 15 | 16 | time_to_target = distance_to_target / plasma_speed 17 | print "Time to hit droid is", time_to_target, "seconds" 18 | 19 | #bolt_location += plasma_heading * time_passed_seconds + plasma_speed -------------------------------------------------------------------------------- /bpwpapcode/Chapter04/arctest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import pygame 4 | from pygame.locals import * 5 | from sys import exit 6 | 7 | from random import * 8 | from math import pi 9 | 10 | pygame.init() 11 | screen = pygame.display.set_mode((640, 480), 0, 32) 12 | 13 | while True: 14 | 15 | for event in pygame.event.get(): 16 | if event.type == QUIT: 17 | exit() 18 | 19 | x, y = pygame.mouse.get_pos() 20 | angle = (x/639.)*pi*2. 21 | screen.fill((255,255,255)) 22 | pygame.draw.arc(screen, (0,0,0), (0,0,639,479), 0, angle) 23 | 24 | pygame.display.update() 25 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter04/circletest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import pygame 4 | from pygame.locals import * 5 | from sys import exit 6 | 7 | from random import * 8 | 9 | pygame.init() 10 | screen = pygame.display.set_mode((640, 480), 0, 32) 11 | 12 | while True: 13 | 14 | for event in pygame.event.get(): 15 | if event.type == QUIT: 16 | exit() 17 | 18 | random_color = (randint(0,255), randint(0,255), randint(0,255)) 19 | random_pos = (randint(0,639), randint(0,479)) 20 | random_radius = randint(1,200) 21 | pygame.draw.circle(screen, random_color, random_pos, random_radius) 22 | 23 | pygame.display.update() 24 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter12/tanksky/skybox.mtl: -------------------------------------------------------------------------------- 1 | newmtl acmat_0 2 | Kd 1 1 1 3 | Ka 0.2 0.2 0.2 4 | Ks 0.2 0.2 0.2 5 | Ns 128 6 | Tr 0 7 | map_Kd rt.png 8 | newmtl acmat_1 9 | Kd 1 1 1 10 | Ka 0.2 0.2 0.2 11 | Ks 0.2 0.2 0.2 12 | Ns 128 13 | Tr 0 14 | map_Kd dn.png 15 | newmtl acmat_2 16 | Kd 1 1 1 17 | Ka 0.2 0.2 0.2 18 | Ks 0.2 0.2 0.2 19 | Ns 128 20 | Tr 0 21 | map_Kd up.png 22 | newmtl acmat_3 23 | Kd 1 1 1 24 | Ka 0.2 0.2 0.2 25 | Ks 0.2 0.2 0.2 26 | Ns 128 27 | Tr 0 28 | map_Kd ft.png 29 | newmtl acmat_4 30 | Kd 1 1 1 31 | Ka 0.2 0.2 0.2 32 | Ks 0.2 0.2 0.2 33 | Ns 128 34 | Tr 0 35 | map_Kd bk.png 36 | newmtl acmat_5 37 | Kd 1 1 1 38 | Ka 0.2 0.2 0.2 39 | Ks 0.2 0.2 0.2 40 | Ns 128 41 | Tr 0 42 | map_Kd lt.png 43 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to Apress Source Code 2 | 3 | Copyright for Apress source code belongs to the author(s). However, under fair use you are encouraged to fork and contribute minor corrections and updates for the benefit of the author(s) and other readers. 4 | 5 | ## How to Contribute 6 | 7 | 1. Make sure you have a GitHub account. 8 | 2. Fork the repository for the relevant book. 9 | 3. Create a new branch on which to make your change, e.g. 10 | `git checkout -b my_code_contribution` 11 | 4. Commit your change. Include a commit message describing the correction. Please note that if your commit message is not clear, the correction will not be accepted. 12 | 5. Submit a pull request. 13 | 14 | Thank you for your contribution! -------------------------------------------------------------------------------- /bpwpapcode/Chapter04/polytest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import pygame 4 | from pygame.locals import * 5 | from sys import exit 6 | 7 | pygame.init() 8 | screen = pygame.display.set_mode((640, 480), 0, 32) 9 | 10 | points = [] 11 | 12 | while True: 13 | 14 | for event in pygame.event.get(): 15 | if event.type == QUIT: 16 | exit() 17 | if event.type == MOUSEBUTTONDOWN: 18 | points.append(event.pos) 19 | 20 | screen.fill((255,255,255)) 21 | 22 | if len(points) >= 3: 23 | pygame.draw.polygon(screen, (0,255,0), points) 24 | for point in points: 25 | pygame.draw.circle(screen, (0,0,255), point, 5) 26 | 27 | pygame.display.update() 28 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter04/colrects.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import pygame 4 | from pygame.locals import * 5 | from sys import exit 6 | 7 | from random import * 8 | 9 | pygame.init() 10 | screen = pygame.display.set_mode((640, 480), 0, 32) 11 | 12 | 13 | while True: 14 | 15 | for event in pygame.event.get(): 16 | if event.type == QUIT: 17 | exit() 18 | 19 | screen.lock() 20 | for count in range(10): 21 | random_color = (randint(0,255), randint(0,255), randint(0,255)) 22 | random_pos = (randint(0,639), randint(0,479)) 23 | random_size = (639-randint(random_pos[0],639), 479-randint(random_pos[1],479)) 24 | pygame.draw.rect(screen, random_color, (random_pos, random_size)) 25 | screen.unlock() 26 | 27 | pygame.display.update() 28 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter03/events.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | 5 | pygame.init() 6 | SCREEN_SIZE = (640, 480) 7 | screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32) 8 | 9 | font = pygame.font.SysFont("arial", 16); 10 | font_height = font.get_linesize() 11 | event_text = [] 12 | 13 | 14 | while True: 15 | 16 | event = pygame.event.wait() 17 | event_text.append(str(event)) 18 | event_text = event_text[-SCREEN_SIZE[1]/font_height:] 19 | 20 | if event.type == QUIT: 21 | exit() 22 | 23 | screen.fill((255, 255, 255)) 24 | 25 | y = SCREEN_SIZE[1]-font_height 26 | for text in reversed(event_text): 27 | screen.blit( font.render(text, True, (0, 0, 0)), (0, y) ) 28 | y-=font_height 29 | 30 | pygame.display.update() 31 | 32 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter03/fullscreentest.py: -------------------------------------------------------------------------------- 1 | background_image_filename = 'sushiplate.jpg' 2 | 3 | import pygame 4 | from pygame.locals import * 5 | from sys import exit 6 | 7 | pygame.init() 8 | screen = pygame.display.set_mode((640, 480), 0, 32) 9 | background = pygame.image.load(background_image_filename).convert() 10 | 11 | Fullscreen = False 12 | 13 | while True: 14 | 15 | for event in pygame.event.get(): 16 | if event.type == QUIT: 17 | exit() 18 | if event.type == KEYDOWN: 19 | if event.key == K_f: 20 | Fullscreen = not Fullscreen 21 | if Fullscreen: 22 | screen = pygame.display.set_mode((640, 480), FULLSCREEN, 32) 23 | else: 24 | screen = pygame.display.set_mode((640, 480), 0, 32) 25 | 26 | screen.blit(background, (0,0)) 27 | pygame.display.update() 28 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter04/multiplelines.py: -------------------------------------------------------------------------------- 1 | background_image_filename = 'sushiplate.jpg' 2 | 3 | import pygame 4 | from pygame.locals import * 5 | from sys import exit 6 | 7 | pygame.init() 8 | screen = pygame.display.set_mode((640, 480), 0, 32) 9 | background = pygame.image.load(background_image_filename).convert() 10 | 11 | Fullscreen = False 12 | 13 | while True: 14 | 15 | for event in pygame.event.get(): 16 | if event.type == QUIT: 17 | exit() 18 | if event.type == KEYDOWN: 19 | if event.key == K_f: 20 | Fullscreen = not Fullscreen 21 | if Fullscreen: 22 | screen = pygame.display.set_mode((640, 480), FULLSCREEN, 32) 23 | else: 24 | screen = pygame.display.set_mode((640, 480), 0, 32) 25 | 26 | screen.blit(background, (0,0)) 27 | pygame.display.update() 28 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter05/simplemove.py: -------------------------------------------------------------------------------- 1 | background_image_filename = 'sushiplate.jpg' 2 | sprite_image_filename = 'fugu.png' 3 | 4 | import pygame 5 | from pygame.locals import * 6 | from sys import exit 7 | 8 | pygame.init() 9 | 10 | screen = pygame.display.set_mode((640, 480), 0, 32) 11 | 12 | background = pygame.image.load(background_image_filename).convert() 13 | sprite = pygame.image.load(sprite_image_filename) 14 | 15 | # The X coordinate of our sprite 16 | x = 0. 17 | 18 | while True: 19 | 20 | for event in pygame.event.get(): 21 | if event.type == QUIT: 22 | exit() 23 | 24 | screen.blit(background, (0,0)) 25 | screen.blit(sprite, (x, 100)) 26 | x+= 10. 27 | 28 | # If the image goes off the end of the screen, move it back 29 | if x > 640.: 30 | x = 0. 31 | 32 | pygame.display.update() 33 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter03/helloworld.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | background_image_filename = 'sushiplate.jpg' 4 | mouse_image_filename = 'fugu.png' 5 | 6 | import pygame 7 | from pygame.locals import * 8 | from sys import exit 9 | 10 | pygame.init() 11 | 12 | screen = pygame.display.set_mode((640, 480), 0, 32) 13 | pygame.display.set_caption("Hello, World!") 14 | 15 | background = pygame.image.load(background_image_filename).convert() 16 | mouse_cursor = pygame.image.load(mouse_image_filename) 17 | 18 | while True: 19 | 20 | for event in pygame.event.get(): 21 | if event.type == QUIT: 22 | exit() 23 | 24 | screen.blit(background, (0,0)) 25 | 26 | x, y = pygame.mouse.get_pos() 27 | x-= mouse_cursor.get_width() / 2 28 | y-= mouse_cursor.get_height() / 2 29 | screen.blit(mouse_cursor, (x, y)) 30 | 31 | pygame.display.update() 32 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter04/drawinglines.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import pygame 4 | from pygame.locals import * 5 | from sys import exit 6 | 7 | pygame.init() 8 | screen = pygame.display.set_mode((640, 480), 0, 32) 9 | 10 | 11 | 12 | while True: 13 | 14 | for event in pygame.event.get(): 15 | if event.type == QUIT: 16 | exit() 17 | 18 | screen.fill((255, 255, 255)) 19 | 20 | mouse_pos = pygame.mouse.get_pos() 21 | 22 | for x in xrange(0,640,20): 23 | pygame.draw.aaline(screen, (0, 0, 0), (x, 0), mouse_pos) 24 | pygame.draw.aaline(screen, (0, 0, 0), (x, 479), mouse_pos) 25 | 26 | for y in xrange(0,480,20): 27 | pygame.draw.line(screen, (0, 0, 0), (0, y), mouse_pos) 28 | pygame.draw.line(screen, (0, 0, 0), (639, y), mouse_pos) 29 | 30 | pygame.display.update() 31 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter06/keydemo.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | 5 | pygame.init() 6 | screen = pygame.display.set_mode((640, 480), 0, 32) 7 | 8 | font = pygame.font.SysFont("arial", 32); 9 | font_height = font.get_linesize() 10 | 11 | while True: 12 | 13 | for event in pygame.event.get(): 14 | if event.type == QUIT: 15 | exit() 16 | 17 | screen.fill((255, 255, 255)) 18 | 19 | pressed_key_text = [] 20 | pressed_keys = pygame.key.get_pressed() 21 | y = font_height 22 | 23 | for key_constant, pressed in enumerate(pressed_keys): 24 | if pressed: 25 | key_name = pygame.key.name(key_constant) 26 | text_surface = font.render(key_name+" pressed (%i)"%key_constant, True, (0,0,0)) 27 | screen.blit(text_surface, (8, y) ) 28 | y+= font_height 29 | 30 | pygame.display.update() 31 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter03/resize.py: -------------------------------------------------------------------------------- 1 | background_image_filename = 'sushiplate.jpg' 2 | 3 | import pygame 4 | from pygame.locals import * 5 | from sys import exit 6 | 7 | SCREEN_SIZE = (640, 480) 8 | 9 | pygame.init() 10 | screen = pygame.display.set_mode(SCREEN_SIZE, RESIZABLE, 32) 11 | 12 | background = pygame.image.load(background_image_filename).convert() 13 | 14 | while True: 15 | 16 | event = pygame.event.wait() 17 | if event.type == QUIT: 18 | exit() 19 | if event.type == VIDEORESIZE: 20 | SCREEN_SIZE = event.size 21 | screen = pygame.display.set_mode(SCREEN_SIZE, RESIZABLE, 32) 22 | pygame.display.set_caption("Window resized to "+str(event.size)) 23 | 24 | screen_width, screen_height = SCREEN_SIZE 25 | for y in range(0, screen_height, background.get_height()): 26 | for x in range(0, screen_width, background.get_width()): 27 | screen.blit(background, (x, y)) 28 | 29 | pygame.display.update() -------------------------------------------------------------------------------- /bpwpapcode/Chapter08/vector3test.py: -------------------------------------------------------------------------------- 1 | from gameobjects.vector3 import * 2 | 3 | A = Vector3(6, 8, 12) 4 | B = Vector3(10, 16, 12) 5 | 6 | print "A is", A 7 | print "B is", B 8 | print "Length of A is", A.get_magnitude() 9 | print "A+B is", A+B 10 | print "A-B is", A-B 11 | print "A normalized is", A.get_normalized() 12 | print "A*2 is", A * 2 13 | 14 | class Vector3(object): 15 | 16 | def __init__(self, x, y, z): 17 | 18 | self.x = x 19 | self.y = y 20 | self.z = z 21 | 22 | def __add__(self, rhs): 23 | 24 | return Vector3(self.x + rhs.x, self.y + rhs.y, self.y + rhs.y) 25 | 26 | def __sub__(self, rhs): 27 | 28 | return Vector3(self.x - rhs.x, self.y - rhs.y, self.y - rhs.y) 29 | 30 | def isographic_projection(vector3): 31 | 32 | return (vector3.x, vector3.y) 33 | 34 | def perspective_projection(vector3, d): 35 | 36 | x, y, z = vector3 37 | return (x * d/z, y * d/z) -------------------------------------------------------------------------------- /bpwpapcode/Chapter03/scrolly.py: -------------------------------------------------------------------------------- 1 | background_image_filename = 'sushiplate.jpg' 2 | SCREEN_SIZE = (640, 480) 3 | message=" This is a demonstration of the scrolly message script. " 4 | 5 | import pygame 6 | from pygame.locals import * 7 | from sys import exit 8 | 9 | pygame.init() 10 | screen = pygame.display.set_mode(SCREEN_SIZE) 11 | 12 | font = pygame.font.SysFont("arial", 80); 13 | text_surface = font.render(message, True, (0, 0, 255)) 14 | 15 | x = 0 16 | y = ( SCREEN_SIZE[1] - text_surface.get_height() ) / 2 17 | 18 | background = pygame.image.load(background_image_filename).convert() 19 | 20 | while True: 21 | 22 | for event in pygame.event.get(): 23 | if event.type == QUIT: 24 | exit() 25 | 26 | screen.blit(background, (0,0)) 27 | 28 | x-= 2 29 | if x < -text_surface.get_width(): 30 | x = 0 31 | 32 | screen.blit(text_surface, (x, y)) 33 | screen.blit(text_surface, (x+text_surface.get_width(), y)) 34 | 35 | pygame.display.update() -------------------------------------------------------------------------------- /bpwpapcode/Chapter02/tankgame.py: -------------------------------------------------------------------------------- 1 | from tank import Tank 2 | 3 | tanks = { "a":Tank("Alice"), "b":Tank("Bob"), "c":Tank("Carol") } 4 | alive_tanks = len(tanks) 5 | 6 | while alive_tanks > 1: 7 | 8 | print 9 | for tank_name in sorted( tanks.keys() ): 10 | print tank_name, tanks[tank_name] 11 | 12 | first = raw_input("Who fires? ").lower() 13 | second = raw_input("Who at? " ).lower() 14 | 15 | try: 16 | first_tank = tanks[first] 17 | second_tank = tanks[second] 18 | except KeyError: 19 | print "No such tank!" 20 | continue 21 | 22 | if not first_tank.alive or not second_tank.alive: 23 | print "One of those tanks is dead!" 24 | continue 25 | 26 | print 27 | print "*"*30 28 | 29 | first_tank.fire_at(second_tank) 30 | if not second_tank.alive: 31 | alive_tanks-= 1 32 | 33 | print "*"*30 34 | 35 | for tank in tanks.values(): 36 | if tank.alive: 37 | print tank.name, "is the winner!" 38 | break 39 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter05/timebasedmovement.py: -------------------------------------------------------------------------------- 1 | background_image_filename = 'sushiplate.jpg' 2 | sprite_image_filename = 'fugu.png' 3 | 4 | import pygame 5 | from pygame.locals import * 6 | from sys import exit 7 | 8 | pygame.init() 9 | 10 | screen = pygame.display.set_mode((640, 480), 0, 32) 11 | 12 | background = pygame.image.load(background_image_filename).convert() 13 | sprite = pygame.image.load(sprite_image_filename) 14 | 15 | # Our clock object 16 | clock = pygame.time.Clock() 17 | 18 | # X coordinate of our sprite 19 | x = 0. 20 | # Speed in pixels per second 21 | speed = 250. 22 | 23 | while True: 24 | 25 | for event in pygame.event.get(): 26 | if event.type == QUIT: 27 | exit() 28 | 29 | screen.blit(background, (0,0)) 30 | screen.blit(sprite, (x, 100)) 31 | 32 | time_passed = clock.tick() 33 | time_passed_seconds = time_passed / 1000.0 34 | 35 | distance_moved = time_passed_seconds * speed 36 | x += distance_moved 37 | 38 | # If the image goes off the end of the screen, move it back 39 | if x > 640.: 40 | x = 0. 41 | 42 | pygame.display.update() 43 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter02/tank.py: -------------------------------------------------------------------------------- 1 | 2 | class Tank(object): 3 | 4 | def __init__(self, name): 5 | 6 | self.name = name 7 | self.alive = True 8 | self.ammo = 5 9 | self.armor = 60 10 | 11 | def __str__(self): 12 | 13 | if self.alive: 14 | return "%s (%i armor, %i shells)"%(self.name, self.armor, self.ammo) 15 | #return self.name+" ("+str(self.armor)+" armor, "+str(self.ammo)+" shells)" 16 | else: 17 | return "%s (DEAD)"%self.name 18 | 19 | def fire_at(self, enemy): 20 | 21 | if self.ammo >= 1: 22 | self.ammo-= 1 23 | print self.name, "fires on", enemy.name 24 | enemy.hit() 25 | else: 26 | print self.name, "has no shells!" 27 | 28 | def hit(self): 29 | 30 | self.armor-= 20 31 | print self.name, "is hit!" 32 | if self.armor <= 0: 33 | self.explode() 34 | 35 | def explode(self): 36 | 37 | self.alive = False 38 | print self.name, "explodes!" 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter06/hatscroll.py: -------------------------------------------------------------------------------- 1 | picture_file = 'cat.jpg' 2 | 3 | import pygame 4 | from pygame.locals import * 5 | from sys import exit 6 | from gameobjects.vector2 import Vector2 7 | 8 | pygame.init() 9 | screen = pygame.display.set_mode((640, 480), 0, 32) 10 | 11 | picture = pygame.image.load(picture_file) 12 | picture_pos = Vector2(0, 0) 13 | scroll_speed = 1000. 14 | 15 | clock = pygame.time.Clock() 16 | 17 | joystick = None 18 | if pygame.joystick.get_count() > 0: 19 | joystick = pygame.joystick.Joystick(0) 20 | joystick.init() 21 | 22 | if joystick is None: 23 | print "Sorry, you need a joystick for this!" 24 | exit() 25 | 26 | while True: 27 | 28 | for event in pygame.event.get(): 29 | if event.type == QUIT: 30 | exit() 31 | 32 | scroll_direction = Vector2(*joystick.get_hat(0)) 33 | scroll_direction.normalize() 34 | 35 | screen.fill((255, 255, 255)) 36 | screen.blit(picture, (-picture_pos.x, picture_pos.y)) 37 | 38 | time_passed = clock.tick() 39 | time_passed_seconds = time_passed / 1000.0 40 | 41 | picture_pos += scroll_direction * scroll_speed * time_passed_seconds 42 | 43 | pygame.display.update() 44 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter06/joystickevents.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | 5 | pygame.init() 6 | 7 | SCREEN_SIZE = (640, 480) 8 | screen = pygame.display.set_mode( SCREEN_SIZE, 0, 32) 9 | 10 | font = pygame.font.SysFont("arial", 16); 11 | font_height = font.get_linesize() 12 | event_text = [] 13 | 14 | joysticks = [] 15 | for joystick_no in xrange(pygame.joystick.get_count()): 16 | stick = pygame.joystick.Joystick(joystick_no) 17 | stick.init() 18 | joysticks.append(stick) 19 | 20 | while True: 21 | 22 | event = pygame.event.wait() 23 | if event.type in (JOYAXISMOTION, 24 | JOYBALLMOTION, 25 | JOYHATMOTION, 26 | JOYBUTTONUP, 27 | JOYBUTTONDOWN): 28 | event_text.append(str(event)) 29 | 30 | event_text = event_text[-SCREEN_SIZE[1]/font_height:] 31 | 32 | if event.type == QUIT: 33 | exit() 34 | 35 | screen.fill((255, 255, 255)) 36 | 37 | y = SCREEN_SIZE[1]-font_height 38 | for text in reversed(event_text): 39 | screen.blit( font.render(text, True, (0, 0, 0)), (0, y) ) 40 | y-=font_height 41 | 42 | pygame.display.update() 43 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter05/vectormovement.py: -------------------------------------------------------------------------------- 1 | background_image_filename = 'sushiplate.jpg' 2 | sprite_image_filename = 'fugu.png' 3 | 4 | import pygame 5 | from pygame.locals import * 6 | from sys import exit 7 | from gameobjects.vector2 import Vector2 8 | 9 | pygame.init() 10 | 11 | screen = pygame.display.set_mode((640, 480), 0, 32) 12 | 13 | background = pygame.image.load(background_image_filename).convert() 14 | sprite = pygame.image.load(sprite_image_filename).convert_alpha() 15 | 16 | clock = pygame.time.Clock() 17 | 18 | position = Vector2(100.0, 100.0) 19 | heading = Vector2() 20 | 21 | while True: 22 | 23 | for event in pygame.event.get(): 24 | if event.type == QUIT: 25 | exit() 26 | 27 | 28 | screen.blit(background, (0,0)) 29 | screen.blit(sprite, position) 30 | 31 | time_passed = clock.tick() 32 | time_passed_seconds = time_passed / 1000.0 33 | 34 | destination = Vector2( *pygame.mouse.get_pos() ) - Vector2( *sprite.get_size() )/2 35 | vector_to_mouse = Vector2.from_points(position, destination) 36 | vector_to_mouse.normalize() 37 | 38 | heading = heading + (vector_to_mouse *.6) 39 | 40 | position += heading * time_passed_seconds 41 | pygame.display.update() 42 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter05/frameratecompare.py: -------------------------------------------------------------------------------- 1 | background_image_filename = 'sushiplate.jpg' 2 | sprite_image_filename = 'fugu.png' 3 | 4 | import pygame 5 | from pygame.locals import * 6 | from sys import exit 7 | 8 | pygame.init() 9 | 10 | screen = pygame.display.set_mode((640, 480), 0, 32) 11 | 12 | background = pygame.image.load(background_image_filename).convert() 13 | sprite = pygame.image.load(sprite_image_filename) 14 | 15 | # Our clock object 16 | clock = pygame.time.Clock() 17 | 18 | x1 = 0. 19 | x2 = 0. 20 | # Speed in pixels per second 21 | speed = 250. 22 | 23 | frame_no = 0 24 | 25 | while True: 26 | 27 | for event in pygame.event.get(): 28 | if event.type == QUIT: 29 | exit() 30 | 31 | screen.blit(background, (0,0)) 32 | screen.blit(sprite, (x1, 50)) 33 | screen.blit(sprite, (x2, 250)) 34 | 35 | time_passed = clock.tick() 36 | time_passed_seconds = time_passed / 1000.0 37 | 38 | distance_moved = time_passed_seconds * speed 39 | x1 += distance_moved 40 | 41 | if (frame_no % 5) == 0: 42 | distance_moved = time_passed_seconds * speed 43 | x2 += distance_moved * 5. 44 | 45 | # If the image goes off the end of the screen, move it back 46 | if x1 > 640.: 47 | x1 -= 640. 48 | if x2 > 640.: 49 | x2 -= 640. 50 | 51 | pygame.display.update() 52 | frame_no += 1 53 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter05/simplevec.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | class Vector2(object): 4 | 5 | def __init__(self, x=0., y=0.): 6 | self.x = x 7 | self.y = y 8 | 9 | def __str__(self): 10 | return "(%s, %s)"%(self.x, self.y) 11 | 12 | @staticmethod 13 | def from_points(P1, P2): 14 | return Vector2( P2[0] - P1[0], P2[1] - P1[1] ) 15 | 16 | def get_magnitude(self): 17 | return math.sqrt( self.x**2 + self.y**2 ) 18 | 19 | def normalize(self): 20 | magnitude = self.get_magnitude() 21 | self.x /= magnitude 22 | self.y /= magnitude 23 | 24 | def __add__(self, rhs): 25 | return Vector2(self.x + rhs.x, self.y + rhs.y) 26 | 27 | def __sub__(self, rhs): 28 | return Vector2(self.x - rhs.x, self.y - rhs.y) 29 | 30 | def __neg__(self): 31 | return Vector2(-self.x, -self.y) 32 | 33 | def __mul__(self, scalar): 34 | return Vector2(self.x * scalar, self.y * scalar) 35 | 36 | def __div__(self, scalar): 37 | return Vector2(self.x / scalar, self.y / scalar) 38 | 39 | 40 | A = (10.0, 20.0) 41 | B = (30.0, 35.0) 42 | AB = Vector2.from_points(A, B) 43 | step = AB * .1 44 | position = Vector2(*A) 45 | for n in range(10): 46 | position += step 47 | print position 48 | 49 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter06/keymovement.py: -------------------------------------------------------------------------------- 1 | background_image_filename = 'sushiplate.jpg' 2 | sprite_image_filename = 'fugu.png' 3 | 4 | import pygame 5 | from pygame.locals import * 6 | from sys import exit 7 | from gameobjects.vector2 import Vector2 8 | 9 | pygame.init() 10 | 11 | screen = pygame.display.set_mode((640, 480), 0, 32) 12 | 13 | background = pygame.image.load(background_image_filename).convert() 14 | sprite = pygame.image.load(sprite_image_filename).convert_alpha() 15 | 16 | clock = pygame.time.Clock() 17 | 18 | sprite_pos = Vector2(200, 150) 19 | sprite_speed = 300. 20 | 21 | while True: 22 | 23 | for event in pygame.event.get(): 24 | if event.type == QUIT: 25 | exit() 26 | 27 | pressed_keys = pygame.key.get_pressed() 28 | 29 | key_direction = Vector2(0, 0) 30 | if pressed_keys[K_LEFT]: 31 | key_direction.x = -1 32 | elif pressed_keys[K_RIGHT]: 33 | key_direction.x = +1 34 | if pressed_keys[K_UP]: 35 | key_direction.y = -1 36 | elif pressed_keys[K_DOWN]: 37 | key_direction.y = +1 38 | 39 | key_direction.normalize() 40 | 41 | screen.blit(background, (0,0)) 42 | screen.blit(sprite, sprite_pos) 43 | 44 | time_passed = clock.tick(30) 45 | time_passed_seconds = time_passed / 1000.0 46 | 47 | sprite_pos+= key_direction * sprite_speed * time_passed_seconds 48 | 49 | pygame.display.update() 50 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter06/diagonalmovement.py: -------------------------------------------------------------------------------- 1 | background_image_filename = 'sushiplate.jpg' 2 | sprite_image_filename = 'fugu.png' 3 | 4 | import pygame 5 | from pygame.locals import * 6 | from sys import exit 7 | from gameobjects.vector2 import Vector2 8 | 9 | pygame.init() 10 | 11 | screen = pygame.display.set_mode((640, 480), 0, 32) 12 | 13 | background = pygame.image.load(background_image_filename).convert() 14 | sprite = pygame.image.load(sprite_image_filename).convert_alpha() 15 | 16 | clock = pygame.time.Clock() 17 | 18 | sprite_pos = Vector2(200, 150) 19 | sprite_speed = 300. 20 | 21 | while True: 22 | 23 | for event in pygame.event.get(): 24 | if event.type == QUIT: 25 | exit() 26 | 27 | pressed_keys = pygame.key.get_pressed() 28 | 29 | key_direction = Vector2(0, 0) 30 | if pressed_keys[K_LEFT]: 31 | key_direction.x = -1 32 | elif pressed_keys[K_RIGHT]: 33 | key_direction.x = +1 34 | if pressed_keys[K_UP]: 35 | key_direction.y = -1 36 | elif pressed_keys[K_DOWN]: 37 | key_direction.y = +1 38 | 39 | key_direction.normalize() 40 | 41 | screen.blit(background, (0,0)) 42 | screen.blit(sprite, sprite_pos) 43 | 44 | time_passed = clock.tick(30) 45 | time_passed_seconds = time_passed / 1000.0 46 | 47 | sprite_pos+= key_direction * sprite_speed * time_passed_seconds 48 | 49 | pygame.display.update() 50 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter06/simplekeyboardmovement.py: -------------------------------------------------------------------------------- 1 | background_image_filename = 'sushiplate.jpg' 2 | sprite_image_filename = 'fugu.png' 3 | 4 | import pygame 5 | from pygame.locals import * 6 | from sys import exit 7 | from gameobjects.vector2 import Vector2 8 | 9 | pygame.init() 10 | 11 | screen = pygame.display.set_mode((640, 480), 0, 32) 12 | 13 | background = pygame.image.load(background_image_filename).convert() 14 | sprite = pygame.image.load(sprite_image_filename).convert_alpha() 15 | 16 | clock = pygame.time.Clock() 17 | 18 | sprite_pos = Vector2(200, 150) 19 | sprite_speed = 300. 20 | 21 | while True: 22 | 23 | for event in pygame.event.get(): 24 | if event.type == QUIT: 25 | exit() 26 | 27 | pressed_keys = pygame.key.get_pressed() 28 | 29 | key_direction = Vector2(0, 0) 30 | if pressed_keys[K_LEFT]: 31 | key_direction.x = -1 32 | elif pressed_keys[K_RIGHT]: 33 | key_direction.x = +1 34 | if pressed_keys[K_UP]: 35 | key_direction.y = -1 36 | elif pressed_keys[K_DOWN]: 37 | key_direction.y = +1 38 | 39 | #key_direction.normalize() 40 | 41 | screen.blit(background, (0,0)) 42 | screen.blit(sprite, sprite_pos) 43 | 44 | time_passed = clock.tick() 45 | time_passed_seconds = time_passed / 1000.0 46 | 47 | sprite_pos+= key_direction * sprite_speed * time_passed_seconds 48 | 49 | pygame.display.update() 50 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter05/diagonalmovement.py: -------------------------------------------------------------------------------- 1 | background_image_filename = 'sushiplate.jpg' 2 | sprite_image_filename = 'fugu.png' 3 | 4 | import pygame 5 | from pygame.locals import * 6 | from sys import exit 7 | 8 | pygame.init() 9 | 10 | screen = pygame.display.set_mode((640, 480), 0, 32) 11 | 12 | background = pygame.image.load(background_image_filename).convert() 13 | sprite = pygame.image.load(sprite_image_filename).convert_alpha() 14 | 15 | clock = pygame.time.Clock() 16 | 17 | x, y = 100., 100. 18 | speed_x, speed_y = 133., 170. 19 | 20 | while True: 21 | 22 | for event in pygame.event.get(): 23 | if event.type == QUIT: 24 | exit() 25 | 26 | screen.blit(background, (0,0)) 27 | screen.blit(sprite, (x, y)) 28 | 29 | time_passed = clock.tick(30) 30 | time_passed_seconds = time_passed / 1000.0 31 | 32 | x += speed_x * time_passed_seconds 33 | y += speed_y * time_passed_seconds 34 | 35 | # If the sprite goes off the edge of the screen, 36 | # make it move in the opposite direction 37 | if x > 640 - sprite.get_width(): 38 | speed_x = -speed_x 39 | x = 640 - sprite.get_width() 40 | elif x < 0: 41 | speed_x = -speed_x 42 | x = 0. 43 | 44 | if y > 480 - sprite.get_height(): 45 | speed_y = -speed_y 46 | y = 480 - sprite.get_height() 47 | elif y < 0: 48 | speed_y = -speed_y 49 | y = 0 50 | 51 | pygame.display.update() 52 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter06/analoguehatscroll.py: -------------------------------------------------------------------------------- 1 | picture_file = 'cat.jpg' 2 | 3 | import pygame 4 | from pygame.locals import * 5 | from sys import exit 6 | from gameobjects.vector2 import Vector2 7 | 8 | pygame.init() 9 | screen = pygame.display.set_mode((640, 480), 0, 32) 10 | 11 | picture = pygame.image.load(picture_file).convert() 12 | picture_pos = Vector2(0, 0) 13 | scroll_speed = 1000. 14 | 15 | clock = pygame.time.Clock() 16 | 17 | joystick = None 18 | if pygame.joystick.get_count() > 0: 19 | joystick = pygame.joystick.Joystick(0) 20 | joystick.init() 21 | 22 | if joystick is None: 23 | print "Sorry, you need a joystick for this!" 24 | exit() 25 | 26 | while True: 27 | 28 | for event in pygame.event.get(): 29 | if event.type == QUIT: 30 | exit() 31 | 32 | scroll_direction = Vector2(0, 0) 33 | if joystick.get_numhats() > 0: 34 | scroll_direction = Vector2(*joystick.get_hat(0)) 35 | scroll_direction.normalize() 36 | 37 | analogue_scroll = Vector2(0, 0) 38 | if joystick.get_numaxes() >= 2: 39 | axis_x = joystick.get_axis(0) 40 | axis_y = joystick.get_axis(1) 41 | analogue_scroll = Vector2(axis_x, -axis_y) 42 | analogue_scroll *= scroll_speed 43 | 44 | screen.fill((255, 255, 255)) 45 | screen.blit(picture, (-picture_pos.x, picture_pos.y)) 46 | 47 | time_passed = clock.tick() 48 | time_passed_seconds = time_passed / 1000.0 49 | 50 | picture_pos += scroll_direction * scroll_speed * time_passed_seconds 51 | picture_pos += analogue_scroll * time_passed_seconds 52 | 53 | pygame.display.update() 54 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter08/parallaxstars.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from random import randint 4 | 5 | class Star(object): 6 | 7 | def __init__(self, x, y, speed): 8 | 9 | self.x = x 10 | self.y = y 11 | self.speed = speed 12 | 13 | 14 | def run(): 15 | 16 | pygame.init() 17 | screen = pygame.display.set_mode((640, 480), FULLSCREEN) 18 | 19 | stars = [] 20 | 21 | # Add a few stars for the first frame 22 | for n in xrange(200): 23 | 24 | x = float(randint(0, 639)) 25 | y = float(randint(0, 479)) 26 | speed = float(randint(10, 300)) 27 | stars.append( Star(x, y, speed) ) 28 | 29 | clock = pygame.time.Clock() 30 | 31 | white = (255, 255, 255) 32 | 33 | while True: 34 | 35 | for event in pygame.event.get(): 36 | if event.type == QUIT: 37 | return 38 | if event.type == KEYDOWN: 39 | return 40 | 41 | # Add a new star 42 | y = float(randint(0, 479)) 43 | speed = float(randint(10, 300)) 44 | star = Star(640., y, speed) 45 | stars.append(star) 46 | 47 | time_passed = clock.tick() 48 | time_passed_seconds = time_passed / 1000. 49 | 50 | screen.fill((0, 0, 0)) 51 | 52 | # Draw the stars 53 | for star in stars: 54 | 55 | new_x = star.x - time_passed_seconds * star.speed 56 | pygame.draw.aaline(screen, white, (new_x, star.y), (star.x+1., star.y)) 57 | star.x = new_x 58 | 59 | def on_screen(star): 60 | return star.x > 0 61 | 62 | # Remove stars that are no longer visible 63 | stars = filter(on_screen, stars) 64 | 65 | pygame.display.update() 66 | 67 | 68 | if __name__ == "__main__": 69 | run() -------------------------------------------------------------------------------- /bpwpapcode/Chapter04/colortest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import pygame 3 | from pygame.locals import * 4 | from sys import exit 5 | 6 | pygame.init() 7 | 8 | screen = pygame.display.set_mode((640, 480), 0, 32) 9 | 10 | def create_scales(height): 11 | red_scale_surface = pygame.surface.Surface((640, height)) 12 | green_scale_surface = pygame.surface.Surface((640, height)) 13 | blue_scale_surface = pygame.surface.Surface((640, height)) 14 | for x in range(640): 15 | c = int((x/640.)*255.) 16 | red = (c, 0, 0) 17 | green = (0, c, 0) 18 | blue = (0, 0, c) 19 | line_rect = Rect(x, 0, 1, height) 20 | pygame.draw.rect(red_scale_surface, red, line_rect) 21 | pygame.draw.rect(green_scale_surface, green, line_rect) 22 | pygame.draw.rect(blue_scale_surface, blue, line_rect) 23 | return red_scale_surface, green_scale_surface, blue_scale_surface 24 | 25 | red_scale, green_scale, blue_scale = create_scales(80) 26 | 27 | color = [127, 127, 127] 28 | 29 | while True: 30 | 31 | for event in pygame.event.get(): 32 | if event.type == QUIT: 33 | exit() 34 | 35 | screen.fill((0, 0, 0)) 36 | 37 | screen.blit(red_scale, (0, 00)) 38 | screen.blit(green_scale, (0, 80)) 39 | screen.blit(blue_scale, (0, 160)) 40 | 41 | x, y = pygame.mouse.get_pos() 42 | 43 | if pygame.mouse.get_pressed()[0]: 44 | for component in range(3): 45 | if y > component*80 and y < (component+1)*80: 46 | color[component] = int((x/639.)*255.) 47 | pygame.display.set_caption("PyGame Color Test - "+str(tuple(color))) 48 | 49 | for component in range(3): 50 | pos = ( int((color[component]/255.)*639), component*80+40 ) 51 | pygame.draw.circle(screen, (255, 255, 255), pos, 20) 52 | 53 | pygame.draw.rect(screen, tuple(color), (0, 240, 640, 240)) 54 | 55 | pygame.display.update() 56 | 57 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter06/keyrotatemovement.py: -------------------------------------------------------------------------------- 1 | background_image_filename = 'sushiplate.jpg' 2 | sprite_image_filename = 'fugu.png' 3 | 4 | import pygame 5 | from pygame.locals import * 6 | from sys import exit 7 | from gameobjects.vector2 import Vector2 8 | from math import * 9 | 10 | pygame.init() 11 | 12 | screen = pygame.display.set_mode((640, 480), 0, 32) 13 | 14 | background = pygame.image.load(background_image_filename).convert() 15 | sprite = pygame.image.load(sprite_image_filename).convert_alpha() 16 | 17 | clock = pygame.time.Clock() 18 | 19 | sprite_pos = Vector2(200, 150) 20 | sprite_speed = 300. 21 | sprite_rotation = 0. 22 | sprite_rotation_speed = 360. # Degrees per second 23 | 24 | while True: 25 | 26 | for event in pygame.event.get(): 27 | if event.type == QUIT: 28 | exit() 29 | 30 | pressed_keys = pygame.key.get_pressed() 31 | 32 | rotation_direction = 0. 33 | movement_direction = 0. 34 | 35 | if pressed_keys[K_LEFT]: 36 | rotation_direction = +1. 37 | if pressed_keys[K_RIGHT]: 38 | rotation_direction = -1. 39 | if pressed_keys[K_UP]: 40 | movement_direction = +1. 41 | if pressed_keys[K_DOWN]: 42 | movement_direction = -1. 43 | 44 | screen.blit(background, (0,0)) 45 | 46 | rotated_sprite = pygame.transform.rotate(sprite, sprite_rotation) 47 | w, h = rotated_sprite.get_size() 48 | sprite_draw_pos = Vector2(sprite_pos.x-w/2, sprite_pos.y-h/2) 49 | screen.blit(rotated_sprite, sprite_draw_pos) 50 | 51 | time_passed = clock.tick() 52 | time_passed_seconds = time_passed / 1000.0 53 | 54 | sprite_rotation += rotation_direction * sprite_rotation_speed * time_passed_seconds 55 | 56 | heading_x = sin(sprite_rotation*pi/180.) 57 | heading_y = cos(sprite_rotation*pi/180.) 58 | heading = Vector2(heading_x, heading_y) 59 | heading *= movement_direction 60 | 61 | sprite_pos+= heading * sprite_speed * time_passed_seconds 62 | 63 | pygame.display.update() 64 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter12/tanksky/skybox.obj: -------------------------------------------------------------------------------- 1 | mtllib skybox.mtl 2 | v -0.5 0.5 0.5 3 | v -0.5 -0.5 0.5 4 | v -0.5 -0.5 -0.5 5 | v -0.5 0.5 -0.5 6 | vn 1 0 0 7 | vn 1 0 0 8 | vn 1 0 0 9 | vn 1 0 0 10 | vn 1 0 0 11 | vn 1 0 0 12 | vt 1 0 13 | vt 0 0 14 | vt 1 1 15 | vt 0 1 16 | vt 1 1 17 | vt 0 0 18 | usemtl acmat_0 19 | f 2/1/1 3/2/2 1/3/3 20 | f 4/4/4 1/5/5 3/6/6 21 | v -0.5 -0.5 0.5 22 | v 0.5 -0.5 0.5 23 | v 0.5 -0.5 -0.5 24 | v -0.5 -0.5 -0.5 25 | vn 0 1 0 26 | vn 0 1 0 27 | vn 0 1 0 28 | vn 0 1 0 29 | vn 0 1 0 30 | vn 0 1 0 31 | vt 1.49012e-007 0 32 | vt 0 1 33 | vt 1 1.19209e-007 34 | vt 1 1 35 | vt 1 1.19209e-007 36 | vt 0 1 37 | usemtl acmat_1 38 | f 7/7/7 8/8/8 6/9/9 39 | f 5/10/10 6/11/11 8/12/12 40 | v -0.5 0.5 -0.5 41 | v 0.5 0.5 -0.5 42 | v 0.5 0.5 0.5 43 | v -0.5 0.5 0.5 44 | vn 0 -1 0 45 | vn 0 -1 0 46 | vn 0 -1 0 47 | vn 0 -1 0 48 | vn 0 -1 0 49 | vn 0 -1 0 50 | vt 5.96046e-008 1 51 | vt 1 0 52 | vt 0 5.96046e-008 53 | vt 1 0 54 | vt 5.96046e-008 1 55 | vt 1 1 56 | usemtl acmat_2 57 | f 10/13/13 12/14/14 9/15/15 58 | f 12/16/16 10/17/17 11/18/18 59 | v 0.5 0.5 0.5 60 | v 0.5 -0.5 0.5 61 | v -0.5 -0.5 0.5 62 | v -0.5 0.5 0.5 63 | vn 0 0 -1 64 | vn 0 0 -1 65 | vn 0 0 -1 66 | vn 0 0 -1 67 | vn 0 0 -1 68 | vn 0 0 -1 69 | vt 0 0 70 | vt 0 1 71 | vt 1 0 72 | vt 1 1 73 | vt 1 0 74 | vt 0 1 75 | usemtl acmat_3 76 | f 15/19/19 16/20/20 14/21/21 77 | f 13/22/22 14/23/23 16/24/24 78 | v -0.5 0.5 -0.5 79 | v -0.5 -0.5 -0.5 80 | v 0.5 -0.5 -0.5 81 | v 0.5 0.5 -0.5 82 | vn 0 0 1 83 | vn 0 0 1 84 | vn 0 0 1 85 | vn 0 0 1 86 | vn 0 0 1 87 | vn 0 0 1 88 | vt 0 0 89 | vt 1 1 90 | vt 1 0 91 | vt 1 1 92 | vt 0 0 93 | vt 0 1 94 | usemtl acmat_4 95 | f 19/25/25 17/26/26 18/27/27 96 | f 17/28/28 19/29/29 20/30/30 97 | v 0.5 0.5 -0.5 98 | v 0.5 -0.5 -0.5 99 | v 0.5 -0.5 0.5 100 | v 0.5 0.5 0.5 101 | vn -1 0 0 102 | vn -1 0 0 103 | vn -1 0 0 104 | vn -1 0 0 105 | vn -1 0 0 106 | vn -1 0 0 107 | vt 0 1 108 | vt 1 0 109 | vt 0 0 110 | vt 1 0 111 | vt 0 1 112 | vt 1 1 113 | usemtl acmat_5 114 | f 24/31/31 22/32/32 23/33/33 115 | f 22/34/34 24/35/35 21/36/36 116 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter06/mouserotatemovement.py: -------------------------------------------------------------------------------- 1 | background_image_filename = 'sushiplate.jpg' 2 | sprite_image_filename = 'fugu.png' 3 | 4 | import pygame 5 | from pygame.locals import * 6 | from sys import exit 7 | from gameobjects.vector2 import Vector2 8 | from math import * 9 | 10 | pygame.init() 11 | screen = pygame.display.set_mode((640, 480), 0, 32) 12 | 13 | background = pygame.image.load(background_image_filename).convert() 14 | sprite = pygame.image.load(sprite_image_filename).convert_alpha() 15 | 16 | clock = pygame.time.Clock() 17 | 18 | pygame.mouse.set_visible(False) 19 | pygame.event.set_grab(True) 20 | 21 | sprite_pos = Vector2(200, 150) 22 | sprite_speed = 300. 23 | sprite_rotation = 0. 24 | sprite_rotation_speed = 360. # Degrees per second 25 | 26 | while True: 27 | 28 | for event in pygame.event.get(): 29 | if event.type == QUIT: 30 | exit() 31 | if event.type == KEYDOWN: 32 | if event.key == K_ESCAPE: 33 | exit() 34 | 35 | pressed_keys = pygame.key.get_pressed() 36 | pressed_mouse = pygame.mouse.get_pressed() 37 | 38 | rotation_direction = 0. 39 | movement_direction = 0. 40 | 41 | rotation_direction = pygame.mouse.get_rel()[0]/5.0 42 | 43 | if pressed_keys[K_LEFT]: 44 | rotation_direction = +1. 45 | if pressed_keys[K_RIGHT]: 46 | rotation_direction = -1. 47 | if pressed_keys[K_UP] or pressed_mouse[0]: 48 | movement_direction = +1. 49 | if pressed_keys[K_DOWN] or pressed_mouse[2]: 50 | movement_direction = -1. 51 | 52 | screen.blit(background, (0,0)) 53 | 54 | rotated_sprite = pygame.transform.rotate(sprite, sprite_rotation) 55 | w, h = rotated_sprite.get_size() 56 | sprite_draw_pos = Vector2(sprite_pos.x-w/2, sprite_pos.y-h/2) 57 | screen.blit(rotated_sprite, sprite_draw_pos) 58 | 59 | time_passed = clock.tick() 60 | time_passed_seconds = time_passed / 1000.0 61 | 62 | sprite_rotation += rotation_direction * sprite_rotation_speed * time_passed_seconds 63 | 64 | heading_x = sin(sprite_rotation*pi/180.) 65 | heading_y = cos(sprite_rotation*pi/180.) 66 | heading = Vector2(heading_x, heading_y) 67 | heading *= movement_direction 68 | 69 | sprite_pos+= heading * sprite_speed * time_passed_seconds 70 | 71 | pygame.display.update() 72 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter11/tankdemo.py: -------------------------------------------------------------------------------- 1 | SCREEN_SIZE = (800, 600) 2 | 3 | from math import radians 4 | 5 | from OpenGL.GL import * 6 | from OpenGL.GLU import * 7 | 8 | import pygame 9 | from pygame.locals import * 10 | 11 | # Import the Model3D class 12 | import model3d 13 | 14 | def resize(width, height): 15 | 16 | glViewport(0, 0, width, height) 17 | glMatrixMode(GL_PROJECTION) 18 | glLoadIdentity() 19 | gluPerspective(60.0, float(width)/height, .1, 1000.) 20 | glMatrixMode(GL_MODELVIEW) 21 | glLoadIdentity() 22 | 23 | 24 | def init(): 25 | 26 | # Enable the GL features we will be using 27 | glEnable(GL_DEPTH_TEST) 28 | glEnable(GL_LIGHTING) 29 | glEnable(GL_COLOR_MATERIAL) 30 | glEnable(GL_TEXTURE_2D) 31 | glEnable(GL_CULL_FACE) 32 | 33 | glShadeModel(GL_SMOOTH) 34 | glClearColor(1.0, 1.0, 1.0, 0.0) # white 35 | 36 | # Set the material 37 | glMaterial(GL_FRONT, GL_AMBIENT, (0.0, 0.0, 0.0, 1.0)) 38 | glMaterial(GL_FRONT, GL_DIFFUSE, (0.2, 0.2, 0.2, 1.0)) 39 | glMaterial(GL_FRONT, GL_SPECULAR, (1.0, 1.0, 1.0, 1.0)) 40 | glMaterial(GL_FRONT, GL_SHININESS, 10.0) 41 | 42 | # Set light parameters 43 | glLight(GL_LIGHT0, GL_AMBIENT, (0.0, 0.0, 0.0, 1.0)) 44 | glLight(GL_LIGHT0, GL_DIFFUSE, (0.4, 0.4, 0.4, 1.0)) 45 | glLight(GL_LIGHT0, GL_SPECULAR, (1.0, 1.0, 1.0, 1.0)) 46 | 47 | # Enable light 1 and set position 48 | glEnable(GL_LIGHT0) 49 | glLight(GL_LIGHT0, GL_POSITION, (0, .5, 1, 0)) 50 | 51 | 52 | def run(): 53 | 54 | pygame.init() 55 | screen = pygame.display.set_mode(SCREEN_SIZE, HWSURFACE|OPENGL|DOUBLEBUF) 56 | 57 | resize(*SCREEN_SIZE) 58 | init() 59 | 60 | clock = pygame.time.Clock() 61 | 62 | # Read the model 63 | tank_model = model3d.Model3D() 64 | tank_model.read_obj('mytank.obj') 65 | 66 | rotation = 0.0 67 | 68 | while True: 69 | 70 | for event in pygame.event.get(): 71 | if event.type == QUIT: 72 | return 73 | 74 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 75 | 76 | time_passed = clock.tick() 77 | time_passed_seconds = time_passed / 1000.0 78 | 79 | glLoadIdentity() 80 | glRotatef(15, 1, 0, 0) 81 | glTranslatef(0.0, -1.5, -3.5) 82 | 83 | rotation += time_passed_seconds * 45.0 84 | glRotatef(rotation, 0, 1, 0) 85 | 86 | tank_model.draw_quick() 87 | 88 | pygame.display.flip() 89 | 90 | 91 | if __name__ == "__main__": 92 | run() 93 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter06/joystickmovement.py: -------------------------------------------------------------------------------- 1 | background_image_filename = 'sushiplate.jpg' 2 | sprite_image_filename = 'fugu.png' 3 | 4 | import pygame 5 | from pygame.locals import * 6 | from sys import exit 7 | from gameobjects.vector2 import Vector2 8 | from math import * 9 | 10 | pygame.init() 11 | screen = pygame.display.set_mode((640, 480), 0, 32) 12 | 13 | background = pygame.image.load(background_image_filename).convert() 14 | sprite = pygame.image.load(sprite_image_filename).convert_alpha() 15 | 16 | clock = pygame.time.Clock() 17 | 18 | pygame.mouse.set_visible(False) 19 | pygame.event.set_grab(True) 20 | 21 | sprite_pos = Vector2(200, 150) 22 | sprite_speed = 300. 23 | sprite_rotation = 0. 24 | sprite_rotation_speed = 360. # Degrees per second 25 | 26 | if pygame.joystick.get_count() > 0: 27 | joystick = pygame.joystick.Joystick(0) 28 | joystick.init() 29 | else: 30 | joystick = None 31 | 32 | while True: 33 | 34 | for event in pygame.event.get(): 35 | if event.type == QUIT: 36 | exit() 37 | if event.type == KEYDOWN: 38 | if event.key == K_ESCAPE: 39 | exit() 40 | 41 | pressed_keys = pygame.key.get_pressed() 42 | pressed_mouse = pygame.mouse.get_pressed() 43 | 44 | rotation_direction = 0. 45 | movement_direction = 0. 46 | 47 | rotation_direction = pygame.mouse.get_rel()[0] / 5. 48 | 49 | if pressed_keys[K_LEFT]: 50 | rotation_direction = +1. 51 | if pressed_keys[K_RIGHT]: 52 | rotation_direction = -1. 53 | if pressed_keys[K_UP] or pressed_mouse[0]: 54 | movement_direction = +1. 55 | if pressed_keys[K_DOWN] or pressed_mouse[2]: 56 | movement_direction = -1. 57 | 58 | if joystick is not None: 59 | axis_x = joystick.get_axis(0) 60 | if abs(axis_x) <0.05: 61 | axis_x = 0. 62 | axis_y = joystick.get_axis(1) 63 | if abs(axis_y) <0.05: 64 | axis_y = 0. 65 | rotation_direction -= axis_x 66 | print axis_y 67 | movement_direction = axis_y 68 | 69 | screen.blit(background, (0,0)) 70 | 71 | rotated_sprite = pygame.transform.rotate(sprite, sprite_rotation) 72 | w, h = rotated_sprite.get_size() 73 | sprite_draw_pos = Vector2(sprite_pos.x-w/2, sprite_pos.y-h/2) 74 | screen.blit(rotated_sprite, sprite_draw_pos) 75 | 76 | time_passed = clock.tick(15) 77 | time_passed_seconds = time_passed / 1000.0 78 | 79 | sprite_rotation += rotation_direction * sprite_rotation_speed * time_passed_seconds 80 | 81 | heading_x = sin(sprite_rotation*pi/180.) 82 | heading_y = cos(sprite_rotation*pi/180.) 83 | heading = Vector2(heading_x, heading_y) 84 | heading *= movement_direction 85 | 86 | sprite_pos+= heading * sprite_speed * time_passed_seconds 87 | 88 | pygame.display.update() 89 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter12/fogdemo.py: -------------------------------------------------------------------------------- 1 | SCREEN_SIZE = (800, 600) 2 | 3 | from math import radians 4 | 5 | from OpenGL.GL import * 6 | from OpenGL.GLU import * 7 | 8 | import pygame 9 | from pygame.locals import * 10 | 11 | # Import the Model3D class 12 | import model3d 13 | 14 | def resize(width, height): 15 | 16 | glViewport(0, 0, width, height) 17 | glMatrixMode(GL_PROJECTION) 18 | glLoadIdentity() 19 | gluPerspective(60.0, float(width)/height, .1, 1000.) 20 | glMatrixMode(GL_MODELVIEW) 21 | glLoadIdentity() 22 | 23 | 24 | def init(): 25 | 26 | # Enable the GL features we will be using 27 | glEnable(GL_DEPTH_TEST) 28 | glEnable(GL_LIGHTING) 29 | glEnable(GL_COLOR_MATERIAL) 30 | glEnable(GL_TEXTURE_2D) 31 | glEnable(GL_CULL_FACE) 32 | 33 | glShadeModel(GL_SMOOTH) 34 | glClearColor(1.0, 1.0, 1.0, 0.0) # white 35 | 36 | # Set the material 37 | glMaterial(GL_FRONT, GL_AMBIENT, (0.0, 0.0, 0.0, 1.0)) 38 | glMaterial(GL_FRONT, GL_DIFFUSE, (0.2, 0.2, 0.2, 1.0)) 39 | glMaterial(GL_FRONT, GL_SPECULAR, (1.0, 1.0, 1.0, 1.0)) 40 | glMaterial(GL_FRONT, GL_SHININESS, 10.0) 41 | 42 | # Set light parameters 43 | glLight(GL_LIGHT0, GL_AMBIENT, (0.0, 0.0, 0.0, 1.0)) 44 | glLight(GL_LIGHT0, GL_DIFFUSE, (0.4, 0.4, 0.4, 1.0)) 45 | glLight(GL_LIGHT0, GL_SPECULAR, (1.0, 1.0, 1.0, 1.0)) 46 | 47 | # Enable light 1 and set position 48 | glEnable(GL_LIGHT0) 49 | glLight(GL_LIGHT0, GL_POSITION, (0, .5, 1, 0)) 50 | 51 | glEnable(GL_FOG) 52 | glFogfv(GL_FOG_COLOR, (1.0, 1.0, 1.0)) 53 | glFogi(GL_FOG_MODE, GL_LINEAR) 54 | glFogf(GL_FOG_START, 1.5) 55 | glFogf(GL_FOG_END, 3.5) 56 | 57 | 58 | #glFogi(GL_FOG_MODE, GL_LINEAR) 59 | #glFogf(GL_FOG_START, 5) 60 | #glFogf(GL_FOG_END, 6) 61 | 62 | glFogfv(GL_FOG_COLOR, (1.0, 0.7, 0.7)) 63 | glFogi(GL_FOG_MODE, GL_EXP2) 64 | glFogf(GL_FOG_DENSITY, 0.2) 65 | 66 | def run(): 67 | 68 | pygame.init() 69 | screen = pygame.display.set_mode(SCREEN_SIZE, HWSURFACE|OPENGL|DOUBLEBUF) 70 | 71 | resize(*SCREEN_SIZE) 72 | init() 73 | 74 | clock = pygame.time.Clock() 75 | 76 | # Read the model 77 | tank_model = model3d.Model3D() 78 | tank_model.read_obj('mytank.obj') 79 | 80 | rotation = 0.0 81 | 82 | while True: 83 | 84 | for event in pygame.event.get(): 85 | if event.type == QUIT: 86 | return 87 | 88 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 89 | 90 | time_passed = clock.tick() 91 | time_passed_seconds = time_passed / 1000.0 92 | 93 | 94 | 95 | glLoadIdentity() 96 | glRotatef(15, 1, 0, 0) 97 | 98 | tank_distance = pygame.mouse.get_pos()[1] / 50.0 99 | glTranslatef(0.0, -1.5, -tank_distance) 100 | 101 | #glTranslatef(0.0, -1.5, -3.5) 102 | 103 | rotation += time_passed_seconds * 45.0 104 | glRotatef(rotation, 0, 1, 0) 105 | 106 | tank_model.draw_quick() 107 | 108 | pygame.display.flip() 109 | 110 | 111 | if __name__ == "__main__": 112 | run() 113 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter11/opengltex.py: -------------------------------------------------------------------------------- 1 | SCREEN_SIZE = (800, 600) 2 | 3 | from math import radians 4 | 5 | from OpenGL.GL import * 6 | from OpenGL.GLU import * 7 | 8 | import pygame 9 | from pygame.locals import * 10 | 11 | 12 | def resize(width, height): 13 | 14 | glViewport(0, 0, width, height) 15 | glMatrixMode(GL_PROJECTION) 16 | glLoadIdentity() 17 | gluPerspective(60.0, float(width)/height, .1, 1000.) 18 | glMatrixMode(GL_MODELVIEW) 19 | glLoadIdentity() 20 | 21 | def init(): 22 | 23 | glEnable(GL_TEXTURE_2D) 24 | glClearColor(1.0, 1.0, 1.0, 0.0) 25 | 26 | def run(): 27 | 28 | pygame.init() 29 | screen = pygame.display.set_mode(SCREEN_SIZE, HWSURFACE|OPENGL|DOUBLEBUF) 30 | 31 | resize(*SCREEN_SIZE) 32 | init() 33 | 34 | # Load the textures 35 | texture_surface = pygame.image.load("sushitex.png") 36 | # Retrieve the texture data 37 | texture_data = pygame.image.tostring(texture_surface, 'RGB', True) 38 | 39 | # Generate a texture id 40 | texture_id = glGenTextures(1) 41 | # Tell OpenGL we will be using this texture id for texture operations 42 | glBindTexture(GL_TEXTURE_2D, texture_id) 43 | 44 | # Tell OpenGL how to scale images 45 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ) 46 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ) 47 | 48 | # Tell OpenGL that data is aligned to byte boundries 49 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1) 50 | 51 | # Get the dimensions of the image 52 | width, height = texture_surface.get_rect().size 53 | 54 | # Upload the image to OpenGL 55 | glTexImage2D( GL_TEXTURE_2D, 56 | 0, 57 | 3, 58 | width, 59 | height, 60 | 0, 61 | GL_RGB, 62 | GL_UNSIGNED_BYTE, 63 | texture_data) 64 | 65 | 66 | clock = pygame.time.Clock() 67 | 68 | tex_rotation = 0.0 69 | 70 | while True: 71 | 72 | for event in pygame.event.get(): 73 | if event.type == QUIT: 74 | return 75 | 76 | 77 | time_passed = clock.tick() 78 | time_passed_seconds = time_passed / 1000. 79 | tex_rotation += time_passed_seconds * 360.0 / 8.0 80 | 81 | 82 | # Clear the screen (similar to fill) 83 | glClear(GL_COLOR_BUFFER_BIT) 84 | 85 | # Clear the model-view matrix 86 | glLoadIdentity() 87 | 88 | # Set the modelview matrix 89 | glTranslatef(0.0, 0.0, -600.0) 90 | glRotate(tex_rotation, 1, 0, 0) 91 | 92 | # Draw a quad (4 vertices, 4 texture coords) 93 | glBegin(GL_QUADS) 94 | 95 | glTexCoord2f(0, 1) 96 | glVertex3f(-300, 300, 0) 97 | 98 | glTexCoord2f(1, 1) 99 | glVertex3f(300, 300, 0) 100 | 101 | glTexCoord2f(1, 0) 102 | glVertex3f(300, -300, 0) 103 | 104 | glTexCoord2f(0, 0) 105 | glVertex3f(-300, -300, 0) 106 | 107 | glEnd() 108 | 109 | pygame.display.flip() 110 | 111 | glDeleteTextures(texture_id) 112 | 113 | if __name__ == "__main__": 114 | run() 115 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter12/skybox.py: -------------------------------------------------------------------------------- 1 | SCREEN_SIZE = (800, 600) 2 | 3 | from math import radians 4 | 5 | from OpenGL.GL import * 6 | from OpenGL.GLU import * 7 | 8 | import pygame 9 | from pygame.locals import * 10 | 11 | # Import the Model3D class 12 | import model3d 13 | 14 | def resize(width, height): 15 | 16 | glViewport(0, 0, width, height) 17 | glMatrixMode(GL_PROJECTION) 18 | glLoadIdentity() 19 | gluPerspective(60.0, float(width)/height, .1, 1000.) 20 | glMatrixMode(GL_MODELVIEW) 21 | glLoadIdentity() 22 | 23 | 24 | def init(): 25 | 26 | # Enable the GL features we will be using 27 | glEnable(GL_DEPTH_TEST) 28 | glEnable(GL_LIGHTING) 29 | glEnable(GL_TEXTURE_2D) 30 | glShadeModel(GL_SMOOTH) 31 | 32 | # Enable light 1 and set position 33 | glEnable(GL_LIGHTING) 34 | glEnable(GL_LIGHT0) 35 | glLight(GL_LIGHT0, GL_POSITION, (0, .5, 1)) 36 | 37 | 38 | def run(): 39 | 40 | pygame.init() 41 | screen = pygame.display.set_mode(SCREEN_SIZE, FULLSCREEN|HWSURFACE|OPENGL|DOUBLEBUF) 42 | 43 | resize(*SCREEN_SIZE) 44 | init() 45 | 46 | # Read the skybox model 47 | sky_box = model3d.Model3D() 48 | sky_box.read_obj('tanksky/skybox.obj') 49 | 50 | # Set the wraping mode of all textures in the sky-box to GL_CLAMP_TO_EDGE 51 | for material in sky_box.materials.itervalues(): 52 | 53 | glBindTexture(GL_TEXTURE_2D, material.texture) 54 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) 55 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) 56 | 57 | 58 | # Used to rotate the world 59 | mouse_x = 0.0 60 | mouse_y = 0.0 61 | 62 | #Don't display the mouse cursor 63 | pygame.mouse.set_visible(False) 64 | 65 | while True: 66 | 67 | for event in pygame.event.get(): 68 | if event.type == QUIT: 69 | return 70 | if event.type == KEYDOWN: 71 | return 72 | 73 | # We don't need to clear the color buffer (GL_COLOR_BUFFER_BIT) 74 | # because the skybox covers the entire screen 75 | glClear(GL_DEPTH_BUFFER_BIT) 76 | 77 | glLoadIdentity() 78 | 79 | mouse_rel_x, mouse_rel_y = pygame.mouse.get_rel() 80 | mouse_x += float(mouse_rel_x) / 5.0 81 | mouse_y += float(mouse_rel_y) / 5.0 82 | 83 | # Rotate around the x and y axes to create a mouse-look camera 84 | glRotatef(mouse_y, 1, 0, 0) 85 | glRotatef(mouse_x, 0, 1, 0) 86 | 87 | # Disable lighting and depth test 88 | glDisable(GL_LIGHTING) 89 | glDepthMask(False) 90 | 91 | # Draw the skybox 92 | sky_box.draw_quick() 93 | 94 | # Re-enable lighting and depth test before we redraw the world 95 | glEnable(GL_LIGHTING) 96 | glDepthMask(True) 97 | 98 | # Here is where we would draw the rest of the world in a game 99 | 100 | pygame.display.flip() 101 | 102 | if __name__ == "__main__": 103 | run() 104 | 105 | 106 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter11/opengltextiled.py: -------------------------------------------------------------------------------- 1 | SCREEN_SIZE = (800, 600) 2 | 3 | from math import radians 4 | 5 | from OpenGL.GL import * 6 | from OpenGL.GLU import * 7 | 8 | import pygame 9 | from pygame.locals import * 10 | 11 | 12 | def resize(width, height): 13 | 14 | glViewport(0, 0, width, height) 15 | glMatrixMode(GL_PROJECTION) 16 | glLoadIdentity() 17 | gluPerspective(60.0, float(width)/height, .1, 1000.) 18 | glMatrixMode(GL_MODELVIEW) 19 | glLoadIdentity() 20 | 21 | def init(): 22 | 23 | glEnable(GL_TEXTURE_2D) 24 | glClearColor(1.0, 1.0, 1.0, 0.0) 25 | 26 | def run(): 27 | 28 | pygame.init() 29 | screen = pygame.display.set_mode(SCREEN_SIZE, HWSURFACE|OPENGL|DOUBLEBUF) 30 | 31 | resize(*SCREEN_SIZE) 32 | init() 33 | 34 | # Load the textures 35 | texture_surface = pygame.image.load("sushitex.png") 36 | # Retrieve the texture data 37 | texture_data = pygame.image.tostring(texture_surface, 'RGB', True) 38 | 39 | # Generate a texture id 40 | texture_id = glGenTextures(1) 41 | # Tell OpenGL we will be using this texture id for texture operations 42 | glBindTexture(GL_TEXTURE_2D, texture_id) 43 | 44 | # Tell OpenGL how to scale images 45 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ) 46 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ) 47 | 48 | # Tell OpenGL that data is aligned to byte boundries 49 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1) 50 | 51 | # Get the dimensions of the image 52 | width, height = texture_surface.get_rect().size 53 | 54 | # Upload the image to OpenGL 55 | glTexImage2D( GL_TEXTURE_2D, 56 | 0, 57 | 3, 58 | width, 59 | height, 60 | 0, 61 | GL_RGB, 62 | GL_UNSIGNED_BYTE, 63 | texture_data) 64 | 65 | 66 | clock = pygame.time.Clock() 67 | 68 | tex_rotation = 0.0 69 | 70 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) 71 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) 72 | 73 | while True: 74 | 75 | for event in pygame.event.get(): 76 | if event.type == QUIT: 77 | return 78 | 79 | 80 | time_passed = clock.tick() 81 | time_passed_seconds = time_passed / 1000. 82 | tex_rotation += time_passed_seconds * 360.0 / 8.0 83 | 84 | 85 | # Clear the screen (similar to fill) 86 | glClear(GL_COLOR_BUFFER_BIT) 87 | 88 | # Clear the model-view matrix 89 | glLoadIdentity() 90 | 91 | # Set the modelview matrix 92 | glTranslatef(0.0, 0.0, -600.0) 93 | glRotate(tex_rotation, 1, 0, 0) 94 | 95 | # Draw a quad (4 vertices, 4 texture coords) 96 | glBegin(GL_QUADS) 97 | 98 | glTexCoord2f(0, 3) 99 | glVertex3f(-300, 300, 0) 100 | 101 | glTexCoord2f(3, 3) 102 | glVertex3f(300, 300, 0) 103 | 104 | glTexCoord2f(3, 0) 105 | glVertex3f(300, -300, 0) 106 | 107 | glTexCoord2f(0, 0) 108 | glVertex3f(-300, -300, 0) 109 | 110 | glEnd() 111 | 112 | pygame.display.flip() 113 | 114 | glDeleteTextures(texture_id) 115 | 116 | if __name__ == "__main__": 117 | run() 118 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter06/joystickdemo.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | 5 | pygame.init() 6 | screen = pygame.display.set_mode((640, 480), 0, 32) 7 | 8 | # Get a list of joystick objects 9 | joysticks = [] 10 | for joystick_no in xrange(pygame.joystick.get_count()): 11 | stick = pygame.joystick.Joystick(joystick_no) 12 | stick.init() 13 | joysticks.append(stick) 14 | 15 | if not joysticks: 16 | print "Sorry! No joystick(s) to test." 17 | exit() 18 | 19 | active_joystick = 0 20 | 21 | pygame.display.set_caption(joysticks[0].get_name()) 22 | 23 | def draw_axis(surface, x, y, axis_x, axis_y, size): 24 | 25 | line_col = (128, 128, 128) 26 | num_lines = 40 27 | step = size / float(num_lines) 28 | for n in xrange(num_lines): 29 | line_col = [(192, 192, 192), (220, 220, 220)][n&1] 30 | pygame.draw.line(surface, line_col, (x+n*step, y), (x+n*step, y+size)) 31 | pygame.draw.line(surface, line_col, (x, y+n*step), (x+size, y+n*step)) 32 | 33 | pygame.draw.line(surface, (0, 0, 0), (x, y+size/2), (x+size, y+size/2)) 34 | pygame.draw.line(surface, (0, 0, 0), (x+size/2, y), (x+size/2, y+size)) 35 | 36 | draw_x = int(x + (axis_x * size + size) / 2.) 37 | draw_y = int(y + (axis_y * size + size) / 2.) 38 | draw_pos = (draw_x, draw_y) 39 | center_pos = (x+size/2, y+size/2) 40 | pygame.draw.line(surface, (0, 0, 0), center_pos, draw_pos, 5) 41 | pygame.draw.circle(surface, (0, 0, 255), draw_pos, 10) 42 | 43 | 44 | def draw_dpad(surface, x, y, axis_x, axis_y): 45 | 46 | col = (255, 0, 0) 47 | if axis_x == -1: 48 | pygame.draw.circle(surface, col, (x-20, y), 10) 49 | elif axis_x == +1: 50 | pygame.draw.circle(surface, col, (x+20, y), 10) 51 | 52 | if axis_y == -1: 53 | pygame.draw.circle(surface, col, (x, y+20), 10) 54 | elif axis_y == +1: 55 | pygame.draw.circle(surface, col, (x, y-20), 10) 56 | 57 | 58 | while True: 59 | 60 | joystick = joysticks[active_joystick] 61 | 62 | for event in pygame.event.get(): 63 | if event.type == QUIT: 64 | exit() 65 | if event.type == KEYDOWN: 66 | if event.key >= K_0 and event.key <= K_1: 67 | num = event.key - K_0 68 | if num < len(joysticks): 69 | active_joystick = num 70 | name = joysticks[active_joystick].get_name() 71 | pygame.display.set_caption(name) 72 | 73 | # Get a list of all the axis 74 | axes = [] 75 | for axis_no in xrange(joystick.get_numaxes()): 76 | axes.append( joystick.get_axis(axis_no) ) 77 | 78 | axis_size = min(256, 640 / (joystick.get_numaxes()/2)) 79 | 80 | pygame.draw.rect(screen, (255, 255,255), (0, 0, 640, 480)) 81 | 82 | # Draw all the axes (analogue sticks) 83 | x = 0 84 | for axis_no in xrange(0, len(axes), 2): 85 | axis_x = axes[axis_no] 86 | if axis_no+1 < len(axes): 87 | axis_y = axes[axis_no+1] 88 | else: 89 | axis_y = 0. 90 | draw_axis(screen, x, 0, axis_x, axis_y, axis_size) 91 | x += axis_size 92 | 93 | 94 | # Draw all the hats (d-pads) 95 | x, y = 50, 300 96 | for hat_no in xrange(joystick.get_numhats()): 97 | axis_x, axis_y = joystick.get_hat(hat_no) 98 | draw_dpad(screen, x, y, axis_x, axis_y) 99 | x+= 100 100 | 101 | 102 | #Draw all the buttons 103 | x, y = 0.0, 390.0 104 | button_width = 640 / joystick.get_numbuttons() 105 | for button_no in xrange(joystick.get_numbuttons()): 106 | if joystick.get_button(button_no): 107 | pygame.draw.circle(screen, (0, 255, 0), (int(x), int(y)), 20) 108 | x+= button_width 109 | 110 | pygame.display.update() 111 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter12/blenddemo.py: -------------------------------------------------------------------------------- 1 | SCREEN_SIZE = (800, 600) 2 | 3 | from OpenGL.GL import * 4 | from OpenGL.GLU import * 5 | 6 | import pygame 7 | from pygame.locals import * 8 | 9 | 10 | def resize(width, height): 11 | 12 | glViewport(0, 0, width, height) 13 | glMatrixMode(GL_PROJECTION) 14 | glLoadIdentity() 15 | gluPerspective(45.0, float(width)/height, .1, 1000.) 16 | glMatrixMode(GL_MODELVIEW) 17 | glLoadIdentity() 18 | 19 | 20 | def init(): 21 | 22 | glEnable(GL_TEXTURE_2D) 23 | glEnable(GL_BLEND) 24 | glClearColor(1.0, 1.0, 1.0, 0.0) 25 | 26 | 27 | def upload_texture(filename, use_alpha=False): 28 | 29 | # Read an image file and upload a texture 30 | if use_alpha: 31 | format, gl_format, bits_per_pixel = 'RGBA', GL_RGBA, 4 32 | else: 33 | format, gl_format, bits_per_pixel = 'RGB', GL_RGB, 3 34 | 35 | img_surface = pygame.image.load(filename) 36 | 37 | #img_surface = premul_surface(img_surface) 38 | 39 | data = pygame.image.tostring(img_surface, format, True) 40 | 41 | texture_id = glGenTextures(1) 42 | 43 | glBindTexture(GL_TEXTURE_2D, texture_id) 44 | 45 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ) 46 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ) 47 | 48 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1) 49 | 50 | width, height = img_surface.get_rect().size 51 | 52 | glTexImage2D( GL_TEXTURE_2D, 53 | 0, 54 | bits_per_pixel, 55 | width, 56 | height, 57 | 0, 58 | gl_format, 59 | GL_UNSIGNED_BYTE, 60 | data ) 61 | 62 | # Return the texture id, so we can use glBindTexture 63 | return texture_id 64 | 65 | 66 | def draw_quad(x, y, z, w, h): 67 | 68 | # Send four vertices to draw a quad 69 | glBegin(GL_QUADS) 70 | 71 | glTexCoord2f(0, 0) 72 | glVertex3f(x-w/2, y-h/2, z) 73 | 74 | glTexCoord2f(1, 0) 75 | glVertex3f(x+w/2, y-h/2, z) 76 | 77 | glTexCoord2f(1, 1) 78 | glVertex3f(x+w/2, y+h/2, z) 79 | 80 | glTexCoord2f(0, 1) 81 | glVertex3f(x-w/2, y+h/2, z) 82 | 83 | glEnd() 84 | 85 | 86 | def run(): 87 | 88 | pygame.init() 89 | screen = pygame.display.set_mode(SCREEN_SIZE, HWSURFACE|OPENGL|DOUBLEBUF) 90 | 91 | resize(*SCREEN_SIZE) 92 | init() 93 | 94 | # Upload the background and fugu texture 95 | background_tex = upload_texture('background.png') 96 | fugu_tex = upload_texture('fugu.png', True) 97 | 98 | while True: 99 | 100 | for event in pygame.event.get(): 101 | if event.type == QUIT: 102 | return 103 | if event.type == KEYDOWN: 104 | if event.key == K_1: 105 | # Simple alpha blending 106 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 107 | glBlendEquation(GL_FUNC_ADD) 108 | elif event.key == K_2: 109 | # Additive alpha blending 110 | glBlendFunc(GL_SRC_ALPHA, GL_ONE) 111 | glBlendEquation(GL_FUNC_ADD) 112 | elif event.key == K_3: 113 | # Subtractive blending 114 | glBlendFunc(GL_SRC_ALPHA, GL_ONE) 115 | glBlendEquation(GL_FUNC_REVERSE_SUBTRACT) 116 | 117 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 118 | 119 | # Draw the background 120 | glBindTexture(GL_TEXTURE_2D, background_tex) 121 | 122 | glDisable(GL_BLEND) 123 | draw_quad(0, 0, -SCREEN_SIZE[1], 600, 600) 124 | glEnable(GL_BLEND) 125 | 126 | # Draw a texture at the mouse position 127 | glBindTexture(GL_TEXTURE_2D, fugu_tex) 128 | x, y = pygame.mouse.get_pos() 129 | x -= SCREEN_SIZE[0]/2 130 | y -= SCREEN_SIZE[1]/2 131 | draw_quad(x, -y, -SCREEN_SIZE[1], 256, 256) 132 | 133 | pygame.display.flip() 134 | 135 | # Free the textures we used 136 | glDeleteTextures(background_tex) 137 | glDeleteTextures(fugu_tex) 138 | 139 | if __name__ == "__main__": 140 | run() 141 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter07/ants.py: -------------------------------------------------------------------------------- 1 | GRID_SIZE = (160, 120) 2 | GRID_SQUARE_SIZE = (4, 4) 3 | ant_image_filename = "ant.png" 4 | ITERATIONS = 10 5 | 6 | import pygame 7 | from pygame.locals import * 8 | 9 | class AntGrid(object): 10 | 11 | def __init__(self, width, height): 12 | 13 | self.width = width 14 | self.height = height 15 | self.clear() 16 | 17 | def clear(self): 18 | 19 | self.rows = [] 20 | for col_no in xrange(self.height): 21 | new_row = [] 22 | self.rows.append(new_row) 23 | for row_no in xrange(self.width): 24 | new_row.append(False) 25 | 26 | def swap(self, x, y): 27 | self.rows[y][x] = not self.rows[y][x] 28 | 29 | def get(self, x, y): 30 | return self.rows[y][x] 31 | 32 | def render(self, surface, colors, square_size): 33 | 34 | w, h = square_size 35 | surface.fill(colors[0]) 36 | 37 | for y, row in enumerate(self.rows): 38 | rect_y = y * h 39 | for x, state in enumerate(row): 40 | if state: 41 | surface.fill(colors[1], (x * w, rect_y, w, h)) 42 | 43 | 44 | class Ant(object): 45 | 46 | directions = ( (0,-1), (+1,0), (0,+1), (-1,0) ) 47 | 48 | def __init__(self, grid, x, y, image, direction=1): 49 | 50 | self.grid = grid 51 | self.x = x 52 | self.y = y 53 | self.image = image 54 | self.direction = direction 55 | 56 | 57 | def move(self): 58 | 59 | self.grid.swap(self.x, self.y) 60 | 61 | self.x = ( self.x + Ant.directions[self.direction][0] ) % self.grid.width 62 | self.y = ( self.y + Ant.directions[self.direction][1] ) % self.grid.height 63 | 64 | if self.grid.get(self.x, self.y): 65 | self.direction = (self.direction-1) % 4 66 | else: 67 | self.direction = (self.direction+1) % 4 68 | 69 | 70 | def render(self, surface, grid_size): 71 | 72 | grid_w, grid_h = grid_size 73 | ant_w, ant_h = self.image.get_size() 74 | render_x = self.x * grid_w - ant_w / 2 75 | render_y = self.y * grid_h - ant_h / 2 76 | surface.blit(self.image, (render_x, render_y)) 77 | 78 | 79 | def run(): 80 | 81 | pygame.init() 82 | w = GRID_SIZE[0] * GRID_SQUARE_SIZE[0] 83 | h = GRID_SIZE[1] * GRID_SQUARE_SIZE[1] 84 | screen = pygame.display.set_mode((w, h), 0, 32) 85 | 86 | ant_image = pygame.image.load(ant_image_filename).convert_alpha() 87 | 88 | default_font = pygame.font.get_default_font() 89 | font = pygame.font.SysFont(default_font, 22) 90 | 91 | ants = [] 92 | grid = AntGrid(*GRID_SIZE) 93 | running = False 94 | 95 | total_iterations = 0 96 | 97 | while True: 98 | 99 | for event in pygame.event.get(): 100 | 101 | if event.type == QUIT: 102 | return 103 | 104 | if event.type == MOUSEBUTTONDOWN: 105 | 106 | x, y = event.pos 107 | x /= GRID_SQUARE_SIZE[0] 108 | y /= GRID_SQUARE_SIZE[1] 109 | 110 | ant = Ant(grid, int(x), int(y), ant_image) 111 | ants.append(ant) 112 | 113 | 114 | if event.type == KEYDOWN: 115 | 116 | if event.key == K_SPACE: 117 | running = not running 118 | 119 | if event.key == K_c: 120 | grid.clear() 121 | total_iterations = 0 122 | del ants[:] 123 | 124 | 125 | grid.render(screen, ((255, 255, 255), (0, 128, 0)), GRID_SQUARE_SIZE) 126 | 127 | if running: 128 | for iteration_no in xrange(ITERATIONS): 129 | for ant in ants: 130 | ant.move() 131 | total_iterations += ITERATIONS 132 | 133 | txt = "%i iterations"%total_iterations 134 | txt_surface = font.render(txt, True, (0, 0, 0)) 135 | screen.blit(txt_surface, (0, 0)) 136 | 137 | for ant in ants: 138 | ant.render(screen, GRID_SQUARE_SIZE) 139 | 140 | 141 | pygame.display.update() 142 | 143 | 144 | if __name__ == "__main__": 145 | run() 146 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter10/bouncesound.py: -------------------------------------------------------------------------------- 1 | SCREEN_SIZE = (640, 480) 2 | 3 | # In pixels per second, per second 4 | GRAVITY = 250.0 5 | # Increase for more bounciness, but don't go over 1! 6 | BOUNCINESS = 0.7 7 | 8 | import pygame 9 | from pygame.locals import * 10 | from random import randint 11 | from gameobjects.vector2 import Vector2 12 | 13 | 14 | def stero_pan(x_coord, screen_width): 15 | 16 | right_volume = float(x_coord) / screen_width 17 | left_volume = 1.0 - right_volume 18 | 19 | return (left_volume, right_volume) 20 | 21 | 22 | class Ball(object): 23 | 24 | def __init__(self, position, speed, image, bounce_sound): 25 | 26 | self.position = Vector2(position) 27 | self.speed = Vector2(speed) 28 | self.image = image 29 | self.bounce_sound = bounce_sound 30 | self.age = 0.0 31 | 32 | def update(self, time_passed): 33 | 34 | w, h = self.image.get_size() 35 | 36 | screen_width, screen_height = SCREEN_SIZE 37 | 38 | x, y = self.position 39 | x -= w/2 40 | y -= h/2 41 | 42 | # Has the ball bounce 43 | bounce = False 44 | 45 | # Has the ball hit the bottom of the screen? 46 | if y + h >= screen_height: 47 | self.speed.y = -self.speed.y * BOUNCINESS 48 | self.position.y = screen_height - h / 2.0 - 1.0 49 | bounce = True 50 | 51 | # Has the ball hit the left of the screen? 52 | if x <= 0: 53 | self.speed.x = -self.speed.x * BOUNCINESS 54 | self.position.x = w / 2.0 + 1 55 | bounce = True 56 | 57 | # Has the ball hit the right of the screen 58 | elif x + w >= screen_width: 59 | self.speed.x = -self.speed.x * BOUNCINESS 60 | self.position.x = screen_width - w / 2.0 - 1 61 | bounce = True 62 | 63 | # Do time based movement 64 | self.position += self.speed * time_passed 65 | # Add gravity 66 | self.speed.y += time_passed * GRAVITY 67 | 68 | if bounce: 69 | self.play_bounce_sound() 70 | 71 | self.age += time_passed 72 | 73 | 74 | def play_bounce_sound(self): 75 | 76 | channel = self.bounce_sound.play() 77 | 78 | if channel is not None: 79 | # Get the left and right volumes 80 | left, right = stero_pan(self.position.x, SCREEN_SIZE[0]) 81 | channel.set_volume(left, right) 82 | 83 | 84 | def render(self, surface): 85 | 86 | # Draw the sprite center at self.position 87 | w, h = self.image.get_size() 88 | x, y = self.position 89 | x -= w/2 90 | y -= h/2 91 | surface.blit(self.image, (x, y)) 92 | 93 | 94 | def run(): 95 | 96 | # Initialise 44KHz 16-bit stero sound 97 | pygame.mixer.pre_init(44100, 16, 2, 1024*4) 98 | pygame.init() 99 | pygame.mixer.set_num_channels(8) 100 | screen = pygame.display.set_mode(SCREEN_SIZE, 0) 101 | 102 | print pygame.display.get_wm_info() 103 | hwnd = pygame.display.get_wm_info()["window"] 104 | import win32gui 105 | import win32con 106 | x, y = (200, 200) 107 | win32gui.SetWindowPos(hwnd, 0, x, y, 0, 0, win32con.SWP_NOSIZE | win32con.SWP_NOZORDER) 108 | 109 | pygame.mouse.set_visible(False) 110 | 111 | clock = pygame.time.Clock() 112 | 113 | ball_image = pygame.image.load("ball.png").convert_alpha() 114 | mouse_image = pygame.image.load("mousecursor.png").convert_alpha() 115 | 116 | # Load the sound file 117 | bounce_sound = pygame.mixer.Sound("bounce.wav") 118 | 119 | balls = [] 120 | 121 | while True: 122 | 123 | for event in pygame.event.get(): 124 | 125 | if event.type == QUIT: 126 | return 127 | 128 | if event.type == MOUSEBUTTONDOWN: 129 | 130 | # Create a new ball at the mouse position 131 | random_speed = ( randint(-400, 400), randint(-300, 0) ) 132 | new_ball = Ball( event.pos, 133 | random_speed, 134 | ball_image, 135 | bounce_sound ) 136 | balls.append(new_ball) 137 | 138 | time_passed_seconds = clock.tick() / 1000. 139 | 140 | screen.fill((255, 255, 255)) 141 | 142 | dead_balls = [] 143 | 144 | for ball in balls: 145 | 146 | ball.update(time_passed_seconds) 147 | ball.render(screen) 148 | 149 | # Make not of any balls that are older than 10 seconds 150 | if ball.age > 10.0: 151 | dead_balls.append(ball) 152 | 153 | # remove any 'dead' balls from the main list 154 | for ball in dead_balls: 155 | 156 | balls.remove(ball) 157 | 158 | # Draw the mouse cursor 159 | mouse_pos = pygame.mouse.get_pos() 160 | screen.blit(mouse_image, mouse_pos) 161 | 162 | pygame.display.update() 163 | 164 | if __name__ == "__main__": 165 | 166 | run() 167 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter08/simple3d.py: -------------------------------------------------------------------------------- 1 | SCREEN_SIZE = (640, 480) 2 | CUBE_SIZE = 300 3 | 4 | import pygame 5 | from pygame.locals import * 6 | from gameobjects.vector3 import Vector3 7 | 8 | from math import * 9 | from random import randint 10 | 11 | def calculate_viewing_distance(fov, screen_width): 12 | 13 | d = (screen_width/2.0) / tan(fov/2.0) 14 | return d 15 | 16 | 17 | def run(): 18 | 19 | pygame.init() 20 | screen = pygame.display.set_mode(SCREEN_SIZE, 0) 21 | 22 | default_font = pygame.font.get_default_font() 23 | font = pygame.font.SysFont(default_font, 24) 24 | 25 | ball = pygame.image.load("ball.png").convert_alpha() 26 | 27 | # The 3D points 28 | points = [] 29 | 30 | fov = 90. # Field of view 31 | viewing_distance = calculate_viewing_distance(radians(fov), SCREEN_SIZE[0]) 32 | 33 | # Create a list of points along the edge of a cube 34 | for x in xrange(0, CUBE_SIZE+1, 20): 35 | edge_x = x == 0 or x == CUBE_SIZE 36 | 37 | for y in xrange(0, CUBE_SIZE+1, 20): 38 | edge_y = y == 0 or y == CUBE_SIZE 39 | 40 | for z in xrange(0, CUBE_SIZE+1, 20): 41 | edge_z = z == 0 or z == CUBE_SIZE 42 | 43 | if sum((edge_x, edge_y, edge_z)) >= 2: 44 | 45 | point_x = float(x) - CUBE_SIZE/2 46 | point_y = float(y) - CUBE_SIZE/2 47 | point_z = float(z) - CUBE_SIZE/2 48 | 49 | points.append(Vector3(point_x, point_y, point_z)) 50 | 51 | # Sort points in z order 52 | def point_z(point): 53 | return point.z 54 | points.sort(key=point_z, reverse=True) 55 | 56 | center_x, center_y = SCREEN_SIZE 57 | center_x /= 2 58 | center_y /= 2 59 | 60 | ball_w, ball_h = ball.get_size() 61 | ball_center_x = ball_w / 2 62 | ball_center_y = ball_h / 2 63 | 64 | camera_position = Vector3(0.0, 0.0, -700.) 65 | camera_speed = Vector3(300.0, 300.0, 300.0) 66 | 67 | clock = pygame.time.Clock() 68 | 69 | while True: 70 | 71 | for event in pygame.event.get(): 72 | if event.type == QUIT: 73 | return 74 | 75 | screen.fill((0, 0, 0)) 76 | 77 | pressed_keys = pygame.key.get_pressed() 78 | 79 | time_passed = clock.tick() 80 | time_passed_seconds = time_passed / 1000. 81 | 82 | direction = Vector3() 83 | if pressed_keys[K_LEFT]: 84 | direction.x = -1.0 85 | elif pressed_keys[K_RIGHT]: 86 | direction.x = +1.0 87 | 88 | if pressed_keys[K_UP]: 89 | direction.y = +1.0 90 | elif pressed_keys[K_DOWN]: 91 | direction.y = -1.0 92 | 93 | if pressed_keys[K_q]: 94 | direction.z = +1.0 95 | elif pressed_keys[K_a]: 96 | direction.z = -1.0 97 | 98 | if pressed_keys[K_w]: 99 | fov = min(179., fov+1.) 100 | w = SCREEN_SIZE[0] 101 | viewing_distance = calculate_viewing_distance(radians(fov), w) 102 | elif pressed_keys[K_s]: 103 | fov = max(1., fov-1.) 104 | w = SCREEN_SIZE[0] 105 | viewing_distance = calculate_viewing_distance(radians(fov), w) 106 | 107 | camera_position += direction * camera_speed * time_passed_seconds 108 | 109 | # Draw the 3D points 110 | for point in points: 111 | 112 | x, y, z = point - camera_position 113 | 114 | if z > 0: 115 | x = x * viewing_distance / z 116 | y = -y * viewing_distance / z 117 | x += center_x 118 | y += center_y 119 | screen.blit(ball, (x-ball_center_x, y-ball_center_y)) 120 | 121 | # Draw the field of view diagram 122 | diagram_width = SCREEN_SIZE[0] / 4 123 | col = (50, 255, 50) 124 | diagram_points = [] 125 | diagram_points.append( (diagram_width/2, 100+viewing_distance/4) ) 126 | diagram_points.append( (0, 100) ) 127 | diagram_points.append( (diagram_width, 100) ) 128 | diagram_points.append( (diagram_width/2, 100+viewing_distance/4) ) 129 | diagram_points.append( (diagram_width/2, 100) ) 130 | pygame.draw.lines(screen, col, False, diagram_points, 2) 131 | 132 | # Draw the text 133 | white = (255, 255, 255) 134 | cam_text = font.render("camera = "+str(camera_position), True, white) 135 | screen.blit(cam_text, (5, 5)) 136 | fov_text = font.render("field of view = %i"%int(fov), True, white) 137 | screen.blit(fov_text, (5, 35)) 138 | txt = "viewing distance = %.3f"%viewing_distance 139 | d_text = font.render(txt, True, white) 140 | screen.blit(d_text, (5, 65)) 141 | 142 | pygame.display.update() 143 | 144 | 145 | if __name__ == "__main__": 146 | run() 147 | 148 | 149 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter12/model3d.py: -------------------------------------------------------------------------------- 1 | 2 | from OpenGL.GL import * 3 | from OpenGL.GLU import * 4 | 5 | import pygame 6 | import os.path 7 | 8 | class Material(object): 9 | 10 | def __init__(self): 11 | 12 | self.name = "" 13 | self.texture_fname = None 14 | self.texture_id = None 15 | 16 | 17 | class FaceGroup(object): 18 | 19 | def __init__(self): 20 | 21 | self.tri_indices = [] 22 | self.material_name = "" 23 | 24 | 25 | class Model3D(object): 26 | 27 | def __init__(self): 28 | 29 | self.vertices = [] 30 | self.tex_coords = [] 31 | self.normals = [] 32 | self.materials = {} 33 | self.face_groups = [] 34 | self.display_list_id = None 35 | 36 | def __del__(self): 37 | 38 | #Called when the model is cleaned up by Python 39 | self.free_resources() 40 | 41 | def free_resources(self): 42 | 43 | # Delete the display list and textures 44 | if self.display_list_id is not None: 45 | glDeleteLists(self.display_list_id, 1) 46 | 47 | for material in self.materials.itervalues(): 48 | if material.texture_id is not None: 49 | glDeleteTextures(material.texture_id, 1) 50 | 51 | self.vertices = [] 52 | self.tex_coords = [] 53 | self.normals = [] 54 | self.materials = {} 55 | self.face_groups = [] 56 | self.display_list_id = None 57 | 58 | 59 | def read_obj(self, fname): 60 | 61 | current_face_group = None 62 | 63 | file_in = file(fname) 64 | 65 | for line in file_in: 66 | 67 | # Parse command and data from each line 68 | words = line.split() 69 | command = words[0] 70 | data = words[1:] 71 | 72 | if command == 'mtllib': # Material library 73 | 74 | model_path = os.path.split(fname)[0] 75 | mtllib_path = os.path.join( model_path, data[0] ) 76 | self.read_mtllib(mtllib_path) 77 | 78 | elif command == 'v': # Vertex 79 | x, y, z = data 80 | vertex = (float(x), float(y), float(z)) 81 | self.vertices.append(vertex) 82 | 83 | elif command == 'vt': # Texture coordinate 84 | 85 | s, t = data 86 | tex_coord = (float(s), float(t)) 87 | self.tex_coords.append(tex_coord) 88 | 89 | elif command == 'vn': # Normal 90 | 91 | x, y, z = data 92 | normal = (float(x), float(y), float(z)) 93 | self.normals.append(normal) 94 | 95 | elif command == 'usemtl' : # Use material 96 | 97 | current_face_group = FaceGroup() 98 | current_face_group.material_name = data[0] 99 | self.face_groups.append( current_face_group ) 100 | 101 | elif command == 'f': 102 | 103 | assert len(data) == 3, "Sorry, only triangles are supported" 104 | 105 | # Parse indices from triples 106 | for word in data: 107 | vi, ti, ni = word.split('/') 108 | indices = (int(vi) - 1, int(ti) - 1, int(ni) - 1) 109 | current_face_group.tri_indices.append(indices) 110 | 111 | 112 | for material in self.materials.itervalues(): 113 | 114 | model_path = os.path.split(fname)[0] 115 | texture_path = os.path.join(model_path, material.texture_fname) 116 | texture_surface = pygame.image.load(texture_path) 117 | texture_data = pygame.image.tostring(texture_surface, 'RGB', True) 118 | 119 | material.texture = glGenTextures(1) 120 | glBindTexture(GL_TEXTURE_2D, material.texture) 121 | 122 | glTexParameteri( GL_TEXTURE_2D, 123 | GL_TEXTURE_MAG_FILTER, 124 | GL_LINEAR) 125 | glTexParameteri( GL_TEXTURE_2D, 126 | GL_TEXTURE_MIN_FILTER, 127 | GL_LINEAR_MIPMAP_LINEAR) 128 | 129 | glPixelStorei(GL_UNPACK_ALIGNMENT,1) 130 | width, height = texture_surface.get_rect().size 131 | 132 | gluBuild2DMipmaps( GL_TEXTURE_2D, 133 | 3, 134 | width, 135 | height, 136 | GL_RGB, 137 | GL_UNSIGNED_BYTE, 138 | texture_data) 139 | 140 | 141 | def read_mtllib(self, mtl_fname): 142 | 143 | file_mtllib = file(mtl_fname) 144 | for line in file_mtllib: 145 | 146 | words = line.split() 147 | command = words[0] 148 | data = words[1:] 149 | 150 | if command == 'newmtl': 151 | material = Material() 152 | material.name = data[0] 153 | self.materials[data[0]] = material 154 | 155 | elif command == 'map_Kd': 156 | material.texture_fname = data[0] 157 | 158 | 159 | def draw(self): 160 | 161 | vertices = self.vertices 162 | tex_coords = self.tex_coords 163 | normals = self.normals 164 | 165 | for face_group in self.face_groups: 166 | 167 | material = self.materials[face_group.material_name] 168 | glBindTexture(GL_TEXTURE_2D, material.texture) 169 | 170 | glBegin(GL_TRIANGLES) 171 | for vi, ti, ni in face_group.tri_indices: 172 | glTexCoord2fv( tex_coords[ti] ) 173 | glNormal3fv( normals[ni] ) 174 | glVertex3fv( vertices[vi] ) 175 | glEnd() 176 | 177 | 178 | def draw_quick(self): 179 | 180 | if self.display_list_id is None: 181 | self.display_list_id = glGenLists(1) 182 | glNewList(self.display_list_id, GL_COMPILE) 183 | self.draw() 184 | glEndList() 185 | 186 | glCallList(self.display_list_id) 187 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter11/model3d.py: -------------------------------------------------------------------------------- 1 | 2 | from OpenGL.GL import * 3 | from OpenGL.GLU import * 4 | 5 | import pygame 6 | import os.path 7 | 8 | class Material(object): 9 | 10 | def __init__(self): 11 | 12 | self.name = "" 13 | self.texture_fname = None 14 | self.texture_id = None 15 | 16 | 17 | class FaceGroup(object): 18 | 19 | def __init__(self): 20 | 21 | self.tri_indices = [] 22 | self.material_name = "" 23 | 24 | 25 | class Model3D(object): 26 | 27 | def __init__(self): 28 | 29 | self.vertices = [] 30 | self.tex_coords = [] 31 | self.normals = [] 32 | self.materials = {} 33 | self.face_groups = [] 34 | self.display_list_id = None 35 | 36 | def __del__(self): 37 | 38 | #Called when the model is cleaned up by Python 39 | self.free_resources() 40 | 41 | def free_resources(self): 42 | 43 | # Delete the display list and textures 44 | if self.display_list_id is not None: 45 | glDeleteLists(self.display_list_id, 1) 46 | self.display_list_id = None 47 | 48 | # Delete any textures we used 49 | for material in self.materials.itervalues(): 50 | if material.texture_id is not None: 51 | glDeleteTextures(material.texture_id) 52 | 53 | # Clear all the materials 54 | self.materials.clear() 55 | 56 | # Clear the geometry lists 57 | del self.vertices[:] 58 | del self.tex_coords[:] 59 | del self.normals[:] 60 | del self.face_groups[:] 61 | 62 | 63 | 64 | def read_obj(self, fname): 65 | 66 | current_face_group = None 67 | 68 | file_in = file(fname) 69 | 70 | for line in file_in: 71 | 72 | # Parse command and data from each line 73 | words = line.split() 74 | command = words[0] 75 | data = words[1:] 76 | 77 | if command == 'mtllib': # Material library 78 | 79 | model_path = os.path.split(fname)[0] 80 | mtllib_path = os.path.join( model_path, data[0] ) 81 | self.read_mtllib(mtllib_path) 82 | 83 | elif command == 'v': # Vertex 84 | x, y, z = data 85 | vertex = (float(x), float(y), float(z)) 86 | self.vertices.append(vertex) 87 | 88 | elif command == 'vt': # Texture coordinate 89 | 90 | s, t = data 91 | tex_coord = (float(s), float(t)) 92 | self.tex_coords.append(tex_coord) 93 | 94 | elif command == 'vn': # Normal 95 | 96 | x, y, z = data 97 | normal = (float(x), float(y), float(z)) 98 | self.normals.append(normal) 99 | 100 | elif command == 'usemtl' : # Use material 101 | 102 | current_face_group = FaceGroup() 103 | current_face_group.material_name = data[0] 104 | self.face_groups.append( current_face_group ) 105 | 106 | elif command == 'f': 107 | 108 | assert len(data) == 3, "Sorry, only triangles are supported" 109 | 110 | # Parse indices from triples 111 | for word in data: 112 | vi, ti, ni = word.split('/') 113 | indices = (int(vi) - 1, int(ti) - 1, int(ni) - 1) 114 | current_face_group.tri_indices.append(indices) 115 | 116 | 117 | for material in self.materials.itervalues(): 118 | 119 | model_path = os.path.split(fname)[0] 120 | texture_path = os.path.join(model_path, material.texture_fname) 121 | texture_surface = pygame.image.load(texture_path) 122 | texture_data = pygame.image.tostring(texture_surface, 'RGB', True) 123 | 124 | material.texture_id = glGenTextures(1) 125 | glBindTexture(GL_TEXTURE_2D, material.texture_id) 126 | 127 | glTexParameteri( GL_TEXTURE_2D, 128 | GL_TEXTURE_MAG_FILTER, 129 | GL_LINEAR) 130 | glTexParameteri( GL_TEXTURE_2D, 131 | GL_TEXTURE_MIN_FILTER, 132 | GL_LINEAR_MIPMAP_LINEAR) 133 | 134 | glPixelStorei(GL_UNPACK_ALIGNMENT,1) 135 | width, height = texture_surface.get_rect().size 136 | gluBuild2DMipmaps( GL_TEXTURE_2D, 137 | 3, 138 | width, 139 | height, 140 | GL_RGB, 141 | GL_UNSIGNED_BYTE, 142 | texture_data) 143 | 144 | 145 | def read_mtllib(self, mtl_fname): 146 | 147 | file_mtllib = file(mtl_fname) 148 | for line in file_mtllib: 149 | 150 | words = line.split() 151 | command = words[0] 152 | data = words[1:] 153 | 154 | if command == 'newmtl': 155 | material = Material() 156 | material.name = data[0] 157 | self.materials[data[0]] = material 158 | 159 | elif command == 'map_Kd': 160 | material.texture_fname = data[0] 161 | 162 | 163 | def draw(self): 164 | 165 | vertices = self.vertices 166 | tex_coords = self.tex_coords 167 | normals = self.normals 168 | 169 | for face_group in self.face_groups: 170 | 171 | material = self.materials[face_group.material_name] 172 | glBindTexture(GL_TEXTURE_2D, material.texture_id) 173 | 174 | glBegin(GL_TRIANGLES) 175 | for vi, ti, ni in face_group.tri_indices: 176 | glTexCoord2fv( tex_coords[ti] ) 177 | glNormal3fv( normals[ni] ) 178 | glVertex3fv( vertices[vi] ) 179 | glEnd() 180 | 181 | 182 | def draw_quick(self): 183 | 184 | if self.display_list_id is None: 185 | self.display_list_id = glGenLists(1) 186 | glNewList(self.display_list_id, GL_COMPILE) 187 | self.draw() 188 | glEndList() 189 | 190 | glCallList(self.display_list_id) 191 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter08/rotation3d.py: -------------------------------------------------------------------------------- 1 | SCREEN_SIZE = (640, 480) 2 | CUBE_SIZE = 300 3 | 4 | import pygame 5 | from pygame.locals import * 6 | from gameobjects.vector3 import Vector3 7 | from gameobjects.matrix44 import Matrix44 as Matrix 8 | 9 | from math import * 10 | from random import randint 11 | 12 | def calculate_viewing_distance(fov, screen_width): 13 | 14 | d = (screen_width/2.0) / tan(fov/2.0) 15 | return d 16 | 17 | 18 | def run(): 19 | 20 | pygame.init() 21 | screen = pygame.display.set_mode(SCREEN_SIZE, 0) 22 | 23 | font = pygame.font.SysFont("courier new", 16, True) 24 | 25 | ball = pygame.image.load("ball.png").convert_alpha() 26 | 27 | points = [] 28 | 29 | fov = 75. # Field of view 30 | viewing_distance = calculate_viewing_distance(radians(fov), SCREEN_SIZE[0]) 31 | 32 | # Create a list of points along the edge of a cube 33 | for x in xrange(0, CUBE_SIZE+1, 10): 34 | edge_x = x == 0 or x == CUBE_SIZE 35 | 36 | for y in xrange(0, CUBE_SIZE+1, 10): 37 | edge_y = y == 0 or y == CUBE_SIZE 38 | 39 | for z in xrange(0, CUBE_SIZE+1, 10): 40 | edge_z = z == 0 or z == CUBE_SIZE 41 | 42 | if sum((edge_x, edge_y, edge_z)) >= 2: 43 | 44 | point_x = float(x) - CUBE_SIZE/2 45 | point_y = float(y) - CUBE_SIZE/2 46 | point_z = float(z) - CUBE_SIZE/2 47 | 48 | points.append(Vector3(point_x, point_y, point_z)) 49 | 50 | def point_z(point): 51 | return point[2] 52 | 53 | center_x, center_y = SCREEN_SIZE 54 | center_x /= 2 55 | center_y /= 2 56 | 57 | ball_w, ball_h = ball.get_size() 58 | ball_center_x = ball_w / 2 59 | ball_center_y = ball_h / 2 60 | 61 | camera_position = Vector3(0.0, 0.0, 600.) 62 | 63 | rotation = Vector3() 64 | rotation_speed = Vector3(radians(20), radians(20), radians(20)) 65 | 66 | clock = pygame.time.Clock() 67 | 68 | # Some colors for drawing 69 | red = (255, 0, 0) 70 | green = (0, 255, 0) 71 | blue = (0, 0, 255) 72 | white = (255, 255, 255) 73 | 74 | # Labels for the axes 75 | x_surface = font.render("X", True, white) 76 | y_surface = font.render("Y", True, white) 77 | z_surface = font.render("Z", True, white) 78 | 79 | while True: 80 | 81 | for event in pygame.event.get(): 82 | if event.type == QUIT: 83 | return 84 | 85 | screen.fill((0, 0, 0)) 86 | 87 | time_passed = clock.tick() 88 | time_passed_seconds = time_passed / 1000. 89 | 90 | rotation_direction = Vector3() 91 | 92 | #Adjust the rotation direction depending on key presses 93 | pressed_keys = pygame.key.get_pressed() 94 | 95 | if pressed_keys[K_q]: 96 | rotation_direction.x = +1.0 97 | elif pressed_keys[K_a]: 98 | rotation_direction.x = -1.0 99 | 100 | if pressed_keys[K_w]: 101 | rotation_direction.y = +1.0 102 | elif pressed_keys[K_s]: 103 | rotation_direction.y = -1.0 104 | 105 | if pressed_keys[K_e]: 106 | rotation_direction.z = +1.0 107 | elif pressed_keys[K_d]: 108 | rotation_direction.z = -1.0 109 | 110 | # Apply time based movement to rotation 111 | rotation += rotation_direction * rotation_speed * time_passed_seconds 112 | 113 | # Build the rotation matrix 114 | rotation_matrix = Matrix.x_rotation(rotation.x) 115 | rotation_matrix *= Matrix.y_rotation(rotation.y) 116 | rotation_matrix *= Matrix.z_rotation(rotation.z) 117 | 118 | transformed_points = [] 119 | 120 | # Transform all the points and adjust for camera position 121 | for point in points: 122 | 123 | p = rotation_matrix.transform_vec3(point) - camera_position 124 | 125 | transformed_points.append(p) 126 | 127 | transformed_points.sort(key=point_z) 128 | 129 | # Perspective project and blit all the points 130 | for x, y, z in transformed_points: 131 | 132 | if z < 0: 133 | x = center_x + x * -viewing_distance / z 134 | y = center_y + -y * -viewing_distance / z 135 | 136 | screen.blit(ball, (x-ball_center_x, y-ball_center_y)) 137 | 138 | 139 | # Function to draw a single axes, see below 140 | def draw_axis(color, axis, label): 141 | 142 | axis = rotation_matrix.transform_vec3(axis * 150.) 143 | SCREEN_SIZE = (640, 480) 144 | center_x = SCREEN_SIZE[0] / 2.0 145 | center_y = SCREEN_SIZE[1] / 2.0 146 | x, y, z = axis - camera_position 147 | 148 | x = center_x + x * -viewing_distance / z 149 | y = center_y + -y * -viewing_distance / z 150 | 151 | pygame.draw.line(screen, color, (center_x, center_y), (x, y), 2) 152 | 153 | w, h = label.get_size() 154 | screen.blit(label, (x-w/2, y-h/2)) 155 | 156 | # Draw the x, y and z axes 157 | x_axis = Vector3(1, 0, 0) 158 | y_axis = Vector3(0, 1, 0) 159 | z_axis = Vector3(0, 0, 1) 160 | 161 | draw_axis(red, x_axis, x_surface) 162 | draw_axis(green, y_axis, y_surface) 163 | draw_axis(blue, z_axis, z_surface) 164 | 165 | # Display rotation information on screen 166 | degrees_txt = tuple(degrees(r) for r in rotation) 167 | rotation_txt = "Rotation: Q/A %.3f, W/S %.3f, E/D %.3f" % degrees_txt 168 | txt_surface = font.render(rotation_txt, True, white) 169 | screen.blit(txt_surface, (5, 5)) 170 | 171 | # Displat the rotation matrix on screen 172 | matrix_txt = str(rotation_matrix) 173 | txt_y = 25 174 | for line in matrix_txt.split('\n'): 175 | txt_surface = font.render(line, True, white) 176 | screen.blit(txt_surface, (5, txt_y)) 177 | txt_y += 20 178 | 179 | pygame.display.update() 180 | 181 | if __name__ == "__main__": 182 | run() 183 | 184 | 185 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter09/rotation3d.py: -------------------------------------------------------------------------------- 1 | SCREEN_SIZE = (640, 480) 2 | CUBE_SIZE = 300 3 | 4 | import pygame 5 | from pygame.locals import * 6 | from gameobjects.vector3 import Vector3 7 | from gameobjects.matrix44 import Matrix44 as Matrix 8 | 9 | from math import * 10 | from random import randint 11 | 12 | def calculate_viewing_distance(fov, screen_width): 13 | 14 | d = (screen_width/2.0) / tan(fov/2.0) 15 | return d 16 | 17 | 18 | def run(): 19 | 20 | pygame.init() 21 | screen = pygame.display.set_mode(SCREEN_SIZE, 0) 22 | 23 | font = pygame.font.SysFont("courier new", 16, True) 24 | 25 | ball = pygame.image.load("ball.png").convert_alpha() 26 | 27 | points = [] 28 | 29 | fov = 75. # Field of view 30 | viewing_distance = calculate_viewing_distance(radians(fov), SCREEN_SIZE[0]) 31 | 32 | # Create a list of points along the edge of a cube 33 | for x in xrange(0, CUBE_SIZE+1, 10): 34 | edge_x = x == 0 or x == CUBE_SIZE 35 | 36 | for y in xrange(0, CUBE_SIZE+1, 10): 37 | edge_y = y == 0 or y == CUBE_SIZE 38 | 39 | for z in xrange(0, CUBE_SIZE+1, 10): 40 | edge_z = z == 0 or z == CUBE_SIZE 41 | 42 | if sum((edge_x, edge_y, edge_z)) >= 2: 43 | 44 | point_x = float(x) - CUBE_SIZE/2 45 | point_y = float(y) - CUBE_SIZE/2 46 | point_z = float(z) - CUBE_SIZE/2 47 | 48 | points.append(Vector3(point_x, point_y, point_z)) 49 | 50 | def point_z(point): 51 | return point[2] 52 | 53 | center_x, center_y = SCREEN_SIZE 54 | center_x /= 2 55 | center_y /= 2 56 | 57 | ball_w, ball_h = ball.get_size() 58 | ball_center_x = ball_w / 2 59 | ball_center_y = ball_h / 2 60 | 61 | camera_position = Vector3(0.0, 0.0, 600.) 62 | 63 | rotation = Vector3() 64 | rotation_speed = Vector3(radians(20), radians(20), radians(20)) 65 | 66 | clock = pygame.time.Clock() 67 | 68 | # Some colors for drawing 69 | red = (255, 0, 0) 70 | green = (0, 255, 0) 71 | blue = (0, 0, 255) 72 | white = (255, 255, 255) 73 | 74 | # Labels for the axes 75 | x_surface = font.render("X", True, white) 76 | y_surface = font.render("Y", True, white) 77 | z_surface = font.render("Z", True, white) 78 | 79 | while True: 80 | 81 | for event in pygame.event.get(): 82 | if event.type == QUIT: 83 | return 84 | 85 | screen.fill((0, 0, 0)) 86 | 87 | time_passed = clock.tick() 88 | time_passed_seconds = time_passed / 1000. 89 | 90 | rotation_direction = Vector3() 91 | 92 | #Adjust the rotation direction depending on key presses 93 | pressed_keys = pygame.key.get_pressed() 94 | 95 | if pressed_keys[K_q]: 96 | rotation_direction.x = +1.0 97 | elif pressed_keys[K_a]: 98 | rotation_direction.x = -1.0 99 | 100 | if pressed_keys[K_w]: 101 | rotation_direction.y = +1.0 102 | elif pressed_keys[K_s]: 103 | rotation_direction.y = -1.0 104 | 105 | if pressed_keys[K_e]: 106 | rotation_direction.z = +1.0 107 | elif pressed_keys[K_d]: 108 | rotation_direction.z = -1.0 109 | 110 | # Apply time based movement to rotation 111 | rotation += rotation_direction * rotation_speed * time_passed_seconds 112 | 113 | # Build the rotation matrix 114 | rotation_matrix = Matrix.x_rotation(rotation.x) 115 | rotation_matrix *= Matrix.y_rotation(rotation.y) 116 | rotation_matrix *= Matrix.z_rotation(rotation.z) 117 | 118 | transformed_points = [] 119 | 120 | # Transform all the points and adjust for camera position 121 | for point in points: 122 | 123 | p = rotation_matrix.transform_vec3(point) - camera_position 124 | 125 | transformed_points.append(p) 126 | 127 | transformed_points.sort(key=point_z) 128 | 129 | # Perspective project and blit all the points 130 | for x, y, z in transformed_points: 131 | 132 | if z < 0: 133 | x = center_x + x * -viewing_distance / z 134 | y = center_y + -y * -viewing_distance / z 135 | 136 | screen.blit(ball, (x-ball_center_x, y-ball_center_y)) 137 | 138 | 139 | # Function to draw a single axes, see below 140 | def draw_axis(color, axis, label): 141 | 142 | axis = rotation_matrix.transform_vec3(axis * 150.) 143 | SCREEN_SIZE = (640, 480) 144 | center_x = SCREEN_SIZE[0] / 2.0 145 | center_y = SCREEN_SIZE[1] / 2.0 146 | x, y, z = axis - camera_position 147 | 148 | x = center_x + x * -viewing_distance / z 149 | y = center_y + -y * -viewing_distance / z 150 | 151 | pygame.draw.line(screen, color, (center_x, center_y), (x, y), 2) 152 | 153 | w, h = label.get_size() 154 | screen.blit(label, (x-w/2, y-h/2)) 155 | 156 | # Draw the x, y and z axes 157 | x_axis = Vector3(1, 0, 0) 158 | y_axis = Vector3(0, 1, 0) 159 | z_axis = Vector3(0, 0, 1) 160 | 161 | draw_axis(red, x_axis, x_surface) 162 | draw_axis(green, y_axis, y_surface) 163 | draw_axis(blue, z_axis, z_surface) 164 | 165 | # Display rotation information on screen 166 | degrees_txt = tuple(degrees(r) for r in rotation) 167 | rotation_txt = "Rotation: Q/A %.3f, W/S %.3f, E/D %.3f" % degrees_txt 168 | txt_surface = font.render(rotation_txt, True, white) 169 | screen.blit(txt_surface, (5, 5)) 170 | 171 | # Displat the rotation matrix on screen 172 | matrix_txt = str(rotation_matrix) 173 | txt_y = 25 174 | for line in matrix_txt.split('\n'): 175 | txt_surface = font.render(line, True, white) 176 | screen.blit(txt_surface, (5, txt_y)) 177 | txt_y += 20 178 | 179 | pygame.display.update() 180 | 181 | if __name__ == "__main__": 182 | run() 183 | 184 | 185 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter10/jukebox.py: -------------------------------------------------------------------------------- 1 | SCREEN_SIZE = (800, 600) 2 | 3 | # Location of music on your computer 4 | MUSIC_PATH = "./MUSIC" 5 | 6 | import pygame 7 | from pygame.locals import * 8 | 9 | from math import sqrt 10 | import os 11 | import os.path 12 | 13 | def get_music(path): 14 | 15 | # Get the filenames in a folder 16 | raw_filenames = os.listdir(path) 17 | 18 | music_files = [] 19 | for filename in raw_filenames: 20 | 21 | # We only want ogg files 22 | if filename.endswith('.ogg'): 23 | music_files.append(os.path.join(MUSIC_PATH, filename)) 24 | 25 | return sorted(music_files) 26 | 27 | 28 | class Button(object): 29 | 30 | def __init__(self, image_filename, position): 31 | 32 | self.position = position 33 | self.image = pygame.image.load(image_filename) 34 | 35 | def render(self, surface): 36 | 37 | # Render at the center 38 | x, y = self.position 39 | w, h = self.image.get_size() 40 | x -= w /2 41 | y -= h / 2 42 | 43 | surface.blit(self.image, (x, y)) 44 | 45 | 46 | def is_over(self, point): 47 | 48 | # Return True if a point is over the button 49 | point_x, point_y = point 50 | x, y = self.position 51 | w, h = self.image.get_size() 52 | x -= w /2 53 | y -= h / 2 54 | 55 | in_x = point_x >= x and point_x < x + w 56 | in_y = point_y >= y and point_y < y + h 57 | 58 | return in_x and in_y 59 | 60 | def run(): 61 | 62 | pygame.mixer.pre_init(44100, 16, 2, 1024*4) 63 | pygame.init() 64 | screen = pygame.display.set_mode(SCREEN_SIZE, 0) 65 | 66 | default_font = pygame.font.get_default_font() 67 | font = pygame.font.SysFont("default_font", 50, False) 68 | 69 | # Create our buttons 70 | x = 100 71 | y = 240 72 | button_width = 150 73 | 74 | # Store the buttons in a dictionary, so we can assign them names 75 | buttons = {} 76 | buttons["prev"] = Button("prev.png", (x, y)) 77 | buttons["pause"] = Button("pause.png", (x+button_width*1, y)) 78 | buttons["stop"] = Button("stop.png", (x+button_width*2, y)) 79 | buttons["play"] = Button("play.png", (x+button_width*3, y)) 80 | buttons["next"] = Button("next.png", (x+button_width*4, y)) 81 | 82 | music_filenames = get_music(MUSIC_PATH) 83 | 84 | if len(music_filenames) == 0: 85 | print "No OGG files found in ", MUSIC_PATH 86 | return 87 | 88 | white = (255, 255, 255) 89 | label_surfaces = [] 90 | 91 | # Render the track names 92 | for filename in music_filenames: 93 | 94 | txt = os.path.split(filename)[-1] 95 | 96 | print "Track:", txt 97 | 98 | txt = txt.split('.')[0] 99 | surface = font.render(txt, True, (100, 0, 100)) 100 | label_surfaces.append(surface) 101 | 102 | current_track = 0 103 | max_tracks = len(music_filenames) 104 | 105 | pygame.mixer.music.load( music_filenames[current_track] ) 106 | 107 | clock = pygame.time.Clock() 108 | 109 | playing = False 110 | paused = False 111 | 112 | # This event is sent when a music track ends 113 | TRACK_END = USEREVENT + 1 114 | pygame.mixer.music.set_endevent(TRACK_END) 115 | 116 | while True: 117 | 118 | button_pressed = None 119 | 120 | for event in pygame.event.get(): 121 | 122 | if event.type == QUIT: 123 | return 124 | 125 | if event.type == MOUSEBUTTONDOWN: 126 | 127 | # Find the pressed button 128 | for button_name, button in buttons.iteritems(): 129 | if button.is_over(event.pos): 130 | print button_name, "pressed" 131 | button_pressed = button_name 132 | break 133 | 134 | if event.type == TRACK_END: 135 | # If the track has ended, simulate pressing the next button 136 | button_pressed = "next" 137 | 138 | if button_pressed is not None: 139 | 140 | if button_pressed == "next": 141 | current_track = (current_track + 1) % max_tracks 142 | pygame.mixer.music.load( music_filenames[current_track] ) 143 | if playing: 144 | pygame.mixer.music.play() 145 | 146 | elif button_pressed == "prev": 147 | 148 | # If the track has been playing for more that 3 seconds, 149 | # rewind i, otherwise select the previous track 150 | if pygame.mixer.music.get_pos() > 3000: 151 | pygame.mixer.music.stop() 152 | pygame.mixer.music.play() 153 | else: 154 | current_track = (current_track - 1) % max_tracks 155 | pygame.mixer.music.load( music_filenames[current_track] ) 156 | if playing: 157 | pygame.mixer.music.play() 158 | 159 | elif button_pressed == "pause": 160 | if paused: 161 | pygame.mixer.music.unpause() 162 | paused = False 163 | else: 164 | pygame.mixer.music.pause() 165 | paused = True 166 | 167 | elif button_pressed == "stop": 168 | pygame.mixer.music.stop() 169 | playing = False 170 | 171 | elif button_pressed == "play": 172 | if paused: 173 | pygame.mixer.music.unpause() 174 | paused = False 175 | else: 176 | if not playing: 177 | pygame.mixer.music.play() 178 | playing = True 179 | 180 | 181 | screen.fill(white) 182 | 183 | 184 | # Render the name of the currently track 185 | label = label_surfaces[current_track] 186 | w, h = label.get_size() 187 | screen_w = SCREEN_SIZE[0] 188 | screen.blit(label, ((screen_w - w)/2, 450)) 189 | 190 | # Render all the buttons 191 | for button in buttons.values(): 192 | button.render(screen) 193 | 194 | # No animation, 5 frames per second is fine! 195 | clock.tick(5) 196 | pygame.display.update() 197 | 198 | 199 | if __name__ == "__main__": 200 | 201 | run() -------------------------------------------------------------------------------- /bpwpapcode/Chapter09/firstopengl.py: -------------------------------------------------------------------------------- 1 | SCREEN_SIZE = (800, 600) 2 | 3 | from math import radians 4 | 5 | from OpenGL.GL import * 6 | from OpenGL.GLU import * 7 | 8 | import pygame 9 | from pygame.locals import * 10 | 11 | from gameobjects.matrix44 import * 12 | from gameobjects.vector3 import * 13 | 14 | 15 | def resize(width, height): 16 | 17 | glViewport(0, 0, width, height) 18 | glMatrixMode(GL_PROJECTION) 19 | glLoadIdentity() 20 | gluPerspective(60.0, float(width)/height, .1, 1000.) 21 | glMatrixMode(GL_MODELVIEW) 22 | glLoadIdentity() 23 | 24 | 25 | def init(): 26 | 27 | glEnable(GL_DEPTH_TEST) 28 | 29 | glShadeModel(GL_FLAT) 30 | glClearColor(1.0, 1.0, 1.0, 0.0) 31 | 32 | glEnable(GL_COLOR_MATERIAL) 33 | 34 | glEnable(GL_LIGHTING) 35 | glEnable(GL_LIGHT0) 36 | glLight(GL_LIGHT0, GL_POSITION, (0, 1, 1, 0)) 37 | 38 | 39 | class Cube(object): 40 | 41 | 42 | def __init__(self, position, color): 43 | 44 | self.position = position 45 | self.color = color 46 | 47 | # Cube information 48 | 49 | num_faces = 6 50 | 51 | vertices = [ (0.0, 0.0, 1.0), 52 | (1.0, 0.0, 1.0), 53 | (1.0, 1.0, 1.0), 54 | (0.0, 1.0, 1.0), 55 | (0.0, 0.0, 0.0), 56 | (1.0, 0.0, 0.0), 57 | (1.0, 1.0, 0.0), 58 | (0.0, 1.0, 0.0) ] 59 | 60 | normals = [ (0.0, 0.0, +1.0), # front 61 | (0.0, 0.0, -1.0), # back 62 | (+1.0, 0.0, 0.0), # right 63 | (-1.0, 0.0, 0.0), # left 64 | (0.0, +1.0, 0.0), # top 65 | (0.0, -1.0, 0.0) ] # bottom 66 | 67 | vertex_indices = [ (0, 1, 2, 3), # front 68 | (4, 5, 6, 7), # back 69 | (1, 5, 6, 2), # right 70 | (0, 4, 7, 3), # left 71 | (3, 2, 6, 7), # top 72 | (0, 1, 5, 4) ] # bottom 73 | 74 | def render(self): 75 | 76 | # Set the cube color, applies to all vertices till next call 77 | glColor( self.color ) 78 | 79 | # Adjust all the vertices so that the cube is at self.position 80 | vertices = [] 81 | for v in self.vertices: 82 | vertices.append( tuple(Vector3(v)+ self.position) ) 83 | 84 | 85 | # Draw all 6 faces of the cube 86 | glBegin(GL_QUADS) 87 | 88 | for face_no in xrange(self.num_faces): 89 | 90 | glNormal3dv( self.normals[face_no] ) 91 | 92 | v1, v2, v3, v4 = self.vertex_indices[face_no] 93 | 94 | glVertex( vertices[v1] ) 95 | glVertex( vertices[v2] ) 96 | glVertex( vertices[v3] ) 97 | glVertex( vertices[v4] ) 98 | 99 | glEnd() 100 | 101 | 102 | class Map(object): 103 | 104 | def __init__(self): 105 | 106 | map_surface = pygame.image.load("map.png") 107 | map_surface.lock() 108 | 109 | w, h = map_surface.get_size() 110 | 111 | self.cubes = [] 112 | 113 | # Create a cube for every non-white pixel 114 | for y in range(h): 115 | for x in range(w): 116 | 117 | r, g, b, a = map_surface.get_at((x, y)) 118 | 119 | if (r, g, b) != (255, 255, 255): 120 | 121 | gl_col = (r/255.0, g/255.0, b/255.0) 122 | position = (float(x), 0.0, float(y)) 123 | cube = Cube( position, gl_col ) 124 | self.cubes.append(cube) 125 | 126 | 127 | map_surface.unlock() 128 | 129 | self.display_list = None 130 | 131 | def render(self): 132 | 133 | if self.display_list is None: 134 | 135 | # Create a display list 136 | self.display_list = glGenLists(1) 137 | glNewList(self.display_list, GL_COMPILE) 138 | 139 | # Draw the cubes 140 | for cube in self.cubes: 141 | cube.render() 142 | 143 | # End the display list 144 | glEndList() 145 | 146 | else: 147 | 148 | # Render the display list 149 | glCallList(self.display_list) 150 | 151 | 152 | def run(): 153 | 154 | pygame.init() 155 | screen = pygame.display.set_mode(SCREEN_SIZE, HWSURFACE|OPENGL|DOUBLEBUF) 156 | 157 | resize(*SCREEN_SIZE) 158 | init() 159 | 160 | clock = pygame.time.Clock() 161 | 162 | # This object renders the 'map' 163 | map = Map() 164 | 165 | # Camera transform matrix 166 | camera_matrix = Matrix44() 167 | camera_matrix.translate = (10.0, .6, 10.0) 168 | 169 | # Initialize speeds and directions 170 | rotation_direction = Vector3() 171 | rotation_speed = radians(90.0) 172 | movement_direction = Vector3() 173 | movement_speed = 5.0 174 | 175 | while True: 176 | 177 | for event in pygame.event.get(): 178 | if event.type == QUIT: 179 | return 180 | if event.type == KEYUP and event.key == K_ESCAPE: 181 | return 182 | 183 | # Clear the screen, and z-buffer 184 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 185 | 186 | time_passed = clock.tick() 187 | time_passed_seconds = time_passed / 1000. 188 | 189 | pressed = pygame.key.get_pressed() 190 | 191 | # Reset rotation and movement directions 192 | rotation_direction.set(0.0, 0.0, 0.0) 193 | movement_direction.set(0.0, 0.0, 0.0) 194 | 195 | # Modify direction vectors for key presses 196 | if pressed[K_LEFT]: 197 | rotation_direction.y = +1.0 198 | elif pressed[K_RIGHT]: 199 | rotation_direction.y = -1.0 200 | if pressed[K_UP]: 201 | rotation_direction.x = -1.0 202 | elif pressed[K_DOWN]: 203 | rotation_direction.x = +1.0 204 | if pressed[K_z]: 205 | rotation_direction.z = -1.0 206 | elif pressed[K_x]: 207 | rotation_direction.z = +1.0 208 | if pressed[K_q]: 209 | movement_direction.z = -1.0 210 | elif pressed[K_a]: 211 | movement_direction.z = +1.0 212 | 213 | # Calculate rotation matrix and multiply by camera matrix 214 | rotation = rotation_direction * rotation_speed * time_passed_seconds 215 | rotation_matrix = Matrix44.xyz_rotation(*rotation) 216 | camera_matrix *= rotation_matrix 217 | 218 | # Calcluate movment and add it to camera matrix translate 219 | heading = Vector3(camera_matrix.forward) 220 | movement = heading * movement_direction.z * movement_speed 221 | camera_matrix.translate += movement * time_passed_seconds 222 | 223 | # Upload the inverse camera matrix to OpenGL 224 | glLoadMatrixd(camera_matrix.get_inverse().to_opengl()) 225 | 226 | # Light must be transformed as well 227 | glLight(GL_LIGHT0, GL_POSITION, (0, 1.5, 1, 0)) 228 | 229 | # Render the map 230 | map.render() 231 | 232 | 233 | # Show the screen 234 | pygame.display.flip() 235 | 236 | if __name__ == "__main__": 237 | run() 238 | -------------------------------------------------------------------------------- /bpwpapcode/AppendixB/antsstatemachine.py: -------------------------------------------------------------------------------- 1 | SCREEN_SIZE = (640, 480) 2 | NEST_POSITION = (320, 240) 3 | ANT_COUNT = 20 4 | NEST_SIZE = 100. 5 | 6 | import pygame 7 | from pygame.locals import * 8 | 9 | from random import randint, choice 10 | from gameobjects.vector2 import Vector2 11 | 12 | class State(object): 13 | 14 | def __init__(self, name): 15 | self.name = name 16 | 17 | def do_actions(self): 18 | pass 19 | 20 | def check_conditions(self): 21 | pass 22 | 23 | def entry_actions(self): 24 | pass 25 | 26 | def exit_actions(self): 27 | pass 28 | 29 | 30 | class StateMachine(object): 31 | 32 | def __init__(self): 33 | 34 | self.states = {} 35 | self.active_state = None 36 | 37 | 38 | def add_state(self, state): 39 | 40 | self.states[state.name] = state 41 | 42 | 43 | def think(self): 44 | 45 | if self.active_state is None: 46 | return 47 | 48 | self.active_state.do_actions() 49 | 50 | new_state_name = self.active_state.check_conditions() 51 | if new_state_name is not None: 52 | self.set_state(new_state_name) 53 | 54 | 55 | def set_state(self, new_state_name): 56 | 57 | if self.active_state is not None: 58 | self.active_state.exit_actions() 59 | 60 | self.active_state = self.states[new_state_name] 61 | self.active_state.entry_actions() 62 | 63 | 64 | 65 | class World(object): 66 | 67 | def __init__(self): 68 | 69 | self.entities = {} 70 | self.entity_id = 0 71 | self.background = pygame.surface.Surface(SCREEN_SIZE).convert() 72 | self.background.fill((255, 255, 255)) 73 | pygame.draw.circle(self.background, (200, 255, 200), NEST_POSITION, int(NEST_SIZE)) 74 | 75 | def add_entity(self, entity): 76 | 77 | self.entities[self.entity_id] = entity 78 | entity.id = self.entity_id 79 | self.entity_id += 1 80 | 81 | def remove_entity(self, entity): 82 | 83 | del self.entities[entity.id] 84 | 85 | def get(self, entity_id): 86 | 87 | if entity_id in self.entities: 88 | return self.entities[entity_id] 89 | else: 90 | return None 91 | 92 | def process(self, time_passed): 93 | 94 | time_passed_seconds = time_passed / 1000.0 95 | for entity in self.entities.values(): 96 | entity.process(time_passed_seconds) 97 | 98 | def render(self, surface): 99 | 100 | surface.blit(self.background, (0, 0)) 101 | for entity in self.entities.itervalues(): 102 | entity.render(surface) 103 | 104 | 105 | def get_close_entity(self, name, location, range=100.): 106 | 107 | location = Vector2(*location) 108 | 109 | for entity in self.entities.itervalues(): 110 | if entity.name == name: 111 | distance = location.get_distance_to(entity.location) 112 | if distance < range: 113 | return entity 114 | return None 115 | 116 | 117 | class GameEntity(object): 118 | 119 | def __init__(self, world, name, image): 120 | 121 | self.world = world 122 | self.name = name 123 | self.image = image 124 | self.location = Vector2(0, 0) 125 | self.destination = Vector2(0, 0) 126 | self.speed = 0. 127 | 128 | self.brain = StateMachine() 129 | 130 | self.id = 0 131 | 132 | def render(self, surface): 133 | 134 | x, y = self.location 135 | w, h = self.image.get_size() 136 | surface.blit(self.image, (x-w/2, y-h/2)) 137 | 138 | def process(self, time_passed): 139 | 140 | self.brain.think() 141 | 142 | if self.speed > 0. and self.location != self.destination: 143 | 144 | vec_to_destination = self.destination - self.location 145 | distance_to_destination = vec_to_destination.get_length() 146 | heading = vec_to_destination.get_normalized() 147 | travel_distance = min(distance_to_destination, time_passed * self.speed) 148 | self.location += travel_distance * heading 149 | 150 | 151 | class Leaf(GameEntity): 152 | 153 | def __init__(self, world, image): 154 | GameEntity.__init__(self, world, "leaf", image) 155 | 156 | 157 | class Spider(GameEntity): 158 | 159 | def __init__(self, world, image): 160 | GameEntity.__init__(self, world, "spider", image) 161 | self.dead_image = pygame.transform.flip(image, 0, 1) 162 | self.health = 25 163 | self.speed = 50. + randint(-20, 20) 164 | 165 | def bitten(self): 166 | 167 | self.health -= 1 168 | if self.health <= 0: 169 | self.speed = 0. 170 | self.image = self.dead_image 171 | self.speed = 140. 172 | 173 | def render(self, surface): 174 | 175 | GameEntity.render(self, surface) 176 | 177 | x, y = self.location 178 | w, h = self.image.get_size() 179 | bar_x = x - 12 180 | bar_y = y + h/2 181 | surface.fill( (255, 0, 0), (bar_x, bar_y, 25, 4)) 182 | surface.fill( (0, 255, 0), (bar_x, bar_y, self.health, 4)) 183 | 184 | def process(self, time_passed): 185 | 186 | x, y = self.location 187 | if x > SCREEN_SIZE[0] + 2: 188 | self.world.remove_entity(self) 189 | return 190 | 191 | GameEntity.process(self, time_passed) 192 | 193 | 194 | class Ant(GameEntity): 195 | 196 | def __init__(self, world, image): 197 | 198 | GameEntity.__init__(self, world, "ant", image) 199 | 200 | exploring_state = AntStateExploring(self) 201 | seeking_state = AntStateSeeking(self) 202 | delivering_state = AntStateDelivering(self) 203 | hunting_state = AntStateHunting(self) 204 | 205 | self.brain.add_state(exploring_state) 206 | self.brain.add_state(seeking_state) 207 | self.brain.add_state(delivering_state) 208 | self.brain.add_state(hunting_state) 209 | 210 | self.carry_image = None 211 | 212 | def carry(self, image): 213 | 214 | self.carry_image = image 215 | 216 | def drop(self, surface): 217 | 218 | if self.carry_image: 219 | x, y = self.location 220 | w, h = self.carry_image.get_size() 221 | surface.blit(self.carry_image, (x-w, y-h/2)) 222 | self.carry_image = None 223 | 224 | def render(self, surface): 225 | 226 | GameEntity.render(self, surface) 227 | 228 | if self.carry_image: 229 | x, y = self.location 230 | w, h = self.carry_image.get_size() 231 | surface.blit(self.carry_image, (x-w, y-h/2)) 232 | 233 | 234 | class AntStateExploring(State): 235 | 236 | def __init__(self, ant): 237 | 238 | State.__init__(self, "exploring") 239 | self.ant = ant 240 | 241 | def random_destination(self): 242 | 243 | w, h = SCREEN_SIZE 244 | self.ant.destination = Vector2(randint(0, w), randint(0, h)) 245 | 246 | def do_actions(self): 247 | 248 | if randint(1, 20) == 1: 249 | self.random_destination() 250 | 251 | def check_conditions(self): 252 | 253 | leaf = self.ant.world.get_close_entity("leaf", self.ant.location) 254 | if leaf is not None: 255 | self.ant.leaf_id = leaf.id 256 | return "seeking" 257 | 258 | spider = self.ant.world.get_close_entity("spider", NEST_POSITION, NEST_SIZE) 259 | if spider is not None: 260 | if self.ant.location.get_distance_to(spider.location) < 100.: 261 | self.ant.spider_id = spider.id 262 | return "hunting" 263 | 264 | return None 265 | 266 | def entry_actions(self): 267 | 268 | self.ant.speed = 120. + randint(-30, 30) 269 | self.random_destination() 270 | 271 | 272 | class AntStateSeeking(State): 273 | 274 | def __init__(self, ant): 275 | 276 | State.__init__(self, "seeking") 277 | self.ant = ant 278 | self.leaf_id = None 279 | 280 | def check_conditions(self): 281 | 282 | leaf = self.ant.world.get(self.ant.leaf_id) 283 | if leaf is None: 284 | return "exploring" 285 | 286 | if self.ant.location.get_distance_to(leaf.location) < 5.0: 287 | 288 | self.ant.carry(leaf.image) 289 | self.ant.world.remove_entity(leaf) 290 | return "delivering" 291 | 292 | return None 293 | 294 | def entry_actions(self): 295 | 296 | leaf = self.ant.world.get(self.ant.leaf_id) 297 | if leaf is not None: 298 | self.ant.destination = leaf.location 299 | self.ant.speed = 160. + randint(-20, 20) 300 | 301 | 302 | class AntStateDelivering(State): 303 | 304 | def __init__(self, ant): 305 | 306 | State.__init__(self, "delivering") 307 | self.ant = ant 308 | 309 | 310 | def check_conditions(self): 311 | 312 | if Vector2(*NEST_POSITION).get_distance_to(self.ant.location) < NEST_SIZE: 313 | if (randint(1, 10) == 1): 314 | self.ant.drop(self.ant.world.background) 315 | return "exploring" 316 | 317 | return None 318 | 319 | 320 | def entry_actions(self): 321 | 322 | self.ant.speed = 60. 323 | random_offset = Vector2(randint(-20, 20), randint(-20, 20)) 324 | self.ant.destination = Vector2(*NEST_POSITION) + random_offset 325 | 326 | 327 | class AntStateHunting(State): 328 | 329 | def __init__(self, ant): 330 | 331 | State.__init__(self, "hunting") 332 | self.ant = ant 333 | self.got_kill = False 334 | 335 | def do_actions(self): 336 | 337 | spider = self.ant.world.get(self.ant.spider_id) 338 | 339 | if spider is None: 340 | return 341 | 342 | self.ant.destination = spider.location 343 | 344 | if self.ant.location.get_distance_to(spider.location) < 15.: 345 | 346 | if randint(1, 5) == 1: 347 | spider.bitten() 348 | 349 | if spider.health <= 0: 350 | self.ant.carry(spider.image) 351 | self.ant.world.remove_entity(spider) 352 | self.got_kill = True 353 | 354 | 355 | def check_conditions(self): 356 | 357 | if self.got_kill: 358 | return "delivering" 359 | 360 | spider = self.ant.world.get(self.ant.spider_id) 361 | 362 | if spider is None: 363 | return "exploring" 364 | 365 | if spider.location.get_distance_to(NEST_POSITION) > NEST_SIZE * 3: 366 | return "exploring" 367 | 368 | return None 369 | 370 | def entry_actions(self): 371 | 372 | self.speed = 160. + randint(0, 50) 373 | 374 | def exit_actions(self): 375 | 376 | self.got_kill = False 377 | 378 | 379 | 380 | def run(): 381 | 382 | pygame.init() 383 | screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32) 384 | 385 | world = World() 386 | 387 | w, h = SCREEN_SIZE 388 | 389 | clock = pygame.time.Clock() 390 | 391 | ant_image = pygame.image.load("ant.png").convert_alpha() 392 | leaf_image = pygame.image.load("leaf.png").convert_alpha() 393 | spider_image = pygame.image.load("spider.png").convert_alpha() 394 | 395 | for ant_no in xrange(ANT_COUNT): 396 | 397 | ant = Ant(world, ant_image) 398 | ant.location = Vector2(randint(0, w), randint(0, h)) 399 | ant.brain.set_state("exploring") 400 | world.add_entity(ant) 401 | 402 | 403 | while True: 404 | 405 | for event in pygame.event.get(): 406 | if event.type == QUIT: 407 | return 408 | 409 | time_passed = clock.tick(30) 410 | 411 | if randint(1, 10) == 1: 412 | leaf = Leaf(world, leaf_image) 413 | leaf.location = Vector2(randint(0, w), randint(0, h)) 414 | world.add_entity(leaf) 415 | 416 | if randint(1, 100) == 1: 417 | spider = Spider(world, spider_image) 418 | spider.location = Vector2(-50, randint(0, h)) 419 | spider.destination = Vector2(w+50, randint(0, h)) 420 | world.add_entity(spider) 421 | 422 | world.process(time_passed) 423 | world.render(screen) 424 | 425 | pygame.display.update() 426 | 427 | if __name__ == "__main__": 428 | run() 429 | 430 | -------------------------------------------------------------------------------- /bpwpapcode/Chapter07/antsstatemachine.py: -------------------------------------------------------------------------------- 1 | SCREEN_SIZE = (640, 480) 2 | NEST_POSITION = (320, 240) 3 | ANT_COUNT = 20 4 | NEST_SIZE = 100. 5 | 6 | import pygame 7 | from pygame.locals import * 8 | 9 | from random import randint, choice 10 | from gameobjects.vector2 import Vector2 11 | 12 | class State(object): 13 | 14 | def __init__(self, name): 15 | self.name = name 16 | 17 | def do_actions(self): 18 | pass 19 | 20 | def check_conditions(self): 21 | pass 22 | 23 | def entry_actions(self): 24 | pass 25 | 26 | def exit_actions(self): 27 | pass 28 | 29 | 30 | class StateMachine(object): 31 | 32 | def __init__(self): 33 | 34 | self.states = {} 35 | self.active_state = None 36 | 37 | 38 | def add_state(self, state): 39 | 40 | self.states[state.name] = state 41 | 42 | 43 | def think(self): 44 | 45 | if self.active_state is None: 46 | return 47 | 48 | self.active_state.do_actions() 49 | 50 | new_state_name = self.active_state.check_conditions() 51 | if new_state_name is not None: 52 | self.set_state(new_state_name) 53 | 54 | 55 | def set_state(self, new_state_name): 56 | 57 | if self.active_state is not None: 58 | self.active_state.exit_actions() 59 | 60 | self.active_state = self.states[new_state_name] 61 | self.active_state.entry_actions() 62 | 63 | 64 | 65 | class World(object): 66 | 67 | def __init__(self): 68 | 69 | self.entities = {} 70 | self.entity_id = 0 71 | self.background = pygame.surface.Surface(SCREEN_SIZE).convert() 72 | self.background.fill((255, 255, 255)) 73 | pygame.draw.circle(self.background, (200, 255, 200), NEST_POSITION, int(NEST_SIZE)) 74 | 75 | def add_entity(self, entity): 76 | 77 | self.entities[self.entity_id] = entity 78 | entity.id = self.entity_id 79 | self.entity_id += 1 80 | 81 | def remove_entity(self, entity): 82 | 83 | del self.entities[entity.id] 84 | 85 | def get(self, entity_id): 86 | 87 | if entity_id in self.entities: 88 | return self.entities[entity_id] 89 | else: 90 | return None 91 | 92 | def process(self, time_passed): 93 | 94 | time_passed_seconds = time_passed / 1000.0 95 | for entity in self.entities.values(): 96 | entity.process(time_passed_seconds) 97 | 98 | def render(self, surface): 99 | 100 | surface.blit(self.background, (0, 0)) 101 | for entity in self.entities.itervalues(): 102 | entity.render(surface) 103 | 104 | 105 | def get_close_entity(self, name, location, range=100.): 106 | 107 | location = Vector2(*location) 108 | 109 | for entity in self.entities.itervalues(): 110 | if entity.name == name: 111 | distance = location.get_distance_to(entity.location) 112 | if distance < range: 113 | return entity 114 | return None 115 | 116 | 117 | class GameEntity(object): 118 | 119 | def __init__(self, world, name, image): 120 | 121 | self.world = world 122 | self.name = name 123 | self.image = image 124 | self.location = Vector2(0, 0) 125 | self.destination = Vector2(0, 0) 126 | self.speed = 0. 127 | 128 | self.brain = StateMachine() 129 | 130 | self.id = 0 131 | 132 | def render(self, surface): 133 | 134 | x, y = self.location 135 | w, h = self.image.get_size() 136 | surface.blit(self.image, (x-w/2, y-h/2)) 137 | 138 | def process(self, time_passed): 139 | 140 | self.brain.think() 141 | 142 | if self.speed > 0. and self.location != self.destination: 143 | 144 | vec_to_destination = self.destination - self.location 145 | distance_to_destination = vec_to_destination.get_length() 146 | heading = vec_to_destination.get_normalized() 147 | travel_distance = min(distance_to_destination, time_passed * self.speed) 148 | self.location += travel_distance * heading 149 | 150 | 151 | class Leaf(GameEntity): 152 | 153 | def __init__(self, world, image): 154 | GameEntity.__init__(self, world, "leaf", image) 155 | 156 | 157 | class Spider(GameEntity): 158 | 159 | def __init__(self, world, image): 160 | GameEntity.__init__(self, world, "spider", image) 161 | self.dead_image = pygame.transform.flip(image, 0, 1) 162 | self.health = 25 163 | self.speed = 50. + randint(-20, 20) 164 | 165 | def bitten(self): 166 | 167 | self.health -= 1 168 | if self.health <= 0: 169 | self.speed = 0. 170 | self.image = self.dead_image 171 | self.speed = 140. 172 | 173 | def render(self, surface): 174 | 175 | GameEntity.render(self, surface) 176 | 177 | x, y = self.location 178 | w, h = self.image.get_size() 179 | bar_x = x - 12 180 | bar_y = y + h/2 181 | surface.fill( (255, 0, 0), (bar_x, bar_y, 25, 4)) 182 | surface.fill( (0, 255, 0), (bar_x, bar_y, self.health, 4)) 183 | 184 | def process(self, time_passed): 185 | 186 | x, y = self.location 187 | if x > SCREEN_SIZE[0] + 2: 188 | self.world.remove_entity(self) 189 | return 190 | 191 | GameEntity.process(self, time_passed) 192 | 193 | 194 | class Ant(GameEntity): 195 | 196 | def __init__(self, world, image): 197 | 198 | GameEntity.__init__(self, world, "ant", image) 199 | 200 | exploring_state = AntStateExploring(self) 201 | seeking_state = AntStateSeeking(self) 202 | delivering_state = AntStateDelivering(self) 203 | hunting_state = AntStateHunting(self) 204 | 205 | self.brain.add_state(exploring_state) 206 | self.brain.add_state(seeking_state) 207 | self.brain.add_state(delivering_state) 208 | self.brain.add_state(hunting_state) 209 | 210 | self.carry_image = None 211 | 212 | def carry(self, image): 213 | 214 | self.carry_image = image 215 | 216 | def drop(self, surface): 217 | 218 | if self.carry_image: 219 | x, y = self.location 220 | w, h = self.carry_image.get_size() 221 | surface.blit(self.carry_image, (x-w, y-h/2)) 222 | self.carry_image = None 223 | 224 | def render(self, surface): 225 | 226 | GameEntity.render(self, surface) 227 | 228 | if self.carry_image: 229 | x, y = self.location 230 | w, h = self.carry_image.get_size() 231 | surface.blit(self.carry_image, (x-w, y-h/2)) 232 | 233 | 234 | class AntStateExploring(State): 235 | 236 | def __init__(self, ant): 237 | 238 | State.__init__(self, "exploring") 239 | self.ant = ant 240 | 241 | def random_destination(self): 242 | 243 | w, h = SCREEN_SIZE 244 | self.ant.destination = Vector2(randint(0, w), randint(0, h)) 245 | 246 | def do_actions(self): 247 | 248 | if randint(1, 20) == 1: 249 | self.random_destination() 250 | 251 | def check_conditions(self): 252 | 253 | leaf = self.ant.world.get_close_entity("leaf", self.ant.location) 254 | if leaf is not None: 255 | self.ant.leaf_id = leaf.id 256 | return "seeking" 257 | 258 | spider = self.ant.world.get_close_entity("spider", NEST_POSITION, NEST_SIZE) 259 | if spider is not None: 260 | if self.ant.location.get_distance_to(spider.location) < 100.: 261 | self.ant.spider_id = spider.id 262 | return "hunting" 263 | 264 | return None 265 | 266 | def entry_actions(self): 267 | 268 | self.ant.speed = 120. + randint(-30, 30) 269 | self.random_destination() 270 | 271 | 272 | class AntStateSeeking(State): 273 | 274 | def __init__(self, ant): 275 | 276 | State.__init__(self, "seeking") 277 | self.ant = ant 278 | self.leaf_id = None 279 | 280 | def check_conditions(self): 281 | 282 | leaf = self.ant.world.get(self.ant.leaf_id) 283 | if leaf is None: 284 | return "exploring" 285 | 286 | if self.ant.location.get_distance_to(leaf.location) < 5.0: 287 | 288 | self.ant.carry(leaf.image) 289 | self.ant.world.remove_entity(leaf) 290 | return "delivering" 291 | 292 | return None 293 | 294 | def entry_actions(self): 295 | 296 | leaf = self.ant.world.get(self.ant.leaf_id) 297 | if leaf is not None: 298 | self.ant.destination = leaf.location 299 | self.ant.speed = 160. + randint(-20, 20) 300 | 301 | 302 | class AntStateDelivering(State): 303 | 304 | def __init__(self, ant): 305 | 306 | State.__init__(self, "delivering") 307 | self.ant = ant 308 | 309 | 310 | def check_conditions(self): 311 | 312 | if Vector2(*NEST_POSITION).get_distance_to(self.ant.location) < NEST_SIZE: 313 | if (randint(1, 10) == 1): 314 | self.ant.drop(self.ant.world.background) 315 | return "exploring" 316 | 317 | return None 318 | 319 | 320 | def entry_actions(self): 321 | 322 | self.ant.speed = 60. 323 | random_offset = Vector2(randint(-20, 20), randint(-20, 20)) 324 | self.ant.destination = Vector2(*NEST_POSITION) + random_offset 325 | 326 | 327 | class AntStateHunting(State): 328 | 329 | def __init__(self, ant): 330 | 331 | State.__init__(self, "hunting") 332 | self.ant = ant 333 | self.got_kill = False 334 | 335 | def do_actions(self): 336 | 337 | spider = self.ant.world.get(self.ant.spider_id) 338 | 339 | if spider is None: 340 | return 341 | 342 | self.ant.destination = spider.location 343 | 344 | if self.ant.location.get_distance_to(spider.location) < 15.: 345 | 346 | if randint(1, 5) == 1: 347 | spider.bitten() 348 | 349 | if spider.health <= 0: 350 | self.ant.carry(spider.image) 351 | self.ant.world.remove_entity(spider) 352 | self.got_kill = True 353 | 354 | 355 | def check_conditions(self): 356 | 357 | if self.got_kill: 358 | return "delivering" 359 | 360 | spider = self.ant.world.get(self.ant.spider_id) 361 | 362 | if spider is None: 363 | return "exploring" 364 | 365 | if spider.location.get_distance_to(NEST_POSITION) > NEST_SIZE * 3: 366 | return "exploring" 367 | 368 | return None 369 | 370 | def entry_actions(self): 371 | 372 | self.speed = 160. + randint(0, 50) 373 | 374 | def exit_actions(self): 375 | 376 | self.got_kill = False 377 | 378 | 379 | 380 | def run(): 381 | 382 | pygame.init() 383 | screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32) 384 | 385 | world = World() 386 | 387 | w, h = SCREEN_SIZE 388 | 389 | clock = pygame.time.Clock() 390 | 391 | ant_image = pygame.image.load("ant.png").convert_alpha() 392 | leaf_image = pygame.image.load("leaf.png").convert_alpha() 393 | spider_image = pygame.image.load("spider.png").convert_alpha() 394 | 395 | for ant_no in xrange(ANT_COUNT): 396 | 397 | ant = Ant(world, ant_image) 398 | ant.location = Vector2(randint(0, w), randint(0, h)) 399 | ant.brain.set_state("exploring") 400 | world.add_entity(ant) 401 | 402 | 403 | while True: 404 | 405 | for event in pygame.event.get(): 406 | if event.type == QUIT: 407 | return 408 | 409 | time_passed = clock.tick(30) 410 | 411 | if randint(1, 10) == 1: 412 | leaf = Leaf(world, leaf_image) 413 | leaf.location = Vector2(randint(0, w), randint(0, h)) 414 | world.add_entity(leaf) 415 | 416 | if randint(1, 100) == 1: 417 | spider = Spider(world, spider_image) 418 | spider.location = Vector2(-50, randint(0, h)) 419 | spider.destination = Vector2(w+50, randint(0, h)) 420 | world.add_entity(spider) 421 | 422 | world.process(time_passed) 423 | world.render(screen) 424 | 425 | pygame.display.update() 426 | 427 | if __name__ == "__main__": 428 | run() 429 | 430 | --------------------------------------------------------------------------------