使用 Tiniest2D 制作 2D 游戏
完整游戏示例
Lesson 10 of 11 • 10 XP
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)
}
设置示例
- 创建精灵:
- Ctrl+Click 在
playerImg上,绘制一个角色(例如,一个简单的人物) - Ctrl+Click 在
wallImg上,绘制一个实心方块 -
Ctrl+Click 在
coinImg上,绘制一个小圆圈或菱形 -
设计场景:
- Ctrl+Click 在
level - 在左侧面板中选择
wallImg,将碰撞设置为“静态” - 在边缘涂画墙壁,创建一个迷宫
- 选择
coinImg,将碰撞设置为“无”以装饰金币图块 -
在关卡中放置金币作为视觉指南
-
创建触发金币对象:
涂入场景的精灵用作图块和装饰,但可收集的金币应该是对象,以便碰撞回调可以移除它们。像这样添加金币对象:
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)
// ... 其余的开始 ...
}
这个相同的模式可以扩展到更多金币、敌人、门或任何需要脚本行为的对象。