0

I have created simple game. Now I want to implement NEAT to learn and control my game.

I followed this tutorial however I found problems.

As part of the game preparation,the author on YT modified his game to create a population of birds. In my case it will be a population of ships.

As I understand I need to create a list of ships[] and loop for ship in ships: ... at some place. The thing is, I have no idea where to put it.

Here is my main.py file (I think all changes should be done here):

import sys
import pygame
import os
import neat
from rocket import Rocket


class Game(object):
    def __init__(self):
        # configuration
        self.tps_max = 60.0
        # initialization
        pygame.init()
        self.screen = pygame.display.set_mode((1280, 720))
        self.screen_rect = self.screen.get_rect()
        self.tps_clock = pygame.time.Clock()
        self.tps_delta = 0.0
        self.player = Rocket(self)
        game = True
        while game is True:
            # Handle events
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    sys.exit(0)
                elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
                    sys.exit(0)

            # ticking
            self.tps_delta += self.tps_clock.tick() / 1000.0
            while self.tps_delta > 1 / self.tps_max:
                self.tick()
                self.tps_delta -= 1 / self.tps_max

            # drawing
            self.screen.fill((164, 222, 245))
            self.draw()
            pygame.display.flip()

    def tick(self):
        # check input
        self.player.tick()

    def draw(self):
        self.player.draw()

# def run(): to be continued
#    config = neat.config.Config(neat.DefaultGenome, neat.DefaultReproduction, neat.DefaultSpeciesSet,
#    neat.DefaultStagnation, config_path)
#
#    p = neat.Population(config)
#    p.add_reporter(neat.StdOutReporter(True))
#    stats = neat.StatisticsReporter()
#    p.add_reporter = stats
#
#    winner =p.run(Rocket.tick() , 50)


if __name__ == "__main__":
    #  local_dir = os.path.dirname(__file__)
    #  config_path = os.path.join(local_dir, "config-feedforward.txt")
    #  run(config_path)
    Game()

My rocket.py file (I expect no changes here):

import pygame
import random
import math
import sys
from pygame.math import Vector2

pygame.font.init()
font = pygame.font.Font(None, 30)
clock = pygame.time.Clock()
start_time = pygame.time.get_ticks()


