一曲 发表于 2026-8-8 11:37:12

Trae CN 智能体编写俄罗斯方块游戏

本帖最后由 一曲 于 2026-8-9 20:04 编辑

今天,测试Trae CN,
使用火山视窗写一个俄罗斯方块游戏
全程监控,代码自动生成,自动编译,只需手动检查软件运行中的错误。真正实现代码零手动。




<火山程序 类型 = "通常" 版本 = 1 />

包 火山.俄罗斯方块

# ============================================================
# 第一部分:启动类
# 参考:所有例程启动类结构(如 vol-选择夹1 / 你好祖国)
# 基础类 = 窗口程序类,必须定义启动方法,并在其中调用创建主窗口
# ============================================================

类 启动类 <公开 基础类 = 窗口程序类>
{
    变量 主窗口对象 <类型 = 我的主窗口 标题 = "俄罗斯方块">

    方法 启动方法 <公开 类型 = 整数>
    {
      // ref: 火山.MFC界面.基本.窗口.创建主窗口
      主窗口对象.创建主窗口 ()
      返回 (1)
    }
}

# ============================================================
# 第二部分:方块形状常量类
# 7种标准俄罗斯方块 × 4种旋转状态 = 28个一维数组(每个16成员=4×4)
# 类型编号约定:
#   0=I(青)1=O(黄)2=T(紫)3=S(绿)4=Z(红)5=L(橙)6=J(蓝)
# 语法参考:vol_win_manual.md P99-P106 数组立即数定义
#   常量 名 <类型 = "整数 []" 值 = { 0,0,0,0,... }>
# ============================================================

类 形状常量 <公开>
{

    # ---------- I型(青色,水平长条)----------

    常量 I_0 <公开 类型 = "整数 []" 值 = {0,0,0,0, 1,1,1,1, 0,0,0,0, 0,0,0,0}>
    常量 I_1 <公开 类型 = "整数 []" 值 = {0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0}>
    常量 I_2 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,0,0,0, 1,1,1,1, 0,0,0,0}>
    常量 I_3 <公开 类型 = "整数 []" 值 = {0,1,0,0, 0,1,0,0, 0,1,0,0, 0,1,0,0}>

    # ---------- O型(黄色,正方形,4旋转相同)----------

    常量 O_0 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,1,1,0, 0,1,1,0, 0,0,0,0}>
    常量 O_1 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,1,1,0, 0,1,1,0, 0,0,0,0}>
    常量 O_2 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,1,1,0, 0,1,1,0, 0,0,0,0}>
    常量 O_3 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,1,1,0, 0,1,1,0, 0,0,0,0}>

    # ---------- T型(紫色,T字)----------

    常量 T_0 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,1,1,1, 0,0,1,0, 0,0,0,0}>
    常量 T_1 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,0,1,0, 0,1,1,0, 0,0,1,0}>
    常量 T_2 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,0,1,0, 0,1,1,1, 0,0,0,0}>
    常量 T_3 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,0,1,0, 0,0,1,1, 0,0,1,0}>

    # ---------- S型(绿色,右斜)----------

    常量 S_0 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,0,1,1, 0,1,1,0, 0,0,0,0}>
    常量 S_1 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,0,1,0, 0,0,1,1, 0,0,0,1}>
    常量 S_2 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,0,0,0, 0,0,1,1, 0,1,1,0}>
    常量 S_3 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,1,0,0, 0,1,1,0, 0,0,1,0}>

    # ---------- Z型(红色,左斜)----------

    常量 Z_0 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,1,1,0, 0,0,1,1, 0,0,0,0}>
    常量 Z_1 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,0,0,1, 0,0,1,1, 0,0,1,0}>
    常量 Z_2 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,0,0,0, 0,1,1,0, 0,0,1,1}>
    常量 Z_3 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,0,1,0, 0,1,1,0, 0,1,0,0}>

    # ---------- L型(橙黄色,L字)----------

    常量 L_0 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,0,0,1, 0,1,1,1, 0,0,0,0}>
    常量 L_1 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,0,1,0, 0,0,1,0, 0,0,1,1}>
    常量 L_2 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,0,0,0, 0,1,1,1, 0,1,0,0}>
    常量 L_3 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,1,1,0, 0,0,1,0, 0,0,1,0}>

    # ---------- J型(蓝色,反L)----------

    常量 J_0 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,1,0,0, 0,1,1,1, 0,0,0,0}>
    常量 J_1 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,0,1,1, 0,0,1,0, 0,0,1,0}>
    常量 J_2 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,0,0,0, 0,1,1,1, 0,0,0,1}>
    常量 J_3 <公开 类型 = "整数 []" 值 = {0,0,0,0, 0,0,1,0, 0,0,1,0, 0,1,1,0}>
}

# ============================================================
# 第三部分:主窗口类
# ============================================================

