class Scene(object): def __init__(self, screen): """Create the scene's objects.""" self.screen = screen self.running = True # Groups for sprites self.players = Group() self.enemies = Group() self.chars = Group() self.weapons = Group() self.projs = Group() self.all = LayeredDirty() # Room self.room = Room(self) self.all.add(self.room) # Weapons self.weapon_list = [ LaserGun(self), Bow(self) ] for weapon in self.weapon_list: self.weapons.add(weapon) # Players self.player = Player(self) self.players.add(self.player) self.all.add(self.players) # Enemies enemy_list = [ Human, Glork ] for enemy in range(0, randint(50,100)): self.enemies.add(choice(enemy_list)(self)) self.all.add(self.enemies) # Characters self.chars.add([self.players, self.enemies]) # Layers self.all = LayeredDirty([ self.room, self.enemies, self.players, self.weapons, self.projs ]) def draw(self): """Draw all of the objects to the screen.""" # Update all scene layers to the screen. self.all.update() self.dirty_rects = self.all.draw(self.screen) display.update(self.dirty_rects)
class Game(BaseScene): def __init__(self, engine): super().__init__(engine, background_color=(10, 21, 41)) self.render_group = LayeredDirty() self.spawn_objects = [InfiniteObjectManager(self, Chimney, self.groups[config.KEY_CHIMNEY])] self.spawner = Spawner() self.spawn_objects.append(self.spawner) santa = Santa(self, Vector(*self.engine.display.get_rect().center), self.groups[config.KEY_GIFTS], self.groups[config.KEY_SANTA]) self.controller = Controller(actor=santa) channel = resources.sounds["santaclauseiscoming"].play(-1) channel.set_volume(0.1) self.score = 0 self.missed_chimneys = 0 Score(self, lambda: self.score, self.groups[config.KEY_UI]) def render(self): window = display.get_surface() for group in self.groups.values(): self.render_group.add(group.sprites()) for sprite in self.render_group.sprites(): self.render_group.change_layer(sprite, sprite.layer) sprite.pre_draw() return self.render_group.draw(window, self.background) def simulate(self, time_delta: float): self.controller.respond() super().simulate(time_delta) for spawn_object in self.spawn_objects: spawn_object.resolve(time_delta) collisions = groupcollide(self.groups[config.KEY_CHIMNEY], self.groups[config.KEY_GIFTS], False, False) successes = 0 for chimney, gifts in collisions.items(): for gift in gifts: if chimney.rect.left < gift.position.x < chimney.rect.right: successes += 1 gift.kill() chimney.delivered = True if successes: self.score += config.POINTS_GIFT_DELIVERED * successes logging.debug(f"{successes} Successes!") if self.missed_chimneys >= config.LIMIT_CHIMNEYS_MISSED: self.running = False
class Scene: ''' Describe a Scene in a game. This is a base class for every scene in the game, has a main_loop that can be called from the main process and the functions start and update to controll the first and sucesives ticks respectively. ''' def __init__(self, screen: Surface): ''' Constructor of the class, takes the screen to gain control over the render of the game objects ''' # Get display info info = Info() # Get Clock to ensure frame rating self.clock = Clock() # The default return value of the Scene self.return_value = -1 # Set the continue condition self.running = True # Get the relevant information from info self.screen_h, self.screen_w = info.current_h, info.current_w # Set the screen of the Scene self.screen: Surface = screen # Main Sprite groups self.event_group = Group() self.update_group = Group() self.render_group = LayeredDirty() def start(self): ''' This function will is the first function called when the scene starts running, here you can configure the position and starting behaviour of your scene ''' pass def update(self): ''' This function will be called every tick of the game and needs to be overrided in every scene to fill the desired behaviour ''' pass def clear(self): ''' This function will be called on the end of the scene to clean any configuration or variables to the next scene. It will raise NotImplementedError if it's not implemented, at least needs a pass function if no work is needed ''' raise NotImplementedError def exit(self, return_value): ''' This function will end the scene and return the value to the parent ''' self.running = False self.return_value = return_value self.event_group.empty() self.update_group.empty() self.render_group.empty() self.clear() def main_loop(self): ''' This is the main loop of the scene, don't overrive if not necesary. Here you will find the main workflow for an scene ''' # Ensures the starts conditions self.running = True self.return_value = -1 # Calls the start function, to configurate the scene self.start() # Main loop of the scene while self.running: # Event catch # Set the event queue of the objet itself self.events = [] for e in event.get(): self.events.append(e) for s in self.event_group.sprites(): s.add_event(e) if e.type == QUIT: self.exit(-1) # Group update self.update_group.update(self.clock.get_time()) # Calls the update function for every tick of the game self.update() # Render group self.render_group.draw(self.screen) display.flip() # Ensure frame rate if DEBUG: print(self.clock.get_fps()) self.clock.tick(60) return self.return_value
class CatUniScene(Scene): def __init__(self, *args, **kwargs): Scene.__init__(self, *args, **kwargs) (width, height) = (1920//2, 1080//2) self.width, self.height = width, height # Loading screen should always be a fallback active scene self.active = False self.first_render = True self.myfont = pygame.font.SysFont("monospace", 20) self.background = gfx('background.png').convert() # self.cat_unicycle = gfx('cat_unicycle.png').convert_alpha() # self.fish = gfx('fish.png').convert_alpha() # self.foot = gfx('foot.png').convert_alpha() # self.foot_part = gfx('foot_part.png').convert_alpha() # self.shark = gfx('shark.png').convert_alpha() sfx('cat_jump.ogg') sfx('eatfish.ogg') #cat variables self.cat_wire_height = height - 100 self.cat_location = [width / 2, height - 100] self.cat_speed = [0, 0] self.cat_speed_max = 8 self.cat_fall_speed_max = 16 self.cat_angle = 0 self.cat_angular_vel = 0 self.cat_head_location = [ int(self.cat_location[0] + 100 * math.cos(self.cat_angle - math.pi / 2)), int(self.cat_location[1] + 100 * math.sin(self.cat_angle - math.pi / 2)), ] self.left_pressed = False self.right_pressed = False self.score = 0 #timing self.dt_scaled = 0 self.total_time = 0 #elephant and shark classes self.elephant = Elephant(self) self.shark_active = False #is the shark enabled yet self.elephant_active = False self.cat = Cat(self) self.score_text = Score(self) self.deadzones = [] # self.deadzones = [ # DeadZone( # [ # [0, height - 100], # [0.1 * width, height - 100], # [0.1 * width, height], # [0, height], # ], # ), # DeadZone( # [ # [0.9 * width, height - 100], # [width, height - 100], # [width, height], # [0.9 * width, height], # ], # ), # ] self.init_sprites() # lists of things to catch by [posx, posy, velx, vely] # self.fish = [[0, height / 2, 10, -5]] self.fish = LayeredDirtyAppend() self.fish.extend([Fish(self.allsprites, 0, height / 2, 10, -5)]) self.not_fish = LayeredDirtyAppend() #difficulty varibles self.number_of_not_fish = 0 def init_sprites(self): """temp, this will go in the init. """ sprite_list = [ self.elephant, self.cat, self.score_text ] sprite_list += self.deadzones self.allsprites = LayeredDirty( sprite_list, _time_threshold=1000/10.0 ) scene = self self.shark = Shark(self.allsprites, scene, self.width, self.height) self.allsprites.add(self.shark) self.allsprites.clear(self.screen, self.background) #what to do when you die, reset the level def reset_on_death(self): self.cat_location = [self.width / 2, self.height - 100] self.cat_speed = [0, 0] self.cat_angle = 0 self.cat_angular_vel = 0 self.score = 0 self.total_time = 0 self.elephant.last_animation = 0 self.elephant.state = 0 self.elephant.just_happened = None self.elephant.dirty = 1 self.elephant_active = False self.shark.last_animation = 0 self.shark.state = 0 self.shark_active = False self.shark.just_happened = None self.shark.dirty = 1 if hasattr(self.shark, 'lazer'): self.shark.lazer.kill() #periodically increase the difficulty def increase_difficulty(self): self.number_of_not_fish = 0 if self.score > 3: self.number_of_not_fish = 1 if self.score > 9: self.number_of_not_fish = 1 if self.score > 15: self.number_of_not_fish = 2 if self.score > 19: self.number_of_not_fish = 1 if self.score > 25: self.number_of_not_fish = 2 if self.score > 35: self.number_of_not_fish = 3 if self.score >= 50: self.number_of_not_fish = int((self.score - 20)/10) #TODO: to make it easier to test. # if self.score >= 15: # self.shark_active = True if self.score >= 10: self.shark_active = True #TODO: to make it easier to test. if self.score >= 20: self.elephant_active = True def render_sprites(self): rects = [] self.allsprites.update() rects.extend(self.allsprites.draw(self.screen)) return rects def render(self): rects = [] if self.first_render: self.first_render = False rects.append(self.screen.get_rect()) rects.extend(self.render_sprites()) return rects # we draw the sprites, and then the lines over the top. self.render_sprites() screen = self.screen width, height = self.width, self.height if 0: background_colour = (0, 0, 0) screen.fill(background_colour) screen.blit(self.background, (0, 0)) self.elephant.render(screen, width, height) self.shark.render(screen, width, height) # draw cat pygame.draw.line( screen, [0, 0, 255], self.cat_location, self.cat_head_location, 20 ) pygame.draw.circle(screen, [0, 0, 255], self.cat_head_location, 50, 1) pygame.draw.circle(screen, [0, 255, 0], self.cat_head_location, 100, 1) # draw dead zones pygame.draw.polygon( screen, [255, 0, 0], [ [0, height - 100], [0.1 * width, height - 100], [0.1 * width, height], [0, height], ], ) pygame.draw.polygon( screen, [255, 0, 0], [ [0.9 * width, height - 100], [width, height - 100], [width, height], [0.9 * width, height], ], ) # draw fish and not fish for f in self.fish: pygame.draw.circle(screen, [0, 255, 0], [int(f.pos[0]), int(f.pos[1])], 10) for f in self.not_fish: pygame.draw.circle(screen, [255, 0, 0], [int(f.pos[0]), int(f.pos[1])], 10) # draw score textsurface = self.myfont.render(str(self.score), True, [0, 0, 0] ) screen.blit(textsurface, (200, 300)) return [screen.get_rect()] def tick(self, dt): self.increase_difficulty() self.total_time += dt #keep track of the total number of ms passed during the game dt_scaled = dt/17 self.dt_scaled = dt_scaled width, height = self.width, self.height ##cat physics self.cat_angular_vel *= 0.9**dt_scaled #max(0.9/(max(0.1,dt_scaled)),0.999) # add gravity self.cat_speed[1] = min(self.cat_speed[1] + (1 * dt_scaled), self.cat_fall_speed_max) # accelerate the cat left or right if self.right_pressed: self.cat_speed[0] = min( self.cat_speed[0] + 0.3 * dt_scaled, self.cat_speed_max ) self.cat_angle -= 0.003 * dt_scaled if self.left_pressed: self.cat_speed[0] = max( self.cat_speed[0] - 0.3 * dt_scaled, -self.cat_speed_max ) self.cat_angle += 0.003 * dt_scaled # make the cat fall angle_sign = 1 if self.cat_angle > 0 else -1 self.cat_angular_vel += 0.0002 * angle_sign * dt_scaled self.cat_angle += self.cat_angular_vel * dt_scaled if (self.cat_angle > math.pi / 2 or self.cat_angle < -math.pi / 2) and self.cat_location[1] > height - 160: self.reset_on_death() # move cat self.cat_location[0] += self.cat_speed[0] * dt_scaled self.cat_location[1] += self.cat_speed[1] * dt_scaled if self.cat_location[1] > self.cat_wire_height and self.cat_location[0] > 0.25 * width: self.cat_location[1] = self.cat_wire_height self.cat_speed[1] = 0 if self.cat_location[1] > height: self.reset_on_death() if self.cat_location[0] > width: self.cat_location[0] = width if self.cat_angle > 0: self.cat_angle *= 0.7 self.cat_head_location = [ int(self.cat_location[0] + 100 * math.cos(self.cat_angle - math.pi / 2)), int(self.cat_location[1] + 100 * math.sin(self.cat_angle - math.pi / 2)), ] # check for out of bounds if self.cat_location[0] > 0.98 * width and self.cat_location[1] > self.cat_wire_height - 30: #bump the cat back in self.cat_angular_vel -= 0.01*dt_scaled self.cat_speed[0] = -5 self.cat_speed[1] = -20 #self.reset_on_death() if self.cat_location[0] < 0.25 * width and self.cat_location[1] > self.cat_wire_height - 30: pass #check for collision with the elephant stomp if self.elephant_active: self.elephant.animate(self.total_time) self.elephant.collide(self, width, height, self.cat_head_location) if self.shark_active: self.shark.animate(self.total_time) self.shark.collide(self, width, height, self.cat_location) ##object physics # move fish and not fish for f in reversed(self.fish.sprites()): f.pos[0] += f.velocity[0] * dt_scaled # speed of the throw f.velocity[1] += 0.2 * dt_scaled # gravity f.pos[1] += f.velocity[1] * dt_scaled # y velocity # check out of bounds if f.pos[1] > height: self.fish.remove(f) f.kill() for f in reversed(self.not_fish.sprites()): f.pos[0] += f.velocity[0] * dt_scaled # speed of the throw f.velocity[1] += 0.2 * dt_scaled # gravity f.pos[1] += f.velocity[1] * dt_scaled # y velocity # check out of bounds if f.pos[1] > height: self.not_fish.remove(f) f.kill() # check collision with the cat for f in reversed(self.fish.sprites()): if distance([f.rect[0], f.rect[1]], self.cat_head_location) < 100: self.score += 1 self.fish.remove(f) sfx('eatfish.ogg', play=1) f.kill() for f in reversed(self.not_fish.sprites()): if distance([f.rect[0], f.rect[1]], self.cat_head_location) < 50: self.not_fish.remove(f) f.kill() self.angle_to_not_fish = ( math.atan2( self.cat_head_location[1] - f.rect[1], self.cat_head_location[0] - f.rect[0], ) - math.pi / 2 ) side = 1 if self.angle_to_not_fish < 0 else -1 self.cat_angular_vel += side * random.uniform(0.08, 0.15) # refresh lists while len(self.fish) < 1: # choose a side of the screen if random.choice([0, 1]) == 0: self.fish.append( Fish(self.allsprites, 0, height/2,#random.randint(0, height / 2), random.randint(3, 7), -random.randint(5, 12), ) ) else: self.fish.append( Fish(self.allsprites, width, height/2,#random.randint(0, height / 2), -random.randint(3, 7), -random.randint(5, 12), ) ) while len(self.not_fish) < self.number_of_not_fish: # choose a side of the screen if random.choice([0, 1]) == 0: self.not_fish.append( NotFish(self.allsprites, 0, height/2,#random.randint(0, height / 2), random.randint(3, 7), -random.randint(5, 12), ) ) else: self.not_fish.append( NotFish(self.allsprites, width, height/2,#random.randint(0, height / 2), -random.randint(3, 7), -random.randint(5, 12), ) ) def event(self, event): width, height = self.width, self.height if event.type == KEYDOWN: if event.key == K_RIGHT: self.right_pressed = True # cat_speed[0] = min(cat_speed[0] + 2, cat_speed_max) # cat_angle -= random.uniform(0.02*math.pi, 0.05*math.pi) elif event.key == K_LEFT: self.left_pressed = True # cat_speed[0] = min(cat_speed[0] - 2, cat_speed_max) # cat_angle += random.uniform(0.02*math.pi, 0.05*math.pi) elif event.key == K_a: self.cat_angular_vel -= random.uniform(0.01 * math.pi, 0.03 * math.pi) elif event.key == K_d: self.cat_angular_vel += random.uniform(0.01 * math.pi, 0.03 * math.pi) elif event.key == K_UP: if self.cat_location[1] > self.cat_wire_height - 1: self.cat_speed[1] -= 25 sfx('cat_jump.ogg', play=1) elif event.type == KEYUP: if event.key == K_UP: if self.cat_speed[1] < 0: self.cat_speed[1] = 0 elif event.key == K_RIGHT: self.right_pressed = False elif event.key == K_LEFT: self.left_pressed = False
class BaseScene(Scene): def __init__(self, engine, *, background_color=(0, 0, 55), container_class=GameObjectCollection, **kwargs): super().__init__(engine) self.background_color = background_color self.background = engine.display.copy() self.background.fill(self.background_color) self.game_objects = container_class() self.render_group = LayeredDirty() def __contains__(self, item: Hashable) -> bool: return item in self.game_objects def render(self): window = self.engine.display self.render_group.add(s for s in self.game_objects) return self.render_group.draw(window, self.background) def simulate(self, time_delta: float): for game_object in self.game_objects: game_object.update(time_delta) def change(self): """ Default case, override in subclass as necessary. """ return self.running, {"scene_class": self.next} def add(self, game_object: Hashable, tags: Iterable = ()) -> None: """ Add a game_object to the scene. game_object: Any GameObject object. The item to be added. tags: An iterable of Hashable objects. Values that can be used to retrieve a group containing the game_object. Examples: scene.add(MyGameObject()) scene.add(MyGameObject(), tags=("red", "blue") """ self.game_objects.add(game_object, tags) def get(self, *, kind: Type = None, tag: Hashable = None, **kwargs) -> Iterator: """ Get an iterator of GameObjects by kind or tag. kind: Any type. Pass to get a subset of contained GameObjects with the given type. tag: Any Hashable object. Pass to get a subset of contained GameObjects with the given tag. Pass both kind and tag to get objects that are both that type and that tag. Examples: scene.get(type=MyGameObject) scene.get(tag="red") scene.get(type=MyGameObject, tag="red") """ return self.game_objects.get(kind=kind, tag=tag, **kwargs) def remove(self, game_object: Hashable) -> None: """ Remove the given object from the scene. game_object: A game object. Example: scene.remove(my_game_object) """ self.game_objects.remove(game_object)
pixel = self.image.get_at((x, y)).r if (pixel > 50): self.image.set_at((x, y), colour) # create sprites bg = PpuiImage("assets/lcars_screen_1.png") button = PpuiImage("assets/button.png") button.applyColour((255, 204, 153)) # add sprites to layer sprites = LayeredDirty() sprites.add(bg) sprites.add(button) # event loop while pygame.display.get_init(): sprites.draw(screenSurface) pygame.display.update() for event in pygame.event.get(): if event.type == KEYUP: pygame.quit() break if (event.type == MOUSEMOTION): # move button around as mouse moves (or touch-drag) button.rect.left = event.pos[0] button.rect.top = event.pos[1] button.dirty = 1
class CatUniScene(Scene): def __init__(self, *args, **kwargs): Scene.__init__(self, *args, **kwargs) (width, height) = (1920 // 2, 1080 // 2) self.width, self.height = width, height # Loading screen should always be a fallback active scene self.active = False self.first_render = True self.myfont = pygame.font.SysFont("monospace", 20) self.background = gfx('background.png', convert=True) # self.cat_unicycle = gfx('cat_unicycle.png').convert_alpha() # self.fish = gfx('fish.png').convert_alpha() # self.foot = gfx('foot.png').convert_alpha() # self.foot_part = gfx('foot_part.png').convert_alpha() # self.shark = gfx('shark.png').convert_alpha() sfx('cat_jump.ogg') sfx('eatfish.ogg') sfx('splash.ogg') sfx('cat_crash.ogg') self.meow_names = [ 'cat_meow01.ogg', 'cat_meow02.ogg', 'cat_meow03.ogg' ] self.last_meow = None self.touching_ground = True self.jumping = False self.jumping_time = 0 self.jump_key = None for meow_name in self.meow_names: sfx(meow_name) self.boing_names = ['boing1.ogg', 'boing2.ogg', 'boing3.ogg'] for boing_name in self.boing_names: sfx(boing_name) #cat variables self.cat_wire_height = height - 100 self.cat_location = [width / 2, height - 100] self.cat_speed = [0, 0] self.cat_speed_max = 8 self.cat_fall_speed_max = 16 self.cat_roll_speed = .01 self.cat_angle = 0 self.cat_angular_vel = 0 self.cat_head_location = [ int(self.cat_location[0] + 100 * math.cos(self.cat_angle - math.pi / 2)), int(self.cat_location[1] + 100 * math.sin(self.cat_angle - math.pi / 2)), ] self.people_mad = False self.people_mad_duration = 3000 #ms self.people_mad_current_time = 0 self.next_notfish = 0 self.notfish_time = 0 self.last_joy_right_tilt = 0 self.last_joy_left_tilt = 0 self.left_pressed = False self.right_pressed = False self.score = 0 #timing self.dt_scaled = 0 self.total_time = 0 #elephant and shark classes self.elephant = Elephant(self) self.shark_active = False #is the shark enabled yet self.elephant_active = False self.cat = Cat(self) self.score_text = Score(self) self.deadzones = [] # self.deadzones = [ # DeadZone( # [ # [0, height - 100], # [0.1 * width, height - 100], # [0.1 * width, height], # [0, height], # ], # ), # DeadZone( # [ # [0.9 * width, height - 100], # [width, height - 100], # [width, height], # [0.9 * width, height], # ], # ), # ] self.init_sprites() # lists of things to catch by [posx, posy, velx, vely] # self.fish = [[0, height / 2, 10, -5]] self.fish = LayeredDirtyAppend() self.fish.extend([Fish(self.allsprites, 0, height / 2, 10, -5)]) self.not_fish = LayeredDirtyAppend() self.unicycle_sound = sfx('unicycle.ogg', play=True, loops=-1, fadein=500) self.reset_meow() #difficulty varibles self.number_of_not_fish = 0 def reset_meow(self): self.next_meow = random.uniform(5000, 10000) def meow(self): # Play a meow sound, but not the same one twice in a row meow_names = self.meow_names[:] if self.last_meow in self.meow_names: meow_names.remove(self.last_meow) self.last_meow = random.choice(meow_names) sfx(self.last_meow, play=1) self.reset_meow() def init_sprites(self): """temp, this will go in the init. """ sprite_list = [self.elephant, self.cat, self.score_text] sprite_list += self.deadzones self.allsprites = LayeredDirty(sprite_list, _time_threshold=1000 / 10.0) scene = self self.shark = Shark(self.allsprites, scene, self.width, self.height) self.allsprites.add(self.shark) self.allsprites.clear(self.screen, self.background) #what to do when you die, reset the level def reset_on_death(self): self.cat_location = [self.width / 2, self.height - 100] self.cat_speed = [0, 0] self.cat_angle = 0 self.cat_angular_vel = 0 self.score = 0 self.total_time = 0 self.elephant.last_animation = 0 self.elephant.state = 0 self.elephant.just_happened = None self.elephant.dirty = 1 self.elephant_active = False self.elephant.animate(self.total_time) #make the shark leave self.shark_active = False self.shark.last_animation = 0 self.shark.dirty = True if self.shark.get_state() in ('aiming', 'fire laser'): self.shark.just_happenend = None self.shark.set_state('leaving') self.shark.applaud = False else: self.shark.just_happenend = None self.shark.set_state('offscreen') self.shark.animate(self.total_time) sfx('shark_appear.ogg', fadeout=1000) if self.shark.lazer: self.shark.lazer.kill() #periodically increase the difficulty def increase_difficulty(self): self.number_of_not_fish = 0 if self.score > 3: self.number_of_not_fish = 1 if self.score > 9: self.number_of_not_fish = 1 if self.score > 15: self.number_of_not_fish = 2 if self.score > 19: self.number_of_not_fish = 1 if self.score > 25: self.number_of_not_fish = 2 if self.score > 35: self.number_of_not_fish = 3 if self.score >= 50: self.number_of_not_fish = int((self.score - 20) / 10) #TODO: to make it easier to test. # if self.score >= 15: # self.shark_active = True if self.score >= 10: self.shark_active = True #TODO: to make it easier to test. # Elephant doesn't work yet, so let's not use it # if self.score >= 20: # self.elephant_active = True def annoy_crowd(self): self.people_mad = True self.people_mad_current_time = 0 def render_sprites(self): rects = [] self.allsprites.update() rects.extend(self.allsprites.draw(self.screen)) return rects def render(self): rects = [] if self.first_render: self.first_render = False rects.append(self.screen.get_rect()) rects.extend(self.render_sprites()) return rects def tick(self, dt): self.increase_difficulty() self.cat.animate(dt) self.total_time += dt #keep track of the total number of ms passed during the game dt_scaled = dt / 17 self.dt_scaled = dt_scaled width, height = self.width, self.height ##cat physics self.cat_angular_vel *= 0.9**dt_scaled #max(0.9/(max(0.1,dt_scaled)),0.999) #make the cat slide in the direction it's rotated self.cat_speed[0] += math.sin( self.cat_angle) * (dt_scaled * self.cat_roll_speed) # add gravity self.cat_speed[1] = min(self.cat_speed[1] + (1 * dt_scaled), self.cat_fall_speed_max) self.unicycle_sound.set_volume( abs(self.cat_speed[0] / self.cat_speed_max)) # accelerate the cat left or right if self.right_pressed: self.cat_speed[0] = min(self.cat_speed[0] + 0.3 * dt_scaled, self.cat_speed_max) self.cat_angle -= 0.003 * dt_scaled if self.left_pressed: self.cat_speed[0] = max(self.cat_speed[0] - 0.3 * dt_scaled, -self.cat_speed_max) self.cat_angle += 0.003 * dt_scaled # make the cat fall angle_sign = 1 if self.cat_angle > 0 else -1 self.cat_angular_vel += 0.0002 * angle_sign * dt_scaled self.cat_angle += self.cat_angular_vel * dt_scaled if (self.cat_angle > math.pi / 2 or self.cat_angle < -math.pi / 2 ) and self.cat_location[1] > height - 160: sfx('cat_crash.ogg', play=1) self.reset_on_death() # move cat self.cat_location[0] += self.cat_speed[0] * dt_scaled self.cat_location[1] += self.cat_speed[1] * dt_scaled if self.cat_location[1] > self.cat_wire_height and self.cat_location[ 0] > 0.25 * width: self.touching_ground = True self.cat_location[1] = self.cat_wire_height self.cat_speed[1] = 0 else: self.touching_ground = False if self.cat_location[1] > height: sfx('splash.ogg', play=1) self.meow() self.reset_on_death() if self.cat_location[0] > width: self.cat_location[0] = width if self.cat_angle > 0: self.cat_angle *= 0.7 self.cat_head_location = [ int(self.cat_location[0] + 100 * math.cos(self.cat_angle - math.pi / 2)), int(self.cat_location[1] + 100 * math.sin(self.cat_angle - math.pi / 2)), ] # check for out of bounds if self.cat_location[0] > 0.98 * width and self.cat_location[ 1] > self.cat_wire_height - 30: #bump the cat back in self.meow() sfx(random.choice(self.boing_names), play=True) self.cat_angular_vel -= 0.01 * dt_scaled self.cat_speed[0] = -5 self.cat_speed[1] = -20 #self.reset_on_death() if self.cat_location[0] < 0.25 * width and self.cat_location[ 1] > self.cat_wire_height - 30: pass #check for collision with the elephant stomp if self.elephant_active: self.elephant.animate(self.total_time) self.elephant.collide(self, width, height, self.cat_head_location) if self.shark_active or self.shark.states[ self.shark.state] == 'leaving': self.shark.animate(self.total_time) self.shark.collide(self, width, height, self.cat_location) #jumping physics if self.jumping: self.cat_speed[1] -= dt * ( (CAT_MAX_JUMPING_TIME - self.jumping_time) / CAT_MAX_JUMPING_TIME) * CAT_JUMP_SPEED self.jumping_time += dt if self.jumping_time >= CAT_MAX_JUMPING_TIME: self.jumping = False ##meow timing if self.next_meow <= 0: self.meow() self.next_meow -= dt ##angry people (increased throwing of not-fish) if self.people_mad: self.people_mad_current_time += dt self.notfish_time += dt if self.notfish_time >= self.next_notfish: self.next_notfish = random.randint(100, 400) self.notfish_time = 0 self.SpawnNotFish() if self.people_mad_current_time >= self.people_mad_duration: self.people_mad = False ##object physics # move fish and not fish for f in reversed(self.fish.sprites()): f.pos[0] += f.velocity[0] * dt_scaled # speed of the throw f.velocity[1] += 0.2 * dt_scaled # gravity f.pos[1] += f.velocity[1] * dt_scaled # y velocity # check out of bounds if f.pos[1] > height: self.fish.remove(f) f.kill() for f in reversed(self.not_fish.sprites()): f.pos[0] += f.velocity[0] * dt_scaled # speed of the throw f.velocity[1] += 0.2 * dt_scaled # gravity f.pos[1] += f.velocity[1] * dt_scaled # y velocity # check out of bounds if f.pos[1] > height: self.not_fish.remove(f) f.kill() # check collision with the cat for f in reversed(self.fish.sprites()): if distance([f.rect[0], f.rect[1]], self.cat_head_location) < 100: self.score += 1 self.fish.remove(f) sfx('eatfish.ogg', play=1) f.kill() for f in reversed(self.not_fish.sprites()): if distance([f.rect[0], f.rect[1]], self.cat_head_location) < 50: self.not_fish.remove(f) f.kill() self.angle_to_not_fish = (math.atan2( self.cat_head_location[1] - f.rect[1], self.cat_head_location[0] - f.rect[0], ) - math.pi / 2) side = 1 if self.angle_to_not_fish < 0 else -1 self.cat_angular_vel += side * random.uniform(0.08, 0.15) sfx(random.choice(self.boing_names), play=True) # refresh lists while len(self.fish) < 1 and not self.people_mad: # choose a side of the screen if random.choice([0, 1]) == 0: self.fish.append( Fish( self.allsprites, 0, height / 2, #random.randint(0, height / 2), random.randint(3, 7), -random.randint(5, 12), )) else: self.fish.append( Fish( self.allsprites, width, height / 2, #random.randint(0, height / 2), -random.randint(3, 7), -random.randint(5, 12), )) while len(self.not_fish) < self.number_of_not_fish: self.SpawnNotFish() def SpawnNotFish(self): # choose a side of the screen velocity_multiplier = 1 x_pos = 0 if random.randint(0, 1): velocity_multiplier *= -1 x_pos = self.width self.not_fish.append( NotFish( self.allsprites, x_pos, self.height / 2, random.randint(3, 7) * velocity_multiplier, -random.randint(5, 12), )) def start_jump(self, key): self.jump_key = key if self.touching_ground and not self.jumping: self.jumping = True self.jumping_time = 0 self.cat_speed[1] -= 12.5 sfx('cat_jump.ogg', play=1) def stop_jump(self): self.jumping = False sfx('cat_jump.ogg', fadeout=50) def tilt_left(self): self.cat_angular_vel -= random.uniform(0.01 * math.pi, 0.03 * math.pi) def tilt_right(self): self.cat_angular_vel += random.uniform(0.01 * math.pi, 0.03 * math.pi) def event(self, event): if event.type == KEYDOWN: if event.key == K_RIGHT: self.right_pressed = True elif event.key == K_LEFT: self.left_pressed = True elif event.key == K_a: self.tilt_left() elif event.key == K_d: self.tilt_right() elif event.key in (K_UP, K_SPACE): self.start_jump(event.key) elif event.type == KEYUP: if event.key == self.jump_key: self.stop_jump() elif event.key == K_RIGHT: self.right_pressed = False elif event.key == K_LEFT: self.left_pressed = False if event.type == JOYBUTTONDOWN: if event.button in JOY_JUMP_BUTTONS: self.start_jump("JOY" + str(event.button)) if event.button in JOY_LEFT_BUTTONS: self.tilt_left() if event.button in JOY_RIGHT_BUTTONS: self.tilt_right() if event.type == JOYBUTTONUP: if "JOY" + str(event.button) == self.jump_key: self.stop_jump() if event.type == JOYAXISMOTION: if event.axis == 0: if event.value >= JOY_SENSE: self.right_pressed = True self.left_pressed = False elif event.value <= -JOY_SENSE: self.right_pressed = False self.left_pressed = True else: self.right_pressed = False self.left_pressed = False if event.axis == JOY_TILT_RIGHT_AXIS: if self.last_joy_right_tilt < JOY_SENSE and event.value >= JOY_SENSE: self.tilt_right() self.last_joy_right_tilt = event.value if event.axis == JOY_TILT_LEFT_AXIS: if self.last_joy_left_tilt < JOY_SENSE and event.value >= JOY_SENSE: self.tilt_left() self.last_joy_left_tilt = event.value
class Screen(object): def __init__(self, name): State.name = name State.screen = self State.controls = State.screens[State.name]['controls'] State.groups = {} self.layers = LayeredDirty() self.add_all() State.save(State.name) def add_all(self): """Add all the objects specified in the screen's configuration resource to their proper sprite groups for rendering.""" for obj in State.screens[State.name]['objects']: self.add_object(obj) def add_object(self, name, amount=1, pos=None): """Add one or many of a single game object resource to the screen. name: the name of the game object. amount: the amount of instances to add. pos: if value is 'random', every object will start in a random location. if value is a (x,y) tuple, every object will start at that screen location.""" obj = State.objects[name] new_pos = None for i in range(0, amount): if pos == 'random': scr = State.window.get_size() spr = obj['size'] new_pos = (randint(0, scr[0]/spr[0]), randint(0, scr[1]/spr[1])) elif type(pos) == type(tuple()): new_pos = pos if new_pos: obj['pos'] = new_pos group = obj['group'] if group not in State.groups: State.groups[group] = Group() sprite = eval(group.capitalize())(obj) State.groups[group].add(sprite) if obj['cursor']: State.cursor = sprite self.layers.add(State.groups[group]) def draw(self): """Run the update method of every sprite, keeping track of which ones are dirty and need updating, and then finally updating only the dirty areas.""" self.layers.update() State.dirty = self.layers.draw(State.window) display.update(State.dirty) def switch(self, name): """Switch to a new screen by saving the current state, and then restoring the specified state.""" State.save(State.name) State.prev_name = State.name State.restore(name) def restore(self): """Called when a screen is restored from a saved state.""" State.pressed = [] for group in State.groups: for sprite in State.groups[group]: sprite.dirty = 1 sprite.stopped = True
class MapView: def __init__(self, action_handler, index): # Init clock self.clock = pyg.time.Clock() # Set handler self.action_handler = action_handler # Init groupsView self.all_sprites = LayeredDirty() Fps.containers += (self.all_sprites,) # Create window self.screen, self.background = reset_screen() if DISPLAY_FPS: Fps(self.clock) # Blit level image, rect = get_stage_image(index) self.background.blit(image, rect) # Tile handling from TileView import TileView TileView.layer_container = self.all_sprites # Initialize attributes self.exit = False self.done = False self.countdown = None def win(self): self.done = True self.win = True self.countdown = countdown(GoalView.len_animation) def lose(self, nb_tiles): self.done = True self.win = False value = MinimizingPlayerView.len_animation value += TeleportingPlayerView.len_animation * (nb_tiles-2) value += FallingPlayerView.len_animation value *= 2 self.countdown = countdown(value) def reactor_loop(self): # Infinite loop while True: # Get input for ev in pyg.event.get(): # Quit if (ev.type == pyg.KEYDOWN and ev.key == pyg.K_ESCAPE)\ or ev.type == pyg.QUIT: safe_exit() # Reset if ev.type == pyg.JOYBUTTONDOWN and \ ev.button in RESET_BUTTONS: win_reset = False, True return win_reset # Handle countdown if self.done and next(self.countdown): self.all_sprites.empty() win_reset = self.win, False return win_reset # Read input if not self.done: self.action_handler.read_inputs() # Clear sprites from screen self.all_sprites.clear(self.screen, self.background) # Update sprites self.all_sprites.update() # Draw sprites on screen dirty = self.all_sprites.draw(self.screen) # Update display pyg.display.flip() # Frame rate control self.clock.tick(FPS)
class CatUniScene(Scene): # pylint:disable=too-many-instance-attributes """Cat unicycle scene.""" def __init__(self, *args, **kwargs): Scene.__init__(self, *args, **kwargs) (width, height) = (1920 // 2, 1080 // 2) self.width, self.height = width, height # Loading screen should always be a fallback active scene self.active = False self.first_render = True self.myfont = pygame.font.SysFont("monospace", 20) self.background = gfx("background.png", convert=True) # self.cat_unicycle = gfx('cat_unicycle.png').convert_alpha() # self.fish = gfx('fish.png').convert_alpha() # self.foot = gfx('foot.png').convert_alpha() # self.foot_part = gfx('foot_part.png').convert_alpha() # self.shark = gfx('shark.png').convert_alpha() sfx("cat_jump.ogg") sfx("eatfish.ogg") sfx("splash.ogg") sfx("cat_crash.ogg") self.meow_names = [ "cat_meow01.ogg", "cat_meow02.ogg", "cat_meow03.ogg" ] self.last_meow = None self.touching_ground = True self.jumping = False self.jumping_time = 0 self.jump_key = None for meow_name in self.meow_names: sfx(meow_name) self.boing_names = ["boing1.ogg", "boing2.ogg", "boing3.ogg"] for boing_name in self.boing_names: sfx(boing_name) self.people_mad = False self.people_mad_duration = 3000 # ms self.people_mad_current_time = 0 self.next_notfish = 0 self.notfish_time = 0 self.last_joy_right_tilt = 0 self.last_joy_left_tilt = 0 self.left_pressed = False self.right_pressed = False self.player_data = PlayerData(width, height) # timing self.dt_scaled = 0 self.total_time = 0 # elephant and shark classes self.elephant = Elephant(self) self.shark_active = False # is the shark enabled yet self.elephant_active = False self.cat = Cat(self) self.score_text = Score(self) self.allsprites = None # type: Optional[LayeredDirty] self.shark = None # type: Optional[Shark] self.init_sprites() # lists of things to catch by [posx, posy, velx, vely] # self.fish = [[0, height / 2, 10, -5]] self.fish = LayeredDirtyAppend() self.fish.extend([Fish(self.allsprites, (0, height / 2), (10, -5))]) self.not_fish = LayeredDirtyAppend() self.unicycle_sound = sfx("unicycle.ogg", play=True, loops=-1, fadein=500) self._reset_meow() # difficulty varibles self.number_of_not_fish = 0 def _reset_meow(self): self.next_meow = random.uniform(5000, 10000) def _meow(self): # Play a meow sound, but not the same one twice in a row meow_names = self.meow_names[:] if self.last_meow in self.meow_names: meow_names.remove(self.last_meow) self.last_meow = random.choice(meow_names) sfx(self.last_meow, play=1) self._reset_meow() def init_sprites(self): """temp, this will go in the init.""" sprite_list = [self.elephant, self.cat, self.score_text] self.allsprites = LayeredDirty(sprite_list, _time_threshold=1000 / 10.0) scene = self self.shark = Shark(self.allsprites, scene, self.width, self.height) self.allsprites.add(self.shark) self.allsprites.clear(self.screen, self.background) def reset_on_death(self): """Reset on death. What to do when you die, reset the level. """ self.player_data.reset() self.total_time = 0 self.elephant.last_animation = 0 self.elephant.state = 0 self.elephant.just_happened = None self.elephant.dirty = 1 self.elephant_active = False self.elephant.animate(self.total_time) # make the shark leave self.shark_active = False self.shark.last_animation = 0 self.shark.dirty = True if self.shark.get_state() in ("aiming", "fire laser"): self.shark.just_happened = None self.shark.set_state("leaving") self.shark.applaud = False else: self.shark.just_happened = None self.shark.set_state("offscreen") self.shark.animate(self.total_time) sfx("shark_appear.ogg", fadeout=1000) if self.shark.lazer: self.shark.lazer.kill() def increase_difficulty(self): """ Periodically increase the difficulty.""" self.number_of_not_fish = 0 if self.player_data.score > 3: self.number_of_not_fish = 1 if self.player_data.score > 9: self.number_of_not_fish = 1 if self.player_data.score > 15: self.number_of_not_fish = 2 if self.player_data.score > 19: self.number_of_not_fish = 1 if self.player_data.score > 25: self.number_of_not_fish = 2 if self.player_data.score > 35: self.number_of_not_fish = 3 if self.player_data.score >= 50: self.number_of_not_fish = int((self.player_data.score - 20) / 10) if self.player_data.score >= 10: self.shark_active = True # Elephant doesn't work yet, so let's not use it # if self.player_data.score >= 20: # self.elephant_active = True def annoy_crowd(self): """ Annoy the crowd.""" self.people_mad = True self.people_mad_current_time = 0 def render_sprites(self): """ Render the sprites.""" rects = [] self.allsprites.update(time_delta=self.dt_scaled, height=self.height, player_data=self.player_data) rects.extend(self.allsprites.draw(self.screen)) return rects def render(self): rects = [] if self.first_render: self.first_render = False rects.append(self.screen.get_rect()) rects.extend(self.render_sprites()) return rects def tick(self, time_delta): self.increase_difficulty() self.cat.animate(time_delta) self.total_time += ( time_delta # keep track of the total number of ms passed during the game ) dt_scaled = time_delta / 17 self.dt_scaled = dt_scaled width, height = self.width, self.height ##cat physics self.player_data.cat_angular_vel *= ( 0.9**dt_scaled) # max(0.9/(max(0.1,dt_scaled)),0.999) # make the cat slide in the direction it's rotated self.player_data.cat_speed[0] += math.sin( self.player_data.cat_angle) * (dt_scaled * self.player_data.cat_roll_speed) # add gravity self.player_data.cat_speed[1] = min( self.player_data.cat_speed[1] + (1 * dt_scaled), self.player_data.cat_fall_speed_max, ) self.unicycle_sound.set_volume( abs(self.player_data.cat_speed[0] / self.player_data.cat_speed_max)) self._move_cat() self._cat_out_of_bounds() # check for collision with the elephant stomp if self.elephant_active: self.elephant.animate(self.total_time) self.elephant.collide(width) if self.shark_active or self.shark.states[ self.shark.state] == "leaving": self.shark.animate(self.total_time) self.shark.collide(self, width, height, self.player_data.cat_location) self._cat_jumping(time_delta) self._cats_meow(time_delta) self._angry_people(time_delta) self._collide_flying_objects() self._spawn_flying_objects() def _move_cat(self): """Move, accelerate, and tilt the cat.""" # accelerate the cat left or right if self.right_pressed: self.player_data.cat_speed[0] = min( self.player_data.cat_speed[0] + 0.3 * self.dt_scaled, self.player_data.cat_speed_max, ) self.player_data.cat_angle -= 0.003 * self.dt_scaled if self.left_pressed: self.player_data.cat_speed[0] = max( self.player_data.cat_speed[0] - 0.3 * self.dt_scaled, -self.player_data.cat_speed_max, ) self.player_data.cat_angle += 0.003 * self.dt_scaled # make the cat fall angle_sign = 1 if self.player_data.cat_angle > 0 else -1 self.player_data.cat_angular_vel += 0.0002 * angle_sign * self.dt_scaled self.player_data.cat_angle += self.player_data.cat_angular_vel * self.dt_scaled if (self.player_data.cat_angle > math.pi / 2 or self.player_data.cat_angle < -math.pi / 2 ) and self.player_data.cat_location[1] > self.height - 160: sfx("cat_crash.ogg", play=1) self.reset_on_death() # move cat self.player_data.cat_location[0] += (self.player_data.cat_speed[0] * self.dt_scaled) self.player_data.cat_location[1] += (self.player_data.cat_speed[1] * self.dt_scaled) if (self.player_data.cat_location[1] > self.player_data.cat_wire_height and self.player_data.cat_location[0] > 0.25 * self.width): self.touching_ground = True self.player_data.cat_location[1] = self.player_data.cat_wire_height self.player_data.cat_speed[1] = 0 else: self.touching_ground = False def _cat_out_of_bounds(self): """check for out of bounds""" # in the pool if self.player_data.cat_location[1] > self.height: sfx("splash.ogg", play=1) self._meow() self.reset_on_death() # to the right of screen. if self.player_data.cat_location[0] > self.width: self.player_data.cat_location[0] = self.width if self.player_data.cat_angle > 0: self.player_data.cat_angle *= 0.7 self.player_data.cat_head_location = [ int(self.player_data.cat_location[0] + 100 * math.cos(self.player_data.cat_angle - math.pi / 2)), int(self.player_data.cat_location[1] + 100 * math.sin(self.player_data.cat_angle - math.pi / 2)), ] if (self.player_data.cat_location[0] > 0.98 * self.width and self.player_data.cat_location[1] > self.player_data.cat_wire_height - 30): # bump the cat back in self._meow() sfx(random.choice(self.boing_names), play=True) self.player_data.cat_angular_vel -= 0.01 * self.dt_scaled self.player_data.cat_speed[0] = -5 self.player_data.cat_speed[1] = -20 # self.reset_on_death() if (self.player_data.cat_location[0] < 0.25 * self.width and self.player_data.cat_location[1] > self.player_data.cat_wire_height - 30): pass def _cat_jumping(self, time_delta): """jumping physics""" if self.jumping: self.player_data.cat_speed[1] -= ( time_delta * ((CAT_MAX_JUMPING_TIME - self.jumping_time) / CAT_MAX_JUMPING_TIME) * CAT_JUMP_SPEED) self.jumping_time += time_delta if self.jumping_time >= CAT_MAX_JUMPING_TIME: self.jumping = False def _cats_meow(self, time_delta): """meow timing""" if self.next_meow <= 0: self._meow() self.next_meow -= time_delta def _angry_people(self, time_delta): """angry people (increased throwing of not-fish)""" if self.people_mad: self.people_mad_current_time += time_delta self.notfish_time += time_delta if self.notfish_time >= self.next_notfish: self.next_notfish = random.randint(100, 400) self.notfish_time = 0 self._spawn_not_fish() if self.people_mad_current_time >= self.people_mad_duration: self.people_mad = False def _collide_flying_objects(self): """object physics""" height = self.height dt_scaled = self.dt_scaled # move fish and not fish for fish in reversed(self.fish.sprites()): fish.pos[0] += fish.velocity[0] * dt_scaled # speed of the throw fish.velocity[1] += 0.2 * dt_scaled # gravity fish.pos[1] += fish.velocity[1] * dt_scaled # y velocity # check out of bounds if fish.pos[1] > height: self.fish.remove(fish) fish.kill() for fish in reversed(self.not_fish.sprites()): fish.pos[0] += fish.velocity[0] * dt_scaled # speed of the throw fish.velocity[1] += 0.2 * dt_scaled # gravity fish.pos[1] += fish.velocity[1] * dt_scaled # y velocity # check out of bounds if fish.pos[1] > height: self.not_fish.remove(fish) fish.kill() # check collision with the cat for fish in reversed(self.fish.sprites()): if (distance([fish.rect[0], fish.rect[1]], self.player_data.cat_head_location) < 100): self.player_data.increment_score() self.fish.remove(fish) sfx("eatfish.ogg", play=1) fish.kill() for fish in reversed(self.not_fish.sprites()): if (distance([fish.rect[0], fish.rect[1]], self.player_data.cat_head_location) < 50): self.not_fish.remove(fish) fish.kill() self.player_data.angle_to_not_fish = (math.atan2( self.player_data.cat_head_location[1] - fish.rect[1], self.player_data.cat_head_location[0] - fish.rect[0], ) - math.pi / 2) side = 1 if self.player_data.angle_to_not_fish < 0 else -1 self.player_data.cat_angular_vel += side * random.uniform( 0.08, 0.15) sfx(random.choice(self.boing_names), play=True) def _spawn_flying_objects(self): """Throws random objects at the cat.""" width, height = self.width, self.height # refresh lists while len(self.fish) < 1 and not self.people_mad: # choose a side of the screen if random.choice([0, 1]) == 0: self.fish.append( Fish( self.allsprites, (0, height / 2), # random.randint(0, height / 2), (random.randint(3, 7), -random.randint(5, 12)), )) else: self.fish.append( Fish( self.allsprites, (width, height / 2), # random.randint(0, height / 2), (-random.randint(3, 7), -random.randint(5, 12)), )) while len(self.not_fish) < self.number_of_not_fish: self._spawn_not_fish() def _spawn_not_fish(self): """Choose a side of the screen.""" velocity_multiplier = 1 x_pos = 0 if random.randint(0, 1): velocity_multiplier *= -1 x_pos = self.width self.not_fish.append( NotFish( self.allsprites, (x_pos, self.height / 2), (random.randint(3, 7) * velocity_multiplier, -random.randint(5, 12)), )) def _start_jump(self, key): self.jump_key = key if self.touching_ground and not self.jumping: self.jumping = True self.jumping_time = 0 self.player_data.cat_speed[1] -= 12.5 sfx("cat_jump.ogg", play=1) def _stop_jump(self): self.jumping = False sfx("cat_jump.ogg", fadeout=50) def _tilt_left(self): self.player_data.cat_angular_vel -= random.uniform( 0.01 * math.pi, 0.03 * math.pi) def _tilt_right(self): self.player_data.cat_angular_vel += random.uniform( 0.01 * math.pi, 0.03 * math.pi) def _event_keydown(self, event): if event.key == pygame.K_RIGHT: self.right_pressed = True elif event.key == pygame.K_LEFT: self.left_pressed = True elif event.key == pygame.K_a: self._tilt_left() elif event.key == pygame.K_d: self._tilt_right() elif event.key in (pygame.K_UP, pygame.K_SPACE): self._start_jump(event.key) def _event_keyup(self, event): if event.key == self.jump_key: self._stop_jump() elif event.key == pygame.K_RIGHT: self.right_pressed = False elif event.key == pygame.K_LEFT: self.left_pressed = False def _event_joybuttondown(self, event): if event.button in JOY_JUMP_BUTTONS: self._start_jump("JOY" + str(event.button)) if event.button in JOY_LEFT_BUTTONS: self._tilt_left() if event.button in JOY_RIGHT_BUTTONS: self._tilt_right() def _event_joybuttonup(self, event): if "JOY" + str(event.button) == self.jump_key: self._stop_jump() def _event_joyaxismotion(self, event): if event.axis == 0: if event.value >= JOY_SENSE: self.right_pressed = True self.left_pressed = False elif event.value <= -JOY_SENSE: self.right_pressed = False self.left_pressed = True else: self.right_pressed = False self.left_pressed = False if event.axis == JOY_TILT_RIGHT_AXIS: # if self.last_joy_right_tilt < JOY_SENSE and event.value >= JOY_SENSE: if self.last_joy_right_tilt < JOY_SENSE < event.value: self._tilt_right() self.last_joy_right_tilt = event.value if event.axis == JOY_TILT_LEFT_AXIS: # if self.last_joy_left_tilt < JOY_SENSE and event.value >= JOY_SENSE: if self.last_joy_left_tilt < JOY_SENSE < event.value: self._tilt_left() self.last_joy_left_tilt = event.value def event(self, event): if event.type == pygame.KEYDOWN: self._event_keydown(event) elif event.type == pygame.KEYUP: self._event_keyup(event) elif event.type == pygame.JOYBUTTONDOWN: self._event_joybuttondown(event) elif event.type == pygame.JOYBUTTONUP: self._event_joybuttonup(event) elif event.type == pygame.JOYAXISMOTION: self._event_joyaxismotion(event)
class MapView: def __init__(self, action_handler, index): # Init clock self.clock = pyg.time.Clock() # Set handler self.action_handler = action_handler # Init groupsView self.all_sprites = LayeredDirty(_use_updates = True, _time_threshold = 1000) Fps.containers += (self.all_sprites,) # Create window self.screen, self.background = reset_screen() if DISPLAY_FPS: Fps(self.clock) # Blit level image, rect = get_stage_image(index) self.background.blit(image, rect) self.screen.blit(self.background, self.background.get_rect()) # Tile handling from TileView import TileView TileView.layer_container = self.all_sprites # Initialize attributes self.exit = False self.done = False self.countdown = None def win(self): self.done = True self.win = True self.countdown = countdown(GoalView.len_animation) def lose(self, nb_tiles): self.done = True self.win = False value = MinimizingPlayerView.len_animation value += TeleportingPlayerView.len_animation * (nb_tiles-2) value += FallingPlayerView.len_animation value *= 2 self.countdown = countdown(value) def reactor_loop(self): # Infinite loop while True: # Get input for ev in pyg.event.get(): # Quit if (ev.type == pyg.KEYDOWN and ev.key == pyg.K_ESCAPE)\ or ev.type == pyg.QUIT: safe_exit() # Fullscreen if ev.type == pyg.KEYDOWN and ev.key == pyg.K_f: # Toggle fullscreen Constants.FULLSCREEN ^= True # Reset screen self.screen, _ = reset_screen() args = self.background, self.background.get_rect() self.screen.blit(*args) # Repaint all self.all_sprites._use_update = False # Mute if ev.type == pyg.KEYDOWN and ev.key == pyg.K_SEMICOLON: volume = 0 if pyg.mixer.music.get_volume() else VOLUME pyg.mixer.music.set_volume(float(volume)/100) # Reset if (ev.type == pyg.KEYDOWN and ev.key == pyg.K_r) or\ (ev.type == pyg.JOYBUTTONDOWN and ev.button in RESET_BUTTONS): win_reset = False, True return win_reset # Handle countdown if self.done and next(self.countdown): self.all_sprites.empty() win_reset = self.win, False return win_reset # Read input if not self.done: self.action_handler.read_inputs() # Clear sprites from screen self.all_sprites.clear(self.screen, self.background) # Update sprites self.all_sprites.update() # Draw sprites on screen dirty = self.all_sprites.draw(self.screen) # Update display pyg.display.update(dirty) # Frame rate control self.clock.tick(FPS)
pixel = self.image.get_at((x, y)).r if pixel > 50: self.image.set_at((x, y), colour) # create sprites bg = PpuiImage("assets/lcars_screen_1.png") button = PpuiImage("assets/button.png") button.applyColour((255, 204, 153)) # add sprites to layer sprites = LayeredDirty() sprites.add(bg) sprites.add(button) # event loop while pygame.display.get_init(): sprites.draw(screenSurface) pygame.display.update() for event in pygame.event.get(): if event.type == KEYUP: pygame.quit() break if event.type == MOUSEMOTION: # move button around as mouse moves (or touch-drag) button.rect.left = event.pos[0] button.rect.top = event.pos[1] button.dirty = 1
class Screen(object): def __init__(self, name): State.name = name State.screen = self State.controls = State.screens[State.name]['controls'] State.groups = util.GroupCache() self.layers = LayeredDirty() self.add_all() State.save(State.name) def new_game(self): self.switch('world') def quit(self): if State.name == 'title': State.running = False else: self.switch(State.prev_name) def menu_up(self): pass def menu_down(self): pass def add_all(self): """Add all the objects specified in the screen's configuration resource to their proper sprite groups for rendering.""" for obj in State.screens[State.name]['objects']: self.add_object(obj) def add_object(self, name, group=None, pos=None): """Add a game object resource to the screen. name: the name of the game object. pos: object will be placed on this tile.""" # Get object data from given name data = State.objects[name] # If group is not set, use object's default group. if not group: group = data['group'] # Creates a game object from the name of its group, and adds it to # the group. sprite = eval(group.capitalize())(data) State.groups[group].add(sprite) # Set the object's starting tile. if pos: data['pos'] = sprite.set_pos(data, pos) # If an object is a player, tell the state so it can be controlled. # TODO: Make State.player a list of sprites. if sprite in State.groups['player']: State.player = sprite # Add the sprite groups to the rendering queue. self.layers.add(State.groups[group]) return sprite def draw(self): """Run the update method of every sprite, keeping track of which ones are dirty and need updating, and then finally updating only the dirty areas.""" self.layers.update() State.dirty = self.layers.draw(State.window) display.update(State.dirty) def switch(self, name): """Switch to a new screen by saving the current state, and then restoring the specified state.""" State.save(State.name) State.prev_name = State.name State.restore(name) def restore(self): """Called when a screen is restored from a saved state.""" State.pressed = [] for group in State.groups: for sprite in State.groups[group]: sprite.dirty = 1 sprite.stopped = True