综合演示:贪吃蛇游戏开发

文档概述

本演示文档展示了如何使用轻语言(Qing)开发一个完整的网页版贪吃蛇游戏。该游戏利用画板组件进行图形渲染,通过键盘事件控制蛇的移动方向,演示了时钟定时器、数组操作、碰撞检测、随机数生成、动态布局调整等核心编程技术。贪吃蛇是一款经典的休闲游戏,玩家通过控制小蛇移动并吃到食物来获得分数,同时避免撞墙。

  • 核心玩法:玩家通过键盘方向键(↑ ↓ ← →)控制小蛇在画布中移动,吃到红色食物即可增加蛇身长度并累计分数
  • 游戏规则
    • 小蛇撞墙即游戏结束
    • 每吃到一个食物,蛇身长度增加,分数增加 10 分
    • 随着蛇身增长,游戏难度逐渐提升(操作空间变小)
  • 技术亮点
    • 使用画板组件进行游戏画面的实时渲染
    • 利用时钟组件实现游戏主循环(每 150 毫秒更新一次状态)
    • 通过键盘事件捕捉玩家操作,动态调整蛇的移动方向
    • 响应式布局适配:窗口尺寸变化时自动调整组件位置

涉及组件

  • 标签:显示游戏标题、玩法说明和得分信息
  • 按钮:开始/重新开始游戏
  • 画板:绘制游戏场景(蛇身、食物、得分)
  • 时钟类:游戏主循环定时器(每 150 毫秒更新一次)
  • 键盘按键被按下事件:捕捉键盘方向键控制蛇的方向
  • 窗口尺寸被改变事件:响应窗口大小变化,自动调整布局
  • 页面加载完毕事件:页面初始化,设置标题和画板尺寸

涉及函数与 API

函数/API用途
创建时钟(子函数, 间隔时间)创建游戏主循环定时器
销毁时钟(时钟ID)游戏结束时销毁定时器
添加成员首(数组, 值)在蛇身数组头部插入新蛇头坐标
删除成员尾(数组)未吃到食物时移除蛇尾,保持蛇身长度不变
取随机整数(最小值, 最大值)随机生成食物位置
置画布尺寸(宽度, 高度)设置画板的绘制区域尺寸
取实际宽度()获取组件的实际渲染宽度
事件源.keyCode获取键盘按键的键码值
置组件水平居中(组件)将组件水平居中
信息框(消息)弹出游戏结束提示框

💡 本演示中使用到的画板绘制函数(填充样式填充矩形画笔样式字体画文本)请参考画板组件专项文档。

程序代码

界面布局文件:游戏页面.spldg

<?xml version="1.0" encoding="utf-8"?>
<页面 标题="贪吃蛇游戏 - 中文代码版" 宽度="734" 高度="509">
  <绝对布局 名称="根布局" 宽度="100" 高度="100">
    <!-- 游戏标题 -->
    <标签 名称="标签2" 左边="115" 顶边="30" 宽度="600" 高度="30" 文本="🐍 贪吃蛇游戏 - 中文代码版" 字体大小="24" 字体粗细="粗体" />
    <!-- 游戏画板 -->
    <画板 名称="画板1" 左边="115" 顶边="80" 宽度="600" 高度="300" 背景颜色="#B5C493" />
    <!-- 玩法说明 -->
    <标签 名称="标签1" 左边="115" 顶边="395" 宽度="350" 高度="65" 文本="🎮 游戏玩法:\n点击「开始游戏」后,按下键盘中的 ↑ ↓ ← → 分别控制小蛇的移动方向。\n🐍 小蛇吃到的食物越多,蛇身越长,得分越高!" 字体大小="14" 文本颜色="#555555" />
    <!-- 开始按钮 -->
    <按钮 名称="按钮1" 左边="480" 宽度="180" 顶边="395" 高度="40" 文本="🚀 开始游戏" 背景颜色="#1890ff" 文本颜色="#ffffff" 边框圆角="6px" />
  </绝对布局>
</页面>

逻辑文件:游戏页面.spl

' ****************************************************************************
' 版权说明:Copyright(C) All Rights Reserved VcnStudio
' 程序版本:V1.0
' 程序作者:VcnStudio
' 联系信息:
' 窗口描述:贪吃蛇游戏 - 中文代码版
' ****************************************************************************

' ========== 游戏核心变量 ==========
' 构建蛇身和食物的小方块尺寸
变量 方块尺寸 = 20

' 记录已经吃到的食物数量(得分)
变量 分数 = 0

' 循环游戏的计时器,负责循环渲染游戏界面
变量 时钟1

' 定义蛇身(数组)数组中的每个项为一个坐标对象
变量 蛇身 = [{X:10, Y:5}]

' 定义食物坐标
变量 食物 = { X:10, Y:10 }

' 定义移动方向(偏移量)
变量 水平偏移 = 1
变量 垂直偏移 = 0

' 定义游戏状态,是否已结束
变量 游戏已结束 = 假

' ========== 页面加载事件 ==========
事件 页面加载完毕()
    ' 设置页面标题
    置页面标题("贪吃蛇游戏网页版 - By:VcnStudio")

    ' 初始化画板
    画板1.置画布尺寸(600, 300)

    ' 调整页面布局(居中、对齐)
    调整页面布局()
结束 事件

' ========== 开始游戏按钮 ==========
事件 按钮1.被单击(源对象, 事件源)
    ' 重置游戏状态
    分数 = 0
    游戏已结束 = 假
    蛇身 = [{X:10, Y:5}]
    食物 = { X:10, Y:10 }
    水平偏移 = 1
    垂直偏移 = 0

    ' 更新按钮文字
    按钮1.文本 = "⏳ 游戏进行中..."
    按钮1.禁用 = 真

    ' 启动游戏主循环(每 150 毫秒更新一次)
    时钟1 = 创建时钟(更新游戏状态, 150)
结束 事件

' ========== 游戏主循环(由时钟触发) ==========
函数 更新游戏状态()
    如果(游戏已结束 == 真)
        返回
    结束 如果

    ' 计算新的蛇头位置(根据当前方向)
    变量 新蛇头坐标 = {
        X: 蛇身[0].X + 水平偏移, 
        Y: 蛇身[0].Y + 垂直偏移 
    }

    ' 检测是否撞墙,撞墙则结束游戏
    如果(检测是否撞墙(新蛇头坐标))
        游戏结束("撞墙了,游戏结束!")
        返回
    结束 如果

    ' 检测是否撞到自己(蛇头碰到蛇身)
    变量循环(计次 = 0, 取数组成员数(蛇身), 1)
        如果(计次 > 0 且 新蛇头坐标.X == 蛇身[计次].X 且 新蛇头坐标.Y == 蛇身[计次].Y)
            游戏结束("咬到自己了,游戏结束!")
            返回
        结束 如果
    结束循环

    ' 将新的蛇头坐标添加到蛇身
    添加成员首(蛇身, 新蛇头坐标)

    ' 检测是否吃到了食物
    如果(新蛇头坐标.X == 食物.X 且 新蛇头坐标.Y == 食物.Y)
        ' 吃到食物,得分增加
        分数 = 分数 + 10

        ' 生成新的食物坐标
        ' 注意:取随机数的最大值不能超过(画板宽度/方块尺寸)- 1
        变量 最大X = 画板1.取渲染宽度() / 方块尺寸 - 1
        变量 最大Y = 画板1.取渲染高度() / 方块尺寸 - 1
        食物 = { 
            X: 取随机整数(1, 最大X - 1), 
            Y: 取随机整数(1, 最大Y - 1) 
        }
    否则
        ' 没有吃到食物,则移除蛇尾
        ' 因为上一步已经添加了新的蛇头,没吃到食物需要保证蛇身长度不变
        删除成员尾(蛇身)
    结束 如果

    ' 绘制游戏元素
    绘制游戏内容()
结束 函数

' ========== 游戏结束处理 ==========
函数 游戏结束(提示信息)
    游戏已结束 = 真
    销毁时钟(时钟1)
    按钮1.文本 = "🔁 重新开始游戏"
    按钮1.禁用 = 假
    信息框(提示信息 + " 得分:" + 分数)
结束 函数

' ========== 绘制游戏画面 ==========
函数 绘制游戏内容()
    ' 清空画板内容(每次绘制都需要先清空上一次绘制的内容)
    画板1.填充样式 = "#B5C493"
    画板1.填充矩形(0, 0, 600, 300)

    ' ===== 绘制蛇身 =====
    画板1.填充样式 = "#2E8B57"
    ' 蛇头用稍微亮一点的颜色
    变量 蛇头 = 蛇身[0]
    画板1.填充矩形(蛇头.X * 方块尺寸, 蛇头.Y * 方块尺寸, 方块尺寸 - 2, 方块尺寸 - 2)

    ' 蛇身用绿色系
    画板1.填充样式 = "#32CD32"
    变量循环(索引 = 0, 取数组成员数(蛇身), 1)
        变量 坐标点 = 蛇身[索引]
        画板1.填充矩形(坐标点.X * 方块尺寸, 坐标点.Y * 方块尺寸, 方块尺寸 - 2, 方块尺寸 - 2)
    结束循环

    ' ===== 绘制食物 =====
    画板1.填充样式 = "#FF4444"
    画板1.填充矩形(食物.X * 方块尺寸, 食物.Y * 方块尺寸, 方块尺寸 - 2, 方块尺寸 - 2)

    ' ===== 绘制分数(左上角) =====
    画板1.画笔样式 = "#333333"
    画板1.字体 = "20px Arial"
    画板1.画文本("🎯 得分:" + 分数, 10, 25)

    ' ===== 如果游戏已结束,显示遮罩和提示 =====
    如果(游戏已结束)
        画板1.填充样式 = "rgba(0,0,0,0.5)"
        画板1.填充矩形(0, 0, 600, 300)
        画板1.画笔样式 = "#ffffff"
        画板1.字体 = "36px Arial"
        画板1.画文本("💀 游戏结束", 180, 130)
        画板1.字体 = "20px Arial"
        画板1.画文本("得分:" + 分数, 240, 180)
    结束 如果
结束 函数

' ========== 碰撞检测 ==========
函数 检测是否撞墙(蛇头坐标)
    变量 最大X = 画板1.取渲染宽度() / 方块尺寸 - 1
    变量 最大Y = 画板1.取渲染高度() / 方块尺寸 - 1

    返回 蛇头坐标.X < 0 或 蛇头坐标.X > 最大X 或 蛇头坐标.Y < 0 或 蛇头坐标.Y > 最大Y
结束 函数

' ========== 键盘控制 ==========
事件 键盘按键被按下(事件源)
    如果(游戏已结束)
        返回
    结束 如果

    变量 键码 = 事件源.keyCode

    判断(键码)
        分支 37  ' ← 左
            如果(水平偏移 != 1)  ' 不能直接掉头
                水平偏移 = -1
                垂直偏移 = 0
            结束 如果
        分支 38  ' ↑ 上
            如果(垂直偏移 != 1)  ' 不能直接掉头
                水平偏移 = 0
                垂直偏移 = -1
            结束 如果
        分支 39  ' → 右
            如果(水平偏移 != -1)  ' 不能直接掉头
                水平偏移 = 1
                垂直偏移 = 0
            结束 如果
        分支 40  ' ↓ 下
            如果(垂直偏移 != -1)  ' 不能直接掉头
                水平偏移 = 0
                垂直偏移 = 1
            结束 如果
    结束 判断
结束 事件

' ========== 窗口自适应 ==========
事件 窗口尺寸被改变()
    调整页面布局()
结束 事件

' ========== 布局调整函数 ==========
函数 调整页面布局()
    ' 将画板和标题水平居中
    置组件水平居中(画板1, 标签2)

    ' 按钮对齐到画板右侧
    按钮1.右侧对齐到(画板1)
    按钮1.顶边对齐到底(画板1, 10)

    ' 标签1对齐到画板左侧
    标签1.左侧对齐到(画板1)
    标签1.顶边对齐到底(画板1, 10)

    ' 标签2顶部边距
    标签2.顶边 = 30
结束 函数

游戏运行效果

运行后,你将看到:

  1. 游戏界面:包含标题、游戏画板、玩法说明和开始按钮
  2. 游戏流程
    • 点击「开始游戏」按钮,游戏启动
    • 使用键盘方向键(↑ ↓ ← →)控制小蛇移动
    • 小蛇吃到红色食物,蛇身变长,得分增加 10 分
    • 小蛇撞墙或咬到自己时,游戏结束
    • 点击「重新开始游戏」按钮可重新开始
  3. 交互反馈
    • 游戏过程中,蛇头和蛇身使用不同的绿色区分
    • 游戏结束时,画板会显示半透明遮罩和游戏结束提示
    • 得分实时显示在画板左上角

学习要点

通过本综合演示,你可以学习到以下轻语言编程技术:

知识点代码位置说明
画板图形绘制绘制游戏内容()使用 填充样式填充矩形画笔样式画文本 等 API 绘制游戏画面
时钟定时器创建时钟(更新游戏状态, 150)创建游戏主循环定时器,每 150 毫秒更新一次游戏状态
键盘事件键盘按键被按下(事件源)捕捉键盘方向键,控制蛇的移动方向
数组操作添加成员首()删除成员尾()管理蛇身坐标数组,实现蛇的移动逻辑
碰撞检测检测是否撞墙()蛇头撞自身检测检测蛇头是否撞墙或撞到自己
随机数生成取随机整数(最小值, 最大值)随机生成食物的位置
响应式布局调整页面布局()置组件水平居中()窗口尺寸变化时自动调整组件位置
事件清理销毁时钟(时钟1)游戏结束时销毁定时器,避免内存泄漏

扩展方向

你可以基于这个游戏继续扩展以下功能:

  • 难度递增:随着得分增加,时钟间隔逐渐缩短(蛇移动速度加快)
  • 障碍物模式:在画板中随机生成障碍物,蛇碰到障碍物则游戏结束
  • 无尽模式:蛇撞墙后从另一侧穿出(类似经典贪吃蛇)
  • 暂停/继续:添加空格键暂停游戏功能
  • 排行榜:使用本地存储(保存配置)记录最高分

💡 相关文档:本演示中使用的画板绘制函数、时钟函数、键盘事件等详细用法,请参考对应的专项文档。