class StateManager(object): def __init__(self): self.quit = False self._init_window() self._init_game() self.mode = "SPLASH" # Prevent bouncing on switching game modes self.debounce_timer = DEBOUNCE # Create a window for the game def _init_window(self): # Window object represents the game's window self.window = pyglet.window.Window(WIDTH, HEIGHT) # Keys holds a handler that keeps track of keyboard state, part of pyglet self.keys = pyglet.window.key.KeyStateHandler() self.window.push_handlers(self.keys) # Stage the game or return it to its initial state def _init_game(self): self.hud = HUD() self.entities = [] self.spawn_player() self.exhaust = ParticleSpawner( self.player.pos.getCopy(), self.player.angle + math.pi, math.pi / 4, .01, ParticleFactory(speed=20, color=(255, 0, 0)), True) self.entities.append(self.exhaust) #Create a new instance of the Player class at the center of the screen def spawn_player(self): self.player = Player(Vect2(x=self.window.width/2, y=self.window.height/2)) self.entities.append(self.player) # This function runs when the look is in game mode, and has all the updating/drawing logic def game_loop(self, dt): #Clear frame before looping self.window.clear() #print(pyglet.gl.get_current_context()) # On a proper engine the controller would probably be its own class. # That level of abstraction makes it easier to use keyboards, mice, and # other controllers the user may have controller = { 'acc': self.keys[key.W], 'left': self.keys[key.A], 'right': self.keys[key.D], 'fire': self.keys[key.SPACE], 'quit': self.keys[key.ESCAPE], 'pause': self.keys[key.P] } self.quit = controller['quit'] if controller['pause'] and self.debounce_timer <= 0: self.mode = "PAUSE" self.debounce_timer = DEBOUNCE self.player.input(controller) #turn on thrust effect if ship is accelerating self.exhaust.active = controller['acc'] self.exhaust.angle = (self.player.angle + math.pi) self.exhaust.pos = self.player.pos.getCopy() self.spawn_bullets() self.spawn_asteroids() self.detect_collisions() for e in self.entities: e.update(dt) #for e in self.entities: # print(e) batch = pyglet.graphics.Batch() for e in self.entities: # batch.add expects a series of arguments # most easily delivered as a tuple. # * is the untuple argument. batch.add(*e.draw()) # Filter out any dead objects self.entities[:] = [e for e in self.entities if e.isAlive()] # Draw objects to the frame batch.draw() self.hud.drawHUD() # Determine if a bullet should be spawned, and then spawns a bullet def spawn_bullets(self): if self.player.isFiring(): self.entities.append( Bullet( self.player.pos.getCopy(), self.player.angle ) ) # Maintain a minimum asteroid population def spawn_asteroids(self): # Asteroid Spawning asteroids = [e for e in self.entities if isinstance(e, Asteroid)] if len(asteroids) < targetNo: newAsteroid = Asteroid(3, Vect2(0, 0)) self.entities.append(newAsteroid) # This function determines if any objects are colliding in a meaningful way for the game def detect_collisions(self): asteroids = [e for e in self.entities if isinstance(e, Asteroid)] for asteroid in asteroids: if self.player.overlaps(asteroid.hit_radius, asteroid.pos.getCopy()): self.player.kill() # Check if player is actually dead, it may be in invuln # period if (self.player.isAlive() != True): if (self.hud.has_lives()): self.spawn_player() self.hud.kill() else: self.mode = "GAMEOVER" # Process asteroid/bullet collisions for bullet in [e for e in self.entities if isinstance(e, Bullet)]: for asteroid in asteroids: if bullet.overlaps( asteroid.hit_radius, asteroid.pos.getCopy()): asteroid.kill() self.entities.append( AsteroidDebris( asteroid.pos.getCopy())) if asteroid.size > 1: # add two baby asteroids! self.entities.append( Asteroid( asteroid.size - 1, asteroid.pos.getCopy())) self.entities.append( Asteroid( asteroid.size - 1, asteroid.pos.getCopy())) # Remove bullet bullet.kill() # Log the points self.hud.hit() # Inform the main function if the player requested to quit def is_quit(self): return self.quit # Dispatch loop to the right function def loop(self, dt): if self.debounce_timer > 0: self.debounce_timer -= dt if self.mode == "GAME": self.game_loop(dt) elif self.mode == "PAUSE": self.pause_loop(dt) elif self.mode == "SPLASH": self.splash_loop(dt) elif self.mode == "GAMEOVER": self.game_over_loop(dt) else: self.quit == True print("Error: Debug: state.mode == Invalid state!") # Pause screen def pause_loop(self, dt): self.window.clear() label = pyglet.text.Label("Game Paused: Press p to unpause, or ESC to quit", font_size=24, x=WIDTH//2, y=HEIGHT//2, anchor_x = 'center', anchor_y = 'center') label.draw() if self.keys[key.P] and self.debounce_timer <= 0: self.mode = "GAME" self.debounce_timer = DEBOUNCE elif self.keys[key.ESCAPE]: self.quit = True # Splash screen def splash_loop(self, dt): label = pyglet.text.Label("Rocks in Space: Press s to start", font_size=38, x=WIDTH//2, y=HEIGHT//2, anchor_x = 'center', anchor_y = 'center') label.draw() if self.keys[key.S]: self.mode = "GAME" elif self.keys[key.ESCAPE]: self.quit = True # Game over screen def game_over_loop(self, dt): self.window.clear() label = pyglet.text.Label("Game over! Press S to restart, or ESC to quit", font_size=24, x=WIDTH//2, y=HEIGHT//2, anchor_x = 'center', anchor_y = 'center') label.draw() if self.keys[key.S]: self.mode = "GAME" self._init_game() elif self.keys[key.ESCAPE]: self.quit = True