社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  chatgpt

喂饭级教程,看我如何用ChatGPT-4o做一款俄罗斯方块游戏!

量子位 • 7 月前 • 336 次点击  

昨天发的一篇文章,讲的是用 Midjourney 加 Kimi 做一款像素游戏。发完后,朋友看到说:“这他妈是游戏嘛,这跟你儿子学的 Scratch 做的游戏有什么区别?”我当时听到很不服气,怎么能把我跟儿子比呢,我吃的盐比他吃的饭还多呢。

于是,我决定用行动来证明自己。昨晚,我开始让 ChatGPT-4o 帮我写一个俄罗斯方块的游戏。通过这次尝试,我希望向大家展示如何利用先进的 AI 技术,快速开发出一款经典的游戏。同时,也希望能够分享在这个过程中所遇到的挑战和解决方案。

好,我们接下来就开始今天的教程,如何用 ChatGPT-4o 制作一款俄罗斯方块的游戏。

第一步:规划方案

我先让 ChatGPT-4o 给我规划一下俄罗斯方块的游戏方案:

第二步:生成代码

我让 ChatGPT-4 给我生成详细的代码:“我想用 Python 做出这款游戏,请生成详细的代码吧。”


第三步:修复bug

代码生成出来后,我把代码放到 VS 里面运行,产生了第一个 bug。我之前没有告诉 ChatGPT-4o,当第一行落地满了时需要自动消除。

第四步:继续修复bug

这个时候,我们得找 ChatGPT-4o,让它修复这个 bug。

ChatGPT-4o 修复了 bug,并告诉我它修复了哪些问题。

第五步:方块下降加速

玩的时候,我发现下落速度有点慢。于是,我又让 ChatGPT-4o 修改代码,加速下落速度。

ChatGPT-4o 告诉我它修改了什么。

第六步:给游戏加图片

其实到这里,这个教程可以结束了。不过,我觉得我们还得继续完善下,给游戏的方块加上点图片,这样会更好看一些。我问了下 GPT,我应该怎么把里面的方块加图片。

同时,我也问他,在设计图片时尺寸应该是多大。

好了,既然我们知道了要设计多大的图片,那我们就得去弄图片。这时 GPT 正在写代码,但我们一时之间也没有头绪,应该设计什么样的方块图片。这时我想起,干脆用 Midjourney 来生成吧。

嗯,Midjourney 生成了 4 张图片供我参考,我选了第二张,然后我用 Pixelmator Pro 把背景去掉,让它变成透明的,并复制了七份。

嗯,将就着用,然后在游戏里面显示的就是下面的效果了。

丑是丑了点,不过,都到这里了,要什么自行车。

本来到这里,教程实际上应该结束了。不过,既然已经进展到这里,我想增加一些复杂度:让 GPT 设计一个带有开场画面的游戏开始界面。

与此同时,我去找 Midjourney 又给我生成了一张背景图片。

很好,运行游戏的时候是下面这样的,不过它怎么直接让我回车进入呢?我不是说用鼠标点击开始再进去吗?

很好,我让它修改下,它给我弄了一个按钮,但是按钮很丑,我又让它给我修改代码。

很好,这个时候我得去弄一个按钮,这个按钮,还不错,我就用它了。

最终我们的教程来到了最后,是看成品的时候了。

小结

在第六步过程中,产生了一些 bug。我们和 GPT 的对话太长了,它开始有点敷衍,导致游戏里的方块落地就自动消失,而不是行填满的时候才消失。最终经过多次修复,问题得以解决。

完整教程总结

通过这次教程,我们成功地利用 ChatGPT-4o 以及相关工具开发了一款功能完整的俄罗斯方块游戏。整个过程涵盖了从初步规划、代码生成到解决 Bug,以及添加图片和设计开局画面的各个环节。

关键步骤回顾

  1. 规划方案:明确游戏的功能和设计需求。
  2. 生成代码:使用 ChatGPT-4o 生成初步代码,并进行调试和优化。
  3. 修复 Bug:通过 ChatGPT-4o 的帮助,解决代码中的问题。
  4. 添加图片:利用 Midjourney 生成游戏所需的图片,并进行优化。
  5. 设计开局画面:通过添加背景图片和可点击的“开始”按钮,提升游戏的用户体验。

反思与展望

在这个项目中,我不仅体验到了利用 AI 进行游戏开发的便捷性,还学到了如何在遇到问题时,通过多次调试和优化,最终实现目标。虽然过程中出现了多次 Bug,但通过坚持不懈的尝试和修复,最终达到了预期的效果。

