红糖云服-小程序

3. 小游戏开发

跳一跳小游戏开发流程演示

本文用 「跳一跳」类休闲小游戏(角色蓄力起跳、落点得分)作为场景,串一遍 Godot 游戏模板 的完整流程:使用 @htyf-mp/cligame-template 生成项目,在 Godot 中迭代玩法与资源,再在 红糖云服 App真机调试(扫码)验证。

你将获得什么

  • 一个可运行的 Godot 跳跃玩法原型(蓄力、跳跃、落地计分)。
  • 一条 game-template 从初始化到真机调试的完整路径。
  • project.godot、场景脚本与 CLI 构建关系的基本理解。

命令行交互可参考 快速开始 中的 「CLI 界面与流程(实拍)」;本篇差别仅在初始化时选择模板为 game-template

关于 `_game_temp_`

CLI 拉取的 Godot 游戏模板 的目录结构,与本仓库示例 _game_temp_ 同类:根目录含 app.jsonhtyf.typegame)、project.godot,以及 scenes/scripts/assets/ 等 Godot 工程内容。
你本地初始化后的文件夹名可自定(例如 jump-game),不必与 _game_temp_ 同名。


流程总览(Checklist)

阶段你要做的事
1. 新建项目空目录执行 npx @htyf-mp/cli🆕 初始化新小程序项目 → 目录名如 jump-game → 模板 game-template → 镜像 GitHub (最新)
2. 安装依赖cd jump-gameyarnnpm install(以模板 README 为准)
3. 安装 Godot使用与模板匹配的 Godot 4.x 编辑器打开工程中的 project.godot
4. 开发「跳一跳」玩法在场景中放置角色与地面/平台,用脚本实现蓄力、跳跃、得分判定(见下文思路)
5. 真机调试项目根执行 npm run htyf📦 小程序 - 真机调试 → 输入版本 → 扫码
6.(可选)打包项目根执行 CLI → 🔍 小程序 - 打包小程序 → 得到游戏资源包(如 dist.*.dgz

详细步骤

1. 新建项目(CLI + game-template

npx @htyf-mp/cli
  1. 选择 🆕 初始化新小程序项目
  2. 填写示例:
    • 应用程序目录名称jump-game(可自定)
    • 应用程序名称:如 跳一跳
    • 模板类型game-template
    • 模板镜像GitHub (最新)

完成后会生成项目目录,根目录应有 app.json(内含 htyf,且 typegame)与 project.godot

2. 安装 Node 侧依赖

cd jump-game
yarn
# 或
npm install

具体以模板 README 与 CLI 成功页提示为准。

3. 用 Godot 打开工程

  1. 安装 Godot(版本需与模板要求一致,常见为 4.x)。
  2. 在 Godot 中选择 导入,指向项目根目录下的 project.godot
  3. 熟悉 scenes/scripts/ 下的示例场景与脚本(模板内通常带有 SDK 脚本如 _HTYF_SDK/htyf_sdk.gd 等,名称以你仓库为准)。

4. 「跳一跳」玩法示例代码(Godot 4.x)

下面给出一份 可直接照抄 的极简 2D 实现:长按蓄力 → 松手朝右前方起跳 → 落地得分。物理参数可按手感微调。

阶段验收:在 Godot 编辑器内按 F5 可正常起跳、落地并看到分数变化。

建议文件布局(与 _game_temp_ 一致:脚本放 scripts/,场景放 scenes/):

文件作用
scripts/jump_player.gd角色:CharacterBody2D,蓄力与抛物线起跳
scripts/jump_game.gd根节点:分数、HtyfSdk 前后台与 Toast(可选)
scenes/jump/jump_main.tscn主场景(在编辑器里搭节点树并挂载脚本)

场景树(在 Godot 中创建) — 根节点 JumpMainNode2D)挂 jump_game.gd,子节点示例:

  • PlayerCharacterBody2D,挂 jump_player.gd,子节点 CollisionShape2D(胶囊或矩形)、Sprite2DColorRect 占位。
  • PlatformStartPlatformNextStaticBody2D + CollisionShape2D(顶面与角色在同一物理层即可)。
  • Camera2D:设为 Player 子节点并勾选 Position Smoothing,或放在根节点跟随 Player
  • CanvasLayerScoreLabelLabel,用于显示得分。

project.godot 入口(新建场景后把主场景指过去,与模板里 run/main_scene="res://scenes/main/main.tscn" 同理):

[application]
run/main_scene="res://scenes/jump/jump_main.tscn"

scripts/jump_player.gd

extends CharacterBody2D
 
## 极简「跳一跳」:落地蓄力,松手起跳;水平 + 垂直速度随蓄力变化
const GRAVITY := 2600.0
const MAX_CHARGE_TIME := 1.15
const CHARGE_RATE := 1.0
const JUMP_UP := 520.0
const JUMP_FORWARD := 420.0
 
var _charging := false
var _charge := 0.0
var _was_on_floor := true
 
signal jumped(strength: float)
signal landed
 
func _physics_process(delta: float) -> void:
	if not is_on_floor():
		velocity.y += GRAVITY * delta
	else:
		velocity.x = move_toward(velocity.x, 0.0, 1400.0 * delta)
 
	if _charging and is_on_floor():
		_charge = minf(_charge + CHARGE_RATE * delta, MAX_CHARGE_TIME)
 
	move_and_slide()
 
	if is_on_floor() and not _was_on_floor:
		landed.emit()
	_was_on_floor = is_on_floor()
 
func _unhandled_input(event: InputEvent) -> void:
	var down := false
	var up := false
	if event is InputEventScreenTouch:
		down = event.pressed
		up = not event.pressed
	elif event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
		down = event.pressed
		up = not event.pressed
	if down and is_on_floor():
		_charging = true
		_charge = 0.0
	elif up and _charging:
		_charging = false
		_do_jump()
 
func _do_jump() -> void:
	if not is_on_floor():
		return
	var t := _charge / MAX_CHARGE_TIME
	var strength := clampf(t, 0.25, 1.0)
	velocity.y = -JUMP_UP * strength
	velocity.x = JUMP_FORWARD * strength
	jumped.emit(strength)

scripts/jump_game.gd

根脚本里演示如何调用 HtyfSdk(与模板 scripts/demo.gd 相同的全局名;project.godot[autoload] 已注册 HtyfSdk):

extends Node2D
 
@onready var _player: CharacterBody2D = $Player
@onready var _score_label: Label = $CanvasLayer/ScoreLabel
 
var _score: int = 0
 
func _ready() -> void:
	_player.jumped.connect(_on_player_jumped)
	_player.landed.connect(_on_player_landed)
	# 与模板 demo.gd 一致:前后台时可用 Toast 提示(可按需删除)
	HtyfSdk.set_host_lifecycle_callback(
		func(what: int):
			if what == NOTIFICATION_APPLICATION_FOCUS_OUT:
				HtyfSdk.call_show_toast("提示", "游戏已切入后台", "info")
			elif what == NOTIFICATION_APPLICATION_FOCUS_IN:
				HtyfSdk.call_show_toast("提示", "欢迎回来", "success")
	)
 
func _on_player_jumped(_strength: float) -> void:
	pass
 
func _on_player_landed() -> void:
	_score += 1
	_score_label.text = "得分: %d" % _score
	if _score % 5 == 0:
		HtyfSdk.call_show_toast("跳一跳", "已连续落地 %d 次" % _score, "success")

碰撞与图层

  • 项目设置 → 图层名称 中为 PlayerStaticBody2D 平台指定 物理层 / 遮罩,保证角色能站在平台上。
  • CharacterBody2DMotion Mode 建议为 GroundedFloor Stop On Slope 可按地形开启。

与模板自带 scenes/main/main.tscn 的关系

  • 你可以 保留 原 RNInterface 演示场景用于查 API,把 run/main_scene 切到 jump_main.tscn 专门调试玩法;真机调试仍在 项目根 跑 CLI 即可。
  • 模板中 HtyfSdk 的用法也可直接参考 scripts/demo.gd(例如 set_host_lifecycle_callbackcall_show_toast)。

提示

真机调试前,先在 Godot 内 F5 运行 主场景无报错,再交给 CLI 打包/调试,可减少排查成本。

5. 真机调试

  1. 确保 iPhone 已安装红糖云服 App,手机与电脑 同一局域网(或已配置端口转发)。
  2. 游戏项目根目录(存在 app.jsonproject.godot 的目录)执行:
npm run htyf
  1. 选择 📦 小程序 - 真机调试(CLI 会按 游戏 类型走 Godot 导出与调试流程,详见 快速开始 中「项目类型说明」)。
  2. 输入版本号,构建完成后 扫码 在 App 内调试。

6.(可选)打包发布

在项目根执行 npx @htyf-mp/cli,选择 🔍 小程序 - 打包小程序,按提示输入版本。
产物路径与格式以 CLI 输出为准;app.json 中的 zipUrl / appUrlConfig 用于后续分发与更新,详见模板 README。

常见卡点

1) Godot 能跑,但真机扫不出来

  • 确认执行 npm run htyf 的目录同时包含 app.jsonproject.godot
  • 确认手机与电脑网络互通(同一局域网或已做端口转发)。