类 我的主窗口 <基础类 = 窗口 注释 = "俄罗斯方块主窗口" @视窗.布局 = "client_size = \"500, 650\"" 标题 = "俄罗斯方块">
{

    # --------------------------------------------------------
    # 3.1 界面组件(10个)
    # --------------------------------------------------------
    # 游戏主画板:10列×20行 × 每格30像素 = 300×600像素
    # ref: 画板类定义(vol_win_sys_pkg_026.md P4400起)+ 例程飞机大战主画板

    变量 游戏画板 <类型 = 画板 隐藏值属性 = "0" 组件边框 = 单线边框式 自动重画 = 真 可停留焦点 = 真 @视窗.布局 = "id = 101\r\npos = \"25, 25, 302, 602\"">

    # 下一方块预览画板:4格×4格 × 30 = 120×120像素

    变量 预览画板 <类型 = 画板 隐藏值属性 = "0" 组件边框 = 单线边框式 自动重画 = 真 @视窗.布局 = "id = 102\r\npos = \"350, 25, 122, 122\"">

    # 游戏时钟(方块下落定时器,放角落,26×26标准尺寸)
    # ref: 时钟例程布局写法

    变量 游戏时钟 <类型 = 时钟 隐藏值属性 = "0" @视窗.布局 = "id = 103\r\npos = \"350, 160, 26, 26\"">

    # 预览区标题标签

    变量 标签_下一块 <类型 = 标签 隐藏值属性 = "0" 横向对齐方式 = 居中 @视窗.布局 = "id = 104\r\npos = \"350, 0, 120, 25\"" 标题 = "下一块">

    # 分数显示标签

    变量 标签_分数 <类型 = 标签 隐藏值属性 = "0" @视窗.布局 = "id = 105\r\npos = \"350, 200, 120, 30\"" 标题 = "分数:0">

    # 等级显示标签

    变量 标签_等级 <类型 = 标签 隐藏值属性 = "0" @视窗.布局 = "id = 106\r\npos = \"350, 240, 120, 30\"" 标题 = "等级:1">

    # 最高分显示标签

    变量 标签_最高分 <类型 = 标签 隐藏值属性 = "0" @视窗.布局 = "id = 110\r\npos = \"350, 270, 120, 30\"" 标题 = "最高分:0">

    # 操作说明标签(自动折行 + \n手动换行)

    变量 标签_说明 <类型 = 标签 隐藏值属性 = "0" 是否自动折行 = 真 @视窗.布局 = "id = 107\r\npos = \"350, 300, 130, 120\""
            标题 = "操作说明:\n← → 移动\n↑ 旋转\n↓ 加速\n空格 直落">

    # 重新开始按钮

    变量 按钮_重来 <类型 = 按钮 隐藏值属性 = "0" @视窗.布局 = "id = 108\r\npos = \"350, 430, 120, 35\"" 标题 = "重新开始">

    # 暂停/继续按钮

    变量 按钮_暂停 <类型 = 按钮 隐藏值属性 = "0" @视窗.布局 = "id = 109\r\npos = \"350, 480, 120, 35\"" 标题 = "暂停">

    # 闪烁时钟(消行动画用,150ms间隔)

    变量 闪烁时钟 <类型 = 时钟 隐藏值属性 = "0" @视窗.布局 = "id = 111\r\npos = \"350, 160, 26, 26\"">

    # --------------------------------------------------------
    # 3.2 游戏状态成员变量
    # --------------------------------------------------------
    # 游戏板:整数数组类,10列×20行=200成员,索引=y*10+x
    # 值:0=空;1~7对应7种方块类型号(I/O/T/S/Z/L/J+1)
    # ref: 整数数组类(vol_win_sys_pkg_081.md P9900起)

    变量 游戏板 <类型 = 整数数组类>

    # 当前下落方块信息

    变量 当前方块类型 <类型 = 整数 注释 = "0~6">
    变量 当前方块旋转 <类型 = 整数 注释 = "0~3">
    变量 当前方块X <类型 = 整数 注释 = "左上角格坐标(列0~9)">
    变量 当前方块Y <类型 = 整数 注释 = "左上角格坐标(行,可为负-表示还在顶部外)">
    变量 下一方块类型 <类型 = 整数 注释 = "0~6">

    # 统计信息

    变量 分数 <类型 = 整数>
    变量 等级 <类型 = 整数>
    变量 已消行数 <类型 = 整数>
    变量 最高分 <类型 = 整数>

    # 流程控制

    变量 是否暂停 <类型 = 逻辑型 值 = 假>
    变量 暂停前周期 <类型 = 整数 值 = 500>
    变量 游戏结束 <类型 = 逻辑型 值 = 假>

    # 消行动画状态

    变量 正在消行 <类型 = 逻辑型 值 = 假>
    变量 闪烁计数 <类型 = 整数 值 = 0>
    变量 闪烁显示白色 <类型 = 逻辑型 值 = 假>
    变量 待消除行号 <类型 = 整数数组类 注释 = "最多4行">
    变量 待消除行数 <类型 = 整数 值 = 0>

    # --------------------------------------------------------
    # 3.3 工具方法
    # --------------------------------------------------------
    # 初始化游戏:重置所有状态

    方法 初始化游戏 <类型 = 整数>
    {
      // 游戏板重置为 10×20=200 成员,全部清零
      // ref: 基本类型数组模板类.重置数组 (vol_win_sys_pkg_081.md P9971)
      游戏板.重置数组 (200, 真)

      // 统计归零
      分数 = 0
      等级 = 1
      已消行数 = 0
      游戏结束 = 假
      是否暂停 = 假
      暂停前周期 = 500
      按钮_暂停.标题 = "暂停"

      // 重置消行动画状态
      正在消行 = 假
      闪烁计数 = 0
      闪烁显示白色 = 假
      待消除行号.重置数组 (4, 真)
      待消除行数 = 0
      闪烁时钟.时钟周期 = 0

      // 读取最高分
      // ref: 文本类.读入文本文件 (vol_win_sys_pkg_081.md P8442)
      变量 文件内容 <类型 = 文本型>
      文件内容 = 读入文本文件 ("tetris_highscore.txt", -1, 文本编码类型.多字节)
      如果 (文件内容 != "")
      {
            最高分 = 文本到整数 (文件内容)
      }
      否则
      {
            最高分 = 0
      }

      // 取下一方块(首次)
      // ref: 算术运算类.取随机数 (vol-飞机大战例程 P19951)
      下一方块类型 = 取随机数 (0, 6)

      // 生成当前方块
      生成新方块 ()

      // 设置时钟周期:等级1=500ms
      // ref: 时钟.时钟周期属性写 (vol_win_sys_pkg_026.md P7238)
      游戏时钟.时钟周期 = 500

      // 更新标签显示
      更新标签显示 ()

      返回 (0)
    }

    # 根据类型号+旋转状态+4x4内索引,返回该位置是否有方块(1/0)
    # 参数:方块类型0~6,旋转0~3,格子索引0~15(4x4=16格)

    方法 取形状格值 <类型 = 整数>
    参数 方块类型 <类型 = 整数>
    参数 旋转状态 <类型 = 整数>
    参数 格子索引 <类型 = 整数>
    {
      // 先做边界钳制,防非法传参
      如果 (方块类型 < 0)
      {
            方块类型 = 0
      }
      如果 (方块类型 > 6)
      {
            方块类型 = 6
      }
      如果 (旋转状态 < 0)
      {
            旋转状态 = 0
      }
      如果 (旋转状态 > 3)
      {
            旋转状态 = 3
      }
      如果 (格子索引 < 0)
      {
            格子索引 = 0
      }
      如果 (格子索引 > 15)
      {
            格子索引 = 15
      }

      变量 结果 <类型 = 整数>
      结果 = 0

      // 根据类型分支
      如果 (方块类型 == 0)
      {
            如果 (旋转状态 == 0)
            {
                结果 = 形状常量.I_0 [格子索引]
            }
            否则 (旋转状态 == 1)
            {
                结果 = 形状常量.I_1 [格子索引]
            }
            否则 (旋转状态 == 2)
            {
                结果 = 形状常量.I_2 [格子索引]
            }
            否则
            {
                结果 = 形状常量.I_3 [格子索引]
            }
      }
      否则 (方块类型 == 1)
      {
            如果 (旋转状态 == 0)
            {
                结果 = 形状常量.O_0 [格子索引]
            }
            否则 (旋转状态 == 1)
            {
                结果 = 形状常量.O_1 [格子索引]
            }
            否则 (旋转状态 == 2)
            {
                结果 = 形状常量.O_2 [格子索引]
            }
            否则
            {
                结果 = 形状常量.O_3 [格子索引]
            }
      }
      否则 (方块类型 == 2)
      {
            如果 (旋转状态 == 0)
            {
                结果 = 形状常量.T_0 [格子索引]
            }
            否则 (旋转状态 == 1)
            {
                结果 = 形状常量.T_1 [格子索引]
            }
            否则 (旋转状态 == 2)
            {
                结果 = 形状常量.T_2 [格子索引]
            }
            否则
            {
                结果 = 形状常量.T_3 [格子索引]
            }
      }
      否则 (方块类型 == 3)
      {
            如果 (旋转状态 == 0)
            {
                结果 = 形状常量.S_0 [格子索引]
            }
            否则 (旋转状态 == 1)
            {
                结果 = 形状常量.S_1 [格子索引]
            }
            否则 (旋转状态 == 2)
            {
                结果 = 形状常量.S_2 [格子索引]
            }
            否则
            {
                结果 = 形状常量.S_3 [格子索引]
            }
      }
      否则 (方块类型 == 4)
      {
            如果 (旋转状态 == 0)
            {
                结果 = 形状常量.Z_0 [格子索引]
            }
            否则 (旋转状态 == 1)
            {
                结果 = 形状常量.Z_1 [格子索引]
            }
            否则 (旋转状态 == 2)
            {
                结果 = 形状常量.Z_2 [格子索引]
            }
            否则
            {
                结果 = 形状常量.Z_3 [格子索引]
            }
      }
      否则 (方块类型 == 5)
      {
            如果 (旋转状态 == 0)
            {
                结果 = 形状常量.L_0 [格子索引]
            }
            否则 (旋转状态 == 1)
            {
                结果 = 形状常量.L_1 [格子索引]
            }
            否则 (旋转状态 == 2)
            {
                结果 = 形状常量.L_2 [格子索引]
            }
            否则
            {
                结果 = 形状常量.L_3 [格子索引]
            }
      }
      否则
      {
            如果 (旋转状态 == 0)
            {
                结果 = 形状常量.J_0 [格子索引]
            }
            否则 (旋转状态 == 1)
            {
                结果 = 形状常量.J_1 [格子索引]
            }
            否则 (旋转状态 == 2)
            {
                结果 = 形状常量.J_2 [格子索引]
            }
            否则
            {
                结果 = 形状常量.J_3 [格子索引]
            }
      }
      返回 (结果)
    }

    # 碰撞检测:返回真表示碰撞
    # 给定方块(类型,旋转,x,y),检查越界或与游戏板重叠

    方法 检测碰撞 <类型 = 逻辑型>
    参数 类型 <类型 = 整数>
    参数 旋转 <类型 = 整数>
    参数 x <类型 = 整数>
    参数 y <类型 = 整数>
    {
      变量 i <类型 = 整数>
      变量 cell_x <类型 = 整数>
      变量 cell_y <类型 = 整数>
      变量 格值 <类型 = 整数>
      变量 板值 <类型 = 整数>

      // 枚举4×4=16格
      // ref: 计次循环用法(例程 vol-飞机大战 P19962)
      计次循环 (16)
      {
            i = 取循环索引 ()
            格值 = 取形状格值 (类型, 旋转, i)
            如果 (格值 == 0)
            {
                // 空格子,跳过
                到循环尾
            }
            // 转全局坐标
            cell_x = x + i % 4
            cell_y = y + i / 4

            // 横向越界(左右)
            如果 (cell_x < 0 || cell_x >= 10)
            {
                返回 (真)
            }
            // 下方越界(落地,y超过底线)
            如果 (cell_y >= 20)
            {
                返回 (真)
            }
            // 上方越界忽略(新生成块允许y<0)
            如果 (cell_y >= 0)
            {
                // 与游戏板上已有方块重叠?
                // ref: 整数数组类.取成员 (vol_win_sys_pkg_081.md P9994)
                板值 = 游戏板.取成员 (cell_y * 10 + cell_x)
                如果 (板值 != 0)
                {
                  返回 (真)
                }
            }
      }
      返回 (假)
    }

    # 生成新方块:下一方块→当前块,重新随机下一块
    # 返回:真=成功;假=生成位置就碰撞(游戏结束)

    方法 生成新方块 <类型 = 逻辑型>
    {
      当前方块类型 = 下一方块类型
      当前方块旋转 = 0
      // 初始位置:水平居中(x=3,4格宽的话占3~6列);y=-1(让顶部先露一部分)
      当前方块X = 3
      当前方块Y = -1

      // 下一方块重新随机
      下一方块类型 = 取随机数 (0, 6)

      // 生成位置即碰撞 → 游戏结束
      如果 (检测碰撞 (当前方块类型, 当前方块旋转, 当前方块X, 当前方块Y))
      {
            返回 (假)
      }
      返回 (真)
    }

    # --------------------------------------------------------
    # 3.4 动作方法
    # --------------------------------------------------------
    # 左移一格

    方法 方块左移 <类型 = 整数>
    {
      如果 (检测碰撞 (当前方块类型, 当前方块旋转, 当前方块X - 1, 当前方块Y) == 假)
      {
            当前方块X = 当前方块X - 1
      }
      返回 (0)
    }

    # 右移一格

    方法 方块右移 <类型 = 整数>
    {
      如果 (检测碰撞 (当前方块类型, 当前方块旋转, 当前方块X + 1, 当前方块Y) == 假)
      {
            当前方块X = 当前方块X + 1
      }
      返回 (0)
    }

    # 旋转:旋转状态 +1 mod 4

    方法 方块旋转 <类型 = 整数>
    {
      变量 新旋转 <类型 = 整数>
      新旋转 = (当前方块旋转 + 1) % 4
      如果 (检测碰撞 (当前方块类型, 新旋转, 当前方块X, 当前方块Y) == 假)
      {
            当前方块旋转 = 新旋转
            // ref: 常用功能类.鸣叫 (vol_win_sys_pkg_081.md P16165)
            鸣叫 (鸣叫声音类型.特别)
      }
      返回 (0)
    }

    # 下落一格:返回真=还可继续下落;假=已落地,已固定

    方法 方块下落一格 <类型 = 逻辑型>
    {
      变量 可继续 <类型 = 逻辑型>
      可继续 = 真

      // 如果再下一格会碰撞 → 固定方块
      如果 (检测碰撞 (当前方块类型, 当前方块旋转, 当前方块X, 当前方块Y + 1))
      {
            固定方块 ()
            // ref: 常用功能类.鸣叫 (vol_win_sys_pkg_081.md P16165)
            鸣叫 (鸣叫声音类型.标准)

            // 检测满行(仅检测不消除)
            待消除行数 = 检测满行 ()
            如果 (待消除行数 > 0)
            {
                // 启动消行闪烁动画
                正在消行 = 真
                闪烁计数 = 0
                闪烁显示白色 = 真
                游戏时钟.时钟周期 = 0
                闪烁时钟.时钟周期 = 150
            }
            否则
            {
                // 无消行,直接生成新方块
                如果 (生成新方块 () == 假)
                {
                  游戏结束处理 ()
                }
            }
            可继续 = 假
      }
      否则
      {
            // 正常下落
            当前方块Y = 当前方块Y + 1
      }
      返回 (可继续)
    }

    # 直接落底:循环调用下落一格直到返回假

    方法 方块直接落底 <类型 = 整数>
    {
      变量 可继续 <类型 = 逻辑型>
      可继续 = 真
      判断循环 (可继续)
      {
            可继续 = 方块下落一格 ()
      }
      返回 (0)
    }

    # 将当前方块4x4中的实心格子写入游戏板数组

    方法 固定方块 <类型 = 整数>
    {
      变量 i <类型 = 整数>
      变量 cell_x <类型 = 整数>
      变量 cell_y <类型 = 整数>
      变量 格值 <类型 = 整数>
      变量 类型号1to7 <类型 = 整数>

      // 类型号存储=类型+1(0~6 → 1~7,保留0表示空)
      类型号1to7 = 当前方块类型 + 1

      计次循环 (16)
      {
            i = 取循环索引 ()
            格值 = 取形状格值 (当前方块类型, 当前方块旋转, i)
            如果 (格值 == 0)
            {
                到循环尾
            }
            cell_x = 当前方块X + i % 4
            cell_y = 当前方块Y + i / 4
            // 仅在可视范围内写入(y>=0)
            如果 (cell_y >= 0 && cell_y < 20 && cell_x >= 0 && cell_x < 10)
            {
                // ref: 基本类型数组模板类.置成员值 (vol_win_sys_pkg_081.md P10011)
                游戏板.置成员值 (cell_y * 10 + cell_x, 类型号1to7)
            }
      }
      返回 (0)
    }

    # 检测满行:仅检测哪些行已满,存入待消除行号数组,返回满行数

    方法 检测满行 <类型 = 整数>
    {
      变量 满行数 <类型 = 整数>
      满行数 = 0
      变量 y <类型 = 整数>
      y = 19
      判断循环 (y >= 0)
      {
            变量 该行全满 <类型 = 逻辑型>
            该行全满 = 真
            变量 x <类型 = 整数>
            x = 0
            判断循环 (x < 10 && 该行全满)
            {
                如果 (游戏板.取成员 (y * 10 + x) == 0)
                {
                  该行全满 = 假
                }
                x = x + 1
            }
            如果 (该行全满)
            {
                // 记录满行行号
                待消除行号.置成员值 (满行数, y)
                满行数 = 满行数 + 1
            }
            y = y - 1
      }
      返回 (满行数)
    }

    # 执行消行:将待消除行号中记录的行实际消除(上方下移)

    方法 执行消行 <类型 = 整数>
    {
      变量 i <类型 = 整数>
      变量 y <类型 = 整数>
      变量 x <类型 = 整数>
      变量 yy <类型 = 整数>

      // 对每个待消除行执行消除(从下往上处理)
      // 先对待消除行号排序(从大到小),避免消除时行号错乱
      变量 tmp <类型 = 整数>
      变量 j <类型 = 整数>
      计次循环 (待消除行数 - 1)
      {
            i = 取循环索引 ()
            j = 0
            判断循环 (j < 待消除行数 - 1 - i)
            {
                如果 (待消除行号.取成员 (j) < 待消除行号.取成员 (j + 1))
                {
                  tmp = 待消除行号.取成员 (j)
                  待消除行号.置成员值 (j, 待消除行号.取成员 (j + 1))
                  待消除行号.置成员值 (j + 1, tmp)
                }
                j = j + 1
            }
      }

      // 逐行消除
      计次循环 (待消除行数)
      {
            i = 取循环索引 ()
            y = 待消除行号.取成员 (i)
            // 上方所有行下移一行
            yy = y
            判断循环 (yy > 0)
            {
                x = 0
                计次循环 (10)
                {
                  x = 取循环索引 ()
                  游戏板.置成员值 (yy * 10 + x, 游戏板.取成员 ((yy - 1) * 10 + x))
                }
                yy = yy - 1
            }
            // 顶行清零
            x = 0
            计次循环 (10)
            {
                x = 取循环索引 ()
                游戏板.置成员值 (x, 0)
            }
      }
      返回 (0)
    }

    # 根据消除行数更新分数和等级

    方法 更新分数等级 <类型 = 整数>
    参数 本次消除行数 <类型 = 整数>
    {
      // 计分规则:1行100 / 2行300 / 3行500 / 4行800
      如果 (本次消除行数 == 1)
      {
            分数 = 分数 + 100
      }
      否则 (本次消除行数 == 2)
      {
            分数 = 分数 + 300
      }
      否则 (本次消除行数 == 3)
      {
            分数 = 分数 + 500
      }
      否则 (本次消除行数 == 4)
      {
            分数 = 分数 + 800
      }

      已消行数 = 已消行数 + 本次消除行数

      // 每消10行升1级
      变量 新等级 <类型 = 整数>
      新等级 = 已消行数 / 10 + 1
      如果 (新等级 != 等级)
      {
            等级 = 新等级
            // 指数加速曲线:500 * 0.85^(等级-1),下限50ms
            变量 新周期 <类型 = 整数>
            新周期 = 500
            计次循环 (等级 - 1)
            {
                新周期 = 新周期 * 85 / 100
            }
            如果 (新周期 < 50)
            {
                新周期 = 50
            }
            游戏时钟.时钟周期 = 新周期
            暂停前周期 = 新周期
      }
      更新标签显示 ()
      返回 (0)
    }

    # 游戏结束处理

    方法 游戏结束处理 <类型 = 整数>
    {
      游戏结束 = 真
      游戏时钟.时钟周期 = 0// 停止时钟
      // ref: 常用功能类.鸣叫 (vol_win_sys_pkg_081.md P16165)
      鸣叫 (鸣叫声音类型.拒绝)

      // 更新最高分
      变量 是否破纪录 <类型 = 逻辑型>
      是否破纪录 = 假
      如果 (分数 > 最高分)
      {
            最高分 = 分数
            是否破纪录 = 真
            // ref: 文本类.写出文本文件 (vol_win_sys_pkg_081.md P8471)
            写出文本文件 (到文本 (分数), "tetris_highscore.txt", -1, 文本编码类型.多字节)
      }
      更新标签显示 ()

      // 提示:信息框(例程vol-飞机大战P19977参考)
      变量 提示文本 <类型 = 文本型>
      提示文本 = "游戏结束!\r\n最终分数:" + 到文本 (分数) + "\r\n等级:" + 到文本 (等级) + "\r\n累计消除行数:" + 到文本 (已消行数)
      如果 (是否破纪录)
      {
            提示文本 = 提示文本 + "\r\n恭喜打破最高分纪录!"
      }
      信息框 (提示文本)
      返回 (0)
    }

    # --------------------------------------------------------
    # 3.5 渲染方法
    # --------------------------------------------------------
    # 根据类型号1~7返回对应颜色整数(刷子填充色)
    # 颜色参考:颜色类成员常量 (vol_win_sys_pkg_081.md P11967起)

    方法 取方块颜色 <类型 = 整数>
    参数 类型号1to7 <类型 = 整数>
    {
      变量 颜色结果 <类型 = 整数>
      颜色结果 = 颜色类.蓝色

      如果 (类型号1to7 == 1)
      {
            颜色结果 = 取颜色值 (0, 255, 255)
      }
      否则 (类型号1to7 == 2)
      {
            颜色结果 = 颜色类.黄色
      }
      否则 (类型号1to7 == 3)
      {
            颜色结果 = 颜色类.紫色
      }
      否则 (类型号1to7 == 4)
      {
            颜色结果 = 颜色类.绿色
      }
      否则 (类型号1to7 == 5)
      {
            颜色结果 = 颜色类.红色
      }
      否则 (类型号1to7 == 6)
      {
            颜色结果 = 颜色类.橙黄色
      }
      否则
      {
            颜色结果 = 颜色类.蓝色
      }
      返回 (颜色结果)
    }

    # 绘制单个方格:在指定画板的 (格内X,格内Y) 位置画指定类型颜色的实心方块
    # 每格30像素,四周留1像素做网格线,所以画 1~29(宽高28px)

    方法 绘制单个方格 <类型 = 整数>
    参数 画板对象 <类型 = 画板>
    参数 格内X <类型 = 整数>
    参数 格内Y <类型 = 整数>
    参数 类型号1to7 <类型 = 整数>
    {
      变量 左x <类型 = 整数>
      变量 顶y <类型 = 整数>
      变量 右x <类型 = 整数>
      变量 底y <类型 = 整数>

      左x = 格内X * 30 + 1
      顶y = 格内Y * 30 + 1
      右x = 格内X * 30 + 29
      底y = 格内Y * 30 + 29

      // 设置刷子颜色 = 方块颜色(填充内部)
      // ref: 画板.刷子颜色属性写 (vol_win_sys_pkg_026.md P4486)
      画板对象.刷子颜色 = 取方块颜色 (类型号1to7)
      // 设置画笔颜色 = 深**(描边框)
      // ref: 画板.画笔颜色属性写 (vol_win_sys_pkg_026.md P4450)
      画板对象.画笔颜色 = 颜色类.**
      // 画笔粗细=1像素
      画板对象.画笔粗细 = 1

      // ref: 画板.画矩形 (vol_win_sys_pkg_026.md P4689)
      画板对象.画矩形 (左x, 顶y, 右x, 底y)

      返回 (0)
    }

    # 更新分数/等级/最高分标签文字

    方法 更新标签显示 <类型 = 整数>
    {
      // ref: 文本类.到文本(例程普遍使用)
      标签_分数.标题 = "分数:" + 到文本 (分数)
      标签_等级.标题 = "等级:" + 到文本 (等级)
      标签_最高分.标题 = "最高分:" + 到文本 (最高分)
      返回 (0)
    }

    # 重绘整个游戏画面

    方法 重绘游戏画面 <类型 = 整数>
    {
      变量 x <类型 = 整数>
      变量 y <类型 = 整数>
      变量 板值 <类型 = 整数>

      // 第一步:清除游戏画板
      // ref: 画板.清除 (vol_win_sys_pkg_026.md P4588)
      游戏画板.清除 ()

      // 第二步:画网格线(浅**,含外边框共竖11条+横21条)
      游戏画板.画笔颜色 = 颜色类.浅**
      游戏画板.画笔粗细 = 0
      // 竖线:x=0,30,60,...,270,300 共11条(含左右外边框)
      计次循环 (11)
      {
            x = 取循环索引 ()
            游戏画板.画直线 (x * 30, 0, x * 30, 600)
      }
      // 横线:y=0,30,60,...,570,600 共21条(含上下外边框)
      计次循环 (21)
      {
            y = 取循环索引 ()
            游戏画板.画直线 (0, y * 30, 300, y * 30)
      }

      // 第三步:遍历游戏板,画所有已落下的方块
      // 如果正在消行闪烁且显示白色,满行画白色
      变量 i <类型 = 整数>
      计次循环 (200)
      {
            变量 idx <类型 = 整数>
            idx = 取循环索引 ()
            板值 = 游戏板.取成员 (idx)
            如果 (板值 != 0)
            {
                x = idx % 10
                y = idx / 10
                // 检查该行是否在待消除行号中
                变量 是满行 <类型 = 逻辑型>
                是满行 = 假
                如果 (正在消行 && 闪烁显示白色)
                {
                  计次循环 (待消除行数)
                  {
                        i = 取循环索引 ()
                        如果 (待消除行号.取成员 (i) == y)
                        {
                            是满行 = 真
                        }
                  }
                }
                如果 (是满行)
                {
                  // 画白色方块
                  游戏画板.刷子颜色 = 颜色类.白色
                  游戏画板.画笔颜色 = 颜色类.**
                  游戏画板.画笔粗细 = 1
                  游戏画板.画矩形 (x * 30 + 1, y * 30 + 1, x * 30 + 29, y * 30 + 29)
                }
                否则
                {
                  绘制单个方格 (游戏画板, x, y, 板值)
                }
            }
      }

      // 第四步:画降落阴影 + 当前方块(若游戏未结束且未在消行动画中)
      如果 (游戏结束 == 假 && 正在消行 == 假)
      {
            // 4a: 计算阴影位置(方块落底后的Y坐标)
            变量 影子Y <类型 = 整数>
            影子Y = 当前方块Y
            判断循环 (检测碰撞 (当前方块类型, 当前方块旋转, 当前方块X, 影子Y + 1) == 假)
            {
                影子Y = 影子Y + 1
            }

            // 4b: 画阴影(仅当影子Y > 当前方块Y时才画)
            如果 (影子Y > 当前方块Y)
            {
                变量 格值 <类型 = 整数>
                变量 cell_x <类型 = 整数>
                变量 cell_y <类型 = 整数>
                计次循环 (16)
                {
                  i = 取循环索引 ()
                  格值 = 取形状格值 (当前方块类型, 当前方块旋转, i)
                  如果 (格值 == 0)
                  {
                        到循环尾
                  }
                  cell_x = 当前方块X + i % 4
                  cell_y = 影子Y + i / 4
                  如果 (cell_y >= 0 && cell_x >= 0 && cell_x < 10 && cell_y < 20)
                  {
                        // 画浅**半透明效果(用浅**填充+**边框)
                        游戏画板.刷子颜色 = 颜色类.浅**
                        游戏画板.画笔颜色 = 颜色类.**
                        游戏画板.画笔粗细 = 1
                        游戏画板.画矩形 (cell_x * 30 + 1, cell_y * 30 + 1, cell_x * 30 + 29, cell_y * 30 + 29)
                  }
                }
            }

            // 4c: 画当前下落方块
            {
                变量 格值2 <类型 = 整数>
                变量 cell_x2 <类型 = 整数>
                变量 cell_y2 <类型 = 整数>
                计次循环 (16)
                {
                  i = 取循环索引 ()
                  格值2 = 取形状格值 (当前方块类型, 当前方块旋转, i)
                  如果 (格值2 == 0)
                  {
                        到循环尾
                  }
                  cell_x2 = 当前方块X + i % 4
                  cell_y2 = 当前方块Y + i / 4
                  如果 (cell_y2 >= 0 && cell_x2 >= 0 && cell_x2 < 10 && cell_y2 < 20)
                  {
                        绘制单个方格 (游戏画板, cell_x2, cell_y2, 当前方块类型 + 1)
                  }
                }
            }
      }

      // 第五步:同步更新预览画板
      重绘预览画面 ()

      返回 (0)
    }

    # 重绘下一方块预览画面

    方法 重绘预览画面 <类型 = 整数>
    {
      预览画板.清除 ()

      // 画预览网格线(4×4格,30像素/格,共120×120像素,含外边框共5竖5横)
      变量 px <类型 = 整数>
      变量 py <类型 = 整数>
      预览画板.画笔颜色 = 颜色类.浅**
      预览画板.画笔粗细 = 0
      // 竖线:x=0,30,60,90,120 共5条(含左右外边框)
      计次循环 (5)
      {
            px = 取循环索引 ()
            预览画板.画直线 (px * 30, 0, px * 30, 120)
      }
      // 横线:y=0,30,60,90,120 共5条(含上下外边框)
      计次循环 (5)
      {
            py = 取循环索引 ()
            预览画板.画直线 (0, py * 30, 120, py * 30)
      }

      // 下一方块居中绘制
      变量 i <类型 = 整数>
      变量 格值 <类型 = 整数>
      变量 gx <类型 = 整数>
      变量 gy <类型 = 整数>
      计次循环 (16)
      {
            i = 取循环索引 ()
            格值 = 取形状格值 (下一方块类型, 0, i)
            如果 (格值 == 0)
            {
                到循环尾
            }
            gx = i % 4
            gy = i / 4
            绘制单个方格 (预览画板, gx, gy, 下一方块类型 + 1)
      }
      返回 (0)
    }

    # --------------------------------------------------------
    # 3.6 事件接收方法
    # --------------------------------------------------------
    # 主窗口创建完毕事件:初始化游戏 + 获取焦点
    # 事件签名参考:例程 vol-选择夹2 P186 / vol-文件浏览 P482
    #   方法 {类名}_创建完毕 <接收事件 类型 = 整数>
    #   参数 来源对象 <类型 = {类名}>
    #   参数 标记值 <类型 = 整数>

    方法 我的主窗口_创建完毕 <接收事件 类型 = 整数>
    参数 来源对象 <类型 = 我的主窗口>
    参数 标记值 <类型 = 整数>
    {
      初始化游戏 ()
      重绘游戏画面 ()
      重绘预览画面 ()

      // 获取焦点到游戏画板,确保能收到键盘事件
      // ref: 窗口组件.获取焦点 (vol_win_sys_pkg_026.md P10120)
      // 画板默认不接收焦点,需配合"可停留焦点=真"属性
      游戏画板.获取焦点 ()

      返回 (0)
    }

    # 时钟周期事件:游戏时钟和闪烁时钟共用,通过来源对象区分
    # ref: 时钟例程 P564 事件签名(两个时钟共用一个事件方法)

    方法 时钟_周期事件 <接收事件 类型 = 整数>
    参数 来源对象 <类型 = 时钟>
    参数 标记值 <类型 = 整数>
    {
      如果 (来源对象 == 游戏时钟)
      {
            // 游戏时钟:方块下落
            如果 (游戏结束 == 假 && 是否暂停 == 假 && 正在消行 == 假)
            {
                方块下落一格 ()
                重绘游戏画面 ()
            }
      }
      否则 (来源对象 == 闪烁时钟)
      {
            // 闪烁时钟:消行动画
            闪烁计数 = 闪烁计数 + 1
            如果 (闪烁显示白色)
            {
                闪烁显示白色 = 假
            }
            否则
            {
                闪烁显示白色 = 真
            }
            重绘游戏画面 ()

            // 4次切换(2次闪烁)后执行消行
            如果 (闪烁计数 >= 4)
            {
                闪烁时钟.时钟周期 = 0
                正在消行 = 假
                执行消行 ()
                更新分数等级 (待消除行数)
                // ref: 常用功能类.鸣叫 (vol_win_sys_pkg_081.md P16165)
                鸣叫 (鸣叫声音类型.感叹)
                // 生成新方块
                如果 (生成新方块 () == 假)
                {
                  游戏结束处理 ()
                }
                // 恢复游戏时钟
                游戏时钟.时钟周期 = 暂停前周期
                重绘游戏画面 ()
            }
      }
      返回 (0)
    }

    # 键盘按下事件:处理方向键 + 空格
    # ref: 窗口组件.按下某键 (vol_win_sys_pkg_026.md P9905)
    # 按键码:左光标键/右光标键/下光标键/上光标键/空格键
    #   (vol_win_sys_pkg_081.md P13056/P13063/P13069/P13076/P13025)

    方法 窗口组件_按下某键 <接收事件 类型 = 整数>
    参数 来源对象 <类型 = 窗口组件>
    参数 标记值 <类型 = 整数>
    参数 键代码 <类型 = 整数>
    参数 辅Zhu键状态 <类型 = 整数>
    {
      如果 (游戏结束 == 假 && 是否暂停 == 假 && 正在消行 == 假)
      {
            如果 (键代码 == 按键码.左光标键)
            {
                方块左移 ()
                重绘游戏画面 ()
            }
            否则 (键代码 == 按键码.右光标键)
            {
                方块右移 ()
                重绘游戏画面 ()
            }
            否则 (键代码 == 按键码.上光标键)
            {
                方块旋转 ()
                重绘游戏画面 ()
            }
            否则 (键代码 == 按键码.下光标键)
            {
                方块下落一格 ()
                重绘游戏画面 ()
            }
            否则 (键代码 == 按键码.空格键)
            {
                方块直接落底 ()
                重绘游戏画面 ()
            }
      }
      // 返回1:表示本事件已处理完成,不再传递给父窗口
      返回 (1)
    }

    # 按钮被单击事件:重新开始 / 暂停切换
    # ref: 所有按钮事件签名(如时钟例程 P580)

    方法 按钮_被单击 <接收事件 类型 = 整数>
    参数 来源对象 <类型 = 按钮>
    参数 标记值 <类型 = 整数>
    {
      如果 (来源对象 == 按钮_重来)
      {
            初始化游戏 ()
            重绘游戏画面 ()
            重绘预览画面 ()
            游戏画板.获取焦点 ()
      }
      否则 (来源对象 == 按钮_暂停)
      {
            如果 (游戏结束 == 假)
            {
                如果 (是否暂停)
                {
                  // 恢复
                  是否暂停 = 假
                  游戏时钟.时钟周期 = 暂停前周期
                  按钮_暂停.标题 = "暂停"
                }
                否则
                {
                  // 暂停
                  暂停前周期 = 游戏时钟.时钟周期
                  游戏时钟.时钟周期 = 0
                  是否暂停 = 真
                  按钮_暂停.标题 = "继续"
                }
            }
            游戏画板.获取焦点 ()
      }
      返回 (0)
    }
}




白雪皑皑0306 发表于 2026-8-8 12:26:26

用哪个技能书的吗

一曲 发表于 2026-8-8 13:00:45

白雪皑皑0306 发表于 2026-8-8 12:26
用哪个技能书的吗

以官方资料为主,自己编写技能书。

兵三进一 发表于 2026-8-9 11:35:19

精品,学习学习:)

fengyishen 发表于 2026-8-9 18:30:41

完成度很高吖,比我用DeepSeek写出来得效果好耶

安若清风 发表于 2026-8-10 10:24:11

不错,学习了

水常流 发表于 2026-8-14 00:09:14

厉害了

语言 发表于 2026-8-14 13:56:01

直接让Trae用主流语言和架构写会更快。。。
页: [1]
查看完整版本: Trae CN 智能体编写俄罗斯方块游戏