未来,我们可以考虑进一步优化游戏,比如:

  • 增加更多游戏模式和难度级别。
  • 优化游戏性能,提升用户体验。
  • 添加音效和背景音乐,增强游戏的娱乐性。

实验目的总结

  1. 实现一个完整的 Tetris 游戏,包括开局画面和游戏主循环。
  2. 在开局画面中使用背景图片和可点击的“开始”按钮。
  3. 确保游戏逻辑正确,包括方块的移动、旋转、合并以及行的清除。

实验步骤回顾

  • 基础实现:

    (1)初步实现了一个基本的 Tetris 游戏,包括方块的移动、旋转和落下。
    (2)实现了行的检测和清除逻辑。

  • 改进和修复:

    (1)修复了方块未填满行时消失的 bug。
    (2)确保方块只有在行完全填满时才会消失。

  • 开局画面:

    (1)添加了开局画面,包含背景图片和“开始”按钮。
    (2)修改代码,实现通过点击按钮来开始游戏。

  • 使用图片作为按钮:

    将“开始”按钮替换为图片,实现更直观的用户界面。

最终代码

我实现了一个功能完整的 Tetris 游戏,包含以下关键功能:

  • 开局画面,使用背景图片和图片按钮。
  • 方块的移动、旋转和正确的碰撞检测。
  • 正确的行清除逻辑,只有在行完全填满时才清除。
  • 游戏结束时显示“Game Over”并提供重新开始的选项。
import pygame
import random

# Initialize Pygame
pygame.init()

# Screen dimensions
screen_width = 300
screen_height = 600
block_size = 30

# Load images for each tetromino (designed at 120x120 pixels)
image_filenames = {
    'I''I.png',
    'J''J.png',
    'L''L.png',
    'O''O.png',
    'S''S.png',
    'T''T.png',
    'Z''Z.png'
}

# Scale images to the desired block size
images = {key: pygame.transform.scale(pygame.image.load(filename), (block_size, block_size))
          for key, filename in image_filenames.items()}

# Load start screen background image
start_bg = pygame.transform.scale(pygame.image.load('start_bg.png'), (screen_width, screen_height))
# Load start button image
start_button_img = pygame.image.load('start_button.png')
start_button_img = pygame.transform.scale(start_button_img, (15050))

# Tetromino shapes and corresponding image keys
shapes = [
    ([[1111]], 'I'),
    ([[111], [010]], 'T'),
    ([[110], [011]], 'Z'),
    ([[011], [110]], 'S'),
    ([[11], [11]], 'O'),
    ([[111], [100]], 'L'),
    ([[111], [001]], 'J')
]

# Initialize the screen
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Tetris")

# Clock
clock = pygame.time.Clock()
fps = 30

# Grid dimensions
grid_width = screen_width // block_size
grid_height = screen_height // block_size

# Create the grid
grid = [[0 for  _ in range(grid_width)] for _ in range(grid_height)]

class Tetromino:
    def __init__(self, shape, image_key):
        self.shape = shape
        self.image_key = image_key
        self.x = grid_width // 2 - len(shape[0]) // 2
        self.y = 0

    def rotate(self):
        self.shape = [list(row) for row in zip(*self.shape[::-1])]

def draw_grid():
    for y in range(grid_height):
        for x in range(grid_width):
            if grid[y][x] != 0:
                screen.blit(images[grid[y][x]], (x * block_size, y * block_size))
            pygame.draw.rect(screen, (255255255), (x * block_size, y * block_size, block_size, block_size), 1)

def check_collision(shape, offset):
    off_x, off_y = offset
    for y, row in enumerate(shape):
        for x, cell in enumerate(row):
            if cell and (x + off_x 0 or x + off_x >= grid_width or y + off_y >= grid_height or grid[y + off_y][x + off_x]):
                return True
    return False

def merge(shape, offset, image_key):
    off_x, off_y = offset
    for y, row in enumerate(shape):
        for x, cell in enumerate(row):
            if cell:
                grid[y + off_y][x + off_x] = image_key

def clear_lines():
    global grid
    lines_cleared = 0
    new_grid = []
    for row in grid:
        if all(cell != 0 for cell in row):
            lines_cleared += 1
        else:
            new_grid.append(row)
    new_grid = [[0 for _ in range(grid_width)] for _ in range(lines_cleared)] + new_grid
    grid = new_grid
    return lines_cleared