class Rocket(object):

    def __init__(self, game):
        self.game = game
        size = self.game.screen.get_size()
        self.speed = 3.0
        self.wind_force = 0.4
        self.wind_angle = random.randint(0, 359)
        self.current_force = 0.2
        self.current_angle = random.randint(0, 359)
        self.random_change = 0
        self.pos = Vector2(size[0] / 2, size[1] / 2)
        self.offset = 0
        self.score = 0
        self.counting_time= 0
        self.counting_seconds = 0
        self.vel = Vector2(0, 0)
        self.acc = Vector2(0, 0)
        # heading vector

        self.heading = self.vel.angle_to(Vector2(0, 1))
        self.angle_speed = 0
        self.heading = random.randint(0, 359)

    def addforce(self, force):
        self.acc += force

    def tick(self):
        # Input

        pressed = pygame.key.get_pressed()
        if pressed[pygame.K_w]:
            self.addforce(Vector2(0, -self.speed * 0.6).rotate(self.heading))
        if pressed[pygame.K_s]:
            self.addforce(Vector2(0, self.speed * 0.3).rotate(self.heading))
        if pressed[pygame.K_d]:
            self.addforce(Vector2(0, self.speed * 0.3).rotate(self.heading - 90))
        if pressed[pygame.K_a]:
            self.addforce(Vector2(0, self.speed * 0.3).rotate(self.heading + 90))
        if pressed[pygame.K_q]:
            self.angle_speed -= 1
        if pressed[pygame.K_e]:
            self.angle_speed += 1
        # Physics

        self.wind_angle = (self.wind_angle + 0.5 * random.randint(-3, 3)) % 360
        self.wind_force += ((random.randint(-2, 3)) / 1000)

        self.current_angle = (self.current_angle + 0.5 * random.randint(-2, 2)) % 360
        self.current_force += ((random.randint(-2, 3)) / 1000)

        self.vel *= 0.5
        self.vel += Vector2(0, self.wind_force).rotate(self.wind_angle)
        self.vel += Vector2(0, self.current_force).rotate(self.current_angle)
        self.vel += self.acc
        self.pos += self.vel
        self.acc *= 0.5
        self.angle_speed *= 0.3

        self.heading = (self.heading + self.angle_speed) % 360
        # offset
        # check distance from centre to vessel pos
        self.offset = math.hypot(((self.vel[0] - self.pos[0]) + 640), ((self.vel[1] - self.pos[1]) + 360))
        # offset as 1
        self.offset /= 400
        # offset as accuracy in %
        self.offset = int((1 - self.offset) * 100)
        self.counting_time = pygame.time.get_ticks() - start_time
        self.counting_seconds = (int((self.counting_time / 1000)))
        self.score = round((self.counting_seconds * 10 + self.offset))
        self.score += self.score
        if self.pos.x < 0 or self.pos.x > 1280 or self.pos.y < 0 or self.pos.y > 720:
            pygame.quit()
            sys.exit(0)
        else:
            pass

    def draw(self):

        # base shape
        vessel = [Vector2(5, 10), Vector2(-5, 10), Vector2(-5, -10), Vector2(0, -15), Vector2(5, -10)]
        wind_arrow = [Vector2(0, 10), Vector2(0, 20), Vector2(20, 20), Vector2(20, 30), Vector2(30, 15), Vector2(20, 0),
                      Vector2(20, 10)]
        current_arrow = [Vector2(0, 10), Vector2(0, 20), Vector2(20, 20), Vector2(20, 30), Vector2(30, 15),
                         Vector2(20, 0),
                         Vector2(20, 10)]

        # rotating points

        vessel = [p.rotate(self.heading) for p in vessel]
        wind_arrow = [p.rotate(self.wind_angle + 90) for p in wind_arrow]
        current_arrow = [p.rotate(self.current_angle + 90) for p in current_arrow]

        # centered position & scale
        vessel = [self.pos + p * 6 for p in vessel]
        wind_arrow = [self.pos + p for p in wind_arrow]
        current_arrow = [self.pos + p for p in current_arrow]
        # draw shape

        pygame.draw.polygon(self.game.screen, (255, 177, 10), vessel)
        pygame.draw.polygon(self.game.screen, (233, 66, 245), wind_arrow)
        pygame.draw.polygon(self.game.screen, (22, 57, 217), current_arrow)
        pygame.draw.circle(self.game.screen, (255, 255, 255,), (640, 360), 5, 3)

        def write(text, location, color=(0, 0, 0)):
            self.game.screen.blit(font.render(text, True, color), location)

        write("Accuracy: " + str(self.offset) + ' %', (20, 10))
        write('Wind direction: ' + str(round(self.wind_angle)) + " deg . Wind force: " + str(
            round((self.wind_force * 10), 2)), (20, 40))
        write('Current direction: ' + str(round(self.current_angle)) + " deg . Current force: " + str(
            round(self.current_force, 2)),
              (20, 60))
        if self.pos.x < 200 or self.pos.x > 1080 or self.pos.y < 200 or self.pos.y > 520:
            write('OUT OF POSITION!', (560, 320))
            # pygame.time.wait(2000)

        else:

            pass

        write("Time: " + str(self.counting_seconds) + " s", (200,10))
        write("Total score: " + str(self.score), (400, 10))

Code of FLappy birds with neat implemented

Another issue is the function def eval_genomes(genomes, config): in flappy bird game.

Which function in my game is related to def eval_genomes(genomes, config)? Is it tick() function from Game class? Or do I need to create it in my main.py outside Game class?

D_00
  • 1,440
  • 2
  • 13
  • 32
dan3el
  • 1
  • 1

1 Answers1

0

for def eval_genomes(genomes, config): function you will have to insert the event handling and ticking. You could do this by turning these blocks of code into method for class Game then inserting it into the function.

Create the list in the function def eval_genomes(genomes, config): as well.