├── 9781484209714.jpg ├── 9781484209714_AppB ├── ant.png ├── ants_game.py ├── gameobjects │ ├── __pycache__ │ │ ├── util.cpython-34.pyc │ │ └── vector2.cpython-34.pyc │ ├── util.py │ └── vector2.py ├── leaf.png ├── setup.py └── spider.png ├── 9781484209714_Chapter_02 ├── tank.py └── tankgame.py ├── 9781484209714_Chapter_03 ├── 3-1.py ├── 3-2.py ├── 3-3.py ├── 3-4.py ├── 3-5.py ├── 3-6.py ├── 3-7.py ├── fugu.png ├── name.png └── sushiplate.jpg ├── 9781484209714_Chapter_04 ├── 4-1.py ├── 4-10.py ├── 4-11.py ├── 4-12.py ├── 4-13.py ├── 4-14.py ├── 4-15.py ├── 4-2.py ├── 4-3.py ├── 4-4.py ├── 4-5.py ├── 4-6.py ├── 4-7.py ├── 4-8.py ├── 4-9.py └── allcolors.bmp ├── 9781484209714_Chapter_05 ├── 5-1.py ├── 5-10.py ├── 5-11.py ├── 5-12.py ├── 5-13.py ├── 5-14.py ├── 5-15.py ├── 5-16.py ├── 5-17.py ├── 5-2.py ├── 5-3.py ├── 5-4.py ├── 5-5.py ├── 5-6.py ├── 5-7.py ├── 5-8.py ├── 5-9.py ├── fugu.png ├── gameobjects │ └── vector2.py └── sushiplate.jpg ├── 9781484209714_Chapter_06 ├── 6-1.py ├── 6-2.py ├── 6-3.py ├── 6-4.py ├── 6-5.py ├── 6-6.py ├── 6-7.py ├── 6-8.py ├── fugu.png ├── gameobjects │ ├── __pycache__ │ │ └── vector2.cpython-34.pyc │ └── vector2.py ├── map.png └── sushiplate.jpg ├── 9781484209714_Chapter_07 ├── 7-1.py ├── 7-2.py ├── 7-3.py ├── 7-4.py ├── 7-5.py ├── 7-6.py ├── 7-7.py ├── 7-8.py ├── 7-9.py ├── ant.png ├── gameobjects │ ├── util.py │ └── vector2.py ├── leaf.png └── spider.png ├── 9781484209714_Chapter_08 ├── 8-1.py ├── 8-2.py ├── 8-3.py ├── 8-4.py ├── 8-5.py ├── 8-6.py ├── 8-7.py ├── 8-8.py ├── ball.png └── gameobjects │ ├── __pycache__ │ ├── util.cpython-34.pyc │ ├── vector2.cpython-34.pyc │ └── vector3.cpython-34.pyc │ ├── util.py │ ├── vector2.py │ └── vector3.py ├── 9781484209714_Chapter_09 ├── 9-1.py ├── 9-2.py ├── 9-3.py ├── 9-4.py ├── 9-5.py ├── 9-6.py ├── 9-7.py ├── 9-8.py ├── ball.png ├── firstopengl.py ├── gameobjects │ ├── __pycache__ │ │ ├── matrix44.cpython-34.pyc │ │ ├── util.cpython-34.pyc │ │ ├── vector2.cpython-34.pyc │ │ └── vector3.cpython-34.pyc │ ├── matrix44.py │ ├── util.py │ ├── vector2.py │ └── vector3.py └── map.png ├── 9781484209714_Chapter_10 ├── 10-1.py ├── 10-2.py ├── 10-3.py ├── 10-4.py ├── 10-5.py ├── 10-6.py ├── ball.png ├── bar.png ├── bounce.wav ├── bouncesound.py ├── cross.png ├── gameobjects │ ├── __pycache__ │ │ ├── matrix44.cpython-34.pyc │ │ ├── util.cpython-34.pyc │ │ ├── vector2.cpython-34.pyc │ │ └── vector3.cpython-34.pyc │ ├── matrix44.py │ ├── util.py │ ├── vector2.py │ └── vector3.py ├── jukebox.py ├── mousecursor.png ├── music │ └── please put some ogg files in the music folder.ogg ├── next.png ├── pause.png ├── play.png ├── prev.png └── stop.png ├── 9781484209714_Chapter_11 ├── 11-1.py ├── 11-2.1.py ├── 11-2.2.py ├── 11-2.3.py ├── 11-2.4.py ├── 11-2.5.py ├── 11-2.py ├── 11-3.py ├── 11-4.py ├── 11-5.py ├── 11-6.py ├── 11-7.py ├── 11-8.py ├── bodytex.jpg ├── booktex.png ├── gameobjects │ ├── __pycache__ │ │ ├── matrix44.cpython-34.pyc │ │ ├── util.cpython-34.pyc │ │ ├── vector2.cpython-34.pyc │ │ └── vector3.cpython-34.pyc │ ├── matrix44.py │ ├── util.py │ ├── vector2.py │ └── vector3.py ├── model3d.py ├── mytank.mtl ├── mytank.obj ├── mytanktex.jpg ├── opengltex.py ├── opengltextiled.py ├── sushitex.png └── tankdemo.py ├── 9781484209714_Chapter_12 ├── 12-1.py ├── 12-2.py ├── 12-3.py ├── 12-4.py ├── 12-5.py ├── 12-6.py ├── background.png ├── blenddemo.py ├── bodytex.jpg ├── booktex.png ├── fogdemo.py ├── fugu.png ├── gameobjects │ ├── __pycache__ │ │ ├── matrix44.cpython-34.pyc │ │ ├── util.cpython-34.pyc │ │ ├── vector2.cpython-34.pyc │ │ └── vector3.cpython-34.pyc │ ├── matrix44.py │ ├── util.py │ ├── vector2.py │ └── vector3.py ├── heavyfogtank.py.py ├── model3d.py ├── mytank.mtl ├── mytank.obj ├── mytanktex.jpg ├── skybox.py └── tanksky │ ├── bk.png │ ├── dn.png │ ├── ft.png │ ├── lt.png │ ├── rt.png │ ├── skybox.mtl │ ├── skybox.obj │ └── up.png ├── Errata for Beginning Python Games.pdf ├── LICENSE.txt ├── README.md └── contributing.md /9781484209714.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714.jpg -------------------------------------------------------------------------------- /9781484209714_AppB/ant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_AppB/ant.png -------------------------------------------------------------------------------- /9781484209714_AppB/gameobjects/__pycache__/util.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_AppB/gameobjects/__pycache__/util.cpython-34.pyc -------------------------------------------------------------------------------- /9781484209714_AppB/gameobjects/__pycache__/vector2.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_AppB/gameobjects/__pycache__/vector2.cpython-34.pyc -------------------------------------------------------------------------------- /9781484209714_AppB/gameobjects/util.py: -------------------------------------------------------------------------------- 1 | from math import * 2 | 3 | def format_number(n, accuracy=6): 4 | """Formats a number in a friendly manner 5 | (removes trailing zeros and unneccesary point.""" 6 | 7 | fs = "%."+str(accuracy)+"f" 8 | str_n = fs%float(n) 9 | if '.' in str_n: 10 | str_n = str_n.rstrip('0').rstrip('.') 11 | if str_n == "-0": 12 | str_n = "0" 13 | #str_n = str_n.replace("-0", "0") 14 | return str_n 15 | 16 | 17 | def lerp(a, b, i): 18 | """Linear enterpolate from a to b.""" 19 | return a+(b-a)*i 20 | 21 | 22 | def range2d(range_x, range_y): 23 | 24 | """Creates a 2D range.""" 25 | 26 | range_x = list(range_x) 27 | return [ (x, y) for y in range_y for x in range_x ] 28 | 29 | 30 | def xrange2d(range_x, range_y): 31 | 32 | """Iterates over a 2D range.""" 33 | 34 | range_x = list(range_x) 35 | for y in range_y: 36 | for x in range_x: 37 | yield (x, y) 38 | 39 | 40 | def saturate(value, low, high): 41 | return min(max(value, low), high) 42 | 43 | 44 | def is_power_of_2(n): 45 | """Returns True if a value is a power of 2.""" 46 | return log(n, 2) % 1.0 == 0.0 47 | 48 | 49 | def next_power_of_2(n): 50 | """Returns the next power of 2 that is >= n""" 51 | return int(2 ** ceil(log(n, 2))) 52 | 53 | if __name__ == "__main__": 54 | 55 | print(list( xrange2d(xrange(3), xrange(3)) )) 56 | print(range2d(xrange(3), xrange(3))) 57 | print(is_power_of_2(7)) 58 | print(is_power_of_2(8)) 59 | print(is_power_of_2(9)) 60 | 61 | print(next_power_of_2(7)) 62 | -------------------------------------------------------------------------------- /9781484209714_AppB/leaf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_AppB/leaf.png -------------------------------------------------------------------------------- /9781484209714_AppB/setup.py: -------------------------------------------------------------------------------- 1 | import cx_Freeze 2 | 3 | executables = [cx_Freeze.Executable("ants_game.py")] 4 | 5 | cx_Freeze.setup( 6 | name="Ant Game", 7 | options={"build_exe": {"packages":["pygame"], 8 | "include_files":["ant.png","leaf.png","spider.png",'gameobjects']}}, 9 | executables = executables 10 | 11 | ) 12 | -------------------------------------------------------------------------------- /9781484209714_AppB/spider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_AppB/spider.png -------------------------------------------------------------------------------- /9781484209714_Chapter_02/tank.py: -------------------------------------------------------------------------------- 1 | class Tank(object): 2 | def __init__ (self, name): 3 | self.name = name 4 | self.alive = True 5 | self.ammo = 5 6 | self.armor = 60 7 | 8 | def __str__ (self): 9 | if self.alive: 10 | return "%s (%i armor, %i shells)" % (self.name, self.armor, self.ammo) 11 | else: 12 | return "%s (DEAD)" % self.name 13 | 14 | def fire_at(self, enemy): 15 | if self.ammo >= 1: 16 | self.ammo -= 1 17 | print(self.name, "fires on", enemy.name) 18 | enemy.hit() 19 | else: 20 | print(self.name, "has no shells!") 21 | 22 | def hit(self): 23 | self.armor -= 20 24 | print(self.name, "is hit!") 25 | if self.armor <= 0: 26 | self.explode() 27 | 28 | def explode(self): 29 | self.alive = False 30 | print(self.name, "explodes!") 31 | -------------------------------------------------------------------------------- /9781484209714_Chapter_02/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 | 9 | for tank_name in sorted( tanks.keys() ): 10 | print(tank_name, tanks[tank_name]) 11 | 12 | first = input("Who fires? ").lower() 13 | second = input("Who at? " ).lower() 14 | 15 | try: 16 | first_tank = tanks[first] 17 | second_tank = tanks[second] 18 | except KeyError as name: 19 | print("No such tank!", name) 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 | 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 | -------------------------------------------------------------------------------- /9781484209714_Chapter_03/3-1.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).convert_alpha() 17 | 18 | while True: 19 | 20 | for event in pygame.event.get(): 21 | if event.type == QUIT: 22 | pygame.quit() 23 | exit() 24 | 25 | screen.blit(background, (0,0)) 26 | 27 | x, y = pygame.mouse.get_pos() 28 | x-= mouse_cursor.get_width() / 2 29 | y-= mouse_cursor.get_height() / 2 30 | screen.blit(mouse_cursor, (x, y)) 31 | 32 | pygame.display.update() 33 | -------------------------------------------------------------------------------- /9781484209714_Chapter_03/3-2.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | 5 | pygame.init() 6 | SCREEN_SIZE = (800, 600) 7 | screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32) 8 | 9 | while True: 10 | 11 | for event in pygame.event.get(): 12 | if event.type == QUIT: 13 | pygame.quit() 14 | exit() 15 | print(event) 16 | 17 | pygame.display.update() 18 | -------------------------------------------------------------------------------- /9781484209714_Chapter_03/3-3.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 | x, y = 0, 0 12 | move_x, move_y = 0, 0 13 | 14 | while True: 15 | 16 | for event in pygame.event.get(): 17 | if event.type == QUIT: 18 | pygame.quit() 19 | exit() 20 | 21 | if event.type == KEYDOWN: 22 | if event.key == K_LEFT: 23 | move_x = -1 24 | elif event.key == K_RIGHT: 25 | move_x = +1 26 | elif event.key == K_UP: 27 | move_y = -1 28 | elif event.key == K_DOWN: 29 | move_y = +1 30 | 31 | 32 | elif event.type == KEYUP: 33 | if event.key == K_LEFT: 34 | move_x = 0 35 | elif event.key == K_RIGHT: 36 | move_x = 0 37 | elif event.key == K_UP: 38 | move_y = 0 39 | elif event.key == K_DOWN: 40 | move_y = 0 41 | 42 | x+= move_x 43 | y+= move_y 44 | 45 | screen.fill((0, 0, 0)) 46 | screen.blit(background, (x, y)) 47 | 48 | pygame.display.update() 49 | -------------------------------------------------------------------------------- /9781484209714_Chapter_03/3-4.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | 5 | background_image_filename = 'sushiplate.jpg' 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 | pygame.quit() 18 | exit() 19 | if event.type == KEYDOWN: 20 | if event.key == K_f: 21 | Fullscreen = not Fullscreen 22 | if Fullscreen: 23 | screen = pygame.display.set_mode((640, 480), FULLSCREEN, 32) 24 | else: 25 | screen = pygame.display.set_mode((640, 480), 0, 32) 26 | 27 | screen.blit(background, (0,0)) 28 | pygame.display.update() 29 | -------------------------------------------------------------------------------- /9781484209714_Chapter_03/3-5.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | 5 | background_image_filename = 'sushiplate.jpg' 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 | pygame.quit() 19 | exit() 20 | if event.type == VIDEORESIZE: 21 | SCREEN_SIZE = event.size 22 | screen = pygame.display.set_mode(SCREEN_SIZE, RESIZABLE, 32) 23 | pygame.display.set_caption("Window resized to "+str(event.size)) 24 | 25 | screen_width, screen_height = SCREEN_SIZE 26 | for y in range(0, screen_height, background.get_height()): 27 | for x in range(0, screen_width, background.get_width()): 28 | screen.blit(background, (x, y)) 29 | 30 | pygame.display.update() 31 | -------------------------------------------------------------------------------- /9781484209714_Chapter_03/3-6.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | my_name = "Harrison Kinsley" 4 | pygame.init() 5 | my_font = pygame.font.SysFont("arial", 64) 6 | name_surface = my_font.render(my_name, True, (0, 0, 0), (255, 255, 255)) 7 | pygame.image.save(name_surface, "name.png") 8 | -------------------------------------------------------------------------------- /9781484209714_Chapter_03/3-7.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | 5 | background_image_filename = 'sushiplate.jpg' 6 | SCREEN_SIZE = (640, 480) 7 | message=" This is a demonstration of the scrolly message script. " 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 | pygame.quit() 25 | exit() 26 | 27 | screen.blit(background, (0,0)) 28 | 29 | x-= 2 30 | if x < -text_surface.get_width(): 31 | x = 0 32 | 33 | screen.blit(text_surface, (x, y)) 34 | screen.blit(text_surface, (x+text_surface.get_width(), y)) 35 | pygame.display.update() 36 | -------------------------------------------------------------------------------- /9781484209714_Chapter_03/fugu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_03/fugu.png -------------------------------------------------------------------------------- /9781484209714_Chapter_03/name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_03/name.png -------------------------------------------------------------------------------- /9781484209714_Chapter_03/sushiplate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_03/sushiplate.jpg -------------------------------------------------------------------------------- /9781484209714_Chapter_04/4-1.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 range(256): 9 | print(r+1, "out of 256") 10 | x = (r&15)*256 11 | y = (r>>4)*256 12 | for g in range(256): 13 | for b in range(256): 14 | all_colors.set_at((x+g, y+b), (r, g, b)) 15 | 16 | pygame.image.save(all_colors, "allcolors.bmp") 17 | pygame.quit() 18 | -------------------------------------------------------------------------------- /9781484209714_Chapter_04/4-10.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 | points = [] 9 | 10 | while True: 11 | 12 | for event in pygame.event.get(): 13 | if event.type == QUIT: 14 | pygame.quit() 15 | exit() 16 | if event.type == MOUSEBUTTONDOWN: 17 | points.append(event.pos) 18 | 19 | screen.fill((255,255,255)) 20 | 21 | if len(points) >= 3: 22 | pygame.draw.polygon(screen, (0,255,0), points) 23 | for point in points: 24 | pygame.draw.circle(screen, (0,0,255), point, 5) 25 | 26 | pygame.display.update() 27 | -------------------------------------------------------------------------------- /9781484209714_Chapter_04/4-11.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | 5 | from random import * 6 | 7 | pygame.init() 8 | screen = pygame.display.set_mode((640, 480), 0, 32) 9 | 10 | 11 | for _ in range(25): 12 | random_color = (randint(0,255), randint(0,255), randint(0,255)) 13 | random_pos = (randint(0,639), randint(0,479)) 14 | random_radius = randint(1,200) 15 | pygame.draw.circle(screen, random_color, random_pos, random_radius) 16 | 17 | pygame.display.update() 18 | 19 | 20 | while True: 21 | 22 | for event in pygame.event.get(): 23 | if event.type == QUIT: 24 | pygame.quit() 25 | exit() 26 | -------------------------------------------------------------------------------- /9781484209714_Chapter_04/4-12.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | 5 | from random import * 6 | 7 | pygame.init() 8 | screen = pygame.display.set_mode((640, 480), 0, 32) 9 | 10 | while True: 11 | 12 | for event in pygame.event.get(): 13 | if event.type == QUIT: 14 | pygame.quit() 15 | exit() 16 | 17 | x, y = pygame.mouse.get_pos() 18 | screen.fill((255,255,255)) 19 | pygame.draw.ellipse(screen, (0,255,0), (0,0,x,y)) 20 | 21 | pygame.display.update() 22 | -------------------------------------------------------------------------------- /9781484209714_Chapter_04/4-13.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | 5 | from random import * 6 | from math import pi 7 | 8 | pygame.init() 9 | screen = pygame.display.set_mode((640, 480), 0, 32) 10 | 11 | while True: 12 | 13 | for event in pygame.event.get(): 14 | if event.type == QUIT: 15 | pygame.quit() 16 | exit() 17 | 18 | x, y = pygame.mouse.get_pos() 19 | angle = (x/639.)*pi*2. 20 | screen.fill((255,255,255)) 21 | pygame.draw.arc(screen, (0,0,0), (0,0,639,479), 0, angle) 22 | 23 | pygame.display.update() 24 | -------------------------------------------------------------------------------- /9781484209714_Chapter_04/4-14.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 | while True: 9 | 10 | for event in pygame.event.get(): 11 | if event.type == QUIT: 12 | pygame.quit() 13 | exit() 14 | 15 | screen.fill((255, 255, 255)) 16 | 17 | mouse_pos = pygame.mouse.get_pos() 18 | 19 | for x in range(0,640,20): 20 | pygame.draw.line(screen, (0, 0, 0), (x, 0), mouse_pos) 21 | pygame.draw.line(screen, (0, 0, 0), (x, 479), mouse_pos) 22 | 23 | for y in range(0,480,20): 24 | pygame.draw.line(screen, (0, 0, 0), (0, y), mouse_pos) 25 | pygame.draw.line(screen, (0, 0, 0), (639, y), mouse_pos) 26 | 27 | pygame.display.update() 28 | -------------------------------------------------------------------------------- /9781484209714_Chapter_04/4-15.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 | points = [] 9 | 10 | while True: 11 | 12 | for event in pygame.event.get(): 13 | if event.type == QUIT: 14 | pygame.quit() 15 | exit() 16 | if event.type == MOUSEMOTION: 17 | points.append(event.pos) 18 | if len(points)>100: 19 | del points[0] 20 | 21 | screen.fill((255, 255, 255)) 22 | 23 | if len(points)>1: 24 | pygame.draw.lines(screen, (0,255,0), False, points, 2) 25 | 26 | pygame.display.update() 27 | -------------------------------------------------------------------------------- /9781484209714_Chapter_04/4-2.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | 5 | pygame.init() 6 | 7 | screen = pygame.display.set_mode((640, 480), 0, 32) 8 | 9 | # Creates images with smooth gradients 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/639.)*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 | pygame.quit() 34 | exit() 35 | 36 | screen.fill((0, 0, 0)) 37 | 38 | # Draw the scales to the screen 39 | screen.blit(red_scale, (0, 00)) 40 | screen.blit(green_scale, (0, 80)) 41 | screen.blit(blue_scale, (0, 160)) 42 | 43 | x, y = pygame.mouse.get_pos() 44 | 45 | # If the mouse was pressed on one of the sliders, adjust the color component 46 | if pygame.mouse.get_pressed()[0]: 47 | for component in range(3): 48 | if y > component*80 and y < (component+1)*80: 49 | color[component] = int((x/639.)*255.) 50 | pygame.display.set_caption("PyGame Color Test - "+str(tuple(color))) 51 | 52 | # Draw a circle for each slider to represent the current setting 53 | for component in range(3): 54 | pos = ( int((color[component]/255.)*639), component*80+40 ) 55 | pygame.draw.circle(screen, (255, 255, 255), pos, 20) 56 | 57 | pygame.draw.rect(screen, tuple(color), (0, 240, 640, 240)) 58 | 59 | pygame.display.update() 60 | -------------------------------------------------------------------------------- /9781484209714_Chapter_04/4-3.py: -------------------------------------------------------------------------------- 1 | def scale_color(color, scale): 2 | red, green, blue = color 3 | red = int(red*scale) 4 | green = int(green*scale) 5 | blue = int(blue*scale) 6 | return red, green, blue 7 | 8 | fireball_orange = (221, 99, 20) 9 | print(fireball_orange) 10 | print(scale_color(fireball_orange, .5)) 11 | -------------------------------------------------------------------------------- /9781484209714_Chapter_04/4-4.py: -------------------------------------------------------------------------------- 1 | def saturate_color(color): 2 | red, green, blue = color 3 | red = min(red, 255) 4 | green = min(green, 255) 5 | blue = min(blue, 255) 6 | return red, green, blue 7 | -------------------------------------------------------------------------------- /9781484209714_Chapter_04/4-5.py: -------------------------------------------------------------------------------- 1 | def lerp(value1, value2, factor): 2 | return value1+(value2-value1)*factor 3 | 4 | print(lerp(100, 200, 0.)) 5 | print(lerp(100, 200, 1.)) 6 | print(lerp(100, 200, .5)) 7 | print(lerp(100, 200, .25)) 8 | -------------------------------------------------------------------------------- /9781484209714_Chapter_04/4-6.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | 5 | pygame.init() 6 | 7 | screen = pygame.display.set_mode((640, 480), 0, 32) 8 | 9 | color1 = (221, 99, 20) 10 | color2 = (96, 130, 51) 11 | factor = 0. 12 | 13 | def blend_color(color1, color2, blend_factor): 14 | red1, green1, blue1 = color1 15 | red2, green2, blue2 = color2 16 | red = red1+(red2-red1)*blend_factor 17 | green = green1+(green2-green1)*blend_factor 18 | blue = blue1+(blue2-blue1)*blend_factor 19 | return int(red), int(green), int(blue) 20 | 21 | while True: 22 | 23 | for event in pygame.event.get(): 24 | if event.type == QUIT: 25 | pygame.quit() 26 | exit() 27 | 28 | screen.fill((255, 255, 255)) 29 | 30 | tri = [ (0,120), (639,100), (639, 140) ] 31 | pygame.draw.polygon(screen, (0,255,0), tri) 32 | pygame.draw.circle(screen, (0,0,0), (int(factor*639.), 120), 10) 33 | 34 | x, y = pygame.mouse.get_pos() 35 | if pygame.mouse.get_pressed()[0]: 36 | factor = x / 639. 37 | pygame.display.set_caption("PyGame Color Blend Test - %.3f"%factor) 38 | 39 | color = blend_color(color1, color2, factor) 40 | pygame.draw.rect(screen, color, (0, 240, 640, 240)) 41 | 42 | pygame.display.update() 43 | -------------------------------------------------------------------------------- /9781484209714_Chapter_04/4-7.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | from random import randint 5 | 6 | pygame.init() 7 | screen = pygame.display.set_mode((640, 480), 0, 32) 8 | 9 | while True: 10 | 11 | for event in pygame.event.get(): 12 | if event.type == QUIT: 13 | pygame.quit() 14 | exit() 15 | 16 | rand_col = (randint(0, 255), randint(0, 255), randint(0, 255)) 17 | for _ in range(100): 18 | rand_pos = (randint(0, 639), randint(0, 479)) 19 | screen.set_at(rand_pos, rand_col) 20 | 21 | pygame.display.update() 22 | -------------------------------------------------------------------------------- /9781484209714_Chapter_04/4-8.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | from random import randint 5 | 6 | pygame.init() 7 | screen = pygame.display.set_mode((640, 480), 0, 32) 8 | 9 | while True: 10 | 11 | for event in pygame.event.get(): 12 | if event.type == QUIT: 13 | pygame.quit() 14 | exit() 15 | 16 | rand_col = (randint(0, 255), randint(0, 255), randint(0, 255)) 17 | screen.lock() 18 | for _ in range(100): 19 | rand_pos = (randint(0, 639), randint(0, 479)) 20 | screen.set_at(rand_pos, rand_col) 21 | screen.unlock() 22 | pygame.display.update() 23 | -------------------------------------------------------------------------------- /9781484209714_Chapter_04/4-9.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | 5 | from random import * 6 | 7 | pygame.init() 8 | screen = pygame.display.set_mode((640, 480), 0, 32) 9 | 10 | screen.lock() 11 | for count in range(10): 12 | random_color = (randint(0,255), randint(0,255), randint(0,255)) 13 | random_pos = (randint(0,639), randint(0,479)) 14 | random_size = (639-randint(random_pos[0],639), 479-randint(random_pos[1],479)) 15 | pygame.draw.rect(screen, random_color, Rect(random_pos, random_size)) 16 | 17 | screen.unlock() 18 | 19 | pygame.display.update() 20 | 21 | while True: 22 | for event in pygame.event.get(): 23 | if event.type == QUIT: 24 | pygame.quit() 25 | exit() 26 | -------------------------------------------------------------------------------- /9781484209714_Chapter_04/allcolors.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_04/allcolors.bmp -------------------------------------------------------------------------------- /9781484209714_Chapter_05/5-1.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | 5 | background_image_filename = 'sushiplate.jpg' 6 | sprite_image_filename = 'fugu.png' 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 | pygame.quit() 23 | exit() 24 | 25 | 26 | screen.blit(background, (0,0)) 27 | screen.blit(sprite, (x, 100)) 28 | x += 1 29 | 30 | # If the image goes off the end of the screen, move it back 31 | if x > 640: 32 | x -= 640 33 | 34 | pygame.display.update() 35 | -------------------------------------------------------------------------------- /9781484209714_Chapter_05/5-10.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | class Vector2: 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 | def from_points(P1, P2): 13 | return Vector2( P2[0] - P1[0], P2[1] - P1[1] ) 14 | 15 | def get_magnitude(self): 16 | return math.sqrt( self.x**2 + self.y**2 ) 17 | 18 | def normalize(self): 19 | magnitude = self.get_magnitude() 20 | self.x /= magnitude 21 | self.y /= magnitude 22 | 23 | # rhs stands for Right Hand Side 24 | def __add__(self, rhs): 25 | return Vector2(self.x + rhs.x, self.y + rhs.y) 26 | 27 | 28 | 29 | A = (10.0, 20.0) 30 | B = (30.0, 35.0) 31 | C = (15.0, 45.0) 32 | 33 | 34 | AB = Vector2.from_points(A, B) 35 | BC = Vector2.from_points(B, C) 36 | 37 | AC = Vector2.from_points(A, C) 38 | print("Vector AC is", AC) 39 | 40 | AC = AB + BC 41 | print("AB + BC is", AC) 42 | -------------------------------------------------------------------------------- /9781484209714_Chapter_05/5-11.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | class Vector2: 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 | def from_points(P1, P2): 13 | return Vector2( P2[0] - P1[0], P2[1] - P1[1] ) 14 | 15 | def get_magnitude(self): 16 | return math.sqrt( self.x**2 + self.y**2 ) 17 | 18 | def normalize(self): 19 | magnitude = self.get_magnitude() 20 | self.x /= magnitude 21 | self.y /= magnitude 22 | 23 | # rhs stands for Right Hand Side 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 | 31 | 32 | A = (10.0, 20.0) 33 | B = (30.0, 35.0) 34 | C = (15.0, 45.0) 35 | 36 | 37 | AB = Vector2.from_points(A, B) 38 | BC = Vector2.from_points(B, C) 39 | 40 | AC = Vector2.from_points(A, C) 41 | print("Vector AC is", AC) 42 | 43 | AC = AB + BC 44 | print("AB + BC is", AC) 45 | -------------------------------------------------------------------------------- /9781484209714_Chapter_05/5-12.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | class Vector2: 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 | def from_points(P1, P2): 13 | return Vector2( P2[0] - P1[0], P2[1] - P1[1] ) 14 | 15 | def get_magnitude(self): 16 | return math.sqrt( self.x**2 + self.y**2 ) 17 | 18 | def normalize(self): 19 | magnitude = self.get_magnitude() 20 | self.x /= magnitude 21 | self.y /= magnitude 22 | 23 | # rhs stands for Right Hand Side 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 | A = (10.0, 20.0) 34 | B = (30.0, 35.0) 35 | C = (15.0, 45.0) 36 | 37 | 38 | AB = Vector2.from_points(A, B) 39 | BC = Vector2.from_points(B, C) 40 | 41 | AC = Vector2.from_points(A, C) 42 | print("Vector AC is", AC) 43 | 44 | AC = AB + BC 45 | print("AB + BC is", AC) 46 | -------------------------------------------------------------------------------- /9781484209714_Chapter_05/5-13.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | class Vector2: 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 | def from_points(P1, P2): 13 | return Vector2( P2[0] - P1[0], P2[1] - P1[1] ) 14 | 15 | def get_magnitude(self): 16 | return math.sqrt( self.x**2 + self.y**2 ) 17 | 18 | def normalize(self): 19 | magnitude = self.get_magnitude() 20 | self.x /= magnitude 21 | self.y /= magnitude 22 | 23 | # rhs stands for Right Hand Side 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 __truediv__(self, scalar): 37 | return Vector2(self.x / scalar, self.y / scalar) 38 | 39 | 40 | 41 | A = (10.0, 20.0) 42 | B = (30.0, 35.0) 43 | C = (15.0, 45.0) 44 | 45 | 46 | AB = Vector2.from_points(A, B) 47 | BC = Vector2.from_points(B, C) 48 | 49 | AC = Vector2.from_points(A, C) 50 | print("Vector AC is", AC) 51 | 52 | AC = AB + BC 53 | print("AB + BC is", AC) 54 | -------------------------------------------------------------------------------- /9781484209714_Chapter_05/5-14.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | class Vector2: 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 | def from_points(P1, P2): 13 | return Vector2( P2[0] - P1[0], P2[1] - P1[1] ) 14 | 15 | def get_magnitude(self): 16 | return math.sqrt( self.x**2 + self.y**2 ) 17 | 18 | def normalize(self): 19 | magnitude = self.get_magnitude() 20 | self.x /= magnitude 21 | self.y /= magnitude 22 | 23 | def __add__(self, rhs): 24 | return Vector2(self.x + rhs.x, self.y + rhs.y) 25 | 26 | def __sub__(self, rhs): 27 | return Vector2(self.x - rhs.x, self.y - rhs.y) 28 | 29 | def __neg__(self): 30 | return Vector2(-self.x, -self.y) 31 | 32 | def __mul__(self, scalar): 33 | return Vector2(self.x * scalar, self.y * scalar) 34 | 35 | def __truediv__(self, scalar): 36 | return Vector2(self.x / scalar, self.y / scalar) 37 | 38 | 39 | A = (10.0, 20.0) 40 | B = (30.0, 35.0) 41 | AB = Vector2.from_points(A, B) 42 | step = AB * .1 43 | position = Vector2(*A) 44 | for n in range(10): 45 | position += step 46 | print(position) 47 | 48 | -------------------------------------------------------------------------------- /9781484209714_Chapter_05/5-15.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | class Vector2: 4 | 5 | def __init__(self, x=0, y=0): 6 | self.x = x 7 | self.y = y 8 | 9 | if hasattr(x, "__getitem__"): 10 | x, y = x 11 | self._v = [float(x), float(y)] 12 | else: 13 | self._v = [float(x), float(y)] 14 | 15 | def __str__(self): 16 | return "(%s, %s)"%(self.x, self.y) 17 | 18 | def from_points(P1, P2): 19 | return Vector2( P2[0] - P1[0], P2[1] - P1[1] ) 20 | 21 | def get_magnitude(self): 22 | return math.sqrt( self.x**2 + self.y**2 ) 23 | 24 | def normalize(self): 25 | magnitude = self.get_magnitude() 26 | self.x /= magnitude 27 | self.y /= magnitude 28 | 29 | def __add__(self, rhs): 30 | return Vector2(self.x + rhs.x, self.y + rhs.y) 31 | 32 | def __sub__(self, rhs): 33 | return Vector2(self.x - rhs.x, self.y - rhs.y) 34 | 35 | def __neg__(self): 36 | return Vector2(-self.x, -self.y) 37 | 38 | def __mul__(self, scalar): 39 | return Vector2(self.x * scalar, self.y * scalar) 40 | 41 | def __truediv__(self, scalar): 42 | return Vector2(self.x / scalar, self.y / scalar) 43 | 44 | def __getitem__(self, index): 45 | return self._v[index] 46 | 47 | def __setitem__(self, index, value): 48 | self._v[index] = 1.0 * value 49 | 50 | 51 | if __name__ == "__main__": 52 | A = (10.0, 20.0) 53 | B = (30.0, 35.0) 54 | AB = Vector2.from_points(A, B) 55 | step = AB * .1 56 | position = Vector2(*A) 57 | for n in range(10): 58 | position += step 59 | print(position) 60 | 61 | -------------------------------------------------------------------------------- /9781484209714_Chapter_05/5-16.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | from gameobjects.vector2 import Vector2 5 | 6 | background_image_filename = 'sushiplate.jpg' 7 | sprite_image_filename = 'fugu.png' 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 | speed = 250 20 | heading = Vector2() 21 | 22 | while True: 23 | 24 | for event in pygame.event.get(): 25 | if event.type == QUIT: 26 | pygame.quit() 27 | exit() 28 | if event.type == MOUSEBUTTONDOWN: 29 | destination = Vector2(*event.pos) - (Vector2(*sprite.get_size())/2) 30 | heading = Vector2.from_points(position, destination) 31 | heading.normalize() 32 | 33 | screen.blit(background, (0,0)) 34 | screen.blit(sprite, (position.x, position.y)) 35 | 36 | time_passed = clock.tick() 37 | time_passed_seconds = time_passed / 1000.0 38 | 39 | distance_moved = time_passed_seconds * speed 40 | position += heading * distance_moved 41 | pygame.display.update() 42 | -------------------------------------------------------------------------------- /9781484209714_Chapter_05/5-17.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | from gameobjects.vector2 import Vector2 5 | 6 | background_image_filename = 'sushiplate.jpg' 7 | sprite_image_filename = 'fugu.png' 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 | speed = 250 20 | heading = Vector2() 21 | 22 | while True: 23 | 24 | for event in pygame.event.get(): 25 | if event.type == QUIT: 26 | pygame.quit() 27 | exit() 28 | if event.type == MOUSEBUTTONDOWN: 29 | destination_x = event.pos[0] - sprite.get_width()/2.0 30 | destination_y = event.pos[1] - sprite.get_height()/2.0 31 | destination = (destination_x, destination_y) 32 | 33 | 34 | heading = Vector2.from_points(position, destination) 35 | heading.normalize() 36 | 37 | screen.blit(background, (0,0)) 38 | screen.blit(sprite, (position.x, position.y)) 39 | 40 | time_passed = clock.tick() 41 | time_passed_seconds = time_passed / 1000.0 42 | 43 | distance_moved = time_passed_seconds * speed 44 | position += heading * distance_moved 45 | pygame.display.update() 46 | -------------------------------------------------------------------------------- /9781484209714_Chapter_05/5-2.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | 5 | background_image_filename = 'sushiplate.jpg' 6 | sprite_image_filename = 'fugu.png' 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 | pygame.quit() 28 | exit() 29 | 30 | 31 | screen.blit(background, (0,0)) 32 | screen.blit(sprite, (x, 100)) 33 | 34 | time_passed = clock.tick() 35 | time_passed_seconds = time_passed / 1000.0 36 | 37 | distance_moved = time_passed_seconds * speed 38 | x += distance_moved 39 | 40 | if x > 640: 41 | x -= 640 42 | 43 | pygame.display.update() 44 | -------------------------------------------------------------------------------- /9781484209714_Chapter_05/5-3.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | 5 | background_image_filename = 'sushiplate.jpg' 6 | sprite_image_filename = 'fugu.png' 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 | 26 | while True: 27 | 28 | for event in pygame.event.get(): 29 | if event.type == QUIT: 30 | pygame.quit() 31 | exit() 32 | 33 | screen.blit(background, (0,0)) 34 | screen.blit(sprite, (x1, 50)) 35 | screen.blit(sprite, (x2, 250)) 36 | 37 | time_passed = clock.tick(30) 38 | time_passed_seconds = time_passed / 1000.0 39 | 40 | distance_moved = time_passed_seconds * speed 41 | x1 += distance_moved 42 | 43 | if (frame_no % 5) == 0: 44 | distance_moved = time_passed_seconds * speed 45 | x2 += distance_moved * 5 46 | 47 | # If the image goes off the end of the screen, move it back 48 | if x1 > 640: 49 | x1 -= 640 50 | if x2 > 640: 51 | x2 -= 640 52 | 53 | pygame.display.update() 54 | frame_no += 1 55 | -------------------------------------------------------------------------------- /9781484209714_Chapter_05/5-4.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | 5 | background_image_filename = 'sushiplate.jpg' 6 | sprite_image_filename = 'fugu.png' 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 | pygame.quit() 25 | exit() 26 | 27 | screen.blit(background, (0,0)) 28 | screen.blit(sprite, (x, y)) 29 | 30 | time_passed = clock.tick(30) 31 | time_passed_seconds = time_passed / 1000.0 32 | 33 | x += speed_x * time_passed_seconds 34 | y += speed_y * time_passed_seconds 35 | 36 | 37 | # If the sprite goes off the edge of the screen, 38 | # make it move in the opposite direction 39 | if x > 640 - sprite.get_width(): 40 | speed_x = -speed_x 41 | x = 640 - sprite.get_width() 42 | elif x < 0: 43 | speed_x = -speed_x 44 | x = 0 45 | 46 | if y > 480 - sprite.get_height(): 47 | speed_y = -speed_y 48 | y = 480 - sprite.get_height() 49 | elif y < 0: 50 | speed_y = -speed_y 51 | y = 0 52 | 53 | pygame.display.update() 54 | -------------------------------------------------------------------------------- /9781484209714_Chapter_05/5-5.py: -------------------------------------------------------------------------------- 1 | class Vector2: 2 | 3 | def __init__(self, x=0, y=0): 4 | self.x = x 5 | self.y = y 6 | 7 | def __str__(self): 8 | return "(%s, %s)"%(self.x, self.y) 9 | -------------------------------------------------------------------------------- /9781484209714_Chapter_05/5-6.py: -------------------------------------------------------------------------------- 1 | class Vector2: 2 | 3 | def __init__(self, x=0, y=0): 4 | self.x = x 5 | self.y = y 6 | 7 | def __str__(self): 8 | return "(%s, %s)"%(self.x, self.y) 9 | 10 | def from_points(P1, P2): 11 | 12 | # ( P2[0] - P1[0], P2[1] - P1[1] ) is the same as: 13 | # numpy.array(P1) - numpy.array(P1) 14 | 15 | return Vector2(P2[0] - P1[0], P2[1] - P1[1]) 16 | -------------------------------------------------------------------------------- /9781484209714_Chapter_05/5-7.py: -------------------------------------------------------------------------------- 1 | class Vector2: 2 | 3 | def __init__(self, x=0, y=0): 4 | self.x = x 5 | self.y = y 6 | 7 | def __str__(self): 8 | return "(%s, %s)"%(self.x, self.y) 9 | 10 | def from_points(P1, P2): 11 | # ( P2[0] - P1[0], P2[1] - P1[1] ) is the same as: 12 | # numpy.array(P1) - numpy.array(P1) 13 | return Vector2(P2[0] - P1[0], P2[1] - P1[1]) 14 | 15 | 16 | A = (10.0, 20.0) 17 | B = (30.0, 35.0) 18 | AB = Vector2.from_points(A, B) 19 | print(AB) 20 | -------------------------------------------------------------------------------- /9781484209714_Chapter_05/5-8.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | class Vector2: 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 | def from_points(P1, P2): 13 | return Vector2( P2[0] - P1[0], P2[1] - P1[1] ) 14 | 15 | def get_magnitude(self): 16 | return math.sqrt( self.x**2 + self.y**2 ) 17 | 18 | 19 | 20 | A = (10.0, 20.0) 21 | B = (30.0, 35.0) 22 | AB = Vector2.from_points(A, B) 23 | print(AB) 24 | print(AB.get_magnitude()) 25 | -------------------------------------------------------------------------------- /9781484209714_Chapter_05/5-9.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | class Vector2: 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 | def from_points(P1, P2): 13 | return Vector2( P2[0] - P1[0], P2[1] - P1[1] ) 14 | 15 | def get_magnitude(self): 16 | return math.sqrt( self.x**2 + self.y**2 ) 17 | 18 | def normalize(self): 19 | magnitude = self.get_magnitude() 20 | self.x /= magnitude 21 | self.y /= magnitude 22 | 23 | 24 | 25 | A = (10.0, 20.0) 26 | B = (30.0, 35.0) 27 | AB = Vector2.from_points(A, B) 28 | print("Vector AB is", AB) 29 | print("Magnitude of Vector AB is", AB.get_magnitude()) 30 | AB.normalize() 31 | print("Vector AB normalized is", AB) 32 | -------------------------------------------------------------------------------- /9781484209714_Chapter_05/fugu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_05/fugu.png -------------------------------------------------------------------------------- /9781484209714_Chapter_05/gameobjects/vector2.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | class Vector2: 4 | 5 | def __init__(self, x=0, y=0): 6 | self.x = x 7 | self.y = y 8 | 9 | if hasattr(x, "__getitem__"): 10 | x, y = x 11 | self._v = [float(x), float(y)] 12 | else: 13 | self._v = [float(x), float(y)] 14 | 15 | def __str__(self): 16 | return "(%s, %s)"%(self.x, self.y) 17 | 18 | def from_points(P1, P2): 19 | return Vector2( P2[0] - P1[0], P2[1] - P1[1] ) 20 | 21 | def get_magnitude(self): 22 | return math.sqrt( self.x**2 + self.y**2 ) 23 | 24 | def normalize(self): 25 | magnitude = self.get_magnitude() 26 | self.x /= magnitude 27 | self.y /= magnitude 28 | 29 | def __add__(self, rhs): 30 | return Vector2(self.x + rhs.x, self.y + rhs.y) 31 | 32 | def __sub__(self, rhs): 33 | return Vector2(self.x - rhs.x, self.y - rhs.y) 34 | 35 | def __neg__(self): 36 | return Vector2(-self.x, -self.y) 37 | 38 | def __mul__(self, scalar): 39 | return Vector2(self.x * scalar, self.y * scalar) 40 | 41 | def __truediv__(self, scalar): 42 | return Vector2(self.x / scalar, self.y / scalar) 43 | 44 | def __getitem__(self, index): 45 | return self._v[index] 46 | 47 | def __setitem__(self, index, value): 48 | self._v[index] = 1.0 * value 49 | 50 | 51 | if __name__ == "__main__": 52 | A = (10.0, 20.0) 53 | B = (30.0, 35.0) 54 | AB = Vector2.from_points(A, B) 55 | step = AB * .1 56 | position = Vector2(*A) 57 | for n in range(10): 58 | position += step 59 | print(position) 60 | 61 | -------------------------------------------------------------------------------- /9781484209714_Chapter_05/sushiplate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_05/sushiplate.jpg -------------------------------------------------------------------------------- /9781484209714_Chapter_06/6-1.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 | pygame.quit() 16 | exit() 17 | 18 | screen.fill((255, 255, 255)) 19 | 20 | pressed_key_text = [] 21 | pressed_keys = pygame.key.get_pressed() 22 | y = font_height 23 | 24 | 25 | for key_constant, pressed in enumerate(pressed_keys): 26 | if pressed: 27 | key_name = pygame.key.name(key_constant) 28 | text_surface = font.render(key_name+" pressed", True, (0,0,0)) 29 | screen.blit(text_surface, (8, y)) 30 | y+= font_height 31 | 32 | pygame.display.update() 33 | -------------------------------------------------------------------------------- /9781484209714_Chapter_06/6-2.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | from gameobjects.vector2 import Vector2 5 | 6 | background_image_filename = 'sushiplate.jpg' 7 | sprite_image_filename = 'fugu.png' 8 | 9 | pygame.init() 10 | 11 | screen = pygame.display.set_mode((640, 480), 0, 32) 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 | sprite_pos = Vector2(200, 150) 18 | sprite_speed = 300 19 | 20 | while True: 21 | 22 | for event in pygame.event.get(): 23 | if event.type == QUIT: 24 | pygame.quit() 25 | exit() 26 | 27 | pressed_keys = pygame.key.get_pressed() 28 | 29 | key_direction = Vector2(0, 0) 30 | 31 | if pressed_keys[K_LEFT]: 32 | key_direction.x = -1 33 | elif pressed_keys[K_RIGHT]: 34 | key_direction.x = +1 35 | if pressed_keys[K_UP]: 36 | key_direction.y = -1 37 | elif pressed_keys[K_DOWN]: 38 | key_direction.y = +1 39 | 40 | key_direction.normalize() 41 | 42 | screen.blit(background, (0,0)) 43 | screen.blit(sprite, (sprite_pos.x,sprite_pos.y)) 44 | 45 | time_passed = clock.tick(30) 46 | time_passed_seconds = time_passed / 1000.0 47 | 48 | sprite_pos += key_direction * sprite_speed * time_passed_seconds 49 | 50 | pygame.display.update() 51 | -------------------------------------------------------------------------------- /9781484209714_Chapter_06/6-3.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | from gameobjects.vector2 import Vector2 5 | from math import * 6 | 7 | background_image_filename = 'sushiplate.jpg' 8 | sprite_image_filename = 'fugu.png' 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 | pygame.quit() 29 | exit() 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.0 37 | if pressed_keys[K_RIGHT]: 38 | rotation_direction = -1.0 39 | if pressed_keys[K_UP]: 40 | movement_direction = +1.0 41 | if pressed_keys[K_DOWN]: 42 | movement_direction = -1.0 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.x,sprite_draw_pos.y)) 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.0) 57 | heading_y = cos(sprite_rotation*pi/180.0) 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 | -------------------------------------------------------------------------------- /9781484209714_Chapter_06/6-4.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | from gameobjects.vector2 import Vector2 5 | from math import * 6 | 7 | background_image_filename = 'sushiplate.jpg' 8 | sprite_image_filename = 'fugu.png' 9 | 10 | 11 | pygame.init() 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 | pygame.mouse.set_visible(False) 20 | pygame.event.set_grab(True) 21 | 22 | sprite_pos = Vector2(200, 150) 23 | sprite_speed = 300. 24 | sprite_rotation = 0. 25 | sprite_rotation_speed = 360. # Degrees per second 26 | 27 | while True: 28 | 29 | for event in pygame.event.get(): 30 | if event.type == QUIT: 31 | pygame.quit() 32 | exit() 33 | if event.type == KEYDOWN: 34 | if event.key == K_ESCAPE: 35 | pygame.quit() 36 | exit() 37 | 38 | 39 | pressed_keys = pygame.key.get_pressed() 40 | pressed_mouse = pygame.mouse.get_pressed() 41 | 42 | rotation_direction = 0. 43 | movement_direction = 0. 44 | 45 | rotation_direction = pygame.mouse.get_rel()[0] / 3. 46 | 47 | if pressed_keys[K_LEFT]: 48 | rotation_direction = +1. 49 | if pressed_keys[K_RIGHT]: 50 | rotation_direction = -1. 51 | if pressed_keys[K_UP] or pressed_mouse[0]: 52 | movement_direction = +1. 53 | if pressed_keys[K_DOWN] or pressed_mouse[2]: 54 | movement_direction = -1. 55 | screen.blit(background, (0,0)) 56 | 57 | rotated_sprite = pygame.transform.rotate(sprite, sprite_rotation) 58 | w, h = rotated_sprite.get_size() 59 | sprite_draw_pos = Vector2(sprite_pos.x-w/2, sprite_pos.y-h/2) 60 | screen.blit(rotated_sprite, (sprite_draw_pos.x, sprite_draw_pos.y)) 61 | 62 | time_passed = clock.tick() 63 | time_passed_seconds = time_passed / 1000.0 64 | 65 | sprite_rotation += rotation_direction * sprite_rotation_speed * time_passed_seconds 66 | 67 | heading_x = sin(sprite_rotation*pi/180.) 68 | heading_y = cos(sprite_rotation*pi/180.) 69 | heading = Vector2(heading_x, heading_y) 70 | heading *= movement_direction 71 | 72 | sprite_pos+= heading * sprite_speed * time_passed_seconds 73 | 74 | pygame.display.update() 75 | -------------------------------------------------------------------------------- /9781484209714_Chapter_06/6-5.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 range(pygame.joystick.get_count()): 16 | stick = pygame.joystick.Joystick(joystick_no) 17 | stick.init() 18 | joysticks.append(stick) 19 | 20 | 21 | while True: 22 | 23 | event = pygame.event.wait() 24 | if event.type in (JOYAXISMOTION, 25 | JOYBALLMOTION, 26 | JOYHATMOTION, 27 | JOYBUTTONUP, 28 | JOYBUTTONDOWN): 29 | event_text.append(str(event)) 30 | 31 | 32 | event_text = event_text[int(-SCREEN_SIZE[1]/font_height):] 33 | 34 | if event.type == QUIT: 35 | pygame.quit() 36 | exit() 37 | 38 | screen.fill((255, 255, 255)) 39 | 40 | y = SCREEN_SIZE[1]-font_height 41 | for text in reversed(event_text): 42 | screen.blit( font.render(text, True, (0, 0, 0)), (0, y) ) 43 | y-=font_height 44 | 45 | pygame.display.update() 46 | -------------------------------------------------------------------------------- /9781484209714_Chapter_06/6-6.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | from gameobjects.vector2 import Vector2 5 | 6 | picture_file = 'map.png' 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 | pygame.quit() 25 | exit() 26 | 27 | 28 | while True: 29 | 30 | for event in pygame.event.get(): 31 | if event.type == QUIT: 32 | pygame.quit() 33 | exit() 34 | 35 | scroll_direction = Vector2(*joystick.get_hat(0)) 36 | scroll_direction.normalize() 37 | 38 | screen.fill((255, 255, 255)) 39 | screen.blit(picture, (-picture_pos.x, picture_pos.y)) 40 | 41 | time_passed = clock.tick() 42 | time_passed_seconds = time_passed / 1000.0 43 | 44 | picture_pos += scroll_direction * scroll_speed * time_passed_seconds 45 | 46 | pygame.display.update() 47 | -------------------------------------------------------------------------------- /9781484209714_Chapter_06/6-7.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from sys import exit 4 | from gameobjects.vector2 import Vector2 5 | 6 | picture_file = 'map.jpg' 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 | pygame.quit() 25 | exit() 26 | 27 | while True: 28 | 29 | for event in pygame.event.get(): 30 | if event.type == QUIT: 31 | pygame.quit() 32 | exit() 33 | 34 | 35 | scroll_direction = Vector2(0, 0) 36 | if joystick.get_numhats() > 0: 37 | scroll_direction = Vector2(*joystick.get_hat(0)) 38 | scroll_direction.normalize() 39 | 40 | analog_scroll = Vector2(0, 0) 41 | if joystick.get_numaxes() >= 2: 42 | axis_x = joystick.get_axis(0) 43 | axis_y = joystick.get_axis(1) 44 | analog_scroll = Vector2(axis_x, -axis_y) 45 | 46 | screen.fill((255, 255, 255)) 47 | screen.blit(picture, (-picture_pos.x, picture_pos.y)) 48 | 49 | time_passed = clock.tick() 50 | time_passed_seconds = time_passed / 1000.0 51 | 52 | picture_pos += scroll_direction * scroll_speed * time_passed_seconds 53 | picture_pos += analog_scroll * scroll_speed * time_passed_seconds 54 | 55 | pygame.display.update() 56 | -------------------------------------------------------------------------------- /9781484209714_Chapter_06/6-8.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 range(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 | pygame.quit() 18 | exit() 19 | 20 | active_joystick = 0 21 | 22 | 23 | pygame.display.set_caption(joysticks[0].get_name()) 24 | 25 | def draw_axis(surface, x, y, axis_x, axis_y, size): 26 | 27 | line_col = (128, 128, 128) 28 | num_lines = 40 29 | step = size / float(num_lines) 30 | for n in range(num_lines): 31 | line_col = [(192, 192, 192), (220, 220, 220)][n&1] 32 | pygame.draw.line(surface, line_col, (x+n*step, y), (x+n*step, y+size)) 33 | pygame.draw.line(surface, line_col, (x, y+n*step), (x+size, y+n*step)) 34 | 35 | pygame.draw.line(surface, (0, 0, 0), (x, y+size/2), (x+size, y+size/2)) 36 | pygame.draw.line(surface, (0, 0, 0), (x+size/2, y), (x+size/2, y+size)) 37 | 38 | draw_x = int(x + (axis_x * size + size) / 2.) 39 | draw_y = int(y + (axis_y * size + size) / 2.) 40 | draw_pos = (draw_x, draw_y) 41 | center_pos = (x+size/2, y+size/2) 42 | pygame.draw.line(surface, (0, 0, 0), center_pos, draw_pos, 5) 43 | pygame.draw.circle(surface, (0, 0, 255), draw_pos, 10) 44 | 45 | 46 | def draw_dpad(surface, x, y, axis_x, axis_y): 47 | 48 | col = (255, 0, 0) 49 | if axis_x == -1: 50 | pygame.draw.circle(surface, col, (x-20, y), 10) 51 | elif axis_x == +1: 52 | pygame.draw.circle(surface, col, (x+20, y), 10) 53 | 54 | if axis_y == -1: 55 | pygame.draw.circle(surface, col, (x, y+20), 10) 56 | elif axis_y == +1: 57 | pygame.draw.circle(surface, col, (x, y-20), 10) 58 | 59 | while True: 60 | 61 | joystick = joysticks[active_joystick] 62 | 63 | for event in pygame.event.get(): 64 | if event.type == QUIT: 65 | pygame.quit() 66 | exit() 67 | 68 | if event.type == KEYDOWN: 69 | if event.key >= K_0 and event.key <= K_1: 70 | num = event.key - K_0 71 | 72 | if num < len(joysticks): 73 | active_joystick = num 74 | name = joysticks[active_joystick].get_name() 75 | pygame.display.set_caption(name) 76 | 77 | # Get a list of all the axis 78 | axes = [] 79 | for axis_no in range(joystick.get_numaxes()): 80 | axes.append( joystick.get_axis(axis_no) ) 81 | 82 | axis_size = min(256, 640 / (joystick.get_numaxes()/2)) 83 | 84 | pygame.draw.rect(screen, (255, 255,255), (0, 0, 640, 480)) 85 | 86 | # Draw all the axes (analog sticks) 87 | x = 0 88 | for axis_no in range(0, len(axes), 2): 89 | axis_x = axes[axis_no] 90 | if axis_no+1 < len(axes): 91 | axis_y = axes[axis_no+1] 92 | else: 93 | axis_y = 0. 94 | draw_axis(screen, x, 0, axis_x, axis_y, axis_size) 95 | x += axis_size 96 | 97 | 98 | # Draw all the hats (d-pads) 99 | x, y = 50, 300 100 | for hat_no in range(joystick.get_numhats()): 101 | axis_x, axis_y = joystick.get_hat(hat_no) 102 | draw_dpad(screen, x, y, axis_x, axis_y) 103 | x+= 100 104 | 105 | 106 | #Draw all the buttons x, y = 0.0, 390.0 107 | button_width = 640 / joystick.get_numbuttons() 108 | for button_no in range(joystick.get_numbuttons()): 109 | if joystick.get_button(button_no): 110 | pygame.draw.circle(screen, (0, 255, 0), (int(x), int(y)), 20) 111 | x += button_width 112 | 113 | pygame.display.update() 114 | -------------------------------------------------------------------------------- /9781484209714_Chapter_06/fugu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_06/fugu.png -------------------------------------------------------------------------------- /9781484209714_Chapter_06/gameobjects/__pycache__/vector2.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_06/gameobjects/__pycache__/vector2.cpython-34.pyc -------------------------------------------------------------------------------- /9781484209714_Chapter_06/gameobjects/vector2.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | class Vector2: 4 | 5 | def __init__(self, x=0, y=0): 6 | self.x = x 7 | self.y = y 8 | 9 | if hasattr(x, "__getitem__"): 10 | x, y = x 11 | self._v = [float(x), float(y)] 12 | else: 13 | self._v = [float(x), float(y)] 14 | 15 | def __str__(self): 16 | return "(%s, %s)"%(self.x, self.y) 17 | 18 | def from_points(P1, P2): 19 | return Vector2( P2[0] - P1[0], P2[1] - P1[1] ) 20 | 21 | def get_magnitude(self): 22 | return math.sqrt( self.x**2 + self.y**2 ) 23 | 24 | def normalize(self): 25 | magnitude = self.get_magnitude() 26 | 27 | try: 28 | self.x /= magnitude 29 | self.y /= magnitude 30 | except ZeroDivisionError: 31 | self.x = 0 32 | self.y = 0 33 | 34 | def __add__(self, rhs): 35 | return Vector2(self.x + rhs.x, self.y + rhs.y) 36 | 37 | def __sub__(self, rhs): 38 | return Vector2(self.x - rhs.x, self.y - rhs.y) 39 | 40 | def __neg__(self): 41 | return Vector2(-self.x, -self.y) 42 | 43 | def __mul__(self, scalar): 44 | return Vector2(self.x * scalar, self.y * scalar) 45 | 46 | def __truediv__(self, scalar): 47 | return Vector2(self.x / scalar, self.y / scalar) 48 | 49 | def __getitem__(self, index): 50 | return self._v[index] 51 | 52 | def __setitem__(self, index, value): 53 | self._v[index] = 1.0 * value 54 | 55 | 56 | if __name__ == "__main__": 57 | A = (10.0, 20.0) 58 | B = (30.0, 35.0) 59 | AB = Vector2.from_points(A, B) 60 | step = AB * .1 61 | position = Vector2(*A) 62 | for n in range(10): 63 | position += step 64 | print(position) 65 | 66 | -------------------------------------------------------------------------------- /9781484209714_Chapter_06/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_06/map.png -------------------------------------------------------------------------------- /9781484209714_Chapter_06/sushiplate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_06/sushiplate.jpg -------------------------------------------------------------------------------- /9781484209714_Chapter_07/7-1.py: -------------------------------------------------------------------------------- 1 | self.move_forward() 2 | if self.hit_wall(): 3 | self.change_direction() 4 | -------------------------------------------------------------------------------- /9781484209714_Chapter_07/7-2.py: -------------------------------------------------------------------------------- 1 | if self.state == "exploring": 2 | self.random_heading() 3 | if self.can_see(player): 4 | self.state = "seeking" 5 | 6 | elif self.state == "seeking": 7 | self.head_towards("player") 8 | if self.in_range_of(player): 9 | self.fire_at(player) 10 | if not self.can_see(player): 11 | self.state = "exploring" 12 | -------------------------------------------------------------------------------- /9781484209714_Chapter_07/7-3.py: -------------------------------------------------------------------------------- 1 | class GameEntity(object): 2 | 3 | def __init__(self, world, name, image): 4 | 5 | self.world = world 6 | self.name = name 7 | self.image = image 8 | self.location = Vector2(0, 0) 9 | self.destination = Vector2(0, 0) 10 | self.speed = 0. 11 | 12 | self.brain = StateMachine() 13 | 14 | self.id = 0 15 | 16 | def render(self, surface): 17 | 18 | x, y = self.location 19 | w, h = self.image.get_size() 20 | surface.blit(self.image, (x-w/2, y-h/2)) 21 | 22 | def process(self, time_passed): 23 | 24 | self.brain.think() 25 | 26 | if self.speed > 0 and self.location != self.destination: 27 | 28 | vec_to_destination = self.destination - self.location 29 | distance_to_destination = vec_to_destination.get_length() 30 | heading = vec_to_destination.get_normalized() 31 | travel_distance = min(distance_to_destination, time_passed * self.speed) 32 | self.location += travel_distance * heading 33 | -------------------------------------------------------------------------------- /9781484209714_Chapter_07/7-4.py: -------------------------------------------------------------------------------- 1 | class World(object): 2 | 3 | def __init__(self): 4 | 5 | self.entities = {} # Store all the entities 6 | self.entity_id = 0 # Last entity id assigned 7 | # Draw the nest (a circle) on the background 8 | self.background = pygame.surface.Surface(SCREEN_SIZE).convert() 9 | self.background.fill((255, 255, 255)) 10 | pygame.draw.circle(self.background, (200, 255, 200), NEST_POSITION, int(NEST_SIZE)) 11 | 12 | def add_entity(self, entity): 13 | 14 | # Stores the entity then advances the current id 15 | self.entities[self.entity_id] = entity 16 | entity.id = self.entity_id 17 | self.entity_id += 1 18 | 19 | def remove_entity(self, entity): 20 | 21 | del self.entities[entity.id] 22 | 23 | def get(self, entity_id): 24 | 25 | # Find the entity, given its id (or None if it is not found) 26 | if entity_id in self.entities: 27 | return self.entities[entity_id] 28 | else: 29 | return None 30 | 31 | def process(self, time_passed): 32 | 33 | # Process every entity in the world 34 | time_passed_seconds = time_passed / 1000.0 35 | for entity in self.entities.itervalues(): 36 | entity.process(time_passed_seconds) 37 | 38 | def render(self, surface): 39 | 40 | # Draw the background and all the entities 41 | surface.blit(self.background, (0, 0)) 42 | for entity in self.entities.values(): 43 | entity.render(surface) 44 | 45 | def get_close_entity(self, name, location, e_range=100): 46 | 47 | # Find an entity within range of a location 48 | location = Vector2(*location) 49 | 50 | for entity in self.entities.values(): 51 | if entity.name == name: 52 | distance = location.get_distance_to(entity.location) 53 | if distance < e_range: 54 | return entity 55 | return None 56 | -------------------------------------------------------------------------------- /9781484209714_Chapter_07/7-5.py: -------------------------------------------------------------------------------- 1 | class Ant(GameEntity): 2 | 3 | def __init__(self, world, image): 4 | 5 | # Call the base class constructor 6 | GameEntity.__init__(self, world, "ant", image) 7 | 8 | # Create instances of each of the states 9 | exploring_state = AntStateExploring(self) 10 | seeking_state = AntStateSeeking(self) 11 | delivering_state = AntStateDelivering(self) 12 | hunting_state = AntStateHunting(self) 13 | 14 | # Add the states to the state machine (self.brain) 15 | self.brain.add_state(exploring_state) 16 | self.brain.add_state(seeking_state) 17 | self.brain.add_state(delivering_state) 18 | self.brain.add_state(hunting_state) 19 | 20 | self.carry_image = None 21 | 22 | def carry(self, image): 23 | 24 | self.carry_image = image 25 | 26 | def drop(self, surface): 27 | 28 | # Blit the 'carry' image to the background and reset it 29 | if self.carry_image: 30 | x, y = self.location 31 | w, h = self.carry_image.get_size() 32 | surface.blit(self.carry_image, (x-w, y-h/2)) 33 | self.carry_image = None 34 | 35 | def render(self, surface): 36 | 37 | # Call the render function of the base class 38 | GameEntity.render(self, surface) 39 | 40 | # Extra code to render the 'carry' image 41 | if self.carry_image: 42 | x, y = self.location 43 | w, h = self.carry_image.get_size() 44 | surface.blit(self.carry_image, (x-w, y-h/2)) 45 | 46 | -------------------------------------------------------------------------------- /9781484209714_Chapter_07/7-6.py: -------------------------------------------------------------------------------- 1 | class State(object): 2 | 3 | def __init__(self, name): 4 | self.name = name 5 | 6 | def do_actions(self): 7 | pass 8 | 9 | def check_conditions(self): 10 | pass 11 | 12 | def entry_actions(self): 13 | pass 14 | 15 | def exit_actions(self): 16 | pass 17 | -------------------------------------------------------------------------------- /9781484209714_Chapter_07/7-7.py: -------------------------------------------------------------------------------- 1 | class StateMachine(object): 2 | 3 | def __init__(self): 4 | 5 | self.states = {} # Stores the states 6 | self.active_state = None # The currently active state 7 | 8 | def add_state(self, state): 9 | 10 | # Add a state to the internal dictionary 11 | self.states[state.name] = state 12 | 13 | def think(self): 14 | 15 | # Only continue if there is an active state 16 | if self.active_state is None: 17 | return 18 | 19 | # Perform the actions of the active state, and check conditions 20 | self.active_state.do_actions() 21 | 22 | new_state_name = self.active_state.check_conditions() 23 | if new_state_name is not None: 24 | self.set_state(new_state_name) 25 | 26 | def set_state(self, new_state_name): 27 | 28 | # Change states and perform any exit / entry actions 29 | if self.active_state is not None: 30 | self.active_state.exit_actions() 31 | 32 | self.active_state = self.states[new_state_name] 33 | self.active_state.entry_actions() 34 | -------------------------------------------------------------------------------- /9781484209714_Chapter_07/7-8.py: -------------------------------------------------------------------------------- 1 | class AntStateExploring(State): 2 | 3 | def __init__(self, ant): 4 | 5 | # Call the base class constructor to initialize the State 6 | State.__init__(self, "exploring") 7 | # Set the ant that this State will manipulate 8 | self.ant = ant 9 | 10 | def random_destination(self): 11 | 12 | # Select a point in the screen 13 | w, h = SCREEN_SIZE 14 | self.ant.destination = Vector2(randint(0, w), randint(0, h)) 15 | 16 | def do_actions(self): 17 | 18 | # Change direction, 1 in 20 calls 19 | if randint(1, 20) == 1: 20 | self.random_destination() 21 | 22 | def check_conditions(self): 23 | 24 | # If there is a nearby leaf, switch to seeking state 25 | leaf = self.ant.world.get_close_entity("leaf", self.ant.location) 26 | if leaf is not None: 27 | self.ant.leaf_id = leaf.id 28 | return "seeking" 29 | # If there is a nearby spider, switch to hunting state 30 | spider = self.ant.world.get_close_entity("spider", NEST_POSITION, NEST_SIZE) 31 | if spider is not None: 32 | if self.ant.location.get_distance_to(spider.location) < 100.: 33 | self.ant.spider_id = spider.id 34 | return "hunting" 35 | 36 | return None 37 | 38 | def entry_actions(self): 39 | 40 | # Start with random speed and heading 41 | self.ant.speed = 120. + randint(-30, 30) 42 | self.random_destination() 43 | -------------------------------------------------------------------------------- /9781484209714_Chapter_07/ant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_07/ant.png -------------------------------------------------------------------------------- /9781484209714_Chapter_07/gameobjects/util.py: -------------------------------------------------------------------------------- 1 | from math import * 2 | 3 | def format_number(n, accuracy=6): 4 | """Formats a number in a friendly manner 5 | (removes trailing zeros and unneccesary point.""" 6 | 7 | fs = "%."+str(accuracy)+"f" 8 | str_n = fs%float(n) 9 | if '.' in str_n: 10 | str_n = str_n.rstrip('0').rstrip('.') 11 | if str_n == "-0": 12 | str_n = "0" 13 | #str_n = str_n.replace("-0", "0") 14 | return str_n 15 | 16 | 17 | def lerp(a, b, i): 18 | """Linear enterpolate from a to b.""" 19 | return a+(b-a)*i 20 | 21 | 22 | def range2d(range_x, range_y): 23 | 24 | """Creates a 2D range.""" 25 | 26 | range_x = list(range_x) 27 | return [ (x, y) for y in range_y for x in range_x ] 28 | 29 | 30 | def xrange2d(range_x, range_y): 31 | 32 | """Iterates over a 2D range.""" 33 | 34 | range_x = list(range_x) 35 | for y in range_y: 36 | for x in range_x: 37 | yield (x, y) 38 | 39 | 40 | def saturate(value, low, high): 41 | return min(max(value, low), high) 42 | 43 | 44 | def is_power_of_2(n): 45 | """Returns True if a value is a power of 2.""" 46 | return log(n, 2) % 1.0 == 0.0 47 | 48 | 49 | def next_power_of_2(n): 50 | """Returns the next power of 2 that is >= n""" 51 | return int(2 ** ceil(log(n, 2))) 52 | 53 | if __name__ == "__main__": 54 | 55 | print(list( xrange2d(xrange(3), xrange(3)) )) 56 | print(range2d(xrange(3), xrange(3))) 57 | print(is_power_of_2(7)) 58 | print(is_power_of_2(8)) 59 | print(is_power_of_2(9)) 60 | 61 | print(next_power_of_2(7)) 62 | -------------------------------------------------------------------------------- /9781484209714_Chapter_07/leaf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_07/leaf.png -------------------------------------------------------------------------------- /9781484209714_Chapter_07/spider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_07/spider.png -------------------------------------------------------------------------------- /9781484209714_Chapter_08/8-1.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 | def run(): 14 | 15 | pygame.init() 16 | screen = pygame.display.set_mode((640, 480), FULLSCREEN) 17 | 18 | stars = [] 19 | 20 | # Add a few stars for the first frame 21 | for n in range(200): 22 | 23 | x = float(randint(0, 639)) 24 | y = float(randint(0, 479)) 25 | speed = float(randint(10, 300)) 26 | stars.append( Star(x, y, speed) ) 27 | 28 | clock = pygame.time.Clock() 29 | 30 | white = (255, 255, 255) 31 | 32 | while True: 33 | 34 | for event in pygame.event.get(): 35 | if event.type == QUIT: 36 | pygame.quit() 37 | quit() 38 | if event.type == KEYDOWN: 39 | pygame.quit() 40 | quit() 41 | 42 | # Add a new star 43 | y = float(randint(0, 479)) 44 | speed = float(randint(10, 300)) 45 | star = Star(640, y, speed) 46 | 47 | stars.append(star) 48 | time_passed = clock.tick() 49 | time_passed_seconds = time_passed / 1000. 50 | 51 | screen.fill((0, 0, 0)) 52 | 53 | # Draw the stars 54 | for star in stars: 55 | 56 | new_x = star.x - time_passed_seconds * star.speed 57 | pygame.draw.aaline(screen, white, (new_x, star.y), (star.x+1., star.y)) 58 | star.x = new_x 59 | 60 | def on_screen(star): 61 | return star.x > 0 62 | 63 | # Remove stars that are no longer visible 64 | stars = list(filter(on_screen, stars)) 65 | 66 | pygame.display.update() 67 | 68 | 69 | if __name__ == "__main__": 70 | run() 71 | -------------------------------------------------------------------------------- /9781484209714_Chapter_08/8-2.py: -------------------------------------------------------------------------------- 1 | from math import sqrt 2 | 3 | class Vector3(object): 4 | 5 | def init (self, x, y, z): 6 | 7 | self.x = x 8 | self.y = y 9 | self.z = z 10 | 11 | def add (self, x, y, z): 12 | 13 | return Vector3(self.x + x, self.y + y, self.z + z) 14 | 15 | def get_magnitude(self): 16 | 17 | return sqrt(self.x ** 2 + self.y ** 2 + self.z ** 2) 18 | -------------------------------------------------------------------------------- /9781484209714_Chapter_08/8-3.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("Magnitude of A is", A.get_magnitude()) 9 | print("A+B is", A+B) 10 | print("A-B is", A-B) 11 | 12 | 13 | print("A normalized is", A.get_normalized()) 14 | print("A*2 is", A * 2) 15 | -------------------------------------------------------------------------------- /9781484209714_Chapter_08/8-4.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 | -------------------------------------------------------------------------------- /9781484209714_Chapter_08/8-5.py: -------------------------------------------------------------------------------- 1 | def parallel_project(vector3): 2 | return (vector3.x, vector3.y) 3 | -------------------------------------------------------------------------------- /9781484209714_Chapter_08/8-6.py: -------------------------------------------------------------------------------- 1 | def perspective_project(vector3, d): 2 | x, y, z = vector3 3 | return (x * d/z, -y * d/z) 4 | -------------------------------------------------------------------------------- /9781484209714_Chapter_08/8-7.py: -------------------------------------------------------------------------------- 1 | from math import tan 2 | 3 | def calculate_viewing_distance(fov, screen_width): 4 | 5 | d = (screen_width/2.0) / tan(fov/2.0) 6 | return d 7 | -------------------------------------------------------------------------------- /9781484209714_Chapter_08/8-8.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from gameobjects.vector3 import Vector3 4 | from math import * 5 | from random import randint 6 | 7 | SCREEN_SIZE = (640, 480) 8 | CUBE_SIZE = 300 9 | 10 | def calculate_viewing_distance(fov, screen_width): 11 | 12 | d = (screen_width/2.0) / tan(fov/2.0) 13 | return d 14 | 15 | 16 | def run(): 17 | 18 | pygame.init() 19 | screen = pygame.display.set_mode(SCREEN_SIZE, 0) 20 | 21 | default_font = pygame.font.get_default_font() 22 | font = pygame.font.SysFont(default_font, 24) 23 | 24 | ball = pygame.image.load("ball.png").convert_alpha() 25 | 26 | # The 3D points 27 | points = [] 28 | 29 | fov = 90. # 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 range(0, CUBE_SIZE+1, 20): 34 | edge_x = x == 0 or x == CUBE_SIZE 35 | 36 | for y in range(0, CUBE_SIZE+1, 20): 37 | edge_y = y == 0 or y == CUBE_SIZE 38 | 39 | for z in range(0, CUBE_SIZE+1, 20): 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 | # Sort points in z order 51 | def point_z(point): 52 | return point.z 53 | points.sort(key=point_z, reverse=True) 54 | 55 | center_x, center_y = SCREEN_SIZE 56 | center_x /= 2 57 | center_y /= 2 58 | 59 | ball_w, ball_h = ball.get_size() 60 | ball_center_x = ball_w / 2 61 | ball_center_y = ball_h / 2 62 | 63 | camera_position = Vector3(0.0, 0.0, -700.) 64 | camera_speed = Vector3(300.0, 300.0, 300.0) 65 | 66 | clock = pygame.time.Clock() 67 | 68 | while True: 69 | 70 | for event in pygame.event.get(): 71 | if event.type == QUIT: 72 | pygame.quit() 73 | quit() 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 | 150 | -------------------------------------------------------------------------------- /9781484209714_Chapter_08/ball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_08/ball.png -------------------------------------------------------------------------------- /9781484209714_Chapter_08/gameobjects/__pycache__/util.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_08/gameobjects/__pycache__/util.cpython-34.pyc -------------------------------------------------------------------------------- /9781484209714_Chapter_08/gameobjects/__pycache__/vector2.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_08/gameobjects/__pycache__/vector2.cpython-34.pyc -------------------------------------------------------------------------------- /9781484209714_Chapter_08/gameobjects/__pycache__/vector3.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_08/gameobjects/__pycache__/vector3.cpython-34.pyc -------------------------------------------------------------------------------- /9781484209714_Chapter_08/gameobjects/util.py: -------------------------------------------------------------------------------- 1 | from math import * 2 | 3 | def format_number(n, accuracy=6): 4 | """Formats a number in a friendly manner 5 | (removes trailing zeros and unneccesary point.""" 6 | 7 | fs = "%."+str(accuracy)+"f" 8 | str_n = fs%float(n) 9 | if '.' in str_n: 10 | str_n = str_n.rstrip('0').rstrip('.') 11 | if str_n == "-0": 12 | str_n = "0" 13 | #str_n = str_n.replace("-0", "0") 14 | return str_n 15 | 16 | 17 | def lerp(a, b, i): 18 | """Linear enterpolate from a to b.""" 19 | return a+(b-a)*i 20 | 21 | 22 | def range2d(range_x, range_y): 23 | 24 | """Creates a 2D range.""" 25 | 26 | range_x = list(range_x) 27 | return [ (x, y) for y in range_y for x in range_x ] 28 | 29 | 30 | def xrange2d(range_x, range_y): 31 | 32 | """Iterates over a 2D range.""" 33 | 34 | range_x = list(range_x) 35 | for y in range_y: 36 | for x in range_x: 37 | yield (x, y) 38 | 39 | 40 | def saturate(value, low, high): 41 | return min(max(value, low), high) 42 | 43 | 44 | def is_power_of_2(n): 45 | """Returns True if a value is a power of 2.""" 46 | return log(n, 2) % 1.0 == 0.0 47 | 48 | 49 | def next_power_of_2(n): 50 | """Returns the next power of 2 that is >= n""" 51 | return int(2 ** ceil(log(n, 2))) 52 | 53 | if __name__ == "__main__": 54 | 55 | print(list( xrange2d(range(3), range(3)) )) 56 | print(range2d(range(3), range(3))) 57 | print(is_power_of_2(7)) 58 | print(is_power_of_2(8)) 59 | print(is_power_of_2(9)) 60 | 61 | print(next_power_of_2(7)) 62 | -------------------------------------------------------------------------------- /9781484209714_Chapter_09/9-1.py: -------------------------------------------------------------------------------- 1 | from gameobjects.matrix44 import * 2 | 3 | identity = Matrix44() 4 | print(identity) 5 | p1 = (1.0, 2.0, 3.0) 6 | identity.transform(p1) 7 | 8 | assert identity.get_column(3) == (0, 0, 0, 1), "Something is wrong with this matrix!" 9 | -------------------------------------------------------------------------------- /9781484209714_Chapter_09/9-2.py: -------------------------------------------------------------------------------- 1 | #pseudocode 2 | tank_heading = Vector3(tank_matrix.forward) 3 | tank_matrix.translation += tank_heading * tank_speed * time_passed 4 | -------------------------------------------------------------------------------- /9781484209714_Chapter_09/9-3.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from gameobjects.vector3 import Vector3 4 | from gameobjects.matrix44 import Matrix44 as Matrix 5 | from math import * 6 | from random import randint 7 | 8 | SCREEN_SIZE = (640, 480) 9 | CUBE_SIZE = 300 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 | font = pygame.font.SysFont("courier new", 16, True) 23 | 24 | ball = pygame.image.load("ball.png").convert_alpha() 25 | 26 | points = [] 27 | 28 | fov = 75. # Field of view 29 | viewing_distance = calculate_viewing_distance(radians(fov), SCREEN_SIZE[0]) 30 | 31 | # Create a list of points along the edge of a cube 32 | for x in range(0, CUBE_SIZE+1, 10): 33 | edge_x = x == 0 or x == CUBE_SIZE 34 | 35 | for y in range(0, CUBE_SIZE+1, 10): 36 | edge_y = y == 0 or y == CUBE_SIZE 37 | 38 | for z in range(0, CUBE_SIZE+1, 10): 39 | edge_z = z == 0 or z == CUBE_SIZE 40 | 41 | if sum((edge_x, edge_y, edge_z)) >= 2: 42 | 43 | point_x = float(x) - CUBE_SIZE/2 44 | point_y = float(y) - CUBE_SIZE/2 45 | point_z = float(z) - CUBE_SIZE/2 46 | 47 | points.append(Vector3(point_x, point_y, point_z)) 48 | 49 | def point_z(point): 50 | return point[2] 51 | 52 | center_x, center_y = SCREEN_SIZE 53 | center_x /= 2 54 | center_y /= 2 55 | 56 | ball_w, ball_h = ball.get_size() 57 | ball_center_x = ball_w / 2 58 | ball_center_y = ball_h / 2 59 | 60 | camera_position = Vector3(0.0, 0.0, 600.) 61 | 62 | rotation = Vector3() 63 | rotation_speed = Vector3(radians(20), radians(20), radians(20)) 64 | 65 | clock = pygame.time.Clock() 66 | 67 | # Some colors for drawing 68 | red = (255, 0, 0) 69 | green = (0, 255, 0) 70 | blue = (0, 0, 255) 71 | white = (255, 255, 255) 72 | 73 | # Labels for the axes 74 | x_surface = font.render("X", True, white) 75 | y_surface = font.render("Y", True, white) 76 | z_surface = font.render("Z", True, white) 77 | 78 | while True: 79 | 80 | for event in pygame.event.get(): 81 | if event.type == QUIT: 82 | pygame.quit() 83 | quit() 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 | 186 | -------------------------------------------------------------------------------- /9781484209714_Chapter_09/9-4.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | from OpenGL.GLU import * 3 | import pygame 4 | from pygame.locals import * 5 | 6 | screen = pygame.display.set_mode((640, 480), HWSURFACE|DOUBLEBUF|OPENGL) 7 | 8 | def resize(width, height): 9 | glViewport(0, 0, width, height) 10 | glMatrixMode(GL_PROJECTION) 11 | glLoadIdentity() 12 | gluPerspective(60, float(width)/height, 1, 10000) 13 | glMatrixMode(GL_MODELVIEW) 14 | glLoadIdentity() 15 | 16 | 17 | -------------------------------------------------------------------------------- /9781484209714_Chapter_09/9-5.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | from OpenGL.GLU import * 3 | import pygame 4 | from pygame.locals import * 5 | 6 | screen = pygame.display.set_mode((640, 480), HWSURFACE|DOUBLEBUF|OPENGL) 7 | 8 | def resize(width, height): 9 | glViewport(0, 0, width, height) 10 | glMatrixMode(GL_PROJECTION) 11 | glLoadIdentity() 12 | gluPerspective(60, float(width)/height, 1, 10000) 13 | glMatrixMode(GL_MODELVIEW) 14 | glLoadIdentity() 15 | 16 | 17 | def init(): 18 | 19 | glEnable(GL_DEPTH_TEST) 20 | glClearColor(1.0, 1.0, 1.0, 0.0) 21 | 22 | glShadeModel(GL_FLAT) 23 | glEnable(GL_COLOR_MATERIAL) 24 | 25 | glEnable(GL_LIGHTING) 26 | glEnable(GL_LIGHT0) 27 | glLight(GL_LIGHT0, GL_POSITION, (0, 1, 1, 0)) 28 | -------------------------------------------------------------------------------- /9781484209714_Chapter_09/9-6.py: -------------------------------------------------------------------------------- 1 | glBegin(GL_QUADS) 2 | glColor(1.0, 0.0, 0.0) # Red 3 | glVertex(100.0, 100.0, 0.0) # Top left 4 | glVertex(200.0, 100.0, 0.0) # Top right 5 | glVertex(200.0, 200.0, 0.0) # Bottom right 6 | glVertex(100.0, 200.0, 0.0) # Bottom left 7 | 8 | glEnd() 9 | -------------------------------------------------------------------------------- /9781484209714_Chapter_09/9-7.py: -------------------------------------------------------------------------------- 1 | # Create a display list 2 | tank_display_list = glGenLists(1) 3 | glNewList(tank_display_list, GL_COMPILE) 4 | 5 | draw_tank() 6 | 7 | # End the display list 8 | glEndList() 9 | -------------------------------------------------------------------------------- /9781484209714_Chapter_09/ball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_09/ball.png -------------------------------------------------------------------------------- /9781484209714_Chapter_09/gameobjects/__pycache__/matrix44.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_09/gameobjects/__pycache__/matrix44.cpython-34.pyc -------------------------------------------------------------------------------- /9781484209714_Chapter_09/gameobjects/__pycache__/util.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_09/gameobjects/__pycache__/util.cpython-34.pyc -------------------------------------------------------------------------------- /9781484209714_Chapter_09/gameobjects/__pycache__/vector2.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_09/gameobjects/__pycache__/vector2.cpython-34.pyc -------------------------------------------------------------------------------- /9781484209714_Chapter_09/gameobjects/__pycache__/vector3.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_09/gameobjects/__pycache__/vector3.cpython-34.pyc -------------------------------------------------------------------------------- /9781484209714_Chapter_09/gameobjects/util.py: -------------------------------------------------------------------------------- 1 | from math import * 2 | 3 | def format_number(n, accuracy=6): 4 | """Formats a number in a friendly manner 5 | (removes trailing zeros and unneccesary point.""" 6 | 7 | fs = "%."+str(accuracy)+"f" 8 | str_n = fs%float(n) 9 | if '.' in str_n: 10 | str_n = str_n.rstrip('0').rstrip('.') 11 | if str_n == "-0": 12 | str_n = "0" 13 | #str_n = str_n.replace("-0", "0") 14 | return str_n 15 | 16 | 17 | def lerp(a, b, i): 18 | """Linear enterpolate from a to b.""" 19 | return a+(b-a)*i 20 | 21 | 22 | def range2d(range_x, range_y): 23 | 24 | """Creates a 2D range.""" 25 | 26 | range_x = list(range_x) 27 | return [ (x, y) for y in range_y for x in range_x ] 28 | 29 | 30 | def xrange2d(range_x, range_y): 31 | 32 | """Iterates over a 2D range.""" 33 | 34 | range_x = list(range_x) 35 | for y in range_y: 36 | for x in range_x: 37 | yield (x, y) 38 | 39 | 40 | def saturate(value, low, high): 41 | return min(max(value, low), high) 42 | 43 | 44 | def is_power_of_2(n): 45 | """Returns True if a value is a power of 2.""" 46 | return log(n, 2) % 1.0 == 0.0 47 | 48 | 49 | def next_power_of_2(n): 50 | """Returns the next power of 2 that is >= n""" 51 | return int(2 ** ceil(log(n, 2))) 52 | 53 | if __name__ == "__main__": 54 | 55 | print(list( xrange2d(range(3), range(3)) )) 56 | print(range2d(range(3), range(3))) 57 | print(is_power_of_2(7)) 58 | print(is_power_of_2(8)) 59 | print(is_power_of_2(9)) 60 | 61 | print(next_power_of_2(7)) 62 | -------------------------------------------------------------------------------- /9781484209714_Chapter_09/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_09/map.png -------------------------------------------------------------------------------- /9781484209714_Chapter_10/10-1.py: -------------------------------------------------------------------------------- 1 | def stereo_pan(x_coord, screen_width): 2 | 3 | right_volume = float(x_coord) / screen_width 4 | left_volume = 1.0 - right_volume 5 | 6 | return (left_volume, right_volume) 7 | -------------------------------------------------------------------------------- /9781484209714_Chapter_10/10-2.py: -------------------------------------------------------------------------------- 1 | tank.explode() # Do explosion visual 2 | explosion_channel = explosion_sound.play() 3 | if explosion_channel is not None: 4 | left, right = stereo_pan(tank.position.x, SCREEN_SIZE[0]) 5 | explosion_channel.set_volume(left, right) 6 | -------------------------------------------------------------------------------- /9781484209714_Chapter_10/10-3.py: -------------------------------------------------------------------------------- 1 | pygame.mixer.set_reserved(2) 2 | reserved_channel_0 = pygame.mixer.Channel(0) 3 | reserved_channel_1 = pygame.mixer.Channel(1) 4 | -------------------------------------------------------------------------------- /9781484209714_Chapter_10/10-4.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from random import randint 4 | from gameobjects.vector2 import Vector2 5 | 6 | SCREEN_SIZE = (640, 480) 7 | 8 | # In pixels per second, per second 9 | GRAVITY = 250.0 10 | # Increase for more bounciness, but don't go over 1! 11 | BOUNCINESS = 0.7 12 | 13 | def stero_pan(x_coord, screen_width): 14 | 15 | right_volume = float(x_coord) / screen_width 16 | left_volume = 1.0 - right_volume 17 | 18 | return (left_volume, right_volume) 19 | 20 | 21 | class Ball(object): 22 | 23 | def __init__(self, position, speed, image, bounce_sound): 24 | 25 | self.position = Vector2(position) 26 | self.speed = Vector2(speed) 27 | self.image = image 28 | self.bounce_sound = bounce_sound 29 | self.age = 0.0 30 | 31 | def update(self, time_passed): 32 | 33 | w, h = self.image.get_size() 34 | 35 | screen_width, screen_height = SCREEN_SIZE 36 | 37 | x, y = self.position 38 | x -= w/2 39 | y -= h/2 40 | 41 | # Has the ball bounce 42 | bounce = False 43 | 44 | # Has the ball hit the bottom of the screen? 45 | if y + h >= screen_height: 46 | self.speed.y = -self.speed.y * BOUNCINESS 47 | self.position.y = screen_height - h / 2.0 - 1.0 48 | bounce = True 49 | 50 | # Has the ball hit the left of the screen? 51 | if x <= 0: 52 | self.speed.x = -self.speed.x * BOUNCINESS 53 | self.position.x = w / 2.0 + 1 54 | bounce = True 55 | 56 | # Has the ball hit the right of the screen 57 | elif x + w >= screen_width: 58 | self.speed.x = -self.speed.x * BOUNCINESS 59 | self.position.x = screen_width - w / 2.0 - 1 60 | bounce = True 61 | 62 | # Do time based movement 63 | self.position += self.speed * time_passed 64 | # Add gravity 65 | self.speed.y += time_passed * GRAVITY 66 | 67 | if bounce: 68 | self.play_bounce_sound() 69 | 70 | self.age += time_passed 71 | 72 | 73 | def play_bounce_sound(self): 74 | 75 | channel = self.bounce_sound.play() 76 | 77 | if channel is not None: 78 | # Get the left and right volumes 79 | left, right = stero_pan(self.position.x, SCREEN_SIZE[0]) 80 | channel.set_volume(left, right) 81 | 82 | 83 | def render(self, surface): 84 | 85 | # Draw the sprite center at self.position 86 | w, h = self.image.get_size() 87 | x, y = self.position 88 | x -= w/2 89 | y -= h/2 90 | surface.blit(self.image, (x, y)) 91 | 92 | 93 | def run(): 94 | 95 | # Initialise 44KHz 16-bit stero sound 96 | pygame.mixer.pre_init(44100, 16, 2, 1024*4) 97 | pygame.init() 98 | pygame.mixer.set_num_channels(8) 99 | screen = pygame.display.set_mode(SCREEN_SIZE, 0) 100 | 101 | print(pygame.display.get_wm_info()) 102 | hwnd = pygame.display.get_wm_info()["window"] 103 | x, y = (200, 200) 104 | 105 | pygame.mouse.set_visible(False) 106 | 107 | clock = pygame.time.Clock() 108 | 109 | ball_image = pygame.image.load("ball.png").convert_alpha() 110 | mouse_image = pygame.image.load("mousecursor.png").convert_alpha() 111 | 112 | # Load the sound file 113 | bounce_sound = pygame.mixer.Sound("bounce.wav") 114 | 115 | balls = [] 116 | 117 | while True: 118 | 119 | for event in pygame.event.get(): 120 | 121 | if event.type == QUIT: 122 | pygame.quit() 123 | quit() 124 | 125 | if event.type == MOUSEBUTTONDOWN: 126 | 127 | # Create a new ball at the mouse position 128 | random_speed = ( randint(-400, 400), randint(-300, 0) ) 129 | new_ball = Ball( event.pos, 130 | random_speed, 131 | ball_image, 132 | bounce_sound ) 133 | balls.append(new_ball) 134 | 135 | time_passed_seconds = clock.tick() / 1000. 136 | 137 | screen.fill((255, 255, 255)) 138 | 139 | dead_balls = [] 140 | 141 | for ball in balls: 142 | 143 | ball.update(time_passed_seconds) 144 | ball.render(screen) 145 | 146 | # Make not of any balls that are older than 10 seconds 147 | if ball.age > 10.0: 148 | dead_balls.append(ball) 149 | 150 | # remove any 'dead' balls from the main list 151 | for ball in dead_balls: 152 | 153 | balls.remove(ball) 154 | 155 | # Draw the mouse cursor 156 | mouse_pos = pygame.mouse.get_pos() 157 | screen.blit(mouse_image, mouse_pos) 158 | 159 | pygame.display.update() 160 | 161 | if __name__ == "__main__": 162 | 163 | run() 164 | -------------------------------------------------------------------------------- /9781484209714_Chapter_10/10-5.py: -------------------------------------------------------------------------------- 1 | pygame.mixer.music.load("techno.ogg") 2 | pygame.mixer.music.play() 3 | -------------------------------------------------------------------------------- /9781484209714_Chapter_10/10-6.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | 4 | from math import sqrt 5 | import os 6 | import os.path 7 | 8 | # Location of music on your computer 9 | MUSIC_PATH = "./MUSIC" 10 | SCREEN_SIZE = (800, 600) 11 | 12 | def get_music(path): 13 | 14 | # Get the filenames in a folder 15 | raw_filenames = os.listdir(path) 16 | 17 | music_files = [] 18 | for filename in raw_filenames: 19 | 20 | # We only want ogg files 21 | if filename.endswith('.ogg'): 22 | music_files.append(os.path.join(MUSIC_PATH, filename)) 23 | 24 | return sorted(music_files) 25 | 26 | 27 | class Button(object): 28 | 29 | def __init__(self, image_filename, position): 30 | 31 | self.position = position 32 | self.image = pygame.image.load(image_filename) 33 | 34 | def render(self, surface): 35 | 36 | # Render at the center 37 | x, y = self.position 38 | w, h = self.image.get_size() 39 | x -= w /2 40 | y -= h / 2 41 | 42 | surface.blit(self.image, (x, y)) 43 | 44 | 45 | def is_over(self, point): 46 | 47 | # Return True if a point is over the button 48 | point_x, point_y = point 49 | x, y = self.position 50 | w, h = self.image.get_size() 51 | x -= w /2 52 | y -= h / 2 53 | 54 | in_x = point_x >= x and point_x < x + w 55 | in_y = point_y >= y and point_y < y + h 56 | 57 | return in_x and in_y 58 | 59 | def run(): 60 | 61 | pygame.mixer.pre_init(44100, 16, 2, 1024*4) 62 | pygame.init() 63 | screen = pygame.display.set_mode(SCREEN_SIZE, 0) 64 | 65 | default_font = pygame.font.get_default_font() 66 | font = pygame.font.SysFont("default_font", 50, False) 67 | 68 | # Create our buttons 69 | x = 100 70 | y = 240 71 | button_width = 150 72 | 73 | # Store the buttons in a dictionary, so we can assign them names 74 | buttons = {} 75 | buttons["prev"] = Button("prev.png", (x, y)) 76 | buttons["pause"] = Button("pause.png", (x+button_width*1, y)) 77 | buttons["stop"] = Button("stop.png", (x+button_width*2, y)) 78 | buttons["play"] = Button("play.png", (x+button_width*3, y)) 79 | buttons["next"] = Button("next.png", (x+button_width*4, y)) 80 | 81 | music_filenames = get_music(MUSIC_PATH) 82 | 83 | if len(music_filenames) == 0: 84 | print("No OGG files found in ", MUSIC_PATH) 85 | return 86 | 87 | white = (255, 255, 255) 88 | label_surfaces = [] 89 | 90 | # Render the track names 91 | for filename in music_filenames: 92 | 93 | txt = os.path.split(filename)[-1] 94 | 95 | print("Track:", txt) 96 | 97 | txt = txt.split('.')[0] 98 | surface = font.render(txt, True, (100, 0, 100)) 99 | label_surfaces.append(surface) 100 | 101 | current_track = 0 102 | max_tracks = len(music_filenames) 103 | 104 | pygame.mixer.music.load( music_filenames[current_track] ) 105 | 106 | clock = pygame.time.Clock() 107 | 108 | playing = False 109 | paused = False 110 | 111 | # This event is sent when a music track ends 112 | TRACK_END = USEREVENT + 1 113 | pygame.mixer.music.set_endevent(TRACK_END) 114 | 115 | while True: 116 | 117 | button_pressed = None 118 | 119 | for event in pygame.event.get(): 120 | 121 | if event.type == QUIT: 122 | pygame.quit() 123 | quit() 124 | 125 | if event.type == MOUSEBUTTONDOWN: 126 | 127 | # Find the pressed button 128 | for button_name, button in buttons.items(): 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 list(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() 202 | -------------------------------------------------------------------------------- /9781484209714_Chapter_10/ball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_10/ball.png -------------------------------------------------------------------------------- /9781484209714_Chapter_10/bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_10/bar.png -------------------------------------------------------------------------------- /9781484209714_Chapter_10/bounce.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_10/bounce.wav -------------------------------------------------------------------------------- /9781484209714_Chapter_10/bouncesound.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | from random import randint 4 | from gameobjects.vector2 import Vector2 5 | 6 | SCREEN_SIZE = (640, 480) 7 | 8 | # In pixels per second, per second 9 | GRAVITY = 250.0 10 | # Increase for more bounciness, but don't go over 1! 11 | BOUNCINESS = 0.7 12 | 13 | def stero_pan(x_coord, screen_width): 14 | 15 | right_volume = float(x_coord) / screen_width 16 | left_volume = 1.0 - right_volume 17 | 18 | return (left_volume, right_volume) 19 | 20 | 21 | class Ball(object): 22 | 23 | def __init__(self, position, speed, image, bounce_sound): 24 | 25 | self.position = Vector2(position) 26 | self.speed = Vector2(speed) 27 | self.image = image 28 | self.bounce_sound = bounce_sound 29 | self.age = 0.0 30 | 31 | def update(self, time_passed): 32 | 33 | w, h = self.image.get_size() 34 | 35 | screen_width, screen_height = SCREEN_SIZE 36 | 37 | x, y = self.position 38 | x -= w/2 39 | y -= h/2 40 | 41 | # Has the ball bounce 42 | bounce = False 43 | 44 | # Has the ball hit the bottom of the screen? 45 | if y + h >= screen_height: 46 | self.speed.y = -self.speed.y * BOUNCINESS 47 | self.position.y = screen_height - h / 2.0 - 1.0 48 | bounce = True 49 | 50 | # Has the ball hit the left of the screen? 51 | if x <= 0: 52 | self.speed.x = -self.speed.x * BOUNCINESS 53 | self.position.x = w / 2.0 + 1 54 | bounce = True 55 | 56 | # Has the ball hit the right of the screen 57 | elif x + w >= screen_width: 58 | self.speed.x = -self.speed.x * BOUNCINESS 59 | self.position.x = screen_width - w / 2.0 - 1 60 | bounce = True 61 | 62 | # Do time based movement 63 | self.position += self.speed * time_passed 64 | # Add gravity 65 | self.speed.y += time_passed * GRAVITY 66 | 67 | if bounce: 68 | self.play_bounce_sound() 69 | 70 | self.age += time_passed 71 | 72 | 73 | def play_bounce_sound(self): 74 | 75 | channel = self.bounce_sound.play() 76 | 77 | if channel is not None: 78 | # Get the left and right volumes 79 | left, right = stero_pan(self.position.x, SCREEN_SIZE[0]) 80 | channel.set_volume(left, right) 81 | 82 | 83 | def render(self, surface): 84 | 85 | # Draw the sprite center at self.position 86 | w, h = self.image.get_size() 87 | x, y = self.position 88 | x -= w/2 89 | y -= h/2 90 | surface.blit(self.image, (x, y)) 91 | 92 | 93 | def run(): 94 | 95 | # Initialise 44KHz 16-bit stero sound 96 | pygame.mixer.pre_init(44100, 16, 2, 1024*4) 97 | pygame.init() 98 | pygame.mixer.set_num_channels(8) 99 | screen = pygame.display.set_mode(SCREEN_SIZE, 0) 100 | 101 | print(pygame.display.get_wm_info()) 102 | hwnd = pygame.display.get_wm_info()["window"] 103 | x, y = (200, 200) 104 | 105 | pygame.mouse.set_visible(False) 106 | 107 | clock = pygame.time.Clock() 108 | 109 | ball_image = pygame.image.load("ball.png").convert_alpha() 110 | mouse_image = pygame.image.load("mousecursor.png").convert_alpha() 111 | 112 | # Load the sound file 113 | bounce_sound = pygame.mixer.Sound("bounce.wav") 114 | 115 | balls = [] 116 | 117 | while True: 118 | 119 | for event in pygame.event.get(): 120 | 121 | if event.type == QUIT: 122 | pygame.quit() 123 | quit() 124 | 125 | if event.type == MOUSEBUTTONDOWN: 126 | 127 | # Create a new ball at the mouse position 128 | random_speed = ( randint(-400, 400), randint(-300, 0) ) 129 | new_ball = Ball( event.pos, 130 | random_speed, 131 | ball_image, 132 | bounce_sound ) 133 | balls.append(new_ball) 134 | 135 | time_passed_seconds = clock.tick() / 1000. 136 | 137 | screen.fill((255, 255, 255)) 138 | 139 | dead_balls = [] 140 | 141 | for ball in balls: 142 | 143 | ball.update(time_passed_seconds) 144 | ball.render(screen) 145 | 146 | # Make not of any balls that are older than 10 seconds 147 | if ball.age > 10.0: 148 | dead_balls.append(ball) 149 | 150 | # remove any 'dead' balls from the main list 151 | for ball in dead_balls: 152 | 153 | balls.remove(ball) 154 | 155 | # Draw the mouse cursor 156 | mouse_pos = pygame.mouse.get_pos() 157 | screen.blit(mouse_image, mouse_pos) 158 | 159 | pygame.display.update() 160 | 161 | if __name__ == "__main__": 162 | 163 | run() 164 | -------------------------------------------------------------------------------- /9781484209714_Chapter_10/cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_10/cross.png -------------------------------------------------------------------------------- /9781484209714_Chapter_10/gameobjects/__pycache__/matrix44.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_10/gameobjects/__pycache__/matrix44.cpython-34.pyc -------------------------------------------------------------------------------- /9781484209714_Chapter_10/gameobjects/__pycache__/util.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_10/gameobjects/__pycache__/util.cpython-34.pyc -------------------------------------------------------------------------------- /9781484209714_Chapter_10/gameobjects/__pycache__/vector2.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_10/gameobjects/__pycache__/vector2.cpython-34.pyc -------------------------------------------------------------------------------- /9781484209714_Chapter_10/gameobjects/__pycache__/vector3.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_10/gameobjects/__pycache__/vector3.cpython-34.pyc -------------------------------------------------------------------------------- /9781484209714_Chapter_10/gameobjects/util.py: -------------------------------------------------------------------------------- 1 | from math import * 2 | 3 | def format_number(n, accuracy=6): 4 | """Formats a number in a friendly manner 5 | (removes trailing zeros and unneccesary point.""" 6 | 7 | fs = "%."+str(accuracy)+"f" 8 | str_n = fs%float(n) 9 | if '.' in str_n: 10 | str_n = str_n.rstrip('0').rstrip('.') 11 | if str_n == "-0": 12 | str_n = "0" 13 | #str_n = str_n.replace("-0", "0") 14 | return str_n 15 | 16 | 17 | def lerp(a, b, i): 18 | """Linear enterpolate from a to b.""" 19 | return a+(b-a)*i 20 | 21 | 22 | def range2d(range_x, range_y): 23 | 24 | """Creates a 2D range.""" 25 | 26 | range_x = list(range_x) 27 | return [ (x, y) for y in range_y for x in range_x ] 28 | 29 | 30 | def xrange2d(range_x, range_y): 31 | 32 | """Iterates over a 2D range.""" 33 | 34 | range_x = list(range_x) 35 | for y in range_y: 36 | for x in range_x: 37 | yield (x, y) 38 | 39 | 40 | def saturate(value, low, high): 41 | return min(max(value, low), high) 42 | 43 | 44 | def is_power_of_2(n): 45 | """Returns True if a value is a power of 2.""" 46 | return log(n, 2) % 1.0 == 0.0 47 | 48 | 49 | def next_power_of_2(n): 50 | """Returns the next power of 2 that is >= n""" 51 | return int(2 ** ceil(log(n, 2))) 52 | 53 | if __name__ == "__main__": 54 | 55 | print(list( xrange2d(range(3), range(3)) )) 56 | print(range2d(range(3), range(3))) 57 | print(is_power_of_2(7)) 58 | print(is_power_of_2(8)) 59 | print(is_power_of_2(9)) 60 | 61 | print(next_power_of_2(7)) 62 | -------------------------------------------------------------------------------- /9781484209714_Chapter_10/jukebox.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | 4 | from math import sqrt 5 | import os 6 | import os.path 7 | 8 | # Location of music on your computer 9 | MUSIC_PATH = "./MUSIC" 10 | SCREEN_SIZE = (800, 600) 11 | 12 | def get_music(path): 13 | 14 | # Get the filenames in a folder 15 | raw_filenames = os.listdir(path) 16 | 17 | music_files = [] 18 | for filename in raw_filenames: 19 | 20 | # We only want ogg files 21 | if filename.endswith('.ogg'): 22 | music_files.append(os.path.join(MUSIC_PATH, filename)) 23 | 24 | return sorted(music_files) 25 | 26 | 27 | class Button(object): 28 | 29 | def __init__(self, image_filename, position): 30 | 31 | self.position = position 32 | self.image = pygame.image.load(image_filename) 33 | 34 | def render(self, surface): 35 | 36 | # Render at the center 37 | x, y = self.position 38 | w, h = self.image.get_size() 39 | x -= w /2 40 | y -= h / 2 41 | 42 | surface.blit(self.image, (x, y)) 43 | 44 | 45 | def is_over(self, point): 46 | 47 | # Return True if a point is over the button 48 | point_x, point_y = point 49 | x, y = self.position 50 | w, h = self.image.get_size() 51 | x -= w /2 52 | y -= h / 2 53 | 54 | in_x = point_x >= x and point_x < x + w 55 | in_y = point_y >= y and point_y < y + h 56 | 57 | return in_x and in_y 58 | 59 | def run(): 60 | 61 | pygame.mixer.pre_init(44100, 16, 2, 1024*4) 62 | pygame.init() 63 | screen = pygame.display.set_mode(SCREEN_SIZE, 0) 64 | 65 | default_font = pygame.font.get_default_font() 66 | font = pygame.font.SysFont("default_font", 50, False) 67 | 68 | # Create our buttons 69 | x = 100 70 | y = 240 71 | button_width = 150 72 | 73 | # Store the buttons in a dictionary, so we can assign them names 74 | buttons = {} 75 | buttons["prev"] = Button("prev.png", (x, y)) 76 | buttons["pause"] = Button("pause.png", (x+button_width*1, y)) 77 | buttons["stop"] = Button("stop.png", (x+button_width*2, y)) 78 | buttons["play"] = Button("play.png", (x+button_width*3, y)) 79 | buttons["next"] = Button("next.png", (x+button_width*4, y)) 80 | 81 | music_filenames = get_music(MUSIC_PATH) 82 | 83 | if len(music_filenames) == 0: 84 | print("No OGG files found in ", MUSIC_PATH) 85 | return 86 | 87 | white = (255, 255, 255) 88 | label_surfaces = [] 89 | 90 | # Render the track names 91 | for filename in music_filenames: 92 | 93 | txt = os.path.split(filename)[-1] 94 | 95 | print("Track:", txt) 96 | 97 | txt = txt.split('.')[0] 98 | surface = font.render(txt, True, (100, 0, 100)) 99 | label_surfaces.append(surface) 100 | 101 | current_track = 0 102 | max_tracks = len(music_filenames) 103 | 104 | pygame.mixer.music.load( music_filenames[current_track] ) 105 | 106 | clock = pygame.time.Clock() 107 | 108 | playing = False 109 | paused = False 110 | 111 | # This event is sent when a music track ends 112 | TRACK_END = USEREVENT + 1 113 | pygame.mixer.music.set_endevent(TRACK_END) 114 | 115 | while True: 116 | 117 | button_pressed = None 118 | 119 | for event in pygame.event.get(): 120 | 121 | if event.type == QUIT: 122 | pygame.quit() 123 | quit() 124 | 125 | if event.type == MOUSEBUTTONDOWN: 126 | 127 | # Find the pressed button 128 | for button_name, button in buttons.items(): 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 list(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() 202 | -------------------------------------------------------------------------------- /9781484209714_Chapter_10/mousecursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_10/mousecursor.png -------------------------------------------------------------------------------- /9781484209714_Chapter_10/music/please put some ogg files in the music folder.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_10/music/please put some ogg files in the music folder.ogg -------------------------------------------------------------------------------- /9781484209714_Chapter_10/next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_10/next.png -------------------------------------------------------------------------------- /9781484209714_Chapter_10/pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_10/pause.png -------------------------------------------------------------------------------- /9781484209714_Chapter_10/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_10/play.png -------------------------------------------------------------------------------- /9781484209714_Chapter_10/prev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_10/prev.png -------------------------------------------------------------------------------- /9781484209714_Chapter_10/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_10/stop.png -------------------------------------------------------------------------------- /9781484209714_Chapter_11/11-1.py: -------------------------------------------------------------------------------- 1 | from math import log, ceil 2 | def next_power_of_2(size): 3 | return 2 ** ceil(log(size, 2)) 4 | -------------------------------------------------------------------------------- /9781484209714_Chapter_11/11-2.1.py: -------------------------------------------------------------------------------- 1 | from math import radians 2 | 3 | from OpenGL.GL import * 4 | from OpenGL.GLU import * 5 | 6 | import pygame 7 | from pygame.locals import * 8 | 9 | SCREEN_SIZE = (800, 600) 10 | 11 | def resize(width, height): 12 | 13 | glViewport(0, 0, width, height) 14 | glMatrixMode(GL_PROJECTION) 15 | glLoadIdentity() 16 | gluPerspective(60.0, float(width)/height, .1, 1000.) 17 | glMatrixMode(GL_MODELVIEW) 18 | glLoadIdentity() 19 | 20 | def init(): 21 | 22 | glEnable(GL_TEXTURE_2D) 23 | glClearColor(1.0, 1.0, 1.0, 0.0) 24 | 25 | def run(): 26 | 27 | pygame.init() 28 | screen = pygame.display.set_mode(SCREEN_SIZE, HWSURFACE|OPENGL|DOUBLEBUF) 29 | 30 | resize(*SCREEN_SIZE) 31 | init() 32 | 33 | # Load the textures 34 | texture_surface = pygame.image.load("sushitex.png") 35 | # Retrieve the texture data 36 | texture_data = pygame.image.tostring(texture_surface, 'RGB', True) 37 | 38 | # Generate a texture id 39 | texture_id = glGenTextures(1) 40 | # Tell OpenGL we will be using this texture id for texture operations 41 | glBindTexture(GL_TEXTURE_2D, texture_id) 42 | 43 | # Tell OpenGL how to scale images 44 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ) 45 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ) 46 | 47 | # Tell OpenGL that data is aligned to byte boundries 48 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1) 49 | 50 | # Get the dimensions of the image 51 | width, height = texture_surface.get_rect().size 52 | 53 | 54 | gluBuild2DMipmaps( GL_TEXTURE_2D, 55 | 3, 56 | width, 57 | height, 58 | GL_RGB, 59 | GL_UNSIGNED_BYTE, 60 | texture_data ) 61 | 62 | 63 | clock = pygame.time.Clock() 64 | 65 | tex_rotation = 0.0 66 | 67 | while True: 68 | 69 | for event in pygame.event.get(): 70 | if event.type == QUIT: 71 | pygame.quit() 72 | quit() 73 | 74 | 75 | time_passed = clock.tick() 76 | time_passed_seconds = time_passed / 1000. 77 | tex_rotation += time_passed_seconds * 360.0 / 8.0 78 | 79 | 80 | # Clear the screen (similar to fill) 81 | glClear(GL_COLOR_BUFFER_BIT) 82 | 83 | # Clear the model-view matrix 84 | glLoadIdentity() 85 | 86 | # Set the modelview matrix 87 | glTranslatef(0.0, 0.0, -600.0) 88 | glRotate(tex_rotation, 1, 0, 0) 89 | 90 | # Draw a quad (4 vertices, 4 texture coords) 91 | glBegin(GL_QUADS) 92 | 93 | glTexCoord2f(0, 1) 94 | glVertex3f(-300, 300, 0) 95 | 96 | glTexCoord2f(1, 1) 97 | glVertex3f(300, 300, 0) 98 | 99 | glTexCoord2f(1, 0) 100 | glVertex3f(300, -300, 0) 101 | 102 | glTexCoord2f(0, 0) 103 | glVertex3f(-300, -300, 0) 104 | 105 | glEnd() 106 | 107 | pygame.display.flip() 108 | 109 | glDeleteTextures(texture_id) 110 | 111 | if __name__ == "__main__": 112 | run() 113 | -------------------------------------------------------------------------------- /9781484209714_Chapter_11/11-2.2.py: -------------------------------------------------------------------------------- 1 | from math import radians 2 | 3 | from OpenGL.GL import * 4 | from OpenGL.GLU import * 5 | 6 | import pygame 7 | from pygame.locals import * 8 | 9 | SCREEN_SIZE = (800, 600) 10 | 11 | def resize(width, height): 12 | 13 | glViewport(0, 0, width, height) 14 | glMatrixMode(GL_PROJECTION) 15 | glLoadIdentity() 16 | gluPerspective(60.0, float(width)/height, .1, 1000.) 17 | glMatrixMode(GL_MODELVIEW) 18 | glLoadIdentity() 19 | 20 | def init(): 21 | 22 | glEnable(GL_TEXTURE_2D) 23 | glClearColor(1.0, 1.0, 1.0, 0.0) 24 | 25 | def run(): 26 | 27 | pygame.init() 28 | screen = pygame.display.set_mode(SCREEN_SIZE, HWSURFACE|OPENGL|DOUBLEBUF) 29 | 30 | resize(*SCREEN_SIZE) 31 | init() 32 | 33 | # Load the textures 34 | texture_surface = pygame.image.load("sushitex.png") 35 | # Retrieve the texture data 36 | texture_data = pygame.image.tostring(texture_surface, 'RGB', True) 37 | 38 | # Generate a texture id 39 | texture_id = glGenTextures(1) 40 | # Tell OpenGL we will be using this texture id for texture operations 41 | glBindTexture(GL_TEXTURE_2D, texture_id) 42 | 43 | # Tell OpenGL how to scale images 44 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) 45 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR) 46 | 47 | # Tell OpenGL that data is aligned to byte boundries 48 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1) 49 | 50 | # Get the dimensions of the image 51 | width, height = texture_surface.get_rect().size 52 | 53 | 54 | gluBuild2DMipmaps( GL_TEXTURE_2D, 55 | 3, 56 | width, 57 | height, 58 | GL_RGB, 59 | GL_UNSIGNED_BYTE, 60 | texture_data ) 61 | 62 | 63 | clock = pygame.time.Clock() 64 | 65 | tex_rotation = 0.0 66 | 67 | while True: 68 | 69 | for event in pygame.event.get(): 70 | if event.type == QUIT: 71 | pygame.quit() 72 | quit() 73 | 74 | 75 | time_passed = clock.tick() 76 | time_passed_seconds = time_passed / 1000. 77 | tex_rotation += time_passed_seconds * 360.0 / 8.0 78 | 79 | 80 | # Clear the screen (similar to fill) 81 | glClear(GL_COLOR_BUFFER_BIT) 82 | 83 | # Clear the model-view matrix 84 | glLoadIdentity() 85 | 86 | # Set the modelview matrix 87 | glTranslatef(0.0, 0.0, -600.0) 88 | glRotate(tex_rotation, 1, 0, 0) 89 | 90 | # Draw a quad (4 vertices, 4 texture coords) 91 | glBegin(GL_QUADS) 92 | 93 | glTexCoord2f(0, 1) 94 | glVertex3f(-300, 300, 0) 95 | 96 | glTexCoord2f(1, 1) 97 | glVertex3f(300, 300, 0) 98 | 99 | glTexCoord2f(1, 0) 100 | glVertex3f(300, -300, 0) 101 | 102 | glTexCoord2f(0, 0) 103 | glVertex3f(-300, -300, 0) 104 | 105 | glEnd() 106 | 107 | pygame.display.flip() 108 | 109 | glDeleteTextures(texture_id) 110 | 111 | if __name__ == "__main__": 112 | run() 113 | -------------------------------------------------------------------------------- /9781484209714_Chapter_11/11-2.3.py: -------------------------------------------------------------------------------- 1 | from math import radians 2 | 3 | from OpenGL.GL import * 4 | from OpenGL.GLU import * 5 | 6 | import pygame 7 | from pygame.locals import * 8 | 9 | SCREEN_SIZE = (800, 600) 10 | 11 | def resize(width, height): 12 | 13 | glViewport(0, 0, width, height) 14 | glMatrixMode(GL_PROJECTION) 15 | glLoadIdentity() 16 | gluPerspective(60.0, float(width)/height, .1, 1000.) 17 | glMatrixMode(GL_MODELVIEW) 18 | glLoadIdentity() 19 | 20 | def init(): 21 | 22 | glEnable(GL_TEXTURE_2D) 23 | glClearColor(1.0, 1.0, 1.0, 0.0) 24 | 25 | def run(): 26 | 27 | pygame.init() 28 | screen = pygame.display.set_mode(SCREEN_SIZE, HWSURFACE|OPENGL|DOUBLEBUF) 29 | 30 | resize(*SCREEN_SIZE) 31 | init() 32 | 33 | # Load the textures 34 | texture_surface = pygame.image.load("sushitex.png") 35 | # Retrieve the texture data 36 | texture_data = pygame.image.tostring(texture_surface, 'RGB', True) 37 | 38 | # Generate a texture id 39 | texture_id = glGenTextures(1) 40 | # Tell OpenGL we will be using this texture id for texture operations 41 | glBindTexture(GL_TEXTURE_2D, texture_id) 42 | 43 | # Tell OpenGL how to scale images 44 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) 45 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR) 46 | 47 | # Tell OpenGL that data is aligned to byte boundries 48 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1) 49 | 50 | # Get the dimensions of the image 51 | width, height = texture_surface.get_rect().size 52 | 53 | 54 | gluBuild2DMipmaps( GL_TEXTURE_2D, 55 | 3, 56 | width, 57 | height, 58 | GL_RGB, 59 | GL_UNSIGNED_BYTE, 60 | texture_data ) 61 | 62 | 63 | clock = pygame.time.Clock() 64 | 65 | tex_rotation = 0.0 66 | 67 | while True: 68 | 69 | for event in pygame.event.get(): 70 | if event.type == QUIT: 71 | pygame.quit() 72 | quit() 73 | 74 | 75 | time_passed = clock.tick() 76 | time_passed_seconds = time_passed / 1000. 77 | tex_rotation += time_passed_seconds * 360.0 / 8.0 78 | 79 | 80 | # Clear the screen (similar to fill) 81 | glClear(GL_COLOR_BUFFER_BIT) 82 | 83 | # Clear the model-view matrix 84 | glLoadIdentity() 85 | 86 | # Set the modelview matrix 87 | glTranslatef(0.0, 0.0, -600.0) 88 | glRotate(tex_rotation, 1, 0, 0) 89 | 90 | # Draw a quad (4 vertices, 4 texture coords) 91 | glBegin(GL_QUADS) 92 | 93 | glTexCoord2f(0, 3) 94 | glVertex3f(-300, 300, 0) 95 | 96 | glTexCoord2f(3, 3) 97 | glVertex3f(300, 300, 0) 98 | 99 | glTexCoord2f(3, 0) 100 | glVertex3f(300, -300, 0) 101 | 102 | glTexCoord2f(0, 0) 103 | glVertex3f(-300, -300, 0) 104 | 105 | glEnd() 106 | 107 | pygame.display.flip() 108 | 109 | glDeleteTextures(texture_id) 110 | 111 | if __name__ == "__main__": 112 | run() 113 | -------------------------------------------------------------------------------- /9781484209714_Chapter_11/11-2.4.py: -------------------------------------------------------------------------------- 1 | from math import radians 2 | 3 | from OpenGL.GL import * 4 | from OpenGL.GLU import * 5 | 6 | import pygame 7 | from pygame.locals import * 8 | 9 | SCREEN_SIZE = (800, 600) 10 | 11 | def resize(width, height): 12 | 13 | glViewport(0, 0, width, height) 14 | glMatrixMode(GL_PROJECTION) 15 | glLoadIdentity() 16 | gluPerspective(60.0, float(width)/height, .1, 1000.) 17 | glMatrixMode(GL_MODELVIEW) 18 | glLoadIdentity() 19 | 20 | def init(): 21 | 22 | glEnable(GL_TEXTURE_2D) 23 | glClearColor(1.0, 1.0, 1.0, 0.0) 24 | 25 | def run(): 26 | 27 | pygame.init() 28 | screen = pygame.display.set_mode(SCREEN_SIZE, HWSURFACE|OPENGL|DOUBLEBUF) 29 | 30 | resize(*SCREEN_SIZE) 31 | init() 32 | 33 | # Load the textures 34 | texture_surface = pygame.image.load("sushitex.png") 35 | # Retrieve the texture data 36 | texture_data = pygame.image.tostring(texture_surface, 'RGB', True) 37 | 38 | # Generate a texture id 39 | texture_id = glGenTextures(1) 40 | # Tell OpenGL we will be using this texture id for texture operations 41 | glBindTexture(GL_TEXTURE_2D, texture_id) 42 | 43 | # Tell OpenGL how to scale images 44 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT) 45 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT) 46 | 47 | # Tell OpenGL that data is aligned to byte boundries 48 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1) 49 | 50 | # Get the dimensions of the image 51 | width, height = texture_surface.get_rect().size 52 | 53 | 54 | gluBuild2DMipmaps( GL_TEXTURE_2D, 55 | 3, 56 | width, 57 | height, 58 | GL_RGB, 59 | GL_UNSIGNED_BYTE, 60 | texture_data ) 61 | 62 | 63 | clock = pygame.time.Clock() 64 | 65 | tex_rotation = 0.0 66 | 67 | while True: 68 | 69 | for event in pygame.event.get(): 70 | if event.type == QUIT: 71 | pygame.quit() 72 | quit() 73 | 74 | 75 | time_passed = clock.tick() 76 | time_passed_seconds = time_passed / 1000. 77 | tex_rotation += time_passed_seconds * 360.0 / 8.0 78 | 79 | 80 | # Clear the screen (similar to fill) 81 | glClear(GL_COLOR_BUFFER_BIT) 82 | 83 | # Clear the model-view matrix 84 | glLoadIdentity() 85 | 86 | # Set the modelview matrix 87 | glTranslatef(0.0, 0.0, -600.0) 88 | glRotate(tex_rotation, 1, 0, 0) 89 | 90 | # Draw a quad (4 vertices, 4 texture coords) 91 | glBegin(GL_QUADS) 92 | 93 | glTexCoord2f(0, 3) 94 | glVertex3f(-300, 300, 0) 95 | 96 | glTexCoord2f(3, 3) 97 | glVertex3f(300, 300, 0) 98 | 99 | glTexCoord2f(3, 0) 100 | glVertex3f(300, -300, 0) 101 | 102 | glTexCoord2f(0, 0) 103 | glVertex3f(-300, -300, 0) 104 | 105 | glEnd() 106 | 107 | pygame.display.flip() 108 | 109 | glDeleteTextures(texture_id) 110 | 111 | if __name__ == "__main__": 112 | run() 113 | -------------------------------------------------------------------------------- /9781484209714_Chapter_11/11-2.5.py: -------------------------------------------------------------------------------- 1 | from math import radians 2 | 3 | from OpenGL.GL import * 4 | from OpenGL.GLU import * 5 | 6 | import pygame 7 | from pygame.locals import * 8 | 9 | SCREEN_SIZE = (800, 600) 10 | 11 | def resize(width, height): 12 | 13 | glViewport(0, 0, width, height) 14 | glMatrixMode(GL_PROJECTION) 15 | glLoadIdentity() 16 | gluPerspective(60.0, float(width)/height, .1, 1000.) 17 | glMatrixMode(GL_MODELVIEW) 18 | glLoadIdentity() 19 | 20 | def init(): 21 | 22 | glEnable(GL_TEXTURE_2D) 23 | glClearColor(1.0, 1.0, 1.0, 0.0) 24 | 25 | def run(): 26 | 27 | pygame.init() 28 | screen = pygame.display.set_mode(SCREEN_SIZE, HWSURFACE|OPENGL|DOUBLEBUF) 29 | 30 | resize(*SCREEN_SIZE) 31 | init() 32 | 33 | # Load the textures 34 | texture_surface = pygame.image.load("sushitex.png") 35 | # Retrieve the texture data 36 | texture_data = pygame.image.tostring(texture_surface, 'RGB', True) 37 | 38 | # Generate a texture id 39 | texture_id = glGenTextures(1) 40 | # Tell OpenGL we will be using this texture id for texture operations 41 | glBindTexture(GL_TEXTURE_2D, texture_id) 42 | 43 | # Tell OpenGL how to scale images 44 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) 45 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) 46 | 47 | # Tell OpenGL that data is aligned to byte boundries 48 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1) 49 | 50 | # Get the dimensions of the image 51 | width, height = texture_surface.get_rect().size 52 | 53 | 54 | gluBuild2DMipmaps( GL_TEXTURE_2D, 55 | 3, 56 | width, 57 | height, 58 | GL_RGB, 59 | GL_UNSIGNED_BYTE, 60 | texture_data ) 61 | 62 | 63 | clock = pygame.time.Clock() 64 | 65 | tex_rotation = 0.0 66 | 67 | while True: 68 | 69 | for event in pygame.event.get(): 70 | if event.type == QUIT: 71 | pygame.quit() 72 | quit() 73 | 74 | 75 | time_passed = clock.tick() 76 | time_passed_seconds = time_passed / 1000. 77 | tex_rotation += time_passed_seconds * 360.0 / 8.0 78 | 79 | 80 | # Clear the screen (similar to fill) 81 | glClear(GL_COLOR_BUFFER_BIT) 82 | 83 | # Clear the model-view matrix 84 | glLoadIdentity() 85 | 86 | # Set the modelview matrix 87 | glTranslatef(0.0, 0.0, -600.0) 88 | glRotate(tex_rotation, 1, 0, 0) 89 | 90 | # Draw a quad (4 vertices, 4 texture coords) 91 | glBegin(GL_QUADS) 92 | 93 | glTexCoord2f(0, 3) 94 | glVertex3f(-300, 300, 0) 95 | 96 | glTexCoord2f(3, 3) 97 | glVertex3f(300, 300, 0) 98 | 99 | glTexCoord2f(3, 0) 100 | glVertex3f(300, -300, 0) 101 | 102 | glTexCoord2f(0, 0) 103 | glVertex3f(-300, -300, 0) 104 | 105 | glEnd() 106 | 107 | pygame.display.flip() 108 | 109 | glDeleteTextures(texture_id) 110 | 111 | if __name__ == "__main__": 112 | run() 113 | -------------------------------------------------------------------------------- /9781484209714_Chapter_11/11-2.py: -------------------------------------------------------------------------------- 1 | from math import radians 2 | 3 | from OpenGL.GL import * 4 | from OpenGL.GLU import * 5 | 6 | import pygame 7 | from pygame.locals import * 8 | 9 | SCREEN_SIZE = (800, 600) 10 | 11 | def resize(width, height): 12 | 13 | glViewport(0, 0, width, height) 14 | glMatrixMode(GL_PROJECTION) 15 | glLoadIdentity() 16 | gluPerspective(60.0, float(width)/height, .1, 1000.) 17 | glMatrixMode(GL_MODELVIEW) 18 | glLoadIdentity() 19 | 20 | def init(): 21 | 22 | glEnable(GL_TEXTURE_2D) 23 | glClearColor(1.0, 1.0, 1.0, 0.0) 24 | 25 | def run(): 26 | 27 | pygame.init() 28 | screen = pygame.display.set_mode(SCREEN_SIZE, HWSURFACE|OPENGL|DOUBLEBUF) 29 | 30 | resize(*SCREEN_SIZE) 31 | init() 32 | 33 | # Load the textures 34 | texture_surface = pygame.image.load("sushitex.png") 35 | # Retrieve the texture data 36 | texture_data = pygame.image.tostring(texture_surface, 'RGB', True) 37 | 38 | # Generate a texture id 39 | texture_id = glGenTextures(1) 40 | # Tell OpenGL we will be using this texture id for texture operations 41 | glBindTexture(GL_TEXTURE_2D, texture_id) 42 | 43 | # Tell OpenGL how to scale images 44 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ) 45 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ) 46 | 47 | # Tell OpenGL that data is aligned to byte boundries 48 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1) 49 | 50 | # Get the dimensions of the image 51 | width, height = texture_surface.get_rect().size 52 | 53 | # Upload the image to OpenGL 54 | glTexImage2D( GL_TEXTURE_2D, 55 | 0, 56 | 3, 57 | width, 58 | height, 59 | 0, 60 | GL_RGB, 61 | GL_UNSIGNED_BYTE, 62 | texture_data) 63 | 64 | 65 | clock = pygame.time.Clock() 66 | 67 | tex_rotation = 0.0 68 | 69 | while True: 70 | 71 | for event in pygame.event.get(): 72 | if event.type == QUIT: 73 | pygame.quit() 74 | quit() 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 | -------------------------------------------------------------------------------- /9781484209714_Chapter_11/11-3.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | from OpenGL.GLU import * 3 | 4 | import pygame 5 | import os.path 6 | 7 | class Material(object): 8 | 9 | def init (self): 10 | 11 | self.name = "" 12 | self.texture_fname = None 13 | self.texture_id = None 14 | 15 | class FaceGroup(object): 16 | 17 | def init (self): 18 | 19 | self.tri_indices = [] 20 | self.material_name = "" 21 | 22 | class Model3D(object): 23 | 24 | def init (self): 25 | 26 | self.vertices = [] 27 | self.tex_coords = [] 28 | self.normals = [] 29 | self.materials = {} 30 | self.face_groups = [] 31 | # Display list id for quick rendering 32 | self.display_list_id = None 33 | -------------------------------------------------------------------------------- /9781484209714_Chapter_11/11-4.py: -------------------------------------------------------------------------------- 1 | def read_obj(self, fname): 2 | 3 | current_face_group = None 4 | 5 | file_in = open(fname) 6 | 7 | for line in file_in: 8 | 9 | # Parse command and data from each line 10 | words = line.split() 11 | command = words[0] 12 | data = words[1:] 13 | 14 | if command == 'mtllib': # Material library 15 | 16 | model_path = os.path.split(fname)[0] 17 | mtllib_path = os.path.join( model_path, data[0] ) 18 | self.read_mtllib(mtllib_path) 19 | 20 | elif command == 'v': # Vertex 21 | x, y, z = data 22 | vertex = (float(x), float(y), float(z)) 23 | self.vertices.append(vertex) 24 | 25 | elif command == 'vt': # Texture coordinate 26 | 27 | s, t = data 28 | tex_coord = (float(s), float(t)) 29 | self.tex_coords.append(tex_coord) 30 | 31 | elif command == 'vn': # Normal 32 | 33 | x, y, z = data 34 | normal = (float(x), float(y), float(z)) 35 | self.normals.append(normal) 36 | 37 | elif command == 'usemtl' : # Use material 38 | 39 | current_face_group = FaceGroup() 40 | current_face_group.material_name = data[0] 41 | self.face_groups.append( current_face_group ) 42 | 43 | elif command == 'f': 44 | 45 | assert len(data) == 3, "Sorry, only triangles are supported" 46 | 47 | # Parse indices from triples 48 | for word in data: 49 | vi, ti, ni = word.split('/') 50 | indices = (int(vi) - 1, int(ti) - 1, int(ni) - 1) 51 | current_face_group.tri_indices.append(indices) 52 | 53 | 54 | for material in self.materials.values(): 55 | 56 | model_path = os.path.split(fname)[0] 57 | texture_path = os.path.join(model_path, material.texture_fname) 58 | texture_surface = pygame.image.load(texture_path) 59 | texture_data = pygame.image.tostring(texture_surface, 'RGB', True) 60 | 61 | material.texture_id = glGenTextures(1) 62 | glBindTexture(GL_TEXTURE_2D, material.texture_id) 63 | 64 | glTexParameteri( GL_TEXTURE_2D, 65 | GL_TEXTURE_MAG_FILTER, 66 | GL_LINEAR) 67 | glTexParameteri( GL_TEXTURE_2D, 68 | GL_TEXTURE_MIN_FILTER, 69 | GL_LINEAR_MIPMAP_LINEAR) 70 | 71 | glPixelStorei(GL_UNPACK_ALIGNMENT,1) 72 | width, height = texture_surface.get_rect().size 73 | gluBuild2DMipmaps( GL_TEXTURE_2D, 74 | 3, 75 | width, 76 | height, 77 | GL_RGB, 78 | GL_UNSIGNED_BYTE, 79 | texture_data) 80 | -------------------------------------------------------------------------------- /9781484209714_Chapter_11/11-5.py: -------------------------------------------------------------------------------- 1 | def read_mtllib(self, mtl_fname): 2 | 3 | file_mtllib = open(mtl_fname) 4 | for line in file_mtllib: 5 | 6 | words = line.split() 7 | command = words[0] 8 | data = words[1:] 9 | 10 | if command == 'newmtl': 11 | material = Material() 12 | material.name = data[0] 13 | self.materials[data[0]] = material 14 | 15 | elif command == 'map_Kd': 16 | material.texture_fname = data[0] 17 | -------------------------------------------------------------------------------- /9781484209714_Chapter_11/11-6.py: -------------------------------------------------------------------------------- 1 | def draw(self): 2 | 3 | vertices = self.vertices 4 | tex_coords = self.tex_coords 5 | normals = self.normals 6 | 7 | for face_group in self.face_groups: 8 | 9 | material = self.materials[face_group.material_name] 10 | glBindTexture(GL_TEXTURE_2D, material.texture_id) 11 | 12 | glBegin(GL_TRIANGLES) 13 | for vi, ti, ni in face_group.tri_indices: 14 | glTexCoord2fv( tex_coords[ti] ) 15 | glNormal3fv( normals[ni] ) 16 | glVertex3fv( vertices[vi] ) 17 | glEnd() 18 | 19 | 20 | def draw_quick(self): 21 | 22 | if self.display_list_id is None: 23 | self.display_list_id = glGenLists(1) 24 | glNewList(self.display_list_id, GL_COMPILE) 25 | self.draw() 26 | glEndList() 27 | 28 | glCallList(self.display_list_id) 29 | -------------------------------------------------------------------------------- /9781484209714_Chapter_11/11-7.py: -------------------------------------------------------------------------------- 1 | def __del__(self): 2 | 3 | #Called when the model is cleaned up by Python 4 | self.free_resources() 5 | 6 | def free_resources(self): 7 | 8 | # Delete the display list and textures 9 | if self.display_list_id is not None: 10 | glDeleteLists(self.display_list_id, 1) 11 | self.display_list_id = None 12 | 13 | # Delete any textures we used 14 | for material in self.materials.values(): 15 | if material.texture_id is not None: 16 | glDeleteTextures(material.texture_id) 17 | 18 | # Clear all the materials 19 | self.materials.clear() 20 | 21 | # Clear the geometry lists 22 | del self.vertices[:] 23 | del self.tex_coords[:] 24 | del self.normals[:] 25 | del self.face_groups[:] 26 | -------------------------------------------------------------------------------- /9781484209714_Chapter_11/11-8.py: -------------------------------------------------------------------------------- 1 | from math import radians 2 | 3 | from OpenGL.GL import * 4 | from OpenGL.GLU import * 5 | 6 | import pygame 7 | from pygame.locals import * 8 | 9 | # Import the Model3D class 10 | import model3d 11 | 12 | SCREEN_SIZE = (800, 600) 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 | pygame.quit() 73 | quit() 74 | 75 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 76 | 77 | time_passed = clock.tick() 78 | time_passed_seconds = time_passed / 1000.0 79 | 80 | glLoadIdentity() 81 | glRotatef(15, 1, 0, 0) 82 | glTranslatef(0.0, -1.5, -3.5) 83 | 84 | rotation += time_passed_seconds * 45.0 85 | glRotatef(rotation, 0, 1, 0) 86 | 87 | tank_model.draw_quick() 88 | 89 | pygame.display.flip() 90 | 91 | 92 | if __name__ == "__main__": 93 | run() 94 | -------------------------------------------------------------------------------- /9781484209714_Chapter_11/bodytex.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_11/bodytex.jpg -------------------------------------------------------------------------------- /9781484209714_Chapter_11/booktex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_11/booktex.png -------------------------------------------------------------------------------- /9781484209714_Chapter_11/gameobjects/__pycache__/matrix44.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_11/gameobjects/__pycache__/matrix44.cpython-34.pyc -------------------------------------------------------------------------------- /9781484209714_Chapter_11/gameobjects/__pycache__/util.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_11/gameobjects/__pycache__/util.cpython-34.pyc -------------------------------------------------------------------------------- /9781484209714_Chapter_11/gameobjects/__pycache__/vector2.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_11/gameobjects/__pycache__/vector2.cpython-34.pyc -------------------------------------------------------------------------------- /9781484209714_Chapter_11/gameobjects/__pycache__/vector3.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_11/gameobjects/__pycache__/vector3.cpython-34.pyc -------------------------------------------------------------------------------- /9781484209714_Chapter_11/gameobjects/util.py: -------------------------------------------------------------------------------- 1 | from math import * 2 | 3 | def format_number(n, accuracy=6): 4 | """Formats a number in a friendly manner 5 | (removes trailing zeros and unneccesary point.""" 6 | 7 | fs = "%."+str(accuracy)+"f" 8 | str_n = fs%float(n) 9 | if '.' in str_n: 10 | str_n = str_n.rstrip('0').rstrip('.') 11 | if str_n == "-0": 12 | str_n = "0" 13 | #str_n = str_n.replace("-0", "0") 14 | return str_n 15 | 16 | 17 | def lerp(a, b, i): 18 | """Linear enterpolate from a to b.""" 19 | return a+(b-a)*i 20 | 21 | 22 | def range2d(range_x, range_y): 23 | 24 | """Creates a 2D range.""" 25 | 26 | range_x = list(range_x) 27 | return [ (x, y) for y in range_y for x in range_x ] 28 | 29 | 30 | def xrange2d(range_x, range_y): 31 | 32 | """Iterates over a 2D range.""" 33 | 34 | range_x = list(range_x) 35 | for y in range_y: 36 | for x in range_x: 37 | yield (x, y) 38 | 39 | 40 | def saturate(value, low, high): 41 | return min(max(value, low), high) 42 | 43 | 44 | def is_power_of_2(n): 45 | """Returns True if a value is a power of 2.""" 46 | return log(n, 2) % 1.0 == 0.0 47 | 48 | 49 | def next_power_of_2(n): 50 | """Returns the next power of 2 that is >= n""" 51 | return int(2 ** ceil(log(n, 2))) 52 | 53 | if __name__ == "__main__": 54 | 55 | print(list( xrange2d(range(3), range(3)) )) 56 | print(range2d(range(3), range(3))) 57 | print(is_power_of_2(7)) 58 | print(is_power_of_2(8)) 59 | print(is_power_of_2(9)) 60 | 61 | print(next_power_of_2(7)) 62 | -------------------------------------------------------------------------------- /9781484209714_Chapter_11/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.values(): 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 = open(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.values(): 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 = open(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 | -------------------------------------------------------------------------------- /9781484209714_Chapter_11/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 | -------------------------------------------------------------------------------- /9781484209714_Chapter_11/mytanktex.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_11/mytanktex.jpg -------------------------------------------------------------------------------- /9781484209714_Chapter_11/opengltex.py: -------------------------------------------------------------------------------- 1 | from math import radians 2 | 3 | from OpenGL.GL import * 4 | from OpenGL.GLU import * 5 | 6 | import pygame 7 | from pygame.locals import * 8 | 9 | SCREEN_SIZE = (800, 600) 10 | 11 | def resize(width, height): 12 | 13 | glViewport(0, 0, width, height) 14 | glMatrixMode(GL_PROJECTION) 15 | glLoadIdentity() 16 | gluPerspective(60.0, float(width)/height, .1, 1000.) 17 | glMatrixMode(GL_MODELVIEW) 18 | glLoadIdentity() 19 | 20 | def init(): 21 | 22 | glEnable(GL_TEXTURE_2D) 23 | glClearColor(1.0, 1.0, 1.0, 0.0) 24 | 25 | def run(): 26 | 27 | pygame.init() 28 | screen = pygame.display.set_mode(SCREEN_SIZE, HWSURFACE|OPENGL|DOUBLEBUF) 29 | 30 | resize(*SCREEN_SIZE) 31 | init() 32 | 33 | # Load the textures 34 | texture_surface = pygame.image.load("sushitex.png") 35 | # Retrieve the texture data 36 | texture_data = pygame.image.tostring(texture_surface, 'RGB', True) 37 | 38 | # Generate a texture id 39 | texture_id = glGenTextures(1) 40 | # Tell OpenGL we will be using this texture id for texture operations 41 | glBindTexture(GL_TEXTURE_2D, texture_id) 42 | 43 | # Tell OpenGL how to scale images 44 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ) 45 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ) 46 | 47 | # Tell OpenGL that data is aligned to byte boundries 48 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1) 49 | 50 | # Get the dimensions of the image 51 | width, height = texture_surface.get_rect().size 52 | 53 | # Upload the image to OpenGL 54 | glTexImage2D( GL_TEXTURE_2D, 55 | 0, 56 | 3, 57 | width, 58 | height, 59 | 0, 60 | GL_RGB, 61 | GL_UNSIGNED_BYTE, 62 | texture_data) 63 | 64 | 65 | clock = pygame.time.Clock() 66 | 67 | tex_rotation = 0.0 68 | 69 | while True: 70 | 71 | for event in pygame.event.get(): 72 | if event.type == QUIT: 73 | pygame.quit() 74 | quit() 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 | -------------------------------------------------------------------------------- /9781484209714_Chapter_11/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 | pygame.quit() 78 | quit() 79 | 80 | 81 | time_passed = clock.tick() 82 | time_passed_seconds = time_passed / 1000. 83 | tex_rotation += time_passed_seconds * 360.0 / 8.0 84 | 85 | 86 | # Clear the screen (similar to fill) 87 | glClear(GL_COLOR_BUFFER_BIT) 88 | 89 | # Clear the model-view matrix 90 | glLoadIdentity() 91 | 92 | # Set the modelview matrix 93 | glTranslatef(0.0, 0.0, -600.0) 94 | glRotate(tex_rotation, 1, 0, 0) 95 | 96 | # Draw a quad (4 vertices, 4 texture coords) 97 | glBegin(GL_QUADS) 98 | 99 | glTexCoord2f(0, 3) 100 | glVertex3f(-300, 300, 0) 101 | 102 | glTexCoord2f(3, 3) 103 | glVertex3f(300, 300, 0) 104 | 105 | glTexCoord2f(3, 0) 106 | glVertex3f(300, -300, 0) 107 | 108 | glTexCoord2f(0, 0) 109 | glVertex3f(-300, -300, 0) 110 | 111 | glEnd() 112 | 113 | pygame.display.flip() 114 | 115 | glDeleteTextures(texture_id) 116 | 117 | if __name__ == "__main__": 118 | run() 119 | -------------------------------------------------------------------------------- /9781484209714_Chapter_11/sushitex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_11/sushitex.png -------------------------------------------------------------------------------- /9781484209714_Chapter_11/tankdemo.py: -------------------------------------------------------------------------------- 1 | from math import radians 2 | 3 | from OpenGL.GL import * 4 | from OpenGL.GLU import * 5 | 6 | import pygame 7 | from pygame.locals import * 8 | 9 | # Import the Model3D class 10 | import model3d 11 | 12 | SCREEN_SIZE = (800, 600) 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 | pygame.quit() 73 | quit() 74 | 75 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 76 | 77 | time_passed = clock.tick() 78 | time_passed_seconds = time_passed / 1000.0 79 | 80 | glLoadIdentity() 81 | glRotatef(15, 1, 0, 0) 82 | glTranslatef(0.0, -1.5, -3.5) 83 | 84 | rotation += time_passed_seconds * 45.0 85 | glRotatef(rotation, 0, 1, 0) 86 | 87 | tank_model.draw_quick() 88 | 89 | pygame.display.flip() 90 | 91 | 92 | if __name__ == "__main__": 93 | run() 94 | -------------------------------------------------------------------------------- /9781484209714_Chapter_12/12-1.py: -------------------------------------------------------------------------------- 1 | def get_attenuation(distance, constant, linear, quadratic): 2 | return 1.0 / (constant + linear * distance + quadratic * (distance ** 2)) 3 | -------------------------------------------------------------------------------- /9781484209714_Chapter_12/12-2.py: -------------------------------------------------------------------------------- 1 | def alpha_blend(src, dst): 2 | return src * src.a + dst * (1.0—src.a) 3 | -------------------------------------------------------------------------------- /9781484209714_Chapter_12/12-3.py: -------------------------------------------------------------------------------- 1 | def additive_blend(src, dst): 2 | return src * src.a + dst 3 | -------------------------------------------------------------------------------- /9781484209714_Chapter_12/12-4.py: -------------------------------------------------------------------------------- 1 | def subtractive_blend(src, dst): 2 | return dst—src * src.a 3 | -------------------------------------------------------------------------------- /9781484209714_Chapter_12/12-5.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | from OpenGL.GLU import * 3 | 4 | import pygame 5 | from pygame.locals import * 6 | 7 | SCREEN_SIZE = (800, 600) 8 | 9 | def resize(width, height): 10 | 11 | glViewport(0, 0, width, height) 12 | glMatrixMode(GL_PROJECTION) 13 | glLoadIdentity() 14 | gluPerspective(45.0, float(width)/height, .1, 1000.) 15 | glMatrixMode(GL_MODELVIEW) 16 | glLoadIdentity() 17 | 18 | 19 | def init(): 20 | 21 | glEnable(GL_TEXTURE_2D) 22 | glEnable(GL_BLEND) 23 | glClearColor(1.0, 1.0, 1.0, 0.0) 24 | 25 | 26 | def upload_texture(filename, use_alpha=False): 27 | 28 | # Read an image file and upload a texture 29 | if use_alpha: 30 | format, gl_format, bits_per_pixel = 'RGBA', GL_RGBA, 4 31 | else: 32 | format, gl_format, bits_per_pixel = 'RGB', GL_RGB, 3 33 | 34 | img_surface = pygame.image.load(filename) 35 | 36 | #img_surface = premul_surface(img_surface) 37 | 38 | data = pygame.image.tostring(img_surface, format, True) 39 | 40 | texture_id = glGenTextures(1) 41 | 42 | glBindTexture(GL_TEXTURE_2D, texture_id) 43 | 44 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ) 45 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ) 46 | 47 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1) 48 | 49 | width, height = img_surface.get_rect().size 50 | 51 | glTexImage2D( GL_TEXTURE_2D, 52 | 0, 53 | bits_per_pixel, 54 | width, 55 | height, 56 | 0, 57 | gl_format, 58 | GL_UNSIGNED_BYTE, 59 | data ) 60 | 61 | # Return the texture id, so we can use glBindTexture 62 | return texture_id 63 | 64 | 65 | def draw_quad(x, y, z, w, h): 66 | 67 | # Send four vertices to draw a quad 68 | glBegin(GL_QUADS) 69 | 70 | glTexCoord2f(0, 0) 71 | glVertex3f(x-w/2, y-h/2, z) 72 | 73 | glTexCoord2f(1, 0) 74 | glVertex3f(x+w/2, y-h/2, z) 75 | 76 | glTexCoord2f(1, 1) 77 | glVertex3f(x+w/2, y+h/2, z) 78 | 79 | glTexCoord2f(0, 1) 80 | glVertex3f(x-w/2, y+h/2, z) 81 | 82 | glEnd() 83 | 84 | 85 | def run(): 86 | 87 | pygame.init() 88 | screen = pygame.display.set_mode(SCREEN_SIZE, HWSURFACE|OPENGL|DOUBLEBUF) 89 | 90 | resize(*SCREEN_SIZE) 91 | init() 92 | 93 | # Upload the background and fugu texture 94 | background_tex = upload_texture('background.png') 95 | fugu_tex = upload_texture('fugu.png', True) 96 | 97 | while True: 98 | 99 | for event in pygame.event.get(): 100 | if event.type == QUIT: 101 | pygame.quit() 102 | quit() 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 | -------------------------------------------------------------------------------- /9781484209714_Chapter_12/12-6.py: -------------------------------------------------------------------------------- 1 | from math import radians 2 | 3 | from OpenGL.GL import * 4 | from OpenGL.GLU import * 5 | 6 | import pygame 7 | from pygame.locals import * 8 | 9 | # Import the Model3D class 10 | import model3d 11 | 12 | SCREEN_SIZE = (800, 600) 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.values(): 52 | 53 | glBindTexture(GL_TEXTURE_2D, material.texture_id) 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 | pygame.quit() 70 | quit() 71 | if event.type == KEYDOWN: 72 | pygame.quit() 73 | quit() 74 | 75 | # We don't need to clear the color buffer (GL_COLOR_BUFFER_BIT) 76 | # because the skybox covers the entire screen 77 | glClear(GL_DEPTH_BUFFER_BIT) 78 | 79 | glLoadIdentity() 80 | 81 | mouse_rel_x, mouse_rel_y = pygame.mouse.get_rel() 82 | mouse_x += float(mouse_rel_x) / 5.0 83 | mouse_y += float(mouse_rel_y) / 5.0 84 | 85 | # Rotate around the x and y axes to create a mouse-look camera 86 | glRotatef(mouse_y, 1, 0, 0) 87 | glRotatef(mouse_x, 0, 1, 0) 88 | 89 | # Disable lighting and depth test 90 | glDisable(GL_LIGHTING) 91 | glDepthMask(False) 92 | 93 | # Draw the skybox 94 | sky_box.draw_quick() 95 | 96 | # Re-enable lighting and depth test before we redraw the world 97 | glEnable(GL_LIGHTING) 98 | glDepthMask(True) 99 | 100 | # Here is where we would draw the rest of the world in a game 101 | 102 | pygame.display.flip() 103 | 104 | if __name__ == "__main__": 105 | run() 106 | 107 | 108 | -------------------------------------------------------------------------------- /9781484209714_Chapter_12/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_12/background.png -------------------------------------------------------------------------------- /9781484209714_Chapter_12/blenddemo.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | from OpenGL.GLU import * 3 | 4 | import pygame 5 | from pygame.locals import * 6 | 7 | SCREEN_SIZE = (800, 600) 8 | 9 | def resize(width, height): 10 | 11 | glViewport(0, 0, width, height) 12 | glMatrixMode(GL_PROJECTION) 13 | glLoadIdentity() 14 | gluPerspective(45.0, float(width)/height, .1, 1000.) 15 | glMatrixMode(GL_MODELVIEW) 16 | glLoadIdentity() 17 | 18 | 19 | def init(): 20 | 21 | glEnable(GL_TEXTURE_2D) 22 | glEnable(GL_BLEND) 23 | glClearColor(1.0, 1.0, 1.0, 0.0) 24 | 25 | 26 | def upload_texture(filename, use_alpha=False): 27 | 28 | # Read an image file and upload a texture 29 | if use_alpha: 30 | format, gl_format, bits_per_pixel = 'RGBA', GL_RGBA, 4 31 | else: 32 | format, gl_format, bits_per_pixel = 'RGB', GL_RGB, 3 33 | 34 | img_surface = pygame.image.load(filename) 35 | 36 | #img_surface = premul_surface(img_surface) 37 | 38 | data = pygame.image.tostring(img_surface, format, True) 39 | 40 | texture_id = glGenTextures(1) 41 | 42 | glBindTexture(GL_TEXTURE_2D, texture_id) 43 | 44 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ) 45 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ) 46 | 47 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1) 48 | 49 | width, height = img_surface.get_rect().size 50 | 51 | glTexImage2D( GL_TEXTURE_2D, 52 | 0, 53 | bits_per_pixel, 54 | width, 55 | height, 56 | 0, 57 | gl_format, 58 | GL_UNSIGNED_BYTE, 59 | data ) 60 | 61 | # Return the texture id, so we can use glBindTexture 62 | return texture_id 63 | 64 | 65 | def draw_quad(x, y, z, w, h): 66 | 67 | # Send four vertices to draw a quad 68 | glBegin(GL_QUADS) 69 | 70 | glTexCoord2f(0, 0) 71 | glVertex3f(x-w/2, y-h/2, z) 72 | 73 | glTexCoord2f(1, 0) 74 | glVertex3f(x+w/2, y-h/2, z) 75 | 76 | glTexCoord2f(1, 1) 77 | glVertex3f(x+w/2, y+h/2, z) 78 | 79 | glTexCoord2f(0, 1) 80 | glVertex3f(x-w/2, y+h/2, z) 81 | 82 | glEnd() 83 | 84 | 85 | def run(): 86 | 87 | pygame.init() 88 | screen = pygame.display.set_mode(SCREEN_SIZE, HWSURFACE|OPENGL|DOUBLEBUF) 89 | 90 | resize(*SCREEN_SIZE) 91 | init() 92 | 93 | # Upload the background and fugu texture 94 | background_tex = upload_texture('background.png') 95 | fugu_tex = upload_texture('fugu.png', True) 96 | 97 | while True: 98 | 99 | for event in pygame.event.get(): 100 | if event.type == QUIT: 101 | pygame.quit() 102 | quit() 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 | -------------------------------------------------------------------------------- /9781484209714_Chapter_12/bodytex.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_12/bodytex.jpg -------------------------------------------------------------------------------- /9781484209714_Chapter_12/booktex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_12/booktex.png -------------------------------------------------------------------------------- /9781484209714_Chapter_12/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 | pygame.quit() 87 | quit() 88 | 89 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 90 | 91 | time_passed = clock.tick() 92 | time_passed_seconds = time_passed / 1000.0 93 | 94 | 95 | 96 | glLoadIdentity() 97 | glRotatef(15, 1, 0, 0) 98 | 99 | tank_distance = pygame.mouse.get_pos()[1] / 50.0 100 | glTranslatef(0.0, -1.5, -tank_distance) 101 | 102 | #glTranslatef(0.0, -1.5, -3.5) 103 | 104 | rotation += time_passed_seconds * 45.0 105 | glRotatef(rotation, 0, 1, 0) 106 | 107 | tank_model.draw_quick() 108 | 109 | pygame.display.flip() 110 | 111 | 112 | if __name__ == "__main__": 113 | run() 114 | -------------------------------------------------------------------------------- /9781484209714_Chapter_12/fugu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_12/fugu.png -------------------------------------------------------------------------------- /9781484209714_Chapter_12/gameobjects/__pycache__/matrix44.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_12/gameobjects/__pycache__/matrix44.cpython-34.pyc -------------------------------------------------------------------------------- /9781484209714_Chapter_12/gameobjects/__pycache__/util.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_12/gameobjects/__pycache__/util.cpython-34.pyc -------------------------------------------------------------------------------- /9781484209714_Chapter_12/gameobjects/__pycache__/vector2.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_12/gameobjects/__pycache__/vector2.cpython-34.pyc -------------------------------------------------------------------------------- /9781484209714_Chapter_12/gameobjects/__pycache__/vector3.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_12/gameobjects/__pycache__/vector3.cpython-34.pyc -------------------------------------------------------------------------------- /9781484209714_Chapter_12/gameobjects/util.py: -------------------------------------------------------------------------------- 1 | from math import * 2 | 3 | def format_number(n, accuracy=6): 4 | """Formats a number in a friendly manner 5 | (removes trailing zeros and unneccesary point.""" 6 | 7 | fs = "%."+str(accuracy)+"f" 8 | str_n = fs%float(n) 9 | if '.' in str_n: 10 | str_n = str_n.rstrip('0').rstrip('.') 11 | if str_n == "-0": 12 | str_n = "0" 13 | #str_n = str_n.replace("-0", "0") 14 | return str_n 15 | 16 | 17 | def lerp(a, b, i): 18 | """Linear enterpolate from a to b.""" 19 | return a+(b-a)*i 20 | 21 | 22 | def range2d(range_x, range_y): 23 | 24 | """Creates a 2D range.""" 25 | 26 | range_x = list(range_x) 27 | return [ (x, y) for y in range_y for x in range_x ] 28 | 29 | 30 | def xrange2d(range_x, range_y): 31 | 32 | """Iterates over a 2D range.""" 33 | 34 | range_x = list(range_x) 35 | for y in range_y: 36 | for x in range_x: 37 | yield (x, y) 38 | 39 | 40 | def saturate(value, low, high): 41 | return min(max(value, low), high) 42 | 43 | 44 | def is_power_of_2(n): 45 | """Returns True if a value is a power of 2.""" 46 | return log(n, 2) % 1.0 == 0.0 47 | 48 | 49 | def next_power_of_2(n): 50 | """Returns the next power of 2 that is >= n""" 51 | return int(2 ** ceil(log(n, 2))) 52 | 53 | if __name__ == "__main__": 54 | 55 | print(list( xrange2d(range(3), range(3)) )) 56 | print(range2d(range(3), range(3))) 57 | print(is_power_of_2(7)) 58 | print(is_power_of_2(8)) 59 | print(is_power_of_2(9)) 60 | 61 | print(next_power_of_2(7)) 62 | -------------------------------------------------------------------------------- /9781484209714_Chapter_12/heavyfogtank.py.py: -------------------------------------------------------------------------------- 1 | from math import radians 2 | 3 | from OpenGL.GL import * 4 | from OpenGL.GLU import * 5 | 6 | import pygame 7 | from pygame.locals import * 8 | 9 | # Import the Model3D class 10 | import model3d 11 | 12 | SCREEN_SIZE = (800, 600) 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 | glEnable(GL_FOG) 26 | glFogfv(GL_FOG_COLOR, (1.0, 1.0, 1.0)) 27 | glFogi(GL_FOG_MODE, GL_LINEAR) 28 | glFogf(GL_FOG_START, 1.5) 29 | glFogf(GL_FOG_END, 3.5) 30 | 31 | # Enable the GL features we will be using 32 | glEnable(GL_DEPTH_TEST) 33 | glEnable(GL_LIGHTING) 34 | glEnable(GL_COLOR_MATERIAL) 35 | glEnable(GL_TEXTURE_2D) 36 | glEnable(GL_CULL_FACE) 37 | 38 | glShadeModel(GL_SMOOTH) 39 | glClearColor(1.0, 1.0, 1.0, 0.0) # white 40 | 41 | # Set the material 42 | glMaterial(GL_FRONT, GL_AMBIENT, (0.0, 0.0, 0.0, 1.0)) 43 | glMaterial(GL_FRONT, GL_DIFFUSE, (0.2, 0.2, 0.2, 1.0)) 44 | glMaterial(GL_FRONT, GL_SPECULAR, (1.0, 1.0, 1.0, 1.0)) 45 | glMaterial(GL_FRONT, GL_SHININESS, 10.0) 46 | 47 | # Set light parameters 48 | glLight(GL_LIGHT0, GL_AMBIENT, (0.0, 0.0, 0.0, 1.0)) 49 | glLight(GL_LIGHT0, GL_DIFFUSE, (0.4, 0.4, 0.4, 1.0)) 50 | glLight(GL_LIGHT0, GL_SPECULAR, (1.0, 1.0, 1.0, 1.0)) 51 | 52 | # Enable light 1 and set position 53 | glEnable(GL_LIGHT0) 54 | glLight(GL_LIGHT0, GL_POSITION, (0, .5, 1, 0)) 55 | 56 | 57 | def run(): 58 | 59 | pygame.init() 60 | screen = pygame.display.set_mode(SCREEN_SIZE, HWSURFACE|OPENGL|DOUBLEBUF) 61 | 62 | resize(*SCREEN_SIZE) 63 | init() 64 | 65 | clock = pygame.time.Clock() 66 | 67 | # Read the model 68 | tank_model = model3d.Model3D() 69 | tank_model.read_obj('mytank.obj') 70 | 71 | rotation = 0.0 72 | 73 | while True: 74 | 75 | for event in pygame.event.get(): 76 | if event.type == QUIT: 77 | pygame.quit() 78 | quit() 79 | 80 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 81 | 82 | time_passed = clock.tick() 83 | time_passed_seconds = time_passed / 1000.0 84 | 85 | glLoadIdentity() 86 | glRotatef(15, 1, 0, 0) 87 | glTranslatef(0.0, -1.5, -3.5) 88 | 89 | rotation += time_passed_seconds * 45.0 90 | glRotatef(rotation, 0, 1, 0) 91 | 92 | tank_model.draw_quick() 93 | 94 | pygame.display.flip() 95 | 96 | 97 | if __name__ == "__main__": 98 | run() 99 | -------------------------------------------------------------------------------- /9781484209714_Chapter_12/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.values(): 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 = open(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.values(): 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 = open(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 | -------------------------------------------------------------------------------- /9781484209714_Chapter_12/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 | -------------------------------------------------------------------------------- /9781484209714_Chapter_12/mytanktex.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_12/mytanktex.jpg -------------------------------------------------------------------------------- /9781484209714_Chapter_12/skybox.py: -------------------------------------------------------------------------------- 1 | from math import radians 2 | 3 | from OpenGL.GL import * 4 | from OpenGL.GLU import * 5 | 6 | import pygame 7 | from pygame.locals import * 8 | 9 | # Import the Model3D class 10 | import model3d 11 | 12 | SCREEN_SIZE = (800, 600) 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.values(): 52 | 53 | glBindTexture(GL_TEXTURE_2D, material.texture_id) 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 | pygame.quit() 70 | quit() 71 | if event.type == KEYDOWN: 72 | pygame.quit() 73 | quit() 74 | 75 | # We don't need to clear the color buffer (GL_COLOR_BUFFER_BIT) 76 | # because the skybox covers the entire screen 77 | glClear(GL_DEPTH_BUFFER_BIT) 78 | 79 | glLoadIdentity() 80 | 81 | mouse_rel_x, mouse_rel_y = pygame.mouse.get_rel() 82 | mouse_x += float(mouse_rel_x) / 5.0 83 | mouse_y += float(mouse_rel_y) / 5.0 84 | 85 | # Rotate around the x and y axes to create a mouse-look camera 86 | glRotatef(mouse_y, 1, 0, 0) 87 | glRotatef(mouse_x, 0, 1, 0) 88 | 89 | # Disable lighting and depth test 90 | glDisable(GL_LIGHTING) 91 | glDepthMask(False) 92 | 93 | # Draw the skybox 94 | sky_box.draw_quick() 95 | 96 | # Re-enable lighting and depth test before we redraw the world 97 | glEnable(GL_LIGHTING) 98 | glDepthMask(True) 99 | 100 | # Here is where we would draw the rest of the world in a game 101 | 102 | pygame.display.flip() 103 | 104 | if __name__ == "__main__": 105 | run() 106 | 107 | 108 | -------------------------------------------------------------------------------- /9781484209714_Chapter_12/tanksky/bk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_12/tanksky/bk.png -------------------------------------------------------------------------------- /9781484209714_Chapter_12/tanksky/dn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_12/tanksky/dn.png -------------------------------------------------------------------------------- /9781484209714_Chapter_12/tanksky/ft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_12/tanksky/ft.png -------------------------------------------------------------------------------- /9781484209714_Chapter_12/tanksky/lt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_12/tanksky/lt.png -------------------------------------------------------------------------------- /9781484209714_Chapter_12/tanksky/rt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_12/tanksky/rt.png -------------------------------------------------------------------------------- /9781484209714_Chapter_12/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 | -------------------------------------------------------------------------------- /9781484209714_Chapter_12/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 | -------------------------------------------------------------------------------- /9781484209714_Chapter_12/tanksky/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/9781484209714_Chapter_12/tanksky/up.png -------------------------------------------------------------------------------- /Errata for Beginning Python Games.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/Errata for Beginning Python Games.pdf -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/beg-python-games-dev-2ed/d965fc06e1d2a49c623cd31de4d1a9228d37cbf3/LICENSE.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Apress Source Code 2 | 3 | This repository accompanies [*Beginning Python Games Development, Second Edition*](http://www.apress.com/9781484209714) by Will McGugan and Harrison Kinsley (Apress, 2015). 4 | 5 | ![Cover image](9781484209714.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 | -------------------------------------------------------------------------------- /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! --------------------------------------------------------------------------------