def create_offhand_item(name, material): _bonus = material_dict[material][0] _color = material_dict[material][1] _base, _equip, _skill = None, None, None _name = material.capitalize() + ' ' + name.capitalize() if name == 'buckler': _base = Base(name=_name, char=u'\u03C3', color=_color, render_order=RenderOrder.ITEM) _equip = Equippable(slot=Bodyparts.OffHand.name) _skill = Skill(cooldown=5, name='bash', nature='direct') _skill.knockback_force = 2 if name == 'shield': _base = Base(name=_name, char=u'\u0398', color=_color, render_order=RenderOrder.ITEM) _equip = Equippable(slot=Bodyparts.OffHand.name) _skill = Skill(cooldown=5, name='bash', nature='direct') _skill.knockback_force = 4 return _base, _equip, _skill
def create_mainhand_item(name, material): _bonus = material_dict[material][0] _color = material_dict[material][1] _name = material.capitalize() + ' ' + name.capitalize() _base, _equip, _skill = None, None, None if name == 'sword': _base = Base(name=_name, char=u'\u2193', color=_color, render_order=RenderOrder.ITEM) _profile = {} _profile = example_profile() _profile['ATK']['ATK'] = 1.8 + _bonus _equip = Equippable(slot=Bodyparts.MainHand.name, profile=_profile) _profile = {} _profile = example_profile() _profile['ATK']['ATK'] = 1.6 + _bonus _profile['ATK']['MAG'] = 0.2 + _bonus _skill = Skill(cooldown=12, name='pierce', nature='direct', profile=_profile) if name == 'spear': _base = Base(name=_name, char=u'\u2191', color=_color, render_order=RenderOrder.ITEM) _profile = {} _profile = example_profile() _profile['ATK']['ATK'] = 1.2 + _bonus _equip = Equippable(slot=Bodyparts.MainHand.name, profile=_profile) _profile = {} _profile = example_profile() _profile['ATK']['ATK'] = 1.6 + _bonus _profile['ATK']['SPD'] = 0.2 + _bonus _skill = Skill(cooldown=5, name='pierce', nature='direct', profile=_profile) return _base, _equip, _skill
def reset(self) -> None: """ Resets game to prepare for a generation :return: None """ self.score = 0 self.gen += 1 self.birds = [] self.pipes = [Pipe(WIN_WIDTH)] self.base = Base(FLOOR_HEIGHT)
def create_monster(name): _base = Base(name='player', char='@', color=libtcod.white, render_order=RenderOrder.ACTOR) _body = Body() _health = Health() _inv = Inventory() _job = Job.BARBARIAN _pos = Position() _race = Race.HUMAN _soul = Soul(eccentricity=5, rank=10) _status = Status() monster = Entity(base=_base, body=_body, health=_health, inv=_inv, job=_job, pos=_pos, race=_race, soul=_soul, status=_status) monster.health.points = monster.health.max return monster
def create_stairs(): _base = Base(name='stairs', char=u'\u2261', color=libtcod.black, render_order=RenderOrder.STAIRS) _pos = Position() return Entity(base=_base, pos=_pos)
def create_torso_item(name, material): _bonus = material_dict[material][0] _color = material_dict[material][1] _name = material.capitalize() + ' ' + name.capitalize() _base, _equip, _skill = None, None, None if name == 'chain mail': _base = Base(name=_name, char=u'\u2593', color=_color, render_order=RenderOrder.ITEM) _profile = {} _profile = example_profile() _profile['DEF']['DEF'] = 1.2 + _bonus _profile['MAG']['MAG'] = 1.0 + _bonus _equip = Equippable(slot=Bodyparts.Torso.name, profile=_profile) _skill = Skill() if name == 'plate mail': _base = Base(name=_name, char=u'\u2588', color=_color, render_order=RenderOrder.ITEM) _profile = {} _profile = example_profile() _profile['DEF']['DEF'] = 1.9 + _bonus _profile['MAG']['MAG'] = 0.7 + _bonus _equip = Equippable(slot=Bodyparts.Torso.name, profile=_profile) _skill = Skill() return _base, _equip, _skill
def create_head_item(name, material): _bonus = material_dict[material][0] _color = material_dict[material][1] _name = material.capitalize() + ' ' + name.capitalize() _base, _equip, _skill = None, None, None if name == 'helm': _base = Base(name=_name, char=u'\u00A3', color=_color, render_order=RenderOrder.ITEM) _equip = Equippable(slot=Bodyparts.Head.name) _skill = Skill() if name == 'cap': _base = Base(name=_name, char=u'\u207F', color=_color, render_order=RenderOrder.ITEM) _equip = Equippable(slot=Bodyparts.Head.name) _skill = Skill(cooldown=10, name='healing buff', nature='direct') return _base, _equip, _skill
def __init__(self, draw_lines=True): """ Initialise the game object :param draw_lines: defines whether to draw lines from bird to pipe, defaults to True """ self.draw_lines = draw_lines self.score = 0 self.max_score = 0 self.gen = 0 self.clock = pygame.time.Clock() self.birds = [] # birds list self.pipes = [Pipe(WIN_WIDTH)] self.base = Base(FLOOR_HEIGHT) self.window = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT)) self.LINE_THICKNESS = 1 self.tick_rate = 30
def create_ring_finger_item(name, material): _bonus = material_dict[material][0] _color = material_dict[material][1] _name = material.capitalize() + ' ' + name.capitalize() _base, _equip, _skill = None, None, None if name == 'ring': _base = Base(name=_name, char=u'\u00F6', color=_color, render_order=RenderOrder.ITEM) _equip = Equippable(slot=Bodyparts.Head.name) _skill = Skill() return _base, _equip, _skill
def create_feet_item(name, material): _bonus = material_dict[material][0] _color = material_dict[material][1] _name = material.capitalize() + ' ' + name.capitalize() _base, _equip, _skill = None, None, None if name == 'boots': _base = Base(name=_name, char=u'\u221F', color=_color, render_order=RenderOrder.ITEM) _equip = Equippable(slot=Bodyparts.Feet.name) _skill = Skill(cooldown=5, name='leap', nature='direct') return _base, _equip, _skill
def create_soul(entity): _soul_rank = entity.soul.rank _soul_eccentricity = entity.soul.eccentricity _soul_number = entity.soul.soul _soul = Soul(_soul_eccentricity, _soul_rank) _soul.number = _soul_number _base = Base(name='soul', char='*', color=libtcod.dark_green, render_order=RenderOrder.SOUL) _pos = Position() soul_item = Entity(base=_base, pos=_pos, soul=_soul) return soul_item
def create_monster_(difficulty): _rank = pick_rank(difficulty) _race = pick_race(difficulty) _job = pick_job(_race) _ai = AI(brain=BRAIN.ZOMBIE) _body = Body() _health = Health() _pos = Position() _soul = Soul(eccentricity=_race.value['eccentricity'], rank=_rank.value['rank']) _status = Status() _name = str(_rank.value['name']).capitalize() + ' ' + str( _race.value['name']).capitalize() + ' ' + str( _job.value['name']).capitalize() _color = _rank.value['color'] _char = _race.value['char'] _base = Base(name=_name, char=_char, color=_color, render_order=RenderOrder.ACTOR) monster = Entity(ai=_ai, base=_base, body=_body, health=_health, job=_job, pos=_pos, race=_race, soul=_soul, status=_status) monster.health.points = monster.health.max equip_monster(monster) return monster
class Game: """ Game object """ def __init__(self, draw_lines=True): """ Initialise the game object :param draw_lines: defines whether to draw lines from bird to pipe, defaults to True """ self.draw_lines = draw_lines self.score = 0 self.max_score = 0 self.gen = 0 self.clock = pygame.time.Clock() self.birds = [] # birds list self.pipes = [Pipe(WIN_WIDTH)] self.base = Base(FLOOR_HEIGHT) self.window = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT)) self.LINE_THICKNESS = 1 self.tick_rate = 30 def reset(self) -> None: """ Resets game to prepare for a generation :return: None """ self.score = 0 self.gen += 1 self.birds = [] self.pipes = [Pipe(WIN_WIDTH)] self.base = Base(FLOOR_HEIGHT) @staticmethod def should_quit(events) -> bool: """ Determines if we should quit the game :param events: pygame events :return: whether to quit game """ for event in events: if event.type == pygame.QUIT: return True return False def draw_window(self, pipe_ind) -> None: """ Draw window with all the elements :param pipe_ind: index of upcoming pipe in self.pipes :return: None """ # background self.window.blit(BG_IMG, (0, 0)) # pipes for pipe in self.pipes: pipe.draw(self.window) # base self.base.draw(self.window) # draw lines from bird to pipe for bird in self.birds: if self.draw_lines: try: # line to left corners of pipes pygame.draw.line( self.window, (255, 0, 100), (bird.x + bird.img.get_width() / 2, bird.y + bird.img.get_height() / 2), (self.pipes[pipe_ind].x, self.pipes[pipe_ind].height), self.LINE_THICKNESS) pygame.draw.line(self.window, (255, 0, 100), (bird.x + bird.img.get_width() / 2, bird.y + bird.img.get_height() / 2), (self.pipes[pipe_ind].x, self.pipes[pipe_ind].y_bottom), self.LINE_THICKNESS) # line to right corners of pipes pygame.draw.line( self.window, (255, 100, 0), (bird.x + bird.img.get_width() / 2, bird.y + bird.img.get_height() / 2), (self.pipes[pipe_ind].x + self.pipes[pipe_ind].PIPE_TOP_IMG.get_width(), self.pipes[pipe_ind].height), self.LINE_THICKNESS) pygame.draw.line( self.window, (255, 100, 0), (bird.x + bird.img.get_width() / 2, bird.y + bird.img.get_height() / 2), (self.pipes[pipe_ind].x + self.pipes[pipe_ind].PIPE_BOTTOM_IMG.get_width(), self.pipes[pipe_ind].y_bottom), self.LINE_THICKNESS) except: pass # birds bird.draw(self.window) # score and max_score score_text = STAT_FONT.render('Score: ' + str(self.score), 1, (255, 255, 255)) max_score_text = STAT_FONT.render('Max: ' + str(self.max_score), 1, (255, 255, 255)) self.window.blit(score_text, (WIN_WIDTH - 10 - score_text.get_width(), 10)) self.window.blit(max_score_text, (WIN_WIDTH - 10 - max_score_text.get_width(), 50)) # generation score_label = STAT_FONT.render("Gen: " + str(self.gen), 1, (255, 255, 255)) self.window.blit(score_label, (10, 10)) # alive score_label = STAT_FONT.render("Alive: " + str(len(self.birds)), 1, (255, 255, 255)) self.window.blit(score_label, (10, 50)) pygame.display.update() def init_birds(self, genomes, config) -> None: """ Initialise birds, genomes, neural networks :param genomes: genomes :param config: nn config :return: None """ for genome_id, genome in genomes: genome.fitness = 0 net = neat.nn.FeedForwardNetwork.create(genome, config) bird = Bird(230, 350) bird.genome = genome bird.network = net self.birds.append(bird) def kill_bird(self, bird, decrease_fitness=True, decrease_amount=3) -> None: """ Kill a bird at index i and decrease fitness if necessary :param bird: bird object to be killed :param decrease_fitness: whether to decrease fitness :param decrease_amount: amount to decrease fitness by :return: None """ if decrease_fitness: bird.genome.fitness -= decrease_amount # remove birds from lists self.birds.remove(bird) def increase_fitness(self) -> None: """ Increase fitness of all birds alive :return: None """ for bird in self.birds: bird.genome.fitness += 5 def make_birds_jump(self, pipe_ind) -> None: """ Make birds jump based on output from neural network :param pipe_ind: index of upcoming pipe :return: None """ for bird in self.birds: bird.genome.fitness += 1 bird.move() output = bird.network.activate( (bird.y, abs(bird.y - self.pipes[pipe_ind].y_bottom), abs(bird.y - self.pipes[pipe_ind].height), abs(bird.x - self.pipes[pipe_ind].x), abs(bird.x - self.pipes[pipe_ind].x - self.pipes[pipe_ind].PIPE_BOTTOM_IMG.get_width()))) # if output value is more than the min threshold to jump, jump if output[0] > MIN_JUMP_THRESHOLD: bird.jump() def get_pipe_ind(self) -> int: """ Get the index of the upcoming pipe :return: index of upcoming pipe """ pipe_ind = 0 if len(self.birds) > 0 and len( self.pipes ) > 1 and self.birds[0].x + self.pipes[0].PIPE_TOP_IMG.get_width(): pipe_ind = 1 return pipe_ind def add_score_and_update_fitness(self): self.score += 1 if self.max_score < self.score: self.max_score = self.score self.increase_fitness() self.pipes.append(Pipe(WIN_WIDTH)) def move_pipes_and_collision_detection(self) -> list: """ Move pipes and perform collision detection with birds. :return: if pipe has passed, list of pipes to remove """ removed_pipes = [] passed_pipe = False for pipe in self.pipes: pipe.move() # collision detection with pipe for bird in self.birds: if pipe.collide(bird): self.kill_bird(bird, decrease_fitness=True) if not pipe.passed and pipe.x + pipe.PIPE_TOP_IMG.get_width( ) < bird.x: pipe.passed = True if not passed_pipe: passed_pipe = True if pipe.x + pipe.PIPE_TOP_IMG.get_width() < 0: # pipe is offscreen, remove this pipe removed_pipes.append(pipe) if passed_pipe: self.add_score_and_update_fitness() return removed_pipes def update_birds(self) -> None: """ Kill birds that are touching the ceiling or the floor :return: None """ for bird in self.birds: if bird.y + bird.img.get_height( ) - 10 >= FLOOR_HEIGHT or bird.y < -50: self.kill_bird(bird, decrease_fitness=True) def update_pipes_and_score(self, removed_pipes) -> None: """ Remove pipes that are offscreen :param removed_pipes: list of pipes to be removed :return: None """ for removed in removed_pipes: self.pipes.remove(removed) def start(self, genomes, config) -> None: """ Initialise and start game :param genomes: genomes :param config: nn config :return: None """ self.init_birds(genomes, config) self.game() def quit_game(self) -> None: """ Quit game :return: None """ print('Max score reached:', self.max_score) pygame.quit() quit() def game(self) -> None: """ Start game :return: None """ run = True while run and len(self.birds) > 0: self.clock.tick(self.tick_rate) if self.should_quit(pygame.event.get()): run = False self.quit_game() break # move ground self.base.move() # get appropriate pipe index depending on position of pipes pipe_ind = self.get_pipe_ind() # make birds jump self.make_birds_jump(pipe_ind) # move pipes and determine if birds have collided with pipe removed_pipes = self.move_pipes_and_collision_detection() # remove birds that have hit the ground or ceiling self.update_birds() # update pipes list and score self.update_pipes_and_score(removed_pipes) # re-render window self.draw_window(pipe_ind) self.reset()