class Element(object): exist = True def __init__(self, x_co, y_co, w_co, h_co, vx_co, vy_co, mass, level_co, c_co): """ initialize everything x_co, y_co: the center coordinates. w_co, h_co: the width and height. vx_co, vy_co: speed to 2 coordinates. c_co: coefficient of restitution """ self.w = w_co self.h = h_co self.vx = vx_co self.vy = vy_co self.mylevel = level_co self.graphics = Graphics(self) self.m = mass self.c = c_co self.update(x_co, y_co) self.af = 0.9 def set_exist(self, x): self.exist = x def update(self, x1, y1): """ update the position of element """ self.x = x1 self.y = y1 self.left = self.x - self.w / 2.0 self.right = self.x + self.w / 2.0 self.top = self.y - self.h / 2.0 self.bottom = self.y + self.h / 2.0 def in_inter(self, x, a, b): """ return true when x is inside the interval [a, b] """ assert a <= b, 'Invalid interval' if x >= a and x <= b: return True return False def touch(self, elem): """ return true if the two elements are overlapped by the other """ gapright = self.right - elem.left gapleft = elem.right - self.left gaptop = -self.top + elem.bottom gapbottom = -elem.top + self.bottom if gapleft > 0 and gapright > 0 and gaptop > 0 and gapbottom > 0: if min(gapleft, gapright) < min(gaptop, gapbottom): #collision horizontal if gapleft < gapright: return 3 else: return 1 else: #collision vertical if gaptop < gapbottom: return 2 else: return 4 else: return 0 def touch_ammount(self, elem): gapright = self.right - elem.left gapleft = elem.right - self.left gaptop = -self.top + elem.bottom gapbottom = -elem.top + self.bottom direction = self.touch(elem) if direction == 0: return 0 elif direction == 1: return gapright elif direction == 2: return gaptop elif direction == 3: return gapleft elif direction == 4: return gapbottom else: assert False, "invalid direction" def move(self, elem): """ move something out of another element under the presumption that those two elements are overlapped return nothing """ direction = self.touch(elem) ammount = self.touch_ammount(elem) if direction == 0: return elif direction == 1: elem.x += ammount elif direction == 2: elem.y -= ammount elif direction == 3: elem.x -= ammount elif direction == 4: elem.y += ammount else: assert False, "invalid direction" elem.update(elem.x, elem.y) def phy_for(self, va, vb, ma, mb, coef): """ take in objects a and b's speed and mass and return the speed for object b coef is the coefficient of restitution which is the average of the c of two elements """ v = (coef * ma * (va - vb) + ma * va + mb * vb) / (ma + mb) return v def collide(self, elem): """ modify the other element's speed; return nothing """ direction = self.touch(elem) coef = (self.c + elem.c) / 2 if direction == 1 or direction == 3: if elem.vy > 0: elem.vy = max(0, elem.vy - self.af * abs(elem.vx)) else: elem.vy = min(0, elem.vy + self.af * abs(elem.vx)) elem.vx = self.phy_for(self.vx, elem.vx, self.m, elem.m, coef) elif direction == 2 or direction == 4: if elem.vx > 0: elem.vx = max(0, elem.vx - self.af * abs(elem.vy)) else: elem.vx = min(0, elem.vx + self.af * abs(elem.vy)) elem.vy = self.phy_for(self.vy, elem.vy, self.m, elem.m, coef) else: return """ elem.vx = elem.vy = 0""" def sim(self, time): """ simulate the element move in the certain direction for certain time. REMEMBER TO CHECK! """ self.vy += self.mylevel.g * time x1 = self.x + time * self.vx y1 = self.y + time * self.vy self.update(x1, y1) def within_screen(self, scr_left, scr_right, scr_top, scr_bot): """ return True if the element is in screen; False otherwise. scr_left: the left bound of the screen scr_right: the right bound of the screen """ #TODO: Fixme return True def draw(self, screen, x, y, w, h): """ convey the arguments x and y to graphics function to draw things. """ self.graphics.draw(screen, x, y, w, h)
def update(): FPS._current_frames += 1 FPS._previous_time = FPS._current_time FPS._current_time = time.time() FPS._delta_time = FPS._current_time - FPS._previous_time FPS._last_update += FPS._delta_time if FPS._last_update >= 1: FPS._current_fps = FPS._current_frames FPS._current_frames = 0 FPS._last_update = 0 FPS._surface = FPS._font.render("FPS: " + str(FPS._current_fps), 1, System.Color.WHITE) FPS._outline_surface = \ FPS._font.render("FPS: " + str(FPS._current_fps), 1, System.Color.BLACK) FPS._surface_rect = FPS._surface.get_rect() FPS._surface_rect.move_ip(Graphics.get_resolution()[0] / 2, 15) FPS._outline_surface_rect = FPS._surface.get_rect() # Draws an outline for the FPS Graphics.draw(FPS._outline_surface, pygame.Rect(FPS._surface_rect.x + 1, FPS._surface_rect.y, FPS._surface_rect.width, FPS._surface_rect.height)) Graphics.draw(FPS._outline_surface, pygame.Rect(FPS._surface_rect.x - 1, FPS._surface_rect.y, FPS._surface_rect.width, FPS._surface_rect.height)) Graphics.draw(FPS._outline_surface, pygame.Rect(FPS._surface_rect.x, FPS._surface_rect.y + 1, FPS._surface_rect.width, FPS._surface_rect.height)) Graphics.draw(FPS._outline_surface, pygame.Rect(FPS._surface_rect.x, FPS._surface_rect.y - 1, FPS._surface_rect.width, FPS._surface_rect.height)) Graphics.draw(FPS._outline_surface, pygame.Rect(FPS._surface_rect.x + 1, FPS._surface_rect.y + 1, FPS._surface_rect.width, FPS._surface_rect.height)) Graphics.draw(FPS._outline_surface, pygame.Rect(FPS._surface_rect.x - 1, FPS._surface_rect.y - 1, FPS._surface_rect.width, FPS._surface_rect.height)) Graphics.draw(FPS._outline_surface, pygame.Rect(FPS._surface_rect.x - 1, FPS._surface_rect.y + 1, FPS._surface_rect.width, FPS._surface_rect.height)) Graphics.draw(FPS._outline_surface, pygame.Rect(FPS._surface_rect.x + 1, FPS._surface_rect.y - 1, FPS._surface_rect.width, FPS._surface_rect.height)) # End of Outline Graphics.draw(FPS._surface, FPS._surface_rect) FPS._clock.tick(System.Display.TARGET_FPS)
def draw(self): if self._nodes_surface_dirty or self._font_surface_dirty or self._debug_surface_dirty: if self._nodes_surface_dirty: self._nodes_surface.fill(System.Color.TRANSPARENT) if self._font_surface_dirty: self._font_surface.fill(System.Color.TRANSPARENT) if self._debug_surface_dirty: self._debug_surface.fill(System.Color.TRANSPARENT) for x in range(0, len(self._search_space.nodes)): for y in range(0, len(self._search_space.nodes[x])): if self._nodes_surface_dirty: node_surface = pygame.Surface( (System.Graph.NODE_WIDTH, System.Graph.NODE_HEIGHT)) self._search_space.nodes[x][y].update_surface_color( self._search_space.open_list, self._search_space.closed_list, self._search_space.start_node, self._search_space.end_node) node_surface.fill(self._search_space.nodes[x][y].surface_color) self._nodes_surface.blit( node_surface, self._search_space.nodes[x][y].surface_rect) if self._debug_surface_dirty \ and self._search_space.nodes[x][y].parent_node is not None: pygame.draw.line( self._debug_surface, System.Color.BLACK, (self._search_space.nodes[x][y].surface_rect.x + (self._search_space.nodes[x][y].surface_rect.width / 2), self._search_space.nodes[x][y].surface_rect.y + (self._search_space.nodes[x][y].surface_rect.height / 2)), (self._search_space.nodes[x][y].parent_node.surface_rect.x + (self._search_space.nodes[x][y].parent_node.surface_rect.width / 2), self._search_space.nodes[x][y].parent_node.surface_rect.y + (self._search_space.nodes[x][y].parent_node.surface_rect.height / 2) )) if self._font_surface_dirty and self._search_space.nodes[x][y].traversable: text_color = \ System.Color.BLACK \ if self._search_space.nodes[x][y] in self._search_space.open_list \ else System.Color.LIGHT_GREY h_text_surface = self._font.render( 'H: ' + str(self._search_space.nodes[x][y].h_score), 1, text_color) h_text_surface_rect = h_text_surface.get_rect() h_text_surface_rect = ( self._search_space.nodes[x][y].surface_rect.x + self._search_space.nodes[x][y].surface_rect.width - h_text_surface_rect.width, self._search_space.nodes[x][y].surface_rect.y + self._search_space.nodes[x][y].surface_rect.height - h_text_surface_rect.height) g_text_surface = self._font.render( 'G: ' + str(self._search_space.nodes[x][y].g_score), 1, text_color) g_text_surface_rect = h_text_surface.get_rect() g_text_surface_rect = ( self._search_space.nodes[x][y].surface_rect.x, self._search_space.nodes[x][y].surface_rect.y + self._search_space.nodes[x][y].surface_rect.height - g_text_surface_rect.height) f_text_surface = self._font.render( 'F: ' + str(self._search_space.nodes[x][y].f_score), 1, text_color) f_text_surface_rect = self._search_space.nodes[x][y].surface_rect self._font_surface.blit(h_text_surface, h_text_surface_rect) self._font_surface.blit(g_text_surface, g_text_surface_rect) self._font_surface.blit(f_text_surface, f_text_surface_rect) if self._nodes_surface_dirty and not self._display_help: direction_list = [(1, 0), (0, 1), (-1, 0), (0, -1), (1, 1), (-1, -1), (1, -1), (-1, 1), (0, 0)] i = 0 for direction in direction_list: temp_text = self._help_font.render( 'F1 = Help', 1, System.Color.WHITE if i == len(direction_list) - 1 else System.Color.BLACK) temp_text_rect = temp_text.get_rect() temp_text_rect.x += direction[0] temp_text_rect.y += direction[1] self._nodes_surface.blit(temp_text, temp_text_rect) i += 1 if self._debug_surface_dirty: current_path_node = self._search_space.end_node while current_path_node.parent_node is not None: pygame.draw.line( self._debug_surface, System.Color.DARK_GREEN, ( current_path_node.surface_rect.x + (current_path_node.surface_rect.width / 2), current_path_node.surface_rect.y + (current_path_node.surface_rect.height / 2)), ( current_path_node.parent_node.surface_rect.x + (current_path_node.parent_node.surface_rect.width / 2), current_path_node.parent_node.surface_rect.y + (current_path_node.parent_node.surface_rect.height / 2)), 5) current_path_node = current_path_node.parent_node self._nodes_surface_dirty = False self._font_surface_dirty = False self._debug_surface_dirty = False Graphics.draw(self._nodes_surface, self._nodes_surface_rect) if self._display_debug: Graphics.draw(self._debug_surface, self._debug_surface_rect) if self._display_text: Graphics.draw(self._font_surface, self._font_surface_rect) if self._display_help: Graphics.draw(self._help_surface, self._help_surface_rect) if self._paused: Graphics.draw(self._pause_surface, self._pause_surface_rect)
class GameEngine: def __init__(self): self.is_running = False self.is_alive = False self.is_train = False self.is_human = True self.__hero = Hero() self.__score = 0 self.__action_queue = [] self.__width = WIDTH self.__height = HEIGHT self.__clock = None self.__environment = None self.screen = pg.display.set_mode((self.__width, self.__height)) pg.init() self.__graphics = Graphics(self.screen) self.menu = GameMenu(self, self.screen) @staticmethod def off_screen(): pg.display.iconify() def setup(self): self.is_running = True self.is_alive = True self.__action_queue = [] self.__score = 0 self.__hero = Hero() self.__environment = Environment() self.__environment.create_level() self.__clock = pg.time.Clock() def __key_checker(self, event): if not self.is_train: if event.type == pg.KEYDOWN: if event.key == pg.K_ESCAPE: self.menu.pause_menu() elif event.key == pg.K_SPACE: if not self.is_alive: self.menu.start_menu() elif 'jump' not in self.__action_queue: self.__action_queue.append('jump') elif event.key == pg.K_LCTRL: if 'sit' not in self.__action_queue: self.__action_queue.append('sit') elif event.type == pg.KEYUP: if event.key == pg.K_SPACE: if 'jump' in self.__action_queue: self.__action_queue.remove('jump') elif event.key == pg.K_LCTRL: if 'sit' in self.__action_queue: self.__action_queue.remove('sit') def get_action_from_key_check(self): if len(self.__action_queue) == 0: return 'nothing' else: return self.__action_queue[0] def __collision_check(self): collision_logic = CollisionLogic() current_prop = self.__environment.prop_list[0] if collision_logic.check_collision(self.__hero, current_prop): self.is_alive = False def get_state(self): cur_prop = self.__environment.prop_list[0] hero_y = self.__hero.coord[1] hero_x_size, hero_y_size = self.__hero.size hero_r_u_x = hero_x_size hero_r_u_y = hero_y + hero_y_size hero_vel_y = self.__hero.vel[1] hero_acc_y = self.__hero.acc[1] prop_x, prop_y = cur_prop.coord prop_x_size, prop_y_size = cur_prop.size prop_r_u_x = prop_x + prop_x_size prop_r_u_y = prop_y + prop_y_size prop_vel_x = cur_prop.vel[0] hero_y /= self.__height hero_r_u_x /= self.__width hero_r_u_y /= self.__height hero_vel_y /= MAX_VEL hero_acc_y /= MAX_ACC prop_x /= self.__width prop_y /= self.__height prop_r_u_x /= self.__width prop_r_u_y /= self.__height prop_vel_x /= MAX_VEL result = [ hero_y, hero_r_u_x, hero_r_u_y, hero_vel_y, hero_acc_y, prop_x, prop_y, prop_r_u_x, prop_r_u_y, prop_vel_x ] return result def get_all_info(self): next_state = self.get_state() reward = 1 done = not self.is_alive return next_state, reward, done def render(self): self.__clock.tick(FPS) for event in pg.event.get(): if event.type == pg.QUIT: exit(0) else: self.__key_checker(event) if not self.is_alive: finished = self.__graphics.draw_wasted_screen() if finished: self.menu.start_menu() else: visible_obj = self.__environment.prop_list self.__graphics.draw(self.__hero, visible_obj, self.__score, STANDARD_MODE) pg.display.update() def step(self, action): self.__score += 1 self.__collision_check() self.__hero.change_state(action) self.__hero.update() self.__environment.update()
class Element(object): exist = True def __init__(self, x_co, y_co, w_co, h_co, vx_co, vy_co, mass, level_co, c_co): """ initialize everything x_co, y_co: the center coordinates. w_co, h_co: the width and height. vx_co, vy_co: speed to 2 coordinates. c_co: coefficient of restitution """ self.w = w_co self.h = h_co self.vx = vx_co self.vy = vy_co self.mylevel = level_co self.graphics = Graphics(self) self.m = mass self.c = c_co self.update(x_co, y_co) self.af = 0.9 def set_exist(self, x): self.exist = x def update(self, x1, y1): """ update the position of element """ self.x = x1 self.y = y1 self.left = self.x - self.w/2.0 self.right = self.x + self.w/2.0 self.top = self.y - self.h/2.0 self.bottom = self.y + self.h/2.0 def in_inter(self, x, a, b): """ return true when x is inside the interval [a, b] """ assert a <= b, 'Invalid interval' if x >= a and x <= b: return True return False def touch(self, elem): """ return true if the two elements are overlapped by the other """ gapright = self.right - elem.left gapleft = elem.right - self.left gaptop = -self.top + elem.bottom gapbottom = -elem.top + self.bottom if gapleft > 0 and gapright > 0 and gaptop > 0 and gapbottom > 0: if min(gapleft, gapright) < min(gaptop, gapbottom): #collision horizontal if gapleft < gapright: return 3 else: return 1 else: #collision vertical if gaptop < gapbottom: return 2 else: return 4 else: return 0 def touch_ammount(self, elem): gapright = self.right - elem.left gapleft = elem.right - self.left gaptop = -self.top + elem.bottom gapbottom = -elem.top + self.bottom direction = self.touch(elem) if direction == 0: return 0 elif direction == 1: return gapright elif direction == 2: return gaptop elif direction == 3: return gapleft elif direction == 4: return gapbottom else: assert False, "invalid direction" def move(self, elem): """ move something out of another element under the presumption that those two elements are overlapped return nothing """ direction = self.touch(elem) ammount = self.touch_ammount(elem) if direction == 0: return elif direction == 1: elem.x += ammount elif direction == 2: elem.y -= ammount elif direction == 3: elem.x -= ammount elif direction == 4: elem.y += ammount else: assert False, "invalid direction" elem.update(elem.x, elem.y) def phy_for(self, va, vb, ma, mb, coef): """ take in objects a and b's speed and mass and return the speed for object b coef is the coefficient of restitution which is the average of the c of two elements """ v = (coef * ma * (va - vb) + ma * va + mb * vb) / (ma + mb) return v def collide(self, elem): """ modify the other element's speed; return nothing """ direction = self.touch(elem) coef = (self.c + elem.c)/2 if direction == 1 or direction == 3: if elem.vy > 0: elem.vy = max(0, elem.vy - self.af * abs(elem.vx)) else: elem.vy = min(0, elem.vy + self.af * abs(elem.vx)) elem.vx = self.phy_for(self.vx, elem.vx, self.m, elem.m, coef) elif direction == 2 or direction == 4: if elem.vx > 0: elem.vx = max(0, elem.vx - self.af * abs(elem.vy)) else: elem.vx = min(0, elem.vx + self.af * abs(elem.vy)) elem.vy = self.phy_for(self.vy, elem.vy, self.m, elem.m, coef) else: return """ elem.vx = elem.vy = 0""" def sim(self, time): """ simulate the element move in the certain direction for certain time. REMEMBER TO CHECK! """ self.vy += self.mylevel.g * time x1 = self.x + time * self.vx y1 = self.y + time * self.vy self.update(x1, y1) def within_screen(self, scr_left, scr_right, scr_top, scr_bot): """ return True if the element is in screen; False otherwise. scr_left: the left bound of the screen scr_right: the right bound of the screen """ #TODO: Fixme return True def draw(self, screen, x, y, w, h): """ convey the arguments x and y to graphics function to draw things. """ self.graphics.draw(screen, x, y, w, h)
class Game: """A class for starting a game of Minesweeper.""" SAVES_PATH = "./Saves/" SAVE_FILE = SAVES_PATH + "minefield.save" def __init__(self, screen): """ Constructs an instance of Game and returns it. screen: a standard screen object from the curses library. """ # Create a Graphics class to handle drawing. self.graphics = Graphics(screen) # The last valid input by the user. self.last_valid_command = "" # Controls the game loop. self.running = True # Current scene. self.scene = None def start(self): """Starts the game loop at the menu scene.""" self.change_scene(sm.mk_MenuScene(self)) self.loop() def loop(self): """Main game loop.""" while self.running: self.scene.loop() def change_scene(self, scene, command=""): """Sets the next scene.""" self.scene = scene if command == "": command = scene.first_command self.last_valid_command = command def stop(self): """Stops the game loop.""" self.running = False def get_input(self, message="", show_default=True, repeat=chr(10)): """ Gets a one-character input from the user and returns it. A message and a default response are also drawn to the screen.The default response is returned if the user inputs the enter key. message: a string displayed before requesting user input. show_default: shows the default response if True. return: a character input. """ x = 0 y = self.graphics.HEIGHT-1 if show_default: input = "{} ({})".format(message, self.last_valid_command) else: input = message self.graphics.draw(x, y, input) key = self.graphics.get_input() if key == repeat: return self.last_valid_command return key