2) 角色不能站在平台上

  • 优先检查 CharacterBody2D 与平台的碰撞层/遮罩。
  • 再检查平台是否有 CollisionShape2D,且尺寸覆盖可落地区域。

模板结构对照(与 _game_temp_ 同类)

路径 / 文件说明
app.jsonhtyf.typegame,含 appidversionzipUrl
project.godotGodot 工程入口
scenes/scripts/assets/场景、脚本与资源
package.jsonNode 工具链与 @htyf-mp/cli

与模板 README 对齐的配置要点

基于 _game_temp_/README.mdgame-templateapp.json 中建议优先确认:

  • type:应为 game
  • appUrlConfig:游戏配置/元数据地址。
  • zipUrl:游戏资源包地址(分发与更新关键)。
  • version:版本号,配合真机调试/打包管理。
  • engines:Godot 引擎版本声明。

对于游戏模板,可把 app.js 理解为容器入口:负责把打包后的 Godot 资源加载到红糖云服 App 并处理生命周期。

README 推荐工作流(对外分发)

  1. 在 Godot 内完成玩法与资源开发。
  2. app.json 配置好 appUrlConfigzipUrl
  3. 运行 npm run htyf 产出游戏资源包。
  4. 将资源上传到 zipUrl 对应位置,供他人获取更新。

延伸阅读

On this page