def draw_tetromino(tetromino):
    for y, row in enumerate(tetromino.shape):
        for x, cell in enumerate(row):
            if cell:
                screen.blit(images[tetromino.image_key], ((tetromino.x + x) * block_size, (tetromino.y + y) * block_size))

def draw_text(text, size, color, x, y):
    font = pygame.font.Font(None, size)
    text_surface = font.render(text, True, color)
    text_rect = text_surface.get_rect(center=(x, y))
    screen.blit(text_surface, text_rect)

def game_over():
    draw_text("Game Over"74, (255255255), screen_width // 2, screen_height // 2 - 50)
    draw_text("Press R to Restart"36, (255255255), screen_width // 2, screen_height // 2 + 20)
    pygame.display.flip()
    waiting = True
    while waiting:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_r:
                    waiting = False
                    main()

def start_screen():
    start_button_rect = start_button_img.get_rect(center=(screen_width // 2, screen_height // 2))
    while True:
        screen.blit(start_bg, (00))
        draw_text("Tetris"74, (255255255), screen_width // 2, screen_height // 4)
        screen.blit(start_button_img, start_button_rect.topleft)
        pygame.display.flip()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.MOUSEBUTTONDOWN:
                if start_button_rect.collidepoint(event.pos):
                    return

def main():
    global grid
    grid = [[0 for _ in range(grid_width)] for _ in range(grid_height)]
    current_tetromino = Tetromino(*random.choice(shapes))
    next_tetromino = Tetromino(*random.choice(shapes))
    fall_time = 0
    fall_speed = 500  # Initial fall speed in milliseconds
    score = 0
    level = 1
    lines_cleared = 0

    while True:
        screen.fill((000))
        draw_grid()
        draw_tetromino(current_tetromino)
        draw_text(f"Score: {score}"24, (255255255), screen_width - 7030)
        draw_text(f"Level: {level}"24, (255255255), screen_width - 7060)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                return
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    current_tetromino.x -= 1
                    if check_collision(current_tetromino.shape, (current_tetromino.x, current_tetromino.y)):
                        current_tetromino.x += 1
                if event.key == pygame.K_RIGHT:
                    current_tetromino.x += 1
                    if check_collision(current_tetromino.shape, (current_tetromino.x, current_tetromino.y)):
                        current_tetromino.x -= 1
                if event.key == pygame.K_DOWN:
                    current_tetromino.y += 1
                    if check_collision(current_tetromino.shape, (current_tetromino.x, current_tetromino.y)):
                        current_tetromino.y -= 1
                if event.key == pygame.K_UP:
                    current_tetromino.rotate()
                    if check_collision(current_tetromino.shape, (current_tetromino.x, current_tetromino.y)):
                        current_tetromino.rotate()
                        current_tetromino.rotate()
                        current_tetromino.rotate()

        keys = pygame.key.get_pressed()
        if keys[pygame.K_DOWN]:
            fall_speed = 50  # Increase fall speed when down key is pressed
        else:
            fall_speed = 500  # Default fall speed

        fall_time += clock.get_rawtime()
        clock.tick()
        if fall_time >= fall_speed:
            current_tetromino.y += 1
            if check_collision(current_tetromino.shape, (current_tetromino.x, current_tetromino.y)):
                current_tetromino.y -= 1
                merge(current_tetromino.shape, (current_tetromino.x, current_tetromino.y), current_tetromino.image_key)
                lines = clear_lines()
                lines_cleared += lines
                score += lines * 100
                if lines_cleared >= level * 10:
                    level += 1
                    fall_speed = max(100, fall_speed - 20)
                current_tetromino = next_tetromino
                next_tetromino = Tetromino(*random.choice(shapes))
                if check_collision(current_tetromino.shape, (current_tetromino.x, current_tetromino.y)):
                    game_over()
            fall_time = 0

        draw_tetromino(current_tetromino)
        pygame.display.update()

if __name__ == "__main__":
    start_screen()
    main()

通过这个项目,我们不仅完成了一款俄罗斯方块游戏,还积累了丰富的开发经验。希望大家在未来的项目中,也能利用 AI 工具,创造出更多有趣且实用的应用。

量子位年度AI主题策划正在征集中!

欢迎投稿专题 一千零一个AI应365行AI落地方案

或与我们分享你在寻找的AI产品,或发现的AI新动向


点这里👇关注我,记得标星哦~

一键三连「分享」、「点赞」和「在看」

科技前沿进展日日相见 ~ 

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/170519
 
336 次点击