Keep your place in this quest

Log in or sign up for free to subscribe, follow lesson progress, and access more learning content.

示例:完整游戏

本课构建了一个小型收集游戏。玩家在场景中移动,碰到墙壁,收集金币,并在游戏结束时打印最终分数。

为了避免一次性粘贴整个脚本,示例分为你在大多数 Tiniest2D 项目中将使用的相同部分:

  • 资源和状态变量
  • start()
  • onUpdate(dt)
  • onCollision(objA, objB)
  • end()

1. 资源和游戏状态

第一部分创建游戏脚本其余部分将使用的资源和变量。精灵是图像,场景是关卡,玩家是放置在该场景中的对象,分数/速度变量存储简单的游戏状态。

// 创建资源
var playerImg = Sprite(16, 16)
var wallImg = Sprite(16, 16)
var coinImg = Sprite(8, 8)
var level = Scene()

// 创建玩家对象
var player = Object("Player")

// 游戏状态
var score = 0
var speed = 100

此时,变量存在,但游戏尚未将任何内容放置到场景中。该设置发生在 start() 中。

2. start() 函数

start() 在游戏开始时运行一次。使用它来配置对象,设置第一个场景,定位相机,并准备任何起始值。

func start() {
    // 设置玩家
    setSprite(player, playerImg)
    setCollisionType(player, COLLISION_DYNAMIC())
    setX(player, 50)
    setY(player, 50)
    addObject(level, player)

    // 设置起始场景
    setScene(level)

    // 相机居中在玩家上
    setCameraX(level, getX(player))
    setCameraY(level, getY(player))
    setCameraZoom(level, 3)

    print("收集金币!")
}

玩家使用 COLLISION_DYNAMIC() 因为它应该与墙壁发生碰撞并被推出。相机开始时以玩家为中心,因此关卡视图在正确的位置开始。

3. onUpdate(dt) 函数

onUpdate(dt) 每帧运行一次。此时玩家读取输入、移动、更新相机并检查重置键。

dt 是 "增量时间":自上一帧以来经过的时间。将运动乘以 dt 使运动速度在不同帧速率之间保持一致。

func onUpdate(dt) {
    // 玩家移动
    var moveX = 0
    var moveY = 0

    if (isKeyHeld(KEY_LEFT()) || isKeyHeld(KEY_A())) {
        moveX = -1
    }
    if (isKeyHeld(KEY_RIGHT()) || isKeyHeld(KEY_D())) {
        moveX = 1
    }
    if (isKeyHeld(KEY_UP()) || isKeyHeld(KEY_W())) {
        moveY = -1
    }
    if (isKeyHeld(KEY_DOWN()) || isKeyHeld(KEY_S())) {
        moveY = 1
    }

    // 应用移动
    setX(player, getX(player) + moveX * speed * dt)
    setY(player, getY(player) + moveY * speed * dt)

    // 相机跟随玩家
    setCameraX(level, getX(player))
    setCameraY(level, getY(player))

    // 使用 R 键重置关卡
    if (isKeyPressed(KEY_R())) {
        resetScene(level)
        setX(player, 50)
        setY(player, 50)
        score = 0
        print("关卡重置!")
    }
}

移动代码从键盘输入构建方向。然后将该方向添加到玩家的当前位置。在移动后更新相机,以便它跟随新位置。

4. onCollision(objA, objB) 函数

onCollision(objA, objB) 当两个对象碰撞时运行。在这个例子中,金币应该使用 COLLISION_TRIGGER()。触发对象报告重叠,但不阻止移动。

func onCollision(objA, objB) {
    var nameB = getName(objB)
    var typeB = getCollisionType(objB)

    // 收集金币(金币应在场景编辑器中为 TRIGGER 类型)
    if (typeB == COLLISION_TRIGGER()) {
        removeObject(level, objB)
        score = score + 1
        print("分数: " + score)
    }
}

当玩家触碰到触发器时,脚本将该对象从场景中移除并增加分数。这是拾取物、钥匙、增强物和检查点的基本模式。

5. end() 函数

end() 在游戏停止时运行。这个例子仅打印最终得分,但较大的游戏可以使用此函数进行清理或最终调试消息。

func end() {
    print("最终分数: " + score)
}

设置示例

  1. 创建精灵:
  2. Ctrl+Click 在 playerImg 上,绘制一个角色(例如,一个简单的人物)
  3. Ctrl+Click 在 wallImg 上,绘制一个实心方块
  4. Ctrl+Click 在 coinImg 上,绘制一个小圆圈或菱形

  5. 设计场景:

  6. Ctrl+Click 在 level
  7. 在左侧面板中选择 wallImg,将碰撞设置为“静态”
  8. 在边缘涂画墙壁,创建一个迷宫
  9. 选择 coinImg,将碰撞设置为“无”以装饰金币图块
  10. 在关卡中放置金币作为视觉指南

  11. 创建触发金币对象:

涂入场景的精灵用作图块和装饰,但可收集的金币应该是对象,以便碰撞回调可以移除它们。像这样添加金币对象:

var coin1 = Object("Coin1")
var coin2 = Object("Coin2")

func start() {
    // ... 玩家设置 ...

    // 设置金币为触发器
    setSprite(coin1, coinImg)
    setCollisionType(coin1, COLLISION_TRIGGER())
    setX(coin1, 100)
    setY(coin1, 80)
    addObject(level, coin1)

    setSprite(coin2, coinImg)
    setCollisionType(coin2, COLLISION_TRIGGER())
    setX(coin2, 150)
    setY(coin2, 120)
    addObject(level, coin2)

    // ... 其余的开始 ...
}

这个相同的模式可以扩展到更多金币、敌人、门或任何需要脚本行为的对象。