def fit_to_plane(sprite: Sprite, plane: Plane): scale = min(plane.width / sprite.image.width, plane.height / sprite.image.height) x = (plane.width - (sprite.image.width * scale)) / 2 y = (plane.height - (sprite.image.height * scale)) / 2 sprite.update(x=x, y=y, scale=scale)
def _create_and_scale_sprite(self, resource_name): knight_image = image.load(resource_name) sprite_scaling = self._calculate_scaling_for_sprite(knight_image.width, SQUARE_SIZE * CHESS_PIECE_SCALING) sprite = Sprite(knight_image, self.x, self.y) sprite.update(self.x, self.y, scale=sprite_scaling) sprite.anchor_x = sprite.width // 2 sprite.anchor_y = sprite.height // 2 return sprite
class O_Bullet: def __init__(self, x, y, rot, weapon, game): self.pos = Vector(x, y) self.rot = rot self.sprite = Sprite(game.bullet_img, x, y, batch=game.bullet_batch) self.sprite.update(rotation=rot, scale=WEAPONS[weapon]["bullet_size"]) self.sprite.image.anchor_x = self.sprite.image.width / 2 self.sprite.image.anchor_y = self.sprite.image.height / 2
class MapSpriteV2(SpriteV2, ABC): def __init__(self, logger, parent_viewport, map_id): super().__init__(logger, parent_viewport) self.map_id = map_id self.rotation = 0 self.x = 0 self.y = 0 @final def on_update(self): if not self.sprite and self.is_located_inside_viewport(): self.sprite = PygletSprite(self.texture, x=self.x, y=self.y, batch=self.batch, group=self.group, usage=self.usage, subpixel=self.subpixel) self.sprite.opacity = self.opacity self.sprite.rotation = self.rotation elif self.is_located_outside_viewport() and self.sprite: self.sprite.delete() self.sprite = None @final def on_position_update(self, x=0, y=0, rotation=0): self.x = x self.y = y self.rotation = rotation if self.sprite: self.sprite.update(x=self.x, y=self.y, rotation=self.rotation) @final def is_located_outside_viewport(self): return self.x - self.texture.anchor_x \ - (MAP_CAMERA.offset_x + self.parent_viewport.x2) / MAP_CAMERA.zoom \ > SPRITE_VIEWPORT_EDGE_OFFSET_LIMIT_X \ or self.x + self.texture.width - self.texture.anchor_x \ - (MAP_CAMERA.offset_x + self.parent_viewport.x1) / MAP_CAMERA.zoom \ < -SPRITE_VIEWPORT_EDGE_OFFSET_LIMIT_X \ or self.y - self.texture.anchor_y \ - (MAP_CAMERA.offset_y + self.parent_viewport.y2) / MAP_CAMERA.zoom \ > SPRITE_VIEWPORT_EDGE_OFFSET_LIMIT_Y \ or self.y + self.texture.height - self.texture.anchor_y \ - (MAP_CAMERA.offset_y + self.parent_viewport.y1) / MAP_CAMERA.zoom \ < -SPRITE_VIEWPORT_EDGE_OFFSET_LIMIT_Y @final def is_located_inside_viewport(self): return not self.is_located_outside_viewport()
class Omobs: def __init__(self, x, y, rot, game): self.pos = Vector(x, y) self.rot = rot self.sprite = Sprite(game.mob_image, x, y, batch=game.mob_batch) self.sprite.update(rotation=rot) self.sprite.image.anchor_x = self.sprite.image.width / 2 - MOB_IMAGE_OFFSET.x self.sprite.image.anchor_y = self.sprite.image.height / 2 - MOB_IMAGE_OFFSET.y self.hit_box = MOB_HIT_BOX.copy() self.hit_box.x = self.pos.x - self.hit_box.width / 2 self.hit_box.y = self.pos.y - self.hit_box.height / 2
class UISpriteV2(SpriteV2, ABC): @abstractmethod def get_x(self): pass @abstractmethod def get_y(self): pass @abstractmethod def get_scale(self): pass @final @is_not_active def on_activate(self): super().on_activate() if not self.sprite: self.sprite = PygletSprite(self.texture, x=self.get_x(), y=self.get_y(), batch=self.batch, group=self.group, usage=self.usage, subpixel=self.subpixel) self.sprite.opacity = self.opacity self.sprite.scale = self.get_scale() @final @window_size_has_changed def on_window_resize(self, width, height): super().on_window_resize(width, height) if self.sprite: self.sprite.update(x=self.get_x(), y=self.get_y(), scale=self.get_scale()) @final @is_active def on_position_update(self): self.sprite.update(x=self.get_x(), y=self.get_y())
def draw_snake(self): if self.__alive: for block in self.__body: block_pic = Sprite(self.body_sprite, x=block[0] * BLOCK_SIZE[0], y=block[1] * BLOCK_SIZE[1]) block_pic.update(scale_x=SCALE_X, scale_y=SCALE_Y) block_pic.draw() if self.__direction == Side.west: head_sprite = self.head_sprites.w elif self.__direction == Side.north: head_sprite = self.head_sprites.n elif self.__direction == Side.south: head_sprite = self.head_sprites.s else: head_sprite = self.head_sprites.e head_pic = Sprite(head_sprite, x=self.__head[0] * BLOCK_SIZE[0], y=self.__head[1] * BLOCK_SIZE[1]) head_pic.update(scale_x=SCALE_X, scale_y=SCALE_Y) head_pic.draw()
class MuzzleFlash: def __init__(self, pos, rot, game): self.pos = pos self.rot = rot self.time = 0 self.sprite = Sprite(game.muzzle_flash_img, batch=game.effects_batch) self.sprite.update(rotation=rot) self.sprite.image.anchor_x = self.sprite.width / 3 self.sprite.image.anchor_y = self.sprite.height / 2 self.dead = False self.sprite.x = pos.x self.sprite.y = pos.y def update(self, dt): self.time += dt if self.time > MUZZLE_FLASH_LIFESPAWN: self.sprite.delete() self.dead = True
class Player: def __init__(self, x, y, game, weapon): self.pos = Vector(x, y) self.vel = Vector(0, 0) self.rot = 0 self.game = game self.weapons = [None, Weapon("pistol")] self.grenades = [ Grenade(self.game, "grenade"), Grenade(self.game, "grenade"), Grenade(self.game, "grenade"), Grenade(self.game, "grenade"), Grenade(self.game, "grenade") ] self.grenade_num = 0 self.last_shot = 0 self.hit_box = PLAYER_HIT_BOX.copy() self.hit_box.x = x self.hit_box.y = y self.o = Vector(self.pos.x, self.pos.y) self.health = PLAYER_HEALTH self.num = 1 self.sprite = Sprite(game.player_images[self.weapons[self.num].name]) self.width = self.sprite.width self.height = self.sprite.height self.sprite.image.anchor_x = self.sprite.image.width / 2 - WEAPONS[ self.weapons[self.num].name]['img_offset'].x self.sprite.image.anchor_y = self.sprite.image.height / 2 - WEAPONS[ self.weapons[self.num].name]['img_offset'].y self.knock_back = Vector(0, 0) def see_player(self, player): corner2 = Vector(self.hit_box.x + self.hit_box.width / 2, self.hit_box.y + self.hit_box.height / 2) return self.see_point(player, corner2) def see_point(self, player, point_1): o_point_1 = player.hit_box.copy() o_point_2 = Vector(player.hit_box.x, player.hit_box.y + player.hit_box.height) o_point_3 = Vector(player.hit_box.x + player.hit_box.width, player.hit_box.y + player.hit_box.height) o_point_4 = Vector(player.hit_box.x + player.hit_box.width, player.hit_box.y) glBegin(GL_LINES) glVertex2i(int(point_1.x), int(point_1.y)) glVertex2i(int(o_point_1.x), int(o_point_1.y)) glEnd() glBegin(GL_LINES) glVertex2i(int(point_1.x), int(point_1.y)) glVertex2i(int(o_point_2.x), int(o_point_2.y)) glEnd() glBegin(GL_LINES) glVertex2i(int(point_1.x), int(point_1.y)) glVertex2i(int(o_point_3.x), int(o_point_3.y)) glEnd() glBegin(GL_LINES) glVertex2i(int(point_1.x), int(point_1.y)) glVertex2i(int(o_point_4.x), int(o_point_4.y)) glEnd() if self.line_collide(self.game, point_1, o_point_1) and self.line_collide(self.game, point_1, o_point_2) and self.line_collide(self.game, point_1, o_point_3) \ and self.line_collide(self.game, point_1, o_point_4): return False return True def line_collide(self, game, pos, o): for wall in game.walls: topleft = [wall.pos.x, wall.pos.y + wall.height] topright = [wall.pos.x + wall.width, wall.pos.y + wall.height] bottomleft = [wall.pos.x, wall.pos.y] bottomright = [wall.pos.x + wall.width, wall.pos.y] left = lineLine(pos.x, pos.y, o.x, o.y, topleft[0], topleft[1], topleft[0], bottomleft[1]) right = lineLine(pos.x, pos.y, o.x, o.y, topright[0], topright[1], topright[0], bottomright[1]) top = lineLine(pos.x, pos.y, o.x, o.y, topleft[0], topleft[1], topright[0], topright[1]) bottom = lineLine(pos.x, pos.y, o.x, o.y, bottomleft[0], bottomleft[1], bottomright[0], bottomright[1]) if left or right or top or bottom: return True return False def switch(self): self.num += 1 if len(self.weapons) - 1 < self.num: self.num = 0 if self.weapons[self.num] is None: self.switch() def get_rotation(self, point1, point2): return math.degrees( math.atan2(point1.x - point2.x, point1.y - point2.y)) def throw(self, dt): if len(self.grenades) > 0: self.grenades[self.grenade_num].throw( Vector(self.pos.x, self.pos.y), GRENADE_STARTING_VEL + self.vel * Vector(dt, dt), self.rot) self.grenades.remove(self.grenades[self.grenade_num]) self.grenade_num = 0 def shoot(self): if self.last_shot <= 0 < self.health: rot = self.get_rotation(self.o, self.game.mouse.get_map_pos()) + 90 if abs(self.rot) - abs(rot) > 10 or abs(rot) - abs(self.rot) > 10: rot = self.rot if self.weapons[self.num].ammo_in_mag > 0 and ( not self.weapons[self.num].fired or self.weapons[self.num].type == "auto"): self.knock_back = WEAPONS[self.weapons[ self.num].name]["knock_back"].rotate(self.rot) self.weapons[self.num].shoot(self.o, self.pos, rot, self.game) self.last_shot = WEAPONS[self.weapons[self.num].name]["rate"] def rotate_to_mouse(self): ''' v = self.pos - self.game.mouse.get_map_pos() s = self.game.mouse.get_map_pos() pos = pg.Vector2(self.pos.x, self.pos.y) pos2 = pg.Vector2(s.x, s.y) v2 = pos - pos2 print("v: ", v) print("v2: ", v2) # print(v.angle_to(Vector(-1, 0))) # print(v2.angle_to(pg.Vector2(-1, 0))) # print(self.rot) print(v.magnitude()) print(v2.magnitude()) ''' self.rot = self.get_rotation(self.pos, self.game.mouse.get_map_pos()) + 90 def collide_with_walls(self, dir): if self.health > 0: if dir == "x": for wall in self.game.walls: if (self.hit_box.x + self.hit_box.width > wall.pos.x and self.hit_box.y + self.hit_box.height > wall.pos.y ) and (self.hit_box.x < wall.pos.x + wall.width and self.hit_box.y < wall.pos.y + wall.height): if wall.center.x > self.hit_box.get_center().x: self.hit_box.x = wall.pos.x - self.hit_box.width elif wall.center.x < self.hit_box.get_center().x: self.hit_box.x = wall.pos.x + wall.width self.vel.x = 0 for mob in self.game.mobs: if (self.hit_box.x + self.hit_box.width > mob.hit_box.x and self.hit_box.y + self.hit_box.height > mob.hit_box.y) and ( self.hit_box.x < mob.hit_box.x + mob.hit_box.width and self.hit_box.y < mob.hit_box.y + mob.hit_box.height): if mob.hit_box.get_center( ).x > self.hit_box.get_center().x: self.hit_box.x = mob.hit_box.x - self.hit_box.width elif mob.hit_box.get_center( ).x < self.hit_box.get_center().x: self.hit_box.x = mob.hit_box.x + mob.hit_box.width self.vel.x = 0 elif dir == "y": for wall in self.game.walls: if (self.hit_box.x + self.hit_box.width > wall.pos.x and self.hit_box.y + self.hit_box.height > wall.pos.y ) and (self.hit_box.x < wall.pos.x + wall.width and self.hit_box.y < wall.pos.y + wall.height): if wall.center.y > self.hit_box.get_center().y: self.hit_box.y = wall.pos.y - self.hit_box.height elif wall.center.y < self.hit_box.get_center().y: self.hit_box.y = wall.pos.y + wall.height self.vel.y = 0 for mob in self.game.mobs: if (self.hit_box.x + self.hit_box.width > mob.hit_box.x and self.hit_box.y + self.hit_box.height > mob.hit_box.y) and ( self.hit_box.x < mob.hit_box.x + mob.hit_box.width and self.hit_box.y < mob.hit_box.y + mob.hit_box.height): if mob.hit_box.get_center( ).y > self.hit_box.get_center().y: self.hit_box.y = mob.hit_box.y - self.hit_box.height elif mob.hit_box.get_center( ).y < self.hit_box.get_center().y: self.hit_box.y = mob.hit_box.y + mob.hit_box.height self.vel.y = 0 def update(self, dt, server=False): self.sprite = Sprite( self.game.player_images[self.weapons[self.num].name]) self.width = self.sprite.width self.height = self.sprite.height self.sprite.image.anchor_x = self.sprite.image.width / 2 - WEAPONS[ self.weapons[self.num].name]['img_offset'].x self.sprite.image.anchor_y = self.sprite.image.height / 2 - WEAPONS[ self.weapons[self.num].name]['img_offset'].y self.vel.x -= self.knock_back.x self.vel.y += self.knock_back.y # check hit box collisions self.hit_box.x += self.vel.x * dt if not server: self.collide_with_walls("x") self.hit_box.y += self.vel.y * dt if not server: self.collide_with_walls("y") self.knock_back.multiply(0) self.pos.x = self.hit_box.x + self.hit_box.width / 2 self.pos.y = self.hit_box.y + self.hit_box.height / 2 o = WEAPONS[self.weapons[self.num].name]['offset'].copy().rotate( -self.rot) self.o = Vector(self.pos.x, self.pos.y) self.o.x += o.x self.o.y += o.y if self.last_shot > 0: self.last_shot -= dt if not self.game.buy_menu: self.rotate_to_mouse() self.sprite.update(rotation=self.rot) self.sprite.x = self.hit_box.get_center().x self.sprite.y = self.hit_box.get_center().y self.weapons[self.num].update(dt) def draw_hit_box(self): glBegin(GL_LINES) glVertex2i(int(self.hit_box.x), int(self.hit_box.y)) glVertex2i(int(self.hit_box.x), int(self.hit_box.y + self.hit_box.height)) glVertex2i(int(self.hit_box.x), int(self.hit_box.y + self.hit_box.height)) glVertex2i(int(self.hit_box.x + self.hit_box.width), int(self.hit_box.y + self.hit_box.height)) glVertex2i(int(self.hit_box.x + self.hit_box.width), int(self.hit_box.y + self.hit_box.height)) glVertex2i(int(self.hit_box.x + self.hit_box.width), int(self.hit_box.y)) glVertex2i(int(self.hit_box.x + self.hit_box.width), int(self.hit_box.y)) glVertex2i(int(self.hit_box.x), int(self.hit_box.y)) glEnd() def draw(self): s = self.game.mouse.get_map_pos() pyglet.gl.glBegin(pyglet.gl.GL_LINES) pyglet.gl.glVertex2i(int(self.pos.x), int(self.pos.y)) pyglet.gl.glVertex2i(int(s.x), int(s.y)) pyglet.gl.glEnd() pyglet.gl.glBegin(pyglet.gl.GL_LINES) pyglet.gl.glVertex2i(int(self.o.x), int(self.o.y)) pyglet.gl.glVertex2i(int(s.x), int(s.y)) pyglet.gl.glEnd() self.draw_hit_box() self.sprite.draw()
class Oplayers: def __init__(self, id, pos, rot, weapon, game): self.id = id self.pos = pos self.rot = rot self.weapon = weapon self.sprite = Sprite(game.player_images[weapon]) self.width = self.sprite.width self.height = self.sprite.height self.hit_box = PLAYER_HIT_BOX.copy() self.hit_box.x = pos.x self.hit_box.y = pos.y self.sprite.image.anchor_x = self.sprite.image.width / 2 - WEAPONS[ weapon]['img_offset'].x self.sprite.image.anchor_y = self.sprite.image.height / 2 - WEAPONS[ weapon]['img_offset'].y self.game = game self.health = PLAYER_HEALTH self.dead = False def update(self): self.sprite = Sprite(self.game.player_images[self.weapon]) self.width = self.sprite.width self.height = self.sprite.height self.sprite.image.anchor_x = self.sprite.image.width / 2 - WEAPONS[ self.weapon]['img_offset'].x self.sprite.image.anchor_y = self.sprite.image.height / 2 - WEAPONS[ self.weapon]['img_offset'].y self.sprite.update(rotation=self.rot) self.sprite.x = self.pos.x self.sprite.y = self.pos.y self.hit_box.x = self.pos.x - self.hit_box.width / 2 self.hit_box.y = self.pos.y - self.hit_box.height / 2 # print(self.pos) def draw_hit_box(self): glBegin(GL_LINES) glVertex2i(int(self.hit_box.x), int(self.hit_box.y)) glVertex2i(int(self.hit_box.x), int(self.hit_box.y + self.hit_box.height)) glVertex2i(int(self.hit_box.x), int(self.hit_box.y + self.hit_box.height)) glVertex2i(int(self.hit_box.x + self.hit_box.width), int(self.hit_box.y + self.hit_box.height)) glVertex2i(int(self.hit_box.x + self.hit_box.width), int(self.hit_box.y + self.hit_box.height)) glVertex2i(int(self.hit_box.x + self.hit_box.width), int(self.hit_box.y)) glVertex2i(int(self.hit_box.x + self.hit_box.width), int(self.hit_box.y)) glVertex2i(int(self.hit_box.x), int(self.hit_box.y)) glEnd()
class Mob: def __init__(self, x, y, game): self.pos = Vector(x, y) self.vel = Vector(0, 0) self.acc = Vector(0, 0) self.game = game self.rot = 0 self.hit_box = MOB_HIT_BOX.copy() self.sprite = Sprite(game.mob_image, batch=game.mob_batch) self.width = self.sprite.width self.height = self.sprite.height self.sprite.image.anchor_x = self.sprite.image.width / 2 - MOB_IMAGE_OFFSET.x self.sprite.image.anchor_y = self.sprite.image.height / 2 - MOB_IMAGE_OFFSET.y self.sprite.x = x self.sprite.y = y self.health = MOB_HEALTH self.hit_box.x = self.pos.x - self.hit_box.width / 2 self.hit_box.y = self.pos.y - self.hit_box.height / 2 self.target = None self.q = Queue(self.game) self.id = game.new_mob_id() self.last_hit = datetime.now() def collide_with_walls(self, dir): if self.health > 0: if dir == "x": for wall in self.game.walls: if (self.hit_box.x + self.hit_box.width > wall.pos.x and self.hit_box.y + self.hit_box.height > wall.pos.y ) and (self.hit_box.x < wall.pos.x + wall.width and self.hit_box.y < wall.pos.y + wall.height): if wall.center.x > self.hit_box.get_center().x: self.hit_box.x = wall.pos.x - self.hit_box.width elif wall.center.x < self.hit_box.get_center().x: self.hit_box.x = wall.pos.x + wall.width self.vel.x = 0 for mob in self.game.mobs: if (self.hit_box.x + self.hit_box.width > mob.hit_box.x and self.hit_box.y + self.hit_box.height > mob.hit_box.y) and ( self.hit_box.x < mob.hit_box.x + mob.hit_box.width and self.hit_box.y < mob.hit_box.y + mob.hit_box.height): if mob.hit_box.get_center( ).x > self.hit_box.get_center().x: self.hit_box.x = mob.hit_box.x - self.hit_box.width elif mob.hit_box.get_center( ).x < self.hit_box.get_center().x: self.hit_box.x = mob.hit_box.x + mob.hit_box.width self.vel.x = 0 for player in self.game.o_players: if (self.hit_box.x + self.hit_box.width > player.hit_box.x and self.hit_box.y + self.hit_box.height > player.hit_box.y) and ( self.hit_box.x < player.hit_box.x + player.hit_box.width and self.hit_box.y < player.hit_box.y + player.hit_box.height): if player.hit_box.get_center( ).x > self.hit_box.get_center().x: self.hit_box.x = player.hit_box.x - self.hit_box.width elif player.hit_box.get_center( ).x < self.hit_box.get_center().x: self.hit_box.x = player.hit_box.x + player.hit_box.width self.vel.x = 0 self.hit(player) elif dir == "y": for wall in self.game.walls: if (self.hit_box.x + self.hit_box.width > wall.pos.x and self.hit_box.y + self.hit_box.height > wall.pos.y ) and (self.hit_box.x < wall.pos.x + wall.width and self.hit_box.y < wall.pos.y + wall.height): if wall.center.y > self.hit_box.get_center().y: self.hit_box.y = wall.pos.y - self.hit_box.height elif wall.center.y < self.hit_box.get_center().y: self.hit_box.y = wall.pos.y + wall.height self.vel.y = 0 for mob in self.game.mobs: if (self.hit_box.x + self.hit_box.width > mob.hit_box.x and self.hit_box.y + self.hit_box.height > mob.hit_box.y) and ( self.hit_box.x < mob.hit_box.x + mob.hit_box.width and self.hit_box.y < mob.hit_box.y + mob.hit_box.height): if mob.hit_box.get_center( ).y > self.hit_box.get_center().y: self.hit_box.y = mob.hit_box.y - self.hit_box.height elif mob.hit_box.get_center( ).y < self.hit_box.get_center().y: self.hit_box.y = mob.hit_box.y + mob.hit_box.height self.vel.y = 0 for player in self.game.o_players: if (self.hit_box.x + self.hit_box.width > player.hit_box.x and self.hit_box.y + self.hit_box.height > player.hit_box.y) and ( self.hit_box.x < player.hit_box.x + player.hit_box.width and self.hit_box.y < player.hit_box.y + player.hit_box.height): if player.hit_box.get_center( ).y > self.hit_box.get_center().y: self.hit_box.y = player.hit_box.y - self.hit_box.height elif player.hit_box.get_center( ).y < self.hit_box.get_center().y: self.hit_box.y = player.hit_box.y + player.hit_box.height self.vel.y = 0 self.hit(player) def hit(self, player): if (datetime.now() - self.last_hit).seconds > MOB_DAMGAGE_RATE: player.health -= MOB_DAMAGE self.last_hit = datetime.now() def rot_towards_target(self, target_dist): rotT = target_dist.get_angle() - 90 angle = math.atan2(-target_dist.x, -target_dist.y) / math.pi * 180.0 diff = (angle - self.rot - 90) % 360 if 175 < int(diff) < 183: rot = rotT elif diff > 180: rot = self.rot + MOB_ROTATION_SPEED else: rot = self.rot - MOB_ROTATION_SPEED return rot def move(self, target, player=False): dist = Vector(target.x, target.y) - self.pos if dist.magnitude() <= MOB_NODE_DIST and player is False: self.get_path() dist.set_length(MOB_SPEED) self.vel = dist self.rot = self.rot_towards_target(dist) def get_closest(self): dist = None player_pos = None for player in self.game.o_players: if not player.dead: new_dist = player.pos - self.pos if dist is None: dist = new_dist player_pos = player elif new_dist.magnitude() < dist.magnitude(): dist = new_dist player_pos = player return player_pos def see_player(self, player): if self.q.line_collide(self.game, Vector(player.hit_box.x, player.hit_box.y), self.pos) \ or self.q.line_collide(self.game, Vector(player.hit_box.x + player.hit_box.width, player.hit_box.y), self.pos) \ or self.q.line_collide(self.game, Vector(player.hit_box.x + player.hit_box.width, player.hit_box.y + player.hit_box.height), self.pos) \ or self.q.line_collide(self.game, Vector(player.hit_box.x, player.hit_box.y + player.hit_box.height), self.pos): return False else: return True def get_path(self): player_pos = self.get_closest() if player_pos is not None: if not self.see_player(player_pos): self.q.find_path(self.pos, player_pos.pos.copy()) else: self.move(player_pos.pos, True) else: self.q.s = None self.vel.multiply(0) def update(self, dt): if self.q.s is None: self.get_path() else: pos = self.get_closest() if pos is not None: pos = pos.pos if self.q.line_collide(self.game, pos, self.pos): self.move(self.q.s[0]) else: self.move(pos, True) self.q.s = None else: self.q.s = None self.hit_box.x += self.vel.x * dt self.collide_with_walls("x") self.hit_box.y += self.vel.y * dt self.collide_with_walls("y") self.pos.x = self.hit_box.x + self.hit_box.width / 2 self.pos.y = self.hit_box.y + self.hit_box.height / 2 self.sprite.update(rotation=self.rot) self.sprite.x = self.hit_box.get_center().x self.sprite.y = self.hit_box.get_center().y def draw_hit_box(self): glBegin(GL_LINES) glVertex2i(int(self.hit_box.x), int(self.hit_box.y)) glVertex2i(int(self.hit_box.x), int(self.hit_box.y + self.hit_box.height)) glVertex2i(int(self.hit_box.x), int(self.hit_box.y + self.hit_box.height)) glVertex2i(int(self.hit_box.x + self.hit_box.width), int(self.hit_box.y + self.hit_box.height)) glVertex2i(int(self.hit_box.x + self.hit_box.width), int(self.hit_box.y + self.hit_box.height)) glVertex2i(int(self.hit_box.x + self.hit_box.width), int(self.hit_box.y)) glVertex2i(int(self.hit_box.x + self.hit_box.width), int(self.hit_box.y)) glVertex2i(int(self.hit_box.x), int(self.hit_box.y)) glEnd() self.q.draw()
class MobileEntity(Entity): defaults = { 'collidable': True, 'mobile': True, 'width': 50, 'height': 50, 'stat_modifiers': { 'str': 0, 'dex': 0, 'wis': 0, 'int': 0, 'con': 0, 'lck': 0 } } attributes = { 'dead': False, 'image_file': 'app/assets/zombie.png', 'moving_to': None, 'chunk': None, 'sprinting': False, 'in_combat': False, #'in_combat_with': [], 'attack_cooldown': 0, 'projectile_cooldown': 0, 'damage_text_color': (255, 255, 255, 255), 'chunk_container': 'npcs' } overwrite = {} def __init__(self, **kwargs): self.pre_init(**kwargs) super(MobileEntity, self).__init__(**kwargs) def init(self, **kwargs): self.in_combat_with = [] self.image = load_image(self.image_file) self.sprite = Sprite(self.image, self.x, self.y) self.hp_image = load_image('app/assets/healthbar.png') self.hp_sprite = Sprite(self.hp_image, self.x + 1, self.y + self.height + 5) self.set_sprite_render(self.group) self.stats = Stats(modifiers=self.stat_modifiers) entity_container = getattr(self.chunk, self.chunk_container) if self.chunk and self not in entity_container: entity_container.append(self) self.post_init(**kwargs) def pre_init(self, **kwargs): self.attributes = {**self.attributes, **self.overwrite} def post_init(self, **kwargs): pass def set_sprite_render(self, group): self.sprite.batch = self.chunk.draw_batch self.sprite.group = group self.hp_sprite.batch = self.chunk.draw_batch self.hp_sprite.group = group @property def speed(self): walk_speed = self.stats.dex // 3 if self.sprinting: return walk_speed * config.sprint_modifier return walk_speed def check_state(self): if self.dead: self.on_death() elif self.in_combat: if not self.in_combat_with: self.in_combat = False else: self.do_combat() else: self.do_idle() def on_death(self): print(f'{self.name} died!') if self.in_combat: for entity in self.in_combat_with: if self in entity.in_combat_with: entity.in_combat_with.remove(self) self.remove_from_chunk() self.sprite.delete() self.hp_sprite.delete() self.after_death() def remove_from_chunk(self): if self.chunk: container = getattr(self.chunk, self.chunk_container) if self in container: container.remove(self) def after_death(self): pass def do_combat(self): pass def do_idle(self): pass def check_bounds(self): if (self.x + self.width) > config.window_width: self.out_of_bounds('e') elif self.x < 0: self.out_of_bounds('w') elif (self.y + self.height) > config.window_height: self.out_of_bounds('n') elif self.y < 0: self.out_of_bounds('s') def out_of_bounds(self, direction): pass def on_collision(self, obj): x_intersect = calc_1D_intersect(*self.x_1D, *obj.x_1D) y_intersect = calc_1D_intersect(*self.y_1D, *obj.y_1D) if x_intersect < y_intersect: if self.x < obj.x: self.x = obj.x - self.width else: self.x = obj.x + obj.width else: if self.y < obj.y: self.y = obj.y - self.height else: self.y = obj.y + obj.height self.after_collision(obj) def after_collision(self, obj): pass def attack(self): if not self.attack_cooldown: atk_range = 75 for entity in self.chunk.attackable_objects: if entity is not self: if distance(*self.coord, *entity.coord) < atk_range: self.in_combat = True if entity not in self.in_combat_with: self.in_combat_with.append(entity) self.do_damage(entity, d6(num=self.stats.str // 2)) self.attack_cooldown = 50 def do_damage(self, target, dmg): target.take_damage(self, dmg) def take_damage(self, source, dmg): dmg_text = Label(f'{dmg}', x=randint((self.x - 5) // 1, (self.x + self.width + 5) // 1), y=self.y + self.height + 15, font_name='courier new', color=self.damage_text_color, bold=True, batch=self.chunk.draw_batch, group=self.chunk.foreground) clock.schedule_once(lambda df: dmg_text.delete(), 0.5) if (source is not None) and (source is not self): self.in_combat = True if source not in self.in_combat_with: self.in_combat_with.append(source) self.stats.hp -= dmg if self.stats.hp < 1: self.dead = True print( f'{self.name} ({self.stats.hp}/{self.stats.base_hp}) took {dmg} damage from {source.name}!' ) def fire_proj(self): velocity = 10 p_x = self.cursor_coord.x - self.center.x p_y = self.cursor_coord.y - self.center.y d = distance(self.center.x, self.center.y, self.cursor_coord.x, self.cursor_coord.y) r = velocity / d r_p = 30 / d if not self.projectile_cooldown: proj = Projectile(owner=self, chunk=self.chunk, x=self.center.x + p_x * r_p, y=self.center.y + p_y * r_p, damage=d20(num=self.stats.int // 3), velocity_x=p_x * r, velocity_y=p_y * r, batch=self.chunk.draw_batch, group=self.chunk.foreground) self.chunk.objects.append(proj) self.projectile_cooldown = 10 def update_cooldowns(self): if self.attack_cooldown > 0: self.attack_cooldown -= 1 if self.projectile_cooldown > 0: self.projectile_cooldown -= 1 def move(self): if self.moving_to: dist_from_target = np.sqrt((self.x - self.moving_to.x)**2 + (self.y - self.moving_to.y)**2) if dist_from_target <= self.speed: self.x = self.moving_to.x self.y = self.moving_to.y else: dist_ratio = self.speed / dist_from_target self.x = (1.0 - dist_ratio) * self.x + dist_ratio * self.moving_to.x self.y = (1.0 - dist_ratio) * self.y + dist_ratio * self.moving_to.y def update_sprites(self): self.sprite.update(x=self.x, y=self.y) self.hp_sprite.update(x=self.x + 1, y=self.y + self.height + 5, scale_x=self.stats.hp / self.stats.base_hp) def update(self): self.check_state() if not self.dead: self.update_cooldowns() self.move() self.check_bounds() self.update_sprites() else: self.after_death() def draw(self): self.sprite.draw()
class Bullet: def __init__(self, x, y, rot, img, weapon, game, main=True, owner=None): self.o_pos = Vector(x, y) self.prev_pos = Vector(x - 1, y - 1) self.pos = Vector(x, y) self.vector = Vector(WEAPONS[weapon]["bullet_speed"], 0).rotate(-rot) self.weapon = weapon self.sprite = Sprite(img, batch=game.bullet_batch) self.sprite.update(rotation=rot, scale=WEAPONS[weapon]["bullet_size"]) self.sprite.image.anchor_x = self.sprite.image.width / 2 self.sprite.image.anchor_y = self.sprite.image.height / 2 self.distance = 0 self.rot = rot if main: game.o_bullets.append({ "rot": rot, "pos": { "x": x, "y": y }, "weapon": weapon }) self.owner = owner def check(self, game): for wall in game.walls: if wall.pos.x + wall.width > self.pos.x > wall.pos.x and wall.pos.y + wall.height > self.pos.y > wall.pos.y: return True if lineLine(wall.pos.x, wall.pos.y, wall.pos.x, wall.pos.y + wall.height, self.pos.x, self.pos.y, self.prev_pos.x, self.prev_pos.y): return True if lineLine(wall.pos.x, wall.pos.y, wall.pos.x + wall.width, wall.pos.y, self.pos.x, self.pos.y, self.prev_pos.x, self.prev_pos.y): return True if lineLine(wall.pos.x + wall.width, wall.pos.y, wall.pos.x + wall.width, wall.pos.y + wall.height, self.pos.x, self.pos.y, self.prev_pos.x, self.prev_pos.y): return True if lineLine(wall.pos.x + wall.width, wall.pos.y + wall.height, wall.pos.x, wall.pos.y + wall.height, self.pos.x, self.pos.y, self.prev_pos.x, self.prev_pos.y): return True return False def check_player(self, player): if player.hit_box.x + player.hit_box.width > self.pos.x > player.hit_box.x and player.hit_box.y + player.hit_box.height > self.pos.y > player.hit_box.y: return True if lineLine(player.hit_box.x, player.hit_box.y, player.hit_box.x + player.hit_box.width, player.hit_box.y, self.pos.x, self.pos.y, self.prev_pos.x, self.prev_pos.y): return True if lineLine(player.hit_box.x + player.hit_box.width, player.hit_box.y, player.hit_box.x + player.hit_box.width, player.hit_box.y + player.hit_box.height, self.pos.x, self.pos.y, self.prev_pos.x, self.prev_pos.y): return True if lineLine(player.hit_box.x + player.hit_box.width, player.hit_box.y + player.hit_box.height, player.hit_box.x, player.hit_box.y + player.hit_box.height, self.pos.x, self.pos.y, self.prev_pos.x, self.prev_pos.y): return True if lineLine(player.hit_box.x, player.hit_box.y + player.hit_box.height, player.hit_box.x, player.hit_box.y, self.pos.x, self.pos.y, self.prev_pos.x, self.prev_pos.y): return True return False def update(self, dt): self.prev_pos = self.pos.copy() self.pos.x += self.vector.x * dt self.pos.y += self.vector.y * dt self.sprite.x = self.pos.x self.sprite.y = self.pos.y self.distance = Vector(self.pos.x - self.o_pos.x, self.pos.y - self.o_pos.y).magnitude()
class Sprite2D(fixture2d.Fixture2D): def __init__(self, img, x, y, batch=default_batch, group=None): self._sprite = Sprite(img, x=x, y=y, batch=batch, group=group) super().__init__(x, y) def update(self, dt): super().update(dt) self._sprite.update(x=self._pos.x, y=self._pos.y, rotation=self._rot, scale_x=self._sx, scale_y=self._sy) def delete(self): super().delete() self._sprite.delete() def _create_physical_body(self): return pymunk.Body(self._mass, self._inertia, self._body_type) def _create_physical_shape(self): return pymunk.Poly(self._body, [(-self.width / 2, self.height / 2), (self.width / 2, self.height / 2), (self.width / 2, -self.height / 2), (-self.width / 2, -self.height / 2)]) def _get_inertia_for_shape(self): return pymunk.moment_for_poly(self._mass, [(-self.width / 2, self.height / 2), (self.width / 2, self.height / 2), (self.width / 2, -self.height / 2), (-self.width / 2, -self.height / 2)]) def _get_bounding_box(self): return AABB.computeAABB(self.x, self.y, self.width, self.height, self._rot) @property def width(self): return self._sprite.width @property def height(self): return self._sprite.height @property def batch(self): return self._sprite.batch @batch.setter def batch(self, value): self._sprite.batch = value @property def image(self): return self._sprite.image @image.setter def image(self, value): self._sprite.image = value @property def group(self): return self._sprite.group @group.setter def group(self, value): self._sprite.group = value @property def opacity(self): return self._sprite.opacity @opacity.setter def opacity(self, value): self._sprite.opacity = value @property def color(self): return self._sprite.color @color.setter def color(self, value): self._sprite.color = value @property def visible(self): return self._sprite.visible @visible.setter def visible(self, value): self._sprite.visible = value