人工智能和游戏物理

问题描述 投票:0回答:1

我对编码还很陌生,我想构建一个人工智能。我在这个项目中使用 pygame 和 pytorch。有关解决方案或代码格式的任何提示都会有所帮助!

当我运行测试时,只需一次更新即可完全正常工作。然而,当我让 AI 进行输入时,立方体就会从屏幕上掉下来,玩家的位置迅速正向增加,而玩家位置的速度和 y 则负向增加。我被困住了,因为我不认为是与地板的碰撞导致试运行成功。也许是AI的快速输入?这是该项目的 GitHub - https://github.com/hprymak07/physicals-ai-game

  • 我当前的游戏文件:
import pygame
from math import dist

pygame.init()
w, h = 1250, 720

class Direction:
    @staticmethod
    def update(left=0, right=0, jump=0):
        return left, right, jump

class Player:
    def __init__(self, x, y):
        self.rect = pygame.Rect(x, y, 10, 10)
        self.vel_x = 0
        self.vel_y = 0
        self.gravity = 0.2
        self.ground = False
        self.collision_tol = 5

    def update_velo(self, left, right, jump):
        self.vel_x = 300 if right == 1 else 0 if left == 1 else 0
        self.vel_y += self.gravity
        self.vel_y = -10 if jump == 1 else self.vel_y
        print("Velocity X:", self.vel_x)
        print("Velocity Y:", self.vel_y)

    def move(self):
        self.rect.x += self.vel_x
        self.rect.y += self.vel_y
        print("Player Position:", self.rect.x, self.rect.y)

    def collisions(self, objects, walls):

        for object in objects:
            if self.rect.colliderect(object):
                print("Collision detected with object:", object)
                if abs(self.rect.right - object.left) <= self.collision_tol:
                    self.rect.right = object.left
                    self.ground = True
                elif abs(self.rect.left - object.right) <= self.collision_tol:
                    self.rect.left = object.right
                    self.ground = True
                elif self.rect.bottom >= object.top:
                    self.rect.bottom = object.top
                    self.ground = True
                    self.vel_y = 0
                elif self.rect.top <= object.bottom:
                    self.rect.top = object.bottom
                    self.ground = False
                else:
                    self.ground = False
        
        for wall in walls:
            if self.rect.colliderect(wall):
                print("Collision detected with wall:", wall)
                if self.vel_x > 0:
                    self.rect.right = wall.left
                elif self.vel_x < 0:
                    self.rect.left = wall.right

                if self.vel_y > 0:
                    self.rect.bottom = wall.top
                    self.vel_y = 0
                    self.ground = True
                    
                elif self.vel_y < 0:
                    self.rect.top = wall.bottom
                    self.vel_y = 0

    def update(self, left, right, jump, objects, walls):
        self.update_velo(left, right, jump)
        self.move()
        self.collisions(objects, walls)
        print("Player position:", self.rect.x, self.rect.y)

class Game:
    def __init__(self):
        self.display = pygame.display.set_mode((w, h))
        pygame.display.set_caption("AI Game")
        self.clock = pygame.time.Clock()
        self.endpt = pygame.Rect(1200, h - 250, 20, 20)
        self.floor = pygame.Rect(0, h - 20, w, 200)
        self.left_wall = pygame.Rect(0, 0, 20, h)
        self.right_wall = pygame.Rect(w - 20, 0, 20, h)
        self.objects_for_lvl = [
            pygame.Rect(100, h - 100, 100, 80),
            pygame.Rect(250, h - 140, 100, 25),
            pygame.Rect(400, h - 170, 100, 25),
            pygame.Rect(535, h - 170, 75, 25),
            pygame.Rect(735, h - 170, 75, 25),
            pygame.Rect(900, h - 200, 150, 25),
            pygame.Rect(1150, h - 230, 200, 25)
        ]

        self.player = Player(30, 600)
        self.running = True
        self.reset()

    def reset(self):
        self.score = 0
        self.frame_iteration = 0

    def step(self, action):
        self.frame_iteration += 1

        for ev in pygame.event.get():
            if ev.type == pygame.QUIT:
                pygame.quit()
                quit()

        left, right, jump = action
        self.player.update(left, right, jump, self.objects_for_lvl, [self.floor, self.left_wall, self.right_wall])

        reward, game_over = self.calculate_score()

        self._update()

        return reward, game_over, self.score

    def calculate_score(self):
        reward = 0
        game_over = False

        if self.player.rect.colliderect(self.endpt):
            reward += 10
        elif self.player.rect.colliderect(self.floor):
            reward -= 5

        self.score += reward
        game_over = self.player.rect.colliderect(self.left_wall) or self.player.rect.colliderect(self.right_wall)

        return reward, game_over

    def _update(self):    
        self.display.fill('white')  

        for obj in self.objects_for_lvl:  
            pygame.draw.rect(self.display, (128, 128, 128), obj)

        pygame.draw.rect(self.display, (128, 128, 128), self.floor)  
        pygame.draw.rect(self.display, (128, 128, 128), self.left_wall)
        pygame.draw.rect(self.display, (128, 128, 128), self.right_wall)
    
        pygame.draw.rect(self.display, (255, 0, 0), self.player.rect)  # Draw player object
        pygame.draw.rect(self.display, (0, 255, 0), self.endpt)  

        pygame.display.update()


if __name__ == "__main__":
    game = Game()
    while game.running:
        action = Direction.update(1, 0, 0) # move left once 
        print("Action:", action)
        reward, game_over, score = game.step(action)
        if game_over:
            print("Game Over")
            game.running = False
python pytorch pygame artificial-intelligence game-physics
1个回答
0
投票

这似乎是一项相当困难的任务。我认为问题出在碰撞上。我对代码做了一些小改动,它仍然不起作用,但现在你可以使用 SPACE 来进行一步。像这样你可以看到,红色矩形向上移动,然后向下移动,一旦接触地面,它就会停止。它似乎处于无限循环中。现在可能更容易找到错误。

import pygame

pygame.init()
w, h = 1250, 720


class Direction:
    @staticmethod
    def update(left=0, right=0, jump=0):
        return left, right, jump


class Player:
    def __init__(self, x, y):
        self.rect = pygame.Rect(x, y + 1, 10, 10)
        self.vel_x = 0
        self.vel_y = 0
        self.gravity = 0.8
        self.ground = False
        self.collision_tol = 10

    def __repr__(self):
        return f"Player(x={self.rect.x}, y={self.rect.y}, vel_x={self.vel_x}, vel_y={self.vel_y}, ground={self.ground})"

    def update_velo(self, left, right, jump, objects, walls):
        self.vel_x = 10 if right == 1 else 0 if left == 1 else 0
        self.vel_y += self.gravity
        self.ground = self.rect.colliderect(walls[0]) or any(self.rect.colliderect(obj) for obj in objects)

        if jump == 1 and self.ground:
            self.vel_y = -10

        # print("Velocity X:", self.vel_x)
        # print("Velocity Y:", self.vel_y)
        # print(f"self.ground:{self.ground}")

    def move(self):
        self.rect.x += self.vel_x
        self.rect.y += self.vel_y
        # print("Player Position:", self.rect.x, self.rect.y)

    def collisions(self, objects, walls):
        for object in objects:
            if self.rect.colliderect(object):
                print("Collision detected with object:", object)
                if abs(self.rect.right - object.left) <= self.collision_tol:
                    self.rect.right = object.left
                    self.ground = True
                elif abs(self.rect.left - object.right) <= self.collision_tol:
                    self.rect.left = object.right
                    self.ground = True
                elif self.rect.bottom >= object.top:
                    self.rect.bottom = object.top
                    self.ground = True
                    self.vel_y = 0
                elif self.rect.top <= object.bottom:
                    self.rect.top = object.bottom
                    self.ground = False
                else:
                    self.ground = False

        for wall in walls:
            if self.rect.colliderect(wall):
                print("Collision detected with wall:", wall)
                if self.vel_x > 0:
                    self.rect.right = wall.left
                elif self.vel_x < 0:
                    self.rect.left = wall.right

                if self.vel_y > 0:
                    self.rect.bottom = wall.top
                    self.vel_y = 0
                    self.ground = True

                elif self.vel_y < 0:
                    self.rect.top = wall.bottom
                    self.vel_y = 0

    def update(self, left, right, jump, objects, walls):
        self.update_velo(left, right, jump, objects, walls)
        self.move()
        self.collisions(objects, walls)
        # print("Player position:", self.rect.x, self.rect.y)

        print(self)


class Game:
    def __init__(self, display):
        self.display = display
        self.clock = pygame.time.Clock()
        self.endpt = pygame.Rect(1200, h - 250, 20, 20)
        self.floor = pygame.Rect(0, h - 20, w, 200)
        self.left_wall = pygame.Rect(0, 0, 20, h)
        self.right_wall = pygame.Rect(w - 20, 0, 20, h)
        self.objects_for_lvl = [
            pygame.Rect(100, h - 100, 100, 80),
            pygame.Rect(250, h - 140, 100, 25),
            pygame.Rect(400, h - 170, 100, 25),
            pygame.Rect(535, h - 170, 75, 25),
            pygame.Rect(735, h - 170, 75, 25),
            pygame.Rect(900, h - 200, 150, 25),
            pygame.Rect(1150, h - 230, 200, 25)
            ]

        self.player = Player(30, 600)
        self.running = True
        self.reset()

    def reset(self):
        self.score = 0
        self.frame_iteration = 0

    def step(self, action):
        self.frame_iteration += 1

        for ev in pygame.event.get():
            if ev.type == pygame.QUIT:
                pygame.quit()
                quit()

        left, right, jump = action
        self.player.update(left, right, jump, self.objects_for_lvl, [self.floor, self.left_wall, self.right_wall])

        reward, game_over = self.calculate_score()

        # self._update()

        return reward, game_over, self.score

    def calculate_score(self):
        reward = 0
        game_over = False

        if self.player.rect.colliderect(self.endpt):
            reward += 10
        elif self.player.rect.colliderect(self.floor) and self.player.rect.x >= 100:
            reward -= 5

        self.score += reward
        game_over = self.player.rect.colliderect(self.left_wall) or self.player.rect.colliderect(self.floor) and self.player.rect.x >= 100

        return reward, game_over

    def draw(self):
        for obj in self.objects_for_lvl:
            pygame.draw.rect(self.display, (128, 128, 128), obj)

        pygame.draw.rect(self.display, (128, 128, 128), self.floor)
        pygame.draw.rect(self.display, (128, 128, 128), self.left_wall)
        pygame.draw.rect(self.display, (128, 128, 128), self.right_wall)
        pygame.draw.rect(self.display, (255, 0, 0), self.player.rect)  # Draw player object
        pygame.draw.rect(self.display, (0, 255, 0), self.endpt)


if __name__ == "__main__":
    display = pygame.display.set_mode((w, h))
    pygame.display.set_caption("AI Game")
    game = Game(display)
    while game.running:

        # reset screen
        display.fill('white')

        # use SPACE for every step
        events = pygame.event.get()
        for event in events:
            if event.type == pygame.KEYDOWN:
                action = Direction.update(0, 0, 1)  # move up once
                print("Action:", action)
                reward, game_over, score = game.step(action)
                if game_over:
                    print("Game Over")
                    game.running = False

        # draw the stuff
        game.draw()
        pygame.display.update()
© www.soinside.com 2019 - 2024. All rights reserved.