From 25f27ed5e939252d4e504ecb84ca8a981504f861 Mon Sep 17 00:00:00 2001 From: Miguel Angel Astor Romero Date: Mon, 21 Jan 2013 18:02:02 -0430 Subject: [PATCH] Added the OmnidirectionalActor class. --- actor.py | 77 ++++++++++++++++++++++++++++++++++++++++++++++++--- ingame.py | 52 ++++++++++++++++++++++++++-------- math_utils.py | 21 ++++++++++++++ 3 files changed, 134 insertions(+), 16 deletions(-) diff --git a/actor.py b/actor.py index 135f055..0496f3a 100644 --- a/actor.py +++ b/actor.py @@ -208,7 +208,7 @@ class BulletActor(BaseActor): self.now = pygame.time.get_ticks() delta_t = self.now - self.then if delta_t < 0: - delta_t = 0 # Compensatefor overflow of self.now + delta_t = 0 # Compensate for overflow of self.now if game.DEBUG: print @@ -221,11 +221,80 @@ class BulletActor(BaseActor): print "NEW VEL Y: " + str((self.velocity[1] * delta_t) * (self.frame_rate / 1000)) self.position[0] += (self.velocity[0] * delta_t) * (self.frame_rate / 1000) self.position[1] += (self.velocity[1] * delta_t) * (self.frame_rate / 1000) - self.rect.center = (self.position[0], self.position[1]) + self.rect.center = (self.position[0], self.position[1]) if game.DEBUG: print "NEW POSITION: " + str(self.position) - # TODO: Update animation frame if any. - self.then = self.now + +class OmnidirectionalActor(BaseActor): + def __init__(self, id, image, name = "Default", animated = False, visible = True, solid = True, frame_rate = 60.0): + BaseActor.__init__(self, id, image, name, animated, visible, solid) + + self.angle = 0.0 + self.then = pygame.time.get_ticks() + self.frame_rate = frame_rate + self.moving = False + + self.friction = 0.90 + + self.constraint_min_x = 0 + self.constraint_min_y = 0 + self.constraint_max_x = 1024 + self.constraint_max_y = 768 + + def is_moving(self): + return self.moving + + def move(self): + self.moving = True + + def stop(self): + self.moving = False + + def get_angle(self): + return self.angle + + def set_angle(self, angle): + self.angle = float(angle) + + def set_constraints(self, constraints): + self.constraint_min_x = constraints[0] + self.constraint_min_y = constraints[2] + self.constraint_max_x = constraints[1] + self.constraint_max_y = constraints[3] + + def reset_then(self): + self.then = pygame.time.get_ticks() + + def update(self): + now = pygame.time.get_ticks() + delta_t = now - self.then + if delta_t < 0: + delta_t = 0 # Compensate for overflow of now + + if self.moving: + direction = math_utils.angle_to_vector(self.angle) + + self.velocity[0] += direction[0] * 0.9 + self.velocity[1] += direction[1] * 0.9 + + self.position[0] += (self.velocity[0] * delta_t) * (self.frame_rate / 1000) + self.position[1] += (self.velocity[1] * delta_t) * (self.frame_rate / 1000) + + if self.position[0] < self.constraint_min_x: + self.position[0] = self.constraint_min_x + if self.position[0] > self.constraint_max_x: + self.position[0] = self.constraint_max_x + if self.position[1] < self.constraint_min_y: + self.position[1] = self.constraint_min_y + if self.position[1] > self.constraint_max_y: + self.position[1] = self.constraint_max_y + + self.velocity[0] *= self.friction + self.velocity[1] *= self.friction + + self.rect.center = (self.position[0], self.position[1]) + + self.then = now diff --git a/ingame.py b/ingame.py index 48aa825..ae8ed05 100644 --- a/ingame.py +++ b/ingame.py @@ -9,6 +9,7 @@ try: except ImportError: android = None +import math_utils import player import background import imloader @@ -21,7 +22,7 @@ class InGameState(BaseState): self.background_color = (125, 158, 192) - self.next_transition = VALID_STATES['STAY'] + self.next_transition = VALID_STATES['SCORE'] self.cursor_x = 0 self.cursor_y = 0 self.user_click = False @@ -30,15 +31,22 @@ class InGameState(BaseState): self.bckg_y = 0 play_img = imloader.cached_image_loader.get_image_to_screen_percent('gfx/Player/player_idle_front.png') - self.player = actor.BaseActor(0, play_img, "Player", False) + self.player = actor.OmnidirectionalActor(0, play_img, "Player", False) + self.player.set_angle(90) + self.player.set_velocity([0, 0]) # Create a surface for the background. bg_w = int(float(pygame.display.Info().current_w * 1280) / 1024.0) bg_h = int(float(pygame.display.Info().current_h * 1024) / 768.0) self.background = pygame.Surface((bg_w, bg_h)) + self.game_area = pygame.Surface((bg_w, bg_h)) # Center the player. self.player.set_position([bg_w // 2, bg_h // 2]) + constraints = [int((95.0 * float(pygame.display.Info().current_w)) / 1024.0), + bg_w - int((95.0 * float(pygame.display.Info().current_w)) / 1024.0), + int((155.0 * float(pygame.display.Info().current_h)) / 768.0), + bg_h - int((155.0 * float(pygame.display.Info().current_h)) / 768.0)] # Create the floor. floor = background.TiledBackground(bg_w, bg_h, 'gfx/piso.png') @@ -70,9 +78,16 @@ class InGameState(BaseState): # Center the view on the player p_pos = self.player.get_position() - (dist_x, dist_y) = (math.fabs(self.screen_center[0] - p_pos[0]), math.fabs(self.screen_center[0] - p_pos[0])) + (dist_x, dist_y) = (math.fabs(self.screen_center[0] - p_pos[0]), math.fabs(self.screen_center[1] - p_pos[1])) self.bckg_x -= dist_x self.bckg_y -= dist_y + + self.player.set_constraints(constraints) + + self.cursor_x = self.screen_center[0] + self.cursor_y = self.screen_center[1] + self.vec_1 = (float(pygame.display.Info().current_w) - float(self.screen_center[0]), 0.0) + self.vec_1 = math_utils.normalize_vector_2D(self.vec_1) def input(self): for event in pygame.event.get(): @@ -87,22 +102,36 @@ class InGameState(BaseState): if event.type == pygame.QUIT: self.next_transition = VALID_STATES['QUIT'] - # Catch the position of a mouse click (or tap). if event.type == pygame.MOUSEBUTTONDOWN: - (self.cursor_x, self.cursor_y) = event.pos self.user_click = True + self.player.move() + + if event.type == pygame.MOUSEBUTTONUP: + self.user_click = False + self.player.stop() + + if self.user_click: + (self.cursor_x, self.cursor_y) = pygame.mouse.get_pos() def update(self): if self.next_transition != VALID_STATES['QUIT']: if self.next_transition != VALID_STATES['STAY']: self.next_transition = VALID_STATES['STAY'] + self.player.reset_then() + + if self.cursor_x != self.screen_center[0] or self.cursor_y != self.screen_center[1]: + vec_2 = (float(self.cursor_x) - float(self.screen_center[0]), float(self.cursor_y) - float(self.screen_center[1])) + vec_2 = math_utils.normalize_vector_2D(vec_2) + self.player.set_angle(math_utils.angle_vectors_2D(self.vec_1, vec_2)) + + self.player.update() # Reset the view. self.bckg_x = 0 self.bckg_y = 0 # Get the manhattan distance between the screen center and the player. p_pos = self.player.get_position() - (dist_x, dist_y) = (math.fabs(self.screen_center[0] - p_pos[0]), math.fabs(self.screen_center[0] - p_pos[0])) + (dist_x, dist_y) = (math.fabs(self.screen_center[0] - p_pos[0]), math.fabs(self.screen_center[1] - p_pos[1])) # Center the view on the player. self.bckg_x -= dist_x self.bckg_y -= dist_y @@ -117,16 +146,15 @@ class InGameState(BaseState): if self.bckg_x + self.background.get_width() < pygame.display.Info().current_w: self.bckg_x += pygame.display.Info().current_w - (self.bckg_x + self.background.get_width()) - #if self.user_click: - # self.next_transition = VALID_STATES['SCORE'] - # self.user_click = False + self.cursor_x = self.screen_center[0] + self.cursor_y = self.screen_center[1] return self.next_transition def render(self, canvas): - canvas.fill(self.background_color) + self.game_area.blit(self.background, (0, 0)) # Blit everything to the bacground. - self.player.draw(self.background) + self.player.draw(self.game_area) - canvas.blit(self.background, (self.bckg_x, self.bckg_y)) + canvas.blit(self.game_area, (self.bckg_x, self.bckg_y)) diff --git a/math_utils.py b/math_utils.py index 1116035..c1925d8 100644 --- a/math_utils.py +++ b/math_utils.py @@ -3,5 +3,26 @@ ########################################### import math +PI = 3.14159 + def angle_to_vector(angle): return [math.cos(angle), math.sin(angle)] + +def normalize_vector_2D(vec): + norm = norm2_2D(vec) + return (vec[0] / norm, vec[1] / norm) + +def dot_product_2D(vec1, vec2): + return (vec1[0] * vec2[0]) + (vec1[1] * vec2[1]) + +def norm2_2D(vec): + return math.sqrt(dot_product_2D(vec, vec)) + +def angle_vectors_2D(vec1, vec2): + return math.atan2(vec2[1], vec2[0]) - math.atan2(vec1[1], vec1[0]) + +def ang_2_radians(ang): + return ang * (180 / PI) + +def radians_2_ang(rad): + return rad * (PI / 180)