class Application: def __init__(self, title, _width, _height): pygame.init() self.surface = pygame.display.set_mode((_width, _height)) pygame.display.set_caption(title) self.clock = pygame.time.Clock() self.fps = 60 self.running = True self.resolution = 2 self.Scenes = Scene(self.surface, _width, _height) def Run(self): while self.running: for event in pygame.event.get(): if event.type == pygame.QUIT: self.running = False keys = pygame.key.get_pressed() if len(keys): self.Scenes.key_pressed(keys) self.surface.fill((10, 10, 10)) self.Scenes.draw() #print("tick {0} | fps {1}".format(self.clock.tick(self.fps), self.clock.get_fps())) pygame.display.update() pygame.quit()
def draw(self, screen): s = pygame.Surface((SCREEN_W, SCREEN_H)) self.pausedScene.draw(s) self.bluredBackground = self.blur(s, self.b) if self.b < 10: self.b = self.b + 0.1 screen.blit(self.bluredBackground, (0, 0)) Scene.draw(self, screen)
def draw(self, screen): screen.fill(0x000000) if self.bg: screen.blit(self.bg, self.camera.state) if Constants.DEBUG: self.drawRaytracing(screen) self.player.draw(screen, self.camera) for group in self.groups: group.draw(screen, self.camera) self.drawDanger(screen); # TODO: move maps and characters to its own layer Scene.draw(self, screen) # draws rest of layers
def draw(self, screen): screen.fill(0x000000) if self.bg: screen.blit(self.bg, self.camera.state) if Constants.DEBUG: self.drawRaytracing(screen) self.player.draw(screen, self.camera) for group in self.groups: group.draw(screen, self.camera) self.drawDanger(screen) # TODO: move maps and characters to its own layer Scene.draw(self, screen) # draws rest of layers
class Screen: window = None lastFrame = 0 clock = None scene = None framesCount = 0 def __init__(self, sizeX, sizeY): pygame.init() self.window = pygame.display.set_mode((sizeX, sizeY)) self.clock = pygame.time.Clock() self.scene = Scene() def update(self): self.lastFrame += self.clock.tick() if self.lastFrame >= 15: self.framesCount += 1 self.scene.draw(self.window, self.framesCount) self.scene.serveFood() if self.framesCount == 5: self.framesCount = 0 self.lastFrame = 0 pygame.display.update() def getKeyInput(self): keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: if self.scene.snake.moveDirection != "RIGHT": self.scene.snake.moveDirection = "LEFT" elif keys[pygame.K_RIGHT]: if self.scene.snake.moveDirection != "LEFT": self.scene.snake.moveDirection = "RIGHT" elif keys[pygame.K_UP]: if self.scene.snake.moveDirection != "DOWN": self.scene.snake.moveDirection = "UP" elif keys[pygame.K_DOWN]: if self.scene.snake.moveDirection != "UP": self.scene.snake.moveDirection = "DOWN"
def main(): # 初始化 pygame.init() screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("T-Rex Rush-公众号: Charles的皮卡丘") clock = pygame.time.Clock() # 得分 score = 0 # 加载一些素材 jump_sound = pygame.mixer.Sound("./music/jump.wav") jump_sound.set_volume(6) die_sound = pygame.mixer.Sound("./music/die.wav") die_sound.set_volume(6) pygame.mixer.init() pygame.mixer.music.load("./music/bg_music.mp3") pygame.mixer.music.set_volume(0.6) pygame.mixer.music.play(-1) font = pygame.font.Font('./font/simkai.ttf', 20) # 实例化 dinosaur = Dinosaur(WIDTH, HEIGHT) scene = Scene(WIDTH, HEIGHT) plants = pygame.sprite.Group() pteras = pygame.sprite.Group() # 产生障碍物事件 GenPlantEvent = pygame.constants.USEREVENT + 0 pygame.time.set_timer(GenPlantEvent, 1500) GenPteraEvent = pygame.constants.USEREVENT + 1 pygame.time.set_timer(GenPteraEvent, 5000) # 游戏是否结束了 running = True # 是否可以产生障碍物flag flag_plant = False flag_ptera = False t0 = time.time() # 主循环 while running: for event in pygame.event.get(): if event.type == QUIT: sys.exit() pygame.quit() if event.type == GenPlantEvent: flag_plant = True if event.type == GenPteraEvent: if score > 50: flag_ptera = True key_pressed = pygame.key.get_pressed() if key_pressed[pygame.K_SPACE]: dinosaur.is_jumping = True jump_sound.play() screen.fill(BACKGROUND) time_passed = time.time() - t0 t0 = time.time() # 场景 scene.move() scene.draw(screen) # 小恐龙 dinosaur.is_running = True if dinosaur.is_jumping: dinosaur.be_afraid() dinosaur.jump(time_passed) dinosaur.draw(screen) # 障碍物-植物 if random.random() < sigmoid(score) and flag_plant: plant = Plant(WIDTH, HEIGHT) plants.add(plant) flag_plant = False for plant in plants: plant.move() if dinosaur.rect.left > plant.rect.right and not plant.added_score: score += 1 plant.added_score = True if plant.rect.right < 0: plants.remove(plant) continue plant.draw(screen) # 障碍物-飞龙 if random.random() < sigmoid(score) and flag_ptera: if len(pteras) > 1: continue ptera = Ptera(WIDTH, HEIGHT) pteras.add(ptera) flag_ptera = False for ptera in pteras: ptera.move() if dinosaur.rect.left > ptera.rect.right and not ptera.added_score: score += 5 ptera.added_score = True if ptera.rect.right < 0: pteras.remove(ptera) continue ptera.draw(screen) # 碰撞检测 if pygame.sprite.spritecollide(dinosaur, plants, False) or pygame.sprite.spritecollide(dinosaur, pteras, False): die_sound.play() running = False # 显示得分 score_text = font.render("Score: "+str(score), 1, (0, 0, 0)) screen.blit(score_text, [10, 10]) pygame.display.flip() clock.tick(60) res = show_gameover(screen) return res
class HaxballEnvironment : def __init__(self, random_start = True, step_limit = None, ball_idle_limit = None, state_output_mode = 'pixels', rendering = True, frame_skip=4): self.action_space = ActionSpace([Action.up, Action.down, Action.forward, Action.backward, Action.nomoveshoot, Action.nomove]) self.step_limit = step_limit self.ball_idle_limit = ball_idle_limit self.state_output_mode = state_output_mode self.rendering = rendering self.ball_idle = 0 self.step_limit = step_limit if state_output_mode == 'pixels': self.rendering = True self.step_count = 0 self.random_start = random_start self.frame_skip = frame_skip self.scene = Scene(c_width, c_height) self.scene.add_object(Box(5, c_width - 5, 5, c_height - 5, 0)) self.scene.add_object(Disc(c_width / 2, c_height / 2, middle_field_radius, 10, 1, 1, Color.white).make_ghost().make_hollow().set_outer_color(Color.border)) self.scene.add_object(VerticalBorder(c_width / 2, c_height / 2, c_height - 2 * topbottom_margin, None).make_ghost()) self.scene.add_object(HorizontalBorder(c_width / 2, topbottom_margin, c_width - 2 * leftright_margin, border_restitution).extend_to(Way.up).set_collision_mask([Ball])) self.scene.add_object(HorizontalBorder(c_width / 2, c_height - topbottom_margin, c_width - 2 * leftright_margin, border_restitution).extend_to(Way.down).set_collision_mask([Ball])) self.scene.add_object(VerticalBorder(leftright_margin, (c_height / 2 - goal_length / 2 + topbottom_margin) / 2, c_height / 2 - topbottom_margin - goal_length / 2, border_restitution).extend_to(Way.left).set_collision_mask([Ball])) self.scene.add_object(VerticalBorder(leftright_margin, c_height - (c_height / 2 - goal_length / 2 + topbottom_margin) / 2, c_height / 2 - topbottom_margin - goal_length / 2, border_restitution).extend_to(Way.left).set_collision_mask([Ball])) self.scene.add_object(VerticalBorder(c_width - leftright_margin, (c_height / 2 - goal_length / 2 + topbottom_margin) / 2, c_height / 2 - topbottom_margin - goal_length / 2, border_restitution).extend_to(Way.right).set_collision_mask([Ball])) self.scene.add_object(VerticalBorder(c_width - leftright_margin, c_height - (c_height / 2 - goal_length / 2 + topbottom_margin) / 2, c_height / 2 - topbottom_margin - goal_length / 2, border_restitution).extend_to(Way.right).set_collision_mask([Ball])) self.goal1 = Goal(leftright_margin, c_height / 2, Way.left, goal_length) self.goal2 = Goal(c_width - leftright_margin, c_height / 2, Way.right, goal_length) self.player1 = Player(120, c_height / 2, player_radius, player_mass, \ player_restitution, player_damping, player_kick_damping, player_kick_power, Side.red) self.player2 = Player(c_width - 120, c_height / 2, player_radius, player_mass, \ player_restitution, player_damping, player_kick_damping, player_kick_power, Side.blue) self.ball = Ball(c_width / 2, c_height / 2, ball_radius, ball_mass, ball_restitution, ball_damping) self.scene.add_object(self.goal1) self.scene.add_object(self.goal2) self.scene.add_object(self.player1) self.scene.add_object(self.player2) self.scene.add_object(self.ball) self.sequence1 = StateSequence([84, 84, 4]) self.sequence2 = StateSequence([84, 84, 4]) def step(self, action_red, action_blue = -1): #ai action no frameskip if self.player2.center.x > self.ball.center.x: if random.random() < 0.02: self.player2.apply_action(Action.nomoveshoot) else: self.player2.apply_action(Action.nomove) #agent action for n in range(self.frame_skip): self.player2.apply_force(self.ai_select_force()) self.player1.apply_action(self.action_space[action_red]) self.scene.update() self.step_count += 1 if self.rendering == True: self.render() if self.ball.velocity.magnitude() < 0.1: self.ball_idle += 1 else: self.ball_idle = 0 return self._get_state_reward_done_info() def ai_select_force(self): ai_agent_pos = self.player2.center ball_pos = self.ball.center goal_pos = self.goal1.center unit_goal_to_ball = Vector.sub(ball_pos, goal_pos).normalize() attract_point = ball_pos.add(unit_goal_to_ball.mult(self.ball.radius)) repel_point = ball_pos.sub(unit_goal_to_ball.mult(self.ball.radius)) attract_force = Vector.sub(attract_point, ai_agent_pos) repel_force = Vector.sub(ai_agent_pos, repel_point).mult(0.2) unit_total_force = Vector.add(attract_force, repel_force).normalize() return unit_total_force def render(self): self.scene.draw() def reset(self): self.scene.reset() self.ball_idle = 0 self.episode_end = False if (self.random_start) : self.scene.meta_objects['balls'][0].apply_impulse(Vector(random.random() - 0.5, random.random() - 0.5).mult(20)) self.step_count = 0 self.render() return self._calculate_state() def _get_state_reward_done_info(self): state = self._calculate_state() reward = self._calculate_reward() done = self._calculate_done() info = self._calculate_info() return [state, reward, done, info] def _calculate_reward(self): v_player = self.player1.velocity v_ball = self.ball.velocity player_to_ball_vec = Vector.sub(self.ball.center, self.player1.center) if Vector.dot(Vector.sub(v_player, v_ball), player_to_ball_vec) > 0: player_to_ball = 1 else: player_to_ball = 0 ball_to_goal_vec = Vector.sub(self.goal2.center, self.ball.center) if Vector.dot(v_ball, ball_to_goal_vec) > 0: ball_to_goal = 1 else: ball_to_goal = 0 goal = self._calculate_info()['goal'] reward = goal return reward def _calculate_done(self): if self.step_limit == None or self.step_count < self.step_limit : step_limit_reached = False else: step_limit_reached = True if self.ball_idle_limit == None or self.ball_idle < self.ball_idle_limit: ball_idle_limit_reached = False else: ball_idle_limit_reached = True return self.scene.check_goals() or step_limit_reached or ball_idle_limit_reached def _calculate_state(self): if self.state_output_mode == 'locations': p1x = self.player1.center.x p1y = self.player1.center.y bx = self.ball.center.x by = self.ball.center.y p2x = self.player2.center.x p2y = self.player2.center.y horiz = c_width / 2 vert = c_height / 2 p1x = (p1x - horiz) / horiz p1y = (p1y - vert) / vert p2x = (p2x - horiz) / horiz p2y = (p2y - vert) / vert bx = (bx - horiz) / horiz by = (by - vert) / vert state_for_p1 = np.array([p1x, p1y, p2x, p2y, bx, by]) state_for_p2 = np.array([-p2x, p2y, -p1x, p1y, -bx, by]) return [state_for_p1, state_for_p2] elif self.state_output_mode == 'pixels': obs_size = (400, 600) pad_size = obs_size[0] // 2, obs_size[1] // 2 obs = self.scene.get_scene_as_array() # obs = np.pad(obs[:,:,1], ((pad_size[0],), (pad_size[1],)) , 'edge') p1x = int(self.player1.center.x + pad_size[1]) p1y = int(self.player1.center.y + pad_size[0]) # p2x = int(self.player2.center.x + pad_size[1]) # p2y = int(self.player2.center.y + pad_size[0]) # obs1 = obs[p1y - obs_size[0] // 2: p1y + obs_size[0] // 2, p1x - obs_size[1] // 2: p1x + obs_size[1] // 2] # obs2 = obs[p2y - obs_size[0] // 2: p2y + obs_size[0] // 2, p2x - obs_size[1] // 2: p2x + obs_size[1] // 2] obs1 = obs[:,:,0] obs1 = imresize(obs1, (84, 84)) # obs2 = imresize(obs2, (84, 84)) self.sequence1.append_obs(obs1) # self.sequence2.append_obs(obs2[:,::-1]) return self.sequence1.get_sequence()#, self.sequence1.get_sequence() else: raise Exception('invalid state output mode: {}'.format(self.state_output_mode)) def _calculate_info(self): info = { "goal": 0, "ball_at_side": 0, "closer_player_to_ball": -1 } if self.ball.center.x > c_width / 2: info['ball_at_side'] = 1 elif self.ball.center.x < c_width / 2: info['ball_at_side'] = -1 else: info['ball_at_side'] = 0 if self.scene.check_goals(): if info['ball_at_side'] == 1: info['goal'] = 1 elif info['ball_at_side'] == -1: info['goal'] = -1 if Vector.dist(self.player1.center, self.ball.center) < Vector.dist(self.player2.center, self.ball.center): info["closer_player_to_ball"] = 0 else: info["closer_player_to_ball"] = 1 return info def close(self): pass
class PenaltyEnvironment: def __init__(self, frame_skip = 2): height = 400 width = 600 goal_length = 300 self.scene = Scene(width, height) self.frame_skip = frame_skip self.ball_idle = 0 self.ball_idle_limit = 3 self.action_space = ActionSpace([Action.up, Action.down, Action.nomoveshoot]) self.box = Box(0, width, 0, height, 0) self.goal1 = Goal(leftright_margin, height / 2, Way.left, goal_length) self.player1 = Player(80, height / 2, player_radius, player_mass, \ player_restitution, player_damping, player_kick_damping, player_kick_power, Side.red) self.ball = Ball(width - 100, height / 2, ball_radius, ball_mass, ball_restitution, ball_damping) self.penalty_spot = Disc(self.ball.center.x, self.ball.center.y, 4, 0, 0, 0, Color.green).make_ghost().make_hollow() # self.player_border_left = VerticalBorder(50, height / 2, height, 0, visible=True) # self.player_border_right = VerticalBorder(100, height / 2, height, 0, visible=True) self.scene.add_object(self.goal1) self.scene.add_object(self.player1) self.scene.add_object(self.ball) self.scene.add_object(self.penalty_spot) self.scene.add_object(self.box) self.reset() # self.scene.add_object(self.player_border_left) # self.scene.add_object(self.player_border_right) def step(self, action=1): for n in range(self.frame_skip): self.player1.apply_action(self.action_space[action]) self.scene.update() if self.ball.velocity.magnitude() < 0.5: self.ball_idle += 1 return self._get_state_reward_done_info() def reset(self): self.scene.reset() self.ball.apply_impulse(Vector(-25, random.random() * 16 - 8)) self.ball_idle = 0 def render(self): self.scene.draw() def _get_state_reward_done_info(self): state = self._calculate_state() reward = self._calculate_reward() done = self._calculate_done() info = self._calculate_info() return [state, reward, done, info] def _calculate_state(self): self.scene.draw() obs = self.scene.get_scene_as_array() return imresize(obs, [210,160]) def _calculate_reward(self): if self.scene.check_goals(): return -1 elif self.ball_idle > self.ball_idle_limit: return 1 else: return 0 def _calculate_done(self): return self.scene.check_goals() or self.ball_idle > self.ball_idle_limit def _calculate_info(self): return {}
class GameEngine(object): """ The Fortune Engine GameEngine is a main loop wrapper around pygame. It manages the event and drawing loops allowing the user to just register for user events and drawing time in the draw loop. """ instance = None def __init__(self, width=1200, height=900, always_draw=False, fps_cap=15, version=False, title="FortuneEngine"): """ Constructor for the game engine. @param width: Window width @param height: Window height @param always_draw: Boolean to set the animation mode to always draw vs draw when set_dirty is called @param fps_cap: Sets the framerate cap. Set to 0 to disable the cap. Warning: setting the cap to 0 when always draw = False will cause cpu 100% when not driving. @param version: If true, use new rendering system, false uses only the draw system @param title: Window Title """ GameEngine.instance = self pygame.init() pygame.mouse.set_visible(False) self.__version = version #true is new, false is old # Window Settings self.width = width self.height = height size = width, height self.screen = pygame.display.set_mode(size) pygame.display.set_caption(title) self.__fps = DrawableFontObject("", pygame.font.Font(None, 17)) self.__fps.setPosition(0, 0) self.__scene = Scene(self.__fps) # Engine Internal Variables self.__fps_cap = fps_cap self.__showfps = False self.__dirty = True self.__always_draw = always_draw self.__font = pygame.font.Font(None, 17) self.__run_event = False # Variables to hold game engine elements and callbacks self.__event_cb = [] self.__draw_lst = [] self.__object_hold = {} # Game Timers self.__active_event_timers = [] self.__active_event_timers_tick = [] # Game Clock self.clock = pygame.time.Clock() self.__tick_time = 0 # Inspector self._inspector = GameInspect(self.__object_hold) # Time Profiler Timers self.__draw_time = {} self.__draw_calls = {} self.__event_time = {} self.__event_calls = {} self.__timer_time = {} self.__timer_calls = {} # Initialize Py Console self.console = GameEngineConsole(self, (0, 0, width, height / 2)) # Disable Mouse Usage # TODO Allow mouse motion on request pygame.event.set_blocked(pygame.MOUSEMOTION) def set_dirty(self): """ Sets the dirty flag to force the engine to draw the next time it enters the draw flag. """ self.__dirty = True def get_scene(self): """ Returns the scene object @return: Returns the scene object held by the game engine """ return self.__scene def start_event_timer(self, function_cb, time): """ Starts a timer that fires a user event into the queue every "time" milliseconds @param function_cb: The function to call when timer fires @param time: Milliseconds between fires """ avail_timer = len(self.__active_event_timers) if avail_timer + pygame.USEREVENT < pygame.NUMEVENTS: if function_cb not in self.__active_event_timers: self.__timer_time[str(function_cb)] = 0 self.__timer_calls[str(function_cb)] = 0 self.__active_event_timers.append(function_cb) self.__active_event_timers_tick.append(time) pygame.time.set_timer(pygame.USEREVENT + avail_timer, time) else: print "ERROR TIMER IN LIST" else: print "Ran out of timers :(" self.stop_event_loop() def stop_event_timer(self, function_cb): """ Stops the timer that has id from firing @param function_cb: The function registered with the timer that should be canceled """ try: timer_id = self.__active_event_timers.index(function_cb) except ValueError: return pygame.time.set_timer(pygame.USEREVENT + timer_id, 0) del self.__active_event_timers[timer_id] del self.__active_event_timers_tick[timer_id] # Timers have been removed, now need to clear any events # already fired and in the queue pygame.event.clear(pygame.USEREVENT + timer_id) def list_event_timers(self): """ returns a list of configured timers, if the timers has a time of 0 the timer is disabled """ timer_list = "Event Timers:\n" i = 0 for timer_item in self.__active_event_timers: timer_list += "\t%d: %d\n" % (timer_item, self.__active_event_timers_tick[i]) i = i + 1 return timer_list def list_timer_time(self): """ Returns a string representation of the time the game spends in each timer callback. """ mystr = "Timer Times:\n\tName\tCalls\tTotal Time\tAvg" for key in self.__timer_time: timer_times = self.__timer_time[key] timer_calls = self.__timer_calls[key] if timer_calls == 0: avg = 0 else: avg = timer_times / timer_calls mystr = "%s\n\t%s\n\t\t%d\t%f\t%f" % \ (mystr, key, timer_calls, timer_times, avg) return mystr def start_main_loop(self): """ Starts the game loop. This function does not return until after the game loop exits """ self.__run_event = True self._event_loop() def _draw(self, tick_time): """ Draws all elements in draw callback to the screen @param tick_time: The amount of time passed since last draw cycle. (should be produced by pygamme.clock.tick method) """ screen = self.screen # If console is active, we want to draw console, pausing # game drawing (events are still being fired, just no # draw updates. if self.__version: if self.console.active: self.console.draw() pygame.display.flip() else: for fnc in self.__draw_lst: start = time() fnc() self.__draw_time[str(fnc)] += time() - start self.__draw_calls[str(fnc)] += 1 # Print Frame Rate if self.__showfps: self.__fps.changeText('FPS: %d' % self.clock.get_fps(), (255, 255, 255)) else: self.__fps.changeText('') self.__scene.update(tick_time) pygame.display.update(self.__scene.draw(screen)) else: if self.console.active: self.console.draw() pygame.display.flip() else: for fnc in self.__draw_lst: start = time() fnc(screen, tick_time) self.__draw_time[str(fnc)] += time() - start self.__draw_calls[str(fnc)] += 1 # Print Frame Rate if self.__showfps: text = self.__font.render('FPS: %d' % \ self.clock.get_fps(), False, (255, 255, 255), (159, 182, 205)) screen.blit(text, (0, 0)) pygame.display.flip() def _event_loop(self): """ The main event loop. """ while self.__run_event: event = pygame.event.poll() # Handle Game Quit Message if event.type == pygame.QUIT: self.__run_event = False # No-Op sent, draw if set to always draw elif event.type == pygame.NOEVENT: # Tick even if not drawing # We want to pause the cpu from getting into a # 100% usage looping on the poll until something # becomes dirty self.__tick_time += self.clock.tick(self.__fps_cap) if self.__always_draw or self.__dirty: self.__dirty = False self._draw(self.__tick_time) self.__tick_time = 0 # Handle User event Timers elif event.type >= pygame.USEREVENT and \ event.type < pygame.NUMEVENTS: timer_id = event.type - pygame.USEREVENT # Call timer str_rep = str(self.__active_event_timers[timer_id]) start = time() self.__active_event_timers[timer_id]() self.__timer_time[str_rep] += time() - start self.__timer_calls[str_rep] += 1 # Check if we should activate the console elif event.type == pygame.KEYDOWN and event.key == pygame.K_w \ and pygame.key.get_mods() & pygame.KMOD_CTRL: self.console.set_active() self.set_dirty() # Pass event to console elif self.console.process_input(event): self.set_dirty() # Pass events to all others else: # Make a copy first so that adding events don't get fired # right away list_cp = self.__event_cb[:] # Reverse list so that newest stuff is on top # TODO: cache this list list_cp.reverse() for cb in list_cp: # Fire the event for all in cb and stop # if the callback returns True start = time() retur_val = cb(event) self.__event_time[str(cb)] += time() - start self.__event_calls[str(cb)] += 1 if retur_val: break def stop_event_loop(self): """ Sends a pygame.QUIT event into the event queue which exits the event loop """ pygame.event.post(pygame.event.Event(pygame.QUIT)) def add_event_callback(self, cb): """ Adds event callback to the event callback stack @param cb: Callback to be added to the stack when events are fired. """ self.__event_time[str(cb)] = 0 self.__event_calls[str(cb)] = 0 self.__event_cb.append(cb) def remove_event_callback(self, cb): """ Removes an event from the event callback stack @param cb: The callback to remove from the event callback stack @return: Returns true if successful in removing callback """ try: self.__event_cb.remove(cb) return True except: return False def list_event_callbacks(self): """ Returns a string representation of all events registered with the game engine """ event_callbacks = "Event Listeners:\n" for eventlst in self.__event_cb: event_callbacks = "%s\t%s\n" % (event_callbacks, str(eventlst)) return event_callbacks def list_event_time(self): """ Returns a string representation of the time the game spends in each event callback. """ mystr = "Event Times:\n\tName\tCalls\tTotal Time\tAvg" for key in self.__event_time: event_times = self.__event_time[key] event_calls = self.__event_calls[key] if event_calls == 0: avg = 0 else: avg = event_times / event_calls mystr = "%s\n\t%s\n\t\t%d\t%f\t%f" % \ (mystr, key, event_calls, event_times, avg) return mystr def add_draw_callback(self, fnc): """ Adds a callback to the draw list. Function will be passed the game screen it should draw too. @param fnc: The function to call when system is drawing """ self.__draw_time[str(fnc)] = 0 self.__draw_calls[str(fnc)] = 0 self.__draw_lst.append(fnc) def pop_draw_callback(self): """ Removes top of draw stack and returns it @return: Returns the top callback function that was removed """ return self.__draw_lst.pop() def clear_draw_callback(self): """ Empties draw callback stack """ self.__draw_lst = [] def remove_draw_callback(self, fnc): """ Removes a draw callback from the game engine draw function @param fnc: The callback function to remove @return: Returns true if successful removal of the function """ try: self.__draw_lst.remove(fnc) return True except: return False def list_draw_callbacks(self): """ Lists all the draw callbacks currently registered with the game engine """ callbacks = "Draw Callbacks:\n" for eventlst in self.__draw_lst: callbacks += "\t%s\n" % str(eventlst) return callbacks def list_draw_time(self): """ Returns a string representation of the time the game spends in each drawing callback. """ mystr = "Drawing Times:\n\tName\tCalls\tTotal Time\tAvg" for key in self.__draw_time: draw_times = self.__draw_time[key] draw_calls = self.__draw_calls[key] if draw_calls == 0: avg = 0 else: avg = draw_times / draw_calls mystr = "%s\n\t%s\n\t\t%d\t%f\t%f" % \ (mystr, key, draw_calls, draw_times, avg) return mystr def has_object(self, name): """ Returns true if object is stored in game engine @param name: Name of the object to check if exists @return: Returns true if object found """ return name in self.__object_hold def add_object(self, name, obj): """ Adds an object to the game engine datastore @param name: The name used to store the object @param obj: The object to store """ self.__object_hold[name] = obj def get_object(self, name): """ Returns an object from the game engine datastore @param name: The name of object to return @return: Returns the object """ return self.__object_hold[name] def remove_object(self, name): """ Removes an object from the game engine datastore @param name: The name of the object to remove """ del self.__object_hold[name] def list_objects(self): """ Returns a sting of registered objects """ objlist = "Objects Registered:\n" for eventlst in self.__object_hold: objlist += "\t%s\n" % str(eventlst) return objlist def toggle_fps(self): """ Toggles fps display """ self.__showfps = not self.__showfps def art_scale(self, original, expected, width=True): if width: return int(self.width / float(expected) * float(original)) else: return int(self.height / float(expected) * float(original))
def draw(self): Scene.draw(self) self.sprite.draw()
class App: def __init__(self, debug_mode=True): pyxel.init(200, 200, caption="ADV") pyxel.mouse(visible=True) pyxel.load("../asset.pyxres") self.debug_mode = debug_mode messages = self.get_messages() self.scene = Scene(messages, debug_mode=self.debug_mode) pyxel.run(self.update, self.draw) def update(self): if pyxel.btnp(pyxel.KEY_Q): pyxel.quit() if self.scene.flags["clear"]: return self.scene.update() if pyxel.btnp(pyxel.MOUSE_RIGHT_BUTTON): self.scene.click_mouse() def draw(self): self.draw_back_ground() self.scene.draw() self.debug_info() def draw_back_ground(self): pyxel.cls(15) h = pyxel.height / 5 pyxel.rect(0, 4 * h, pyxel.width, h, 4) pyxel.text(125, 80, "\ Escape here! /", 0) pyxel.text(20, 20, "Right click to check.", 0) def get_messages(self): messages = [] def draw_chest(): pyxel.blt(x=30, y=136, img=0, u=0, v=32, w=48, h=24, colkey=7) m = Message(x=30, y=136, h=24, w=48, scene_name="room1", flag_name=f"chest", precondition_name=None, draw_function=draw_chest, text=f"You open the chest.\nNothing in it.") messages.append(m) def draw_potion(): pyxel.blt(x=40, y=128, img=0, u=8, v=16, w=8, h=8, colkey=7) m = Message(x=40, y=128, h=8, w=8, scene_name="room1", flag_name=f"portion", precondition_name=None, draw_function=draw_potion, text=f"This is a portion.\nIt smells bad...") messages.append(m) def draw_meat(): pyxel.blt(x=60, y=128, img=0, u=24, v=8, w=8, h=8, colkey=7) m = Message(x=60, y=128, h=8, w=8, scene_name="room1", flag_name=f"meat", precondition_name=None, draw_function=draw_meat, text=f"This is a meat.\nYou eat it.\nA key is in it.") messages.append(m) def draw_door(): x, y = 130, 90 w, h = 50, 70 pyxel.rect(x, y, w, h, 12) pyxel.rect(x + 5, y + 5, w - 10, h // 2 - 10, 13) pyxel.rectb(x + 5, y + 5, w - 10, h // 2 - 10, 5) pyxel.rect(x + 5, y + h // 2 + 5, w - 10, h // 2 - 10, 13) pyxel.rectb(x + 5, y + h // 2 + 5, w - 10, h // 2 - 10, 5) pyxel.circ(x + 3 * w // 4, y + h // 2, 2, 9) m = Message(x=130, y=90, h=70, w=50, scene_name="room1", flag_name=f"clear", precondition_name=f"meat", draw_function=draw_door, text=f"You unlock the door.\nWell done!\n\"Q\" to quit.") messages.append(m) return messages def debug_info(self): if not self.debug_mode: return info = f"mouse x:{pyxel.mouse_x:.1f}, y:{pyxel.mouse_y:.1f}" pyxel.text(0, 0, info, 7)
def loop(self): pygame.mixer.music.play(-1) while self.is_running: # HUD start_button = Button(0, 30, path_buttonStart) ok_button = Button(0, 30, path_buttonOk) game_name = Button(0, 250, path_gameName) start_text = Button(0, 100, path_textStart) end_text = Button(0, 100, path_textEnd) # Playground player = Player(-150, 0, 51, 36) bg = Scene(path_bg, 0, 100, 864, 768) ground = Scene(path_ground, 0, -368, 900, 168) pipe_group = [] last_pipe = pygame.time.get_ticks() - pipe_frequency restart = False self.game_over = False self.flying = False self.hit_played = False game_name.active = True start_button.active = True start_text.active = True end_text.active = False ok_button.active = False self.score = 0 # ======= # In-game while (not self.game_over or not restart) and self.is_running: # ======= # Events is_flying = False for event in pygame.event.get(): if event.type == QUIT: self.is_running = False if event.type == KEYDOWN: if self.game_over: restart = True is_flying = is_flying | event.key == K_UP if event.type == MOUSEBUTTONDOWN: if self.game_over: restart = ok_button.isHovered() is_flying = is_flying | pygame.mouse.get_pressed(3)[0] is_flying = is_flying & start_button.isHovered() if is_flying and not self.flying and not self.game_over: self.flying = True start_button.active = False start_text.active = False game_name.active = False # ======================= # Controller player.move_handling(self.flying, self.game_over, self.flap_sound) # ============== # Pipes handing if self.flying is True and self.game_over is False: # Pipe random generation time_now = pygame.time.get_ticks() if time_now - last_pipe > pipe_frequency: pipe_height = random.randint(-150, 250) btm_pipe = Pipe(display[0], pipe_height, 78, 568, False) top_pipe = Pipe(display[0], pipe_height, 78, 568, True) pipe_group.append(btm_pipe) pipe_group.append(top_pipe) last_pipe = time_now # Delete out of screen pipes if pipe_group[0].x < -350: pipe_group.pop(0) # Scrolling pipes for i in range(0, len(pipe_group)): pipe_group[i].scrolling() # ================ # Check collision for i in range(0, len(pipe_group)): if check_collision(player, pipe_group[i]): self.game_over = True if player.y >= 425: self.game_over = True if player.y <= -270: self.game_over = True self.flying = False if self.game_over: end_text.active = True ok_button.active = True # ============ # Check score if len(pipe_group) > 0: if player.x - player.width / 2 > pipe_group[0].x - pipe_group[0].width / 2 and \ player.x + player.width / 2 < pipe_group[0].x + pipe_group[0].width / 2 and \ self.pass_pipe is False: self.pass_pipe = True if self.pass_pipe is True: if player.x - player.width / 2 > pipe_group[0].x + pipe_group[0].width / 2: self.score += 1 self.score_sound.play() self.pass_pipe = False # ===================== # Scrolling the ground if not self.game_over: ground.scrolling() # ======= # Sounds if self.game_over is True: if self.hit_played is False: self.hit_sound.play() self.die_sound.play() self.hit_played = True # ======= # Render glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glUseProgram(shader.program) bg.draw() for i in range(0, len(pipe_group)): pipe_group[i].draw() ground.draw() player.draw() # Draw Menu game_name.draw() start_button.draw() start_text.draw() end_text.draw() ok_button.draw() # Draw Score i = 0 numbers = list(str(self.score)) length_numbers = len(numbers) for number in numbers: path_button_score = "Textures/" + number + ".png" score_text = Scene(path_button_score, 0 - (length_numbers - 1) * 25 + i * 40, 350, 36, 54) score_text.draw() i = i + 1 glUseProgram(0) pygame.display.flip() self.timer.tick(fps)
def main(): # 游戏程序初始化 pygame.init() screen = pygame.display.set_mode((Width, Height)) pygame.display.set_caption("梦の彼方") ico = pygame.image.load(icon_img).convert_alpha() pygame.display.set_icon(ico) Clock = pygame.time.Clock() # 得分初始化 score = 0 # 载入游戏素材并初始化 Jump_Sound = pygame.mixer.Sound("./music/jump.wav") Jump_Sound.set_volume(10) Die_Sound = pygame.mixer.Sound("./music/die.wav") Die_Sound.set_volume(10) pygame.mixer.init() pygame.mixer.music.load(Background_Music[Music_Count]) # 背景音乐 pygame.mixer.music.set_volume(5) pygame.mixer.music.play(-1) font = pygame.font.Font("./fonts/FZSJ-TXJW.TTF", 30) # 角色、背景、障碍物实例化 dinosaur = Dinosaur(Width, Height) scene = Scene(speed, Width, Height) plants = pygame.sprite.Group() pteras = pygame.sprite.Group() # 产生障碍物事件 GenPlantEvent = pygame.constants.USEREVENT + 0 pygame.time.set_timer(GenPlantEvent, 2300) GenPteraEvent = pygame.constants.USEREVENT + 1 pygame.time.set_timer(GenPteraEvent, 5000) # 判断游戏是否结束 Running = True # 判断是否可以产生障碍物 Flag_Plant = False Flag_Ptera = False time0 = time.time() # 主循环 while Running: # 计时 total_time = 0 taken_time = pygame.time.get_ticks() # 获取时间 left_time = total_time * 60000 + taken_time # 毫秒 time_min = left_time // 60000 time_sec = left_time % 60000 // 1000 time_text = str(time_min).zfill(2) + ':' + str(time_sec).zfill(2) time_font = pygame.font.Font("./fonts/FZSJ-TXJW.TTF", 30) time_image = time_font.render("Time:" + time_text, True, (0, 0, 0)) screen.blit(time_image, [600, 10]) # 显示得分 score_text = font.render("Score:" + str(score), 1, (0, 0, 0)) screen.blit(score_text, [30, 10]) Probability_text = font.render("障碍物概率:" + str(Probability_2), 1, (0, 0, 0)) screen.blit(Probability_text, [210, 10]) pygame.display.flip() Clock.tick(60) for event in pygame.event.get(): if event.type == QUIT: sys.exit() pygame.quit() if event.type == GenPlantEvent: Flag_Plant = True if event.type == GenPteraEvent: if score > 5: Flag_Ptera = True # 实现鼠标点击恐龙跳跃 if event.type == MOUSEBUTTONDOWN: dinosaur.is_jumping = True dinosaur.is_jumping = True Jump_Sound.play() # 实现空格恐龙跳跃 key_pressed = pygame.key.get_pressed() if key_pressed[pygame.K_SPACE]: dinosaur.is_jumping = True dinosaur.is_jumping = True Jump_Sound.play() if key_pressed[pygame.K_ESCAPE]: Running = False screen.fill(Background_Colour) Time_Passed = time.time() - time0 time0 = time.time() # 场景 scene.move() scene.draw(screen) # 小恐龙 dinosaur.is_running = True if dinosaur.is_jumping: dinosaur.be_afraid() dinosaur.jump(Time_Passed) dinosaur.draw(screen) # 障碍物——植物 if random.random() < Obstache_Probability(score, Grade) and Flag_Plant: plant = Plant(speed_plants, Width, Height) plants.add(plant) Flag_Plant = False for plant in plants: plant.move() if dinosaur.rect.left > plant.rect.right and not plant.added_score: score += 1 plant.added_score = True if plant.rect.right < 0: plants.remove(plant) continue plant.draw(screen) # 障碍物——翼龙 if random.random() < Obstache_Probability(score, Grade) and Flag_Ptera: if len(pteras) > 5: continue ptera = Ptera(speed_ptera, Width, Height) pteras.add(ptera) Flag_Ptera = False for ptera in pteras: ptera.move() if dinosaur.rect.left > ptera.rect.right and not ptera.added_score: score += 5 ptera.added_score = True if ptera.rect.right < 0: pteras.remove(ptera) continue ptera.draw(screen) Flag_Plant = False # 碰撞检测 if pygame.sprite.spritecollide(dinosaur, plants, False) or pygame.sprite.spritecollide( dinosaur, pteras, False): Die_Sound.play() Running = False res = Show_GameOver(screen, score_text, time_image) return res