def __init__(self, weapon, speed=300, max_distance=700): rotation = weapon.owner.transform.rotation position = weapon.owner.transform.position point = weapon.bullet_offset + position c = -math.cos(rotation / 57.295) s = -math.sin(rotation / 57.295) # translate point back to origin: point.x -= position.x point.y -= position.y # rotate point xnew = point.x * s - point.y * c ynew = point.x * c + point.y * s # translate point back: point.x = xnew + position.x point.y = ynew + position.y super().__init__(position=point, rotation=rotation, scale=Vector2(1, 1), origin=Vector2(0.5, 0.5)) self.transform.rotation += (random.random() * 2 - 1) * weapon.spread self.damage = weapon.damage self.speed = speed self.max_distance = max_distance self.add_sprite_renderer(sprite=sprite_manager.get('bullet'), sorting_order=2) self.add_collider('bullet', Vector2(50, 50), Vector2(0, 0), True, True)
def __init__(self, owner, damage, spread, bullets, magazine_size, fire_rate, position=Vector2(0, 0), bullet_offset=Vector2(0, 0), bullet_speed=500, bullet_max_distance=700): ''' ''' super().__init__(position=position, scale=Vector2(1, 1), hitbox=Vector2(0, 0)) self.owner = owner self.bullet_offset = bullet_offset self.bullet_speed = bullet_speed self.bullet_max_distance = bullet_max_distance self.damage = damage self.spread = spread self.bullets = bullets - 1 self.magazine_size = magazine_size self.fire_rate = fire_rate self.name = 'unknown' self.can_shoot = True self.reloading = False self._timer = 0
def __init__(self, player, position=Vector2(0, 0), scale=Vector2(1, 1)): ''' :param position (Vector2): the position of this Character :param rotation (int): the rotation of this Character :param scale (Vector2): the scale of this Character :param origin (Vector2): the origin of this Character :param max_health (int): the max health of this Character ''' super().__init__(position=position, scale=scale, hitbox=Vector2(50, 50), max_health=100, damage=20, speed=60, attack_range=100) self.player = player self.add_sprite_renderer(sorting_order=3) self.collider.tag = 'zombie' self.add_animator() self.animator.add_animation('walk', animation_manager.get('zombie_walk')) self.animator.add_animation('attack', animation_manager.get('zombie_attack')) self.animator.add_animation('dead', animation_manager.get('zombie_attack')) self.animator.animations['attack'].on_done = self.attack self.attack = False
def load_content(self): super().load_content() sound_manager.play_song('game') self.player = Player(Vector2(928, 928)) self.instantiate(self.player) # create enemy spawner enemy_spawner = EnemySpawner(utils.enemy_waves, self.player) enemy_spawner.on_new_wave = self.on_new_wave self.instantiate(enemy_spawner) # map map = [['grass'] * 30 for i in range(30)] for y in range(len(map)): for x in range(len(map[y])): if (random.random() < 0.2 or x == 0 or x == 28 or y == 0 or y == 28): map[y][x] = 'gravel' grassTile = Tile('grass', sprite_manager.get('grass')) gravelTile = Tile('gravel', sprite_manager.get('gravel')) tilemap = Tilemap(self.camera, map, [grassTile, gravelTile], Vector2(64, 64), Vector2(), 0) self.instantiate(tilemap) self._wave_text_timer = 0 self._current_wave = 0
def __init__(self, position=Vector2(0, 0), scale=Vector2(1, 1), hitbox=Vector2(50, 50), max_health=100, damage=10, speed=20, attack_range=80): ''' :param position (Vector2): the position of this Character :param rotation (int): the rotation of this Character :param scale (Vector2): the scale of this Character :param origin (Vector2): the origin of this Character :param max_health (int): the max health of this Character ''' super().__init__(position=position, rotation=0, scale=scale, origin=Vector2(0.5, 0.5), max_health=max_health, speed=speed) self.add_collider('enemy', hitbox, Vector2(0, 0), False, False) self.collider.on_trigger_enter = self.on_trigger_enter self.damage = damage self.attack_range = attack_range
def __init__(self, position=Vector2(0, 0), size=Vector2(0, 0)): ''' :param position (Vector2): the position of the Rectangle :param size (Vector2): the size of the Rectangle ''' self.position = position self.size = size
def load_content(self) -> None: ''' All content the are supposed to be loaded/initialized only once at the beginning are meant to belong in this method, this method is called once :returns: NoReturn :rtype: None ''' self.object_handler = ObjectHandler( Vector2(0, 0), Vector2.tuple_to_vector2(utils.world_size)) self.camera = Camera(utils.window, self.object_handler, Transform(None), Vector2.tuple_to_vector2(utils.window_size), Vector2(0, 0))
def on_render(self, surface) -> None: ''' a method that is invoked when the GameObject about to render :param surface (Surface): the surface this Tilemap will render on :returns: NoReturn :rtype: None ''' super().on_render(surface) # the size of each tile after scaling scaled_tile_size = Vector2( int(self._camera.transform.scale.x * self._tile_size.x), int(self._camera.transform.scale.y * self._tile_size.y)) # calculate how many tiles will fit on the screen max_tiles_on_screen = Vector2( self._camera.size.x // scaled_tile_size.x, self._camera.size.y // scaled_tile_size.y) # calculate the start index to begin drawing the map start_index = (self.transform.position + self._camera.transform.position) // scaled_tile_size if start_index.x < 0: start_index.x = 0 if start_index.y < 0: start_index.y = 0 # calculate the end index to stop drawing the map end_index = start_index + max_tiles_on_screen + Vector2(2, 2) if end_index.x > len(self._map[-1]) - 1: end_index.x = len(self._map[-1]) - 1 if end_index.y > len(self._map) - 1: end_index.y = len(self._map) - 1 for y in range(start_index.y, end_index.y): for x in range(start_index.x, end_index.x): name = self._map[y][x] # get Tile name tile = self._tiles[name] # get Tile # scale the tile sprite = pygame.transform.scale(tile.sprite, scaled_tile_size.to_tuple()) # position of the tile position = self.transform.position - self._camera.transform.position + Vector2( x, y) * scaled_tile_size # draw tile surface.blit(sprite, position.to_tuple(), tile.source_rect)
def update(self, delta_time): ''' ''' super().update(delta_time) if self.is_dead: return # update current gun self.current_gun.update(delta_time) # handle movement self._movement(delta_time) # shoot if event_handler.is_mouse_down(1): self.attack() # switch weapons self._swith_weapons() # get the camera in current screen camera = Screen.get_current_screen().camera # look at mouse self.transform.look_at( camera.screen_to_world_point( Vector2.tuple_to_vector2(pygame.mouse.get_pos()))) # make the camera follow player self._camera_follow(camera)
def _movement(self, delta_time): ''' move the player :returns: NoReturn :rtype: None ''' speed = self.speed * (delta_time / 1000) direction = Vector2(0, 0) if event_handler.is_key_down(pygame.K_w): direction.y += -1 if event_handler.is_key_down(pygame.K_s): direction.y += 1 if event_handler.is_key_down(pygame.K_a): direction.x += -1 if event_handler.is_key_down(pygame.K_d): direction.x += 1 # update position self.transform.position += direction * speed # constrain player position if self.transform.position.x <= 0: self.transform.position.x = 0 elif self.transform.position.x >= utils.world_size[0]: self.transform.position.x = utils.world_size[0] if self.transform.position.y <= 0: self.transform.position.y = 0 elif self.transform.position.y >= utils.world_size[1]: self.transform.position.y = utils.world_size[1]
def __init__(self, position=Vector2(0, 0), rotation=0, scale=Vector2(1, 1), origin=Vector2(0, 0), max_health=100, speed=10): ''' :param position (Vector2): the position of this Character :param rotation (int): the rotation of this Character :param scale (Vector2): the scale of this Character :param origin (Vector2): the origin of this Character, (0, 0) is the top left and (1, 1) is the bottom right :param max_health (int): the max health of this Character ''' super().__init__(position, rotation, scale, origin) self.speed = speed self.health = max_health self.max_health = max_health self.is_dead = False self._alpha = 255
def __init__(self, position): super().__init__(position=position, rotation=random.randint(0, 360), origin=Vector2(0.5, 0.5)) self.add_sprite_renderer(sprite=sprite_manager.get('blood0'), sorting_order=1) self.collider = None self._alpha = 255
def forward(self) -> Vector2: ''' get the forward vector of this Transform :returns: a normalized vector pointing forward :rtype: Vector2 ''' # 57.295 = deg to rad return Vector2(-math.sin(self.rotation / 57.295), -math.cos(self.rotation / 57.295))
def __init__(self, gameobject, position=Vector2(0, 0), rotation=0, scale=Vector2(1, 1), origin=Vector2(0, 0)): ''' :param gameobject (GameObject): the gameObject this Transform is attached to :param position (Vector2): the position of this Transform :param rotation (int): the rotation of this Transform :param scale (Vector2): the scale of this Transform :param origin (Vector2): the origin of this Transform, (0, 0) is the top left and (1, 1) is the bottom right ''' self.gameobject = gameobject self.position = position self.rotation = rotation self.scale = scale self.origin = origin
def _subdivide(self) -> None: ''' subdivides the QuadTree into 4 new QuadTrees :returns: NoReturn :rtype: None ''' position = self.boundary.position half_size = self.boundary.size/2 nw = Rectangle(position, half_size) ne = Rectangle(position + half_size * Vector2(1, 0), half_size) sw = Rectangle(position + half_size * Vector2(0, 1), half_size) se = Rectangle(position + half_size * Vector2(1, 1), half_size) self.north_west = QuadTree(nw, self.capacity) self.north_east = QuadTree(ne, self.capacity) self.south_west = QuadTree(sw, self.capacity) self.south_east = QuadTree(se, self.capacity)
def add_collider(self, tag='', size=Vector2(0, 0), offset=Vector2(0, 0), is_trigger=False, is_static=False) -> None: ''' adds a Collider to the GameObject :param tag (str): the tag of this Collider :param size (Vector2): the size of this Collider :param offset (Vector2): the local offset of the Collider :param is_trigger (bool): is this collider configured as a trigger? :param is_static (bool): is this collider flagged as static? :returns: NoReturn :rtype: None ''' self.collider = Collider(self, tag, size, offset, is_trigger, is_static)
def __init__(self, owner): super().__init__(owner=owner, bullet_offset=Vector2(47, 15), damage=100, spread=3, bullets=1000000, magazine_size=50, fire_rate=80) self.name = 'FN SCAR' self.bullet_speed = 810 self.bullet_max_distance = 1420
def __init__(self, owner): super().__init__(owner=owner, bullet_offset=Vector2(47, 15), damage=25, spread=12, bullets=1000000, magazine_size=6, fire_rate=400) self.name = 'PUMP SHOTGUN' self.bullet_speed = 730 self.bullet_max_distance = 700
def screen_to_world_point(self, point) -> Vector2: ''' transforms a point from screen space into world space :param point (Vector2): the Vector2 to convert to a world point :returns: a new point that is converted to world space :rtype: Vector2 ''' return Vector2( (point.x + self.transform.position.x) / self.transform.scale.x, (point.y + self.transform.position.y) / self.transform.scale.y)
def __init__(self, owner): super().__init__(owner=owner, bullet_offset=Vector2(47, 15), damage=1000, spread=0, bullets=1000000, magazine_size=1000000, fire_rate=350) self.name = 'DEATH BULLET' self.bullet_speed = 800 self.bullet_max_distance = 2000
def __init__(self, owner): super().__init__(owner=owner, bullet_offset=Vector2(47, 15), damage=30, spread=13, bullets=1000000, magazine_size=1, fire_rate=450) self.name = 'SHOTGUN' self.bullet_speed = 710 self.bullet_max_distance = 769
def world_to_screen_point(self, point) -> Vector2: ''' transforms a point from world space into screen space :param point (Vector2): the Vector2 to convert to a screen point :returns: a new point that is converted to screen space :rtype: Vector2 ''' return Vector2( (point.x * self.transform.scale.x - self.transform.position.x), (point.y * self.transform.scale.y - self.transform.position.y))
def __init__(self, position=Vector2(0, 0), rotation=0, scale=Vector2(1, 1), origin=Vector2(0, 0)): ''' :param position (Vector2): the position of this GameObject :param rotation (int): the rotation of this GameObject :param scale (Vector2): the scale of this GameObject :param origin (Vector2): the origin of this GameObject, (0, 0) is the top left and (1, 1) is the bottom right ''' # the Transform of this GameObject self.transform = Transform(self, position, rotation, scale, origin) # the SpriteRenderer of this GameObject self.sprite_renderer = None # the Collider of this GameObject self.collider = None # the Animator of this GameObject self.animator = None self._flagged_as_destroy = False
def render(self) -> None: ''' renders all GameObjects :returns: NoReturn :rtype: None ''' objects = self._object_handler.get_objects() for obj in objects: obj_transform = obj.transform obj_renderer = obj.sprite_renderer obj.on_render(self.surface) if obj_renderer is None or obj_renderer.sprite is None: continue # get the size of the image before rotation and scaling orig_size = obj_renderer.sprite.get_rect().size # calculate the new size of imge new_size = (int(orig_size[0] * obj_transform.scale.x * self.transform.scale.x), int(orig_size[1] * obj_transform.scale.y * self.transform.scale.y)) # scale the image sprite = pygame.transform.scale(obj_renderer.sprite, new_size) # rotate the image sprite = pygame.transform.rotate(sprite, obj_transform.rotation) # get the size of the image after rotation and scaling size = sprite.get_rect().size # calculate the position of the image position = Vector2( obj_transform.position.x * self.transform.scale.x, obj_transform.position.y * self.transform.scale.y) # offset of the image offset = (size[0] * obj_transform.origin.x, size[1] * obj_transform.origin.y) # position of the image with the offset and new_position = (position.x - offset[0] - self.transform.position.x, position.y - offset[1] - self.transform.position.y) if obj_renderer.color is not None: sprite.fill(obj_renderer.color, None, pygame.BLEND_RGBA_MULT) # draw the image self.surface.blit(sprite, new_position, obj_renderer.source_rect)
def spawn_enemy(self, enemy): ''' ''' self.current_wave_index += 1 enemy_type = None position = Vector2(enemy[2], enemy[3]) if enemy[1] == 'normal_zombie': enemy_type = Zombie(self.player, position) elif enemy[1] == 'big_zombie': enemy_type = BigZombie(self.player, position) Screen.get_current_screen().instantiate(enemy_type) self.spawned_enemies.append(enemy_type)
def on_render(self, surface): super().on_render(surface) # display weapon name weapon = self.current_gun bullets = weapon.bullets % weapon.magazine_size + 1 if not weapon.reloading else 0 magazines = weapon.bullets // weapon.magazine_size * weapon.magazine_size if not weapon.reloading else weapon.bullets // weapon.magazine_size * weapon.magazine_size + weapon.magazine_size text = f'{self.current_gun.name} | {bullets}/{magazines}' position = Screen.get_current_screen().camera.world_to_screen_point( self.transform.position - Vector2(len(text) * 0.25 * 11, 55)).to_tuple() utils.draw_font(surface, text, (255, 255, 255), position, size=11, bold=True)
def __init__(self, position=Vector2(0, 0), scale=Vector2(1, 1), hitbox=Vector2(50, 50)): ''' ''' super().__init__(position=position, rotation=0, scale=scale, origin=Vector2(0.5, 0.5)) if hitbox != Vector2(0, 0): self.add_collider('item', hitbox, Vector2(0, 0), False, True) self.collider.on_collider_enter = self.on_pick_up
def zoom(self, amount, to=Vector2(0, 0)) -> None: ''' zoom the camera towards a specified point :param amount (float): the amount to zoom :param to (Vector2): the point to zoom towards (screen coordinates) :returns: NoReturn :rtype: None ''' new_scale = self.transform.scale * amount width = self.transform.position.x + to.x height = self.transform.position.y + to.y self.transform.position.x -= width * ( 1 - new_scale.x / self.transform.scale.x) self.transform.position.y -= height * ( 1 - new_scale.y / self.transform.scale.y) self.transform.scale = new_scale
def __init__(self, owner): super().__init__(owner=owner, bullet_offset=Vector2(47, 15), damage=20, spread=5, bullets=1000000, magazine_size=50, fire_rate=100) self.name = 'UZI' self.bullet_speed = 720
def __init__(self, owner): super().__init__(owner=owner, bullet_offset=Vector2(47, 15), damage=100, spread=1, bullets=1000000, magazine_size=30, fire_rate=130) self.name = 'AK47' self.bullet_speed = 800 self.bullet_max_distance = 1069