初始化
增加环境和太阳光,模型和照相机。
实现跳跃
Player 节点增加脚本Player.cs
using Godot;
using System;
public partial class Player : Node3D
{
public override void _Ready()
{
}
public override void _Process(double delta)
{
// 跳跃
if (Input.IsActionJustPressed("跳跃"))
{
this.Position = new Vector3(Position.X, Position.Y + 2f, Position.Z);
}
}
}
缓慢向上跳跃
using Godot;
using System;
public partial class Player : Node3D
{
public override void _Ready()
{
}
public override void _Process(double delta)
{
// 跳跃
if (Input.IsActionPressed("跳跃"))
{
this.Position = new Vector3(Position.X, Position.Y + (float)delta , Position.Z);
}
}
}
旋转
using Godot;
using System;
public partial class Player : Node3D
{
public override void _Ready()
{
}
public override void _Process(double delta)
{
// 跳跃
if (Input.IsActionPressed("跳跃"))
{
this.Position = new Vector3(Position.X, Position.Y + (float)delta, Position.Z);
}
// 逆时针旋转形状
if (Input.IsActionPressed("左"))
{
this.RotateZ(-(float)delta);
}
// 逆时针旋转形状
if (Input.IsActionPressed("右"))
{
this.RotateZ((float)delta);
}
}
}
游戏设计
主要由发射台、火箭、着陆台、地面、和其他障碍物组成。
等级场景
拆分第一个场景:等级场景。
这里用到一个基础组件CSGBox3D-构造性立体几何,用于创建各种3D模型。
地面基本设置:
创建一个标准物理材质,这会让地面更轻一些。
3D物体的颜色修改,在这里叫反照率(Albedo):
我们这里设置颜色为
#66452d
:创建发射台、着陆台
同上, 发射台、着陆台大小(2,0.4,2),都开启碰撞, 发射台位置(-7.5,0.2,0)颜色#56a9c9
,着陆台位置(7.5,0.2,0)颜色#16ba3d
。
环境
增加环境3要素:环境、太阳、3D相机。
拖动3D相机的z轴到合适的位置,可以点开预览图查看实际效果(最终位置为0,0,11)。
但这不是我这个游戏设计的最终效果,最终位置为(0,4,8.4
),旋转设置为(-2.2,0,0)
游戏运行效果如下:
火箭(玩家)
将玩家场景实例化:
这里我们不需要火箭实现环境3要素,点进去删除:
将火箭放在发射台的子节点,位置归0,就会发现火箭的位置会基于父节点初始化。
火箭向Y轴调整在底座上即可(基座高0.2m+自身一半的高度1m)。
然后将火箭从发射台子节点移出,因为我们并不需要将其设置为发射台的子节点,挪出后坐标数值改变,但模型位置不变。
修改一下脚本
......
// 逆时针旋转形状
if (Input.IsActionPressed("左"))
{
this.RotateZ((float)delta);
}
// 逆时针旋转形状
if (Input.IsActionPressed("右"))
{
this.RotateZ(-(float)delta);
}
......
运行,火箭我们还能继续操控。
增加火箭刚体
进入玩家场景,更改根节点类型为刚体RigidBody3D,并增加碰撞体。
锁定火箭仅支持向右和向上运动,不让沿任何轴旋转,也就是锁定Z轴移动和X轴、Y轴旋转。
提高阻尼,让物理更现实。
修改Player.cs脚本。
using Godot;
using System;
public partial class Player : RigidBody3D
{
public override void _Ready()
{
}
public override void _Process(double delta)
{
// 跳跃
if (Input.IsActionPressed("跳跃"))
{
// this.Position = new Vector3(Position.X, Position.Y + (float)delta, Position.Z);
// 施加中心力,向上
this.ApplyCentralForce(Vector3.Up * (float)delta * 1000.0f);
}
// 逆时针旋转形状
if (Input.IsActionPressed("左"))
{
this.RotateZ((float)delta);
}
// 逆时针旋转形状
if (Input.IsActionPressed("右"))
{
this.RotateZ(-(float)delta);
}
}
}
运行,可以发现火箭已经可以起飞了!
增加旋转
using Godot;
using System;
public partial class Player : RigidBody3D
{
public override void _Ready()
{
}
public override void _Process(double delta)
{
// 跳跃
if (Input.IsActionPressed("跳跃"))
{
// this.Position = new Vector3(Position.X, Position.Y + (float)delta, Position.Z);
// 施加中心力,向上
this.ApplyCentralForce(Vector3.Up * (float)delta * 1000.0f);
}
// 逆时针旋转形状
if (Input.IsActionPressed("左"))
{
// this.RotateZ((float)delta);
this.ApplyTorque(Vector3.Back * (float)delta * 100.0f);
}
// 逆时针旋转形状
if (Input.IsActionPressed("右"))
{
// this.RotateZ(-(float)delta);
this.ApplyTorque(Vector3.Forward * (float)delta * 100.0f);
}
}
}
增加 空间变化的位置。
用到Basis.Y,Basis输出3*3的矩阵。
https://www.bookstack.cn/read/godot-4.2-zh/15622d61f41d4975.md
修改脚本
using Godot;
using System;
public partial class Player : RigidBody3D
{
public override void _Ready()
{
}
public override void _Process(double delta)
{
// 跳跃
if (Input.IsActionPressed("跳跃"))
{
// this.Position = new Vector3(Position.X, Position.Y + (float)delta, Position.Z);
// 施加中心力,向上
this.ApplyCentralForce(Basis.Y * (float)delta * 1000.0f);
}
// 逆时针旋转形状
if (Input.IsActionPressed("左"))
{
// this.RotateZ((float)delta);
this.ApplyTorque(Vector3.Back * (float)delta * 100.0f);
}
// 逆时针旋转形状
if (Input.IsActionPressed("右"))
{
// this.RotateZ(-(float)delta);
this.ApplyTorque(Vector3.Forward * (float)delta * 100.0f);
}
}
}
运行会发现,已经可以像火箭一样发射了。
配置碰撞事件(信号)
Player刚体上有一个属性,打开,并将最大接触点数为10。
修改Plyaer.cs脚本。
using Godot;
using System;
public partial class Player : RigidBody3D
{
public override void _Ready()
{
}
public override void _Process(double delta)
{
// 跳跃
if (Input.IsActionPressed("跳跃"))
{
// this.Position = new Vector3(Position.X, Position.Y + (float)delta, Position.Z);
// 施加中心力,向上
this.ApplyCentralForce(Basis.Y * (float)delta * 1000.0f);
}
// 逆时针旋转形状
if (Input.IsActionPressed("左"))
{
// this.RotateZ((float)delta);
this.ApplyTorque(Vector3.Back * (float)delta * 100.0f);
}
// 逆时针旋转形状
if (Input.IsActionPressed("右"))
{
// this.RotateZ(-(float)delta);
this.ApplyTorque(Vector3.Forward * (float)delta * 100.0f);
}
}
public void onBodyEnterd(Node body)
{
if (body.Name == "LandingPad")
{
GD.Print("闯关成功!");
}
}
}
绑定信号。
游戏可以初步判定是赢了。
优化
利用分组实现判定,Level场景,LandingPad增加分组Goal
。
public void onBodyEnterd(Node body)
{
if (body.GetGroups().Contains("Goal"))
{
GD.Print("闯关成功!");
}
}
增加组就增加失败:
......
public void onBodyEnterd(Node body)
{
if (body.GetGroups().Contains("Goal"))
{
GD.Print("闯关成功!");
}
if (body.GetGroups().Contains("Hazard"))
{
GD.Print("挑战失败!");
}
}
......
将参数暴露出去。
using Godot;
using System;
public partial class Player : RigidBody3D
{
// 推力 "750.0,3000.0,100.0,or_greater,or_less"
/// ## string(推力值)
[Export(PropertyHint.Range, "750.0,3000.0")]
public float THRUST = 1000.0f;
// 倾斜力
[Export(PropertyHint.Range, "20.0,1000.0")]
public float TORQUE_THRUST = 100.0f;
public override void _Ready()
{
}
public override void _Process(double delta)
{
// 跳跃
if (Input.IsActionPressed("跳跃"))
{
// this.Position = new Vector3(Position.X, Position.Y + (float)delta, Position.Z);
// 施加中心力,向上
this.ApplyCentralForce(Basis.Y * (float)delta * THRUST);
}
// 逆时针旋转形状
if (Input.IsActionPressed("左"))
{
// this.RotateZ((float)delta);
this.ApplyTorque(Vector3.Back * (float)delta * TORQUE_THRUST);
}
// 逆时针旋转形状
if (Input.IsActionPressed("右"))
{
// this.RotateZ(-(float)delta);
this.ApplyTorque(Vector3.Forward * (float)delta * TORQUE_THRUST);
}
}
public void onBodyEnterd(Node body)
{
if (body.GetGroups().Contains("Goal"))
{
GD.Print("闯关成功!");
}
if (body.GetGroups().Contains("Hazard"))
{
GD.Print("挑战失败!");
}
}
}
完善游戏逻辑
using Godot;
using System;
public partial class Player : RigidBody3D
{
// 推力 "750.0,3000.0,100.0,or_greater,or_less"
/// ## string(推力值)
[Export(PropertyHint.Range, "750.0,3000.0")]
public float THRUST = 1000.0f;
// 倾斜力
[Export(PropertyHint.Range, "20.0,1000.0")]
public float TORQUE_THRUST = 100.0f;
public override void _Ready()
{
}
public override void _Process(double delta)
{
// 跳跃
if (Input.IsActionPressed("跳跃"))
{
// this.Position = new Vector3(Position.X, Position.Y + (float)delta, Position.Z);
// 施加中心力,向上
this.ApplyCentralForce(Basis.Y * (float)delta * THRUST);
}
// 逆时针旋转形状
if (Input.IsActionPressed("左"))
{
// this.RotateZ((float)delta);
this.ApplyTorque(Vector3.Back * (float)delta * TORQUE_THRUST);
}
// 逆时针旋转形状
if (Input.IsActionPressed("右"))
{
// this.RotateZ(-(float)delta);
this.ApplyTorque(Vector3.Forward * (float)delta * TORQUE_THRUST);
}
}
public void onBodyEnterd(Node body)
{
if (body.GetGroups().Contains("Goal"))
{
completeLevel();
}
if (body.GetGroups().Contains("Hazard"))
{
crashSequence();
}
}
public void crashSequence()
{
GD.Print("大爆炸!");
this.GetTree().ReloadCurrentScene();
}
public void completeLevel()
{
GD.Print("挑战成功!");
this.GetTree().Quit();
}
}
继续优化,增加关卡,关卡障碍绑定到LandingPad节点。
LandingPad节点创建脚本LandingPad.cs
using Godot;
using System;
public partial class LandingPad : CsgBox3D
{
[Export(PropertyHint.File,"*.tscn")]
public string FilePath { get; set; }
public override void _Ready()
{
}
public override void _Process(double delta)
{
}
}
修改Palyer.cs
using Godot;
using System;
public partial class Player : RigidBody3D
{
// 推力 "750.0,3000.0,100.0,or_greater,or_less"
///## string(推力值)
[Export(PropertyHint.Range, "750.0,3000.0")]
public float THRUST = 1000.0f;
// 倾斜力
[Export(PropertyHint.Range, "20.0,1000.0")]
public float TORQUE_THRUST = 100.0f;
public override void _Ready()
{
}
public override void _Process(double delta)
{
// 跳跃
if (Input.IsActionPressed("跳跃"))
{
// this.Position = new Vector3(Position.X, Position.Y + (float)delta, Position.Z);
// 施加中心力,向上
this.ApplyCentralForce(Basis.Y * (float)delta * THRUST);
}
// 逆时针旋转形状
if (Input.IsActionPressed("左"))
{
// this.RotateZ((float)delta);
this.ApplyTorque(Vector3.Back * (float)delta * TORQUE_THRUST);
}
// 逆时针旋转形状
if (Input.IsActionPressed("右"))
{
// this.RotateZ(-(float)delta);
this.ApplyTorque(Vector3.Forward * (float)delta * TORQUE_THRUST);
}
}
public void onBodyEnterd(Node body)
{
if (body.GetGroups().Contains("Goal"))
{
completeLevel(body.Get("FilePath").AsString());
}
if (body.GetGroups().Contains("Hazard"))
{
crashSequence();
}
}
public void crashSequence()
{
GD.Print("大爆炸!");
this.GetTree().ReloadCurrentScene();
}
public void completeLevel(String nextLevelFile)
{
GD.Print(nextLevelFile + ",挑战成功!");
this.GetTree().ChangeSceneToFile(nextLevelFile);
}
}
赋值一个场景。
这样就实现了关卡成功切换下一个关卡。
下一个关卡
Ctrl+D复制场景level.tscn,为level_2.tscn;
打开level_2.tscn,复制粘贴Floor,调整参数,位置参数(0,1,0)
然后修改filePath,即可实现关卡通关,切换下一个关卡场景。
操作的过渡和缓动
调整
public void crashSequence()
{
GD.Print("大爆炸!");
Tween tween = this.GetTree().CreateTween();;
tween.TweenInterval(1.0);
tween.TweenCallback(Callable.From(this.GetTree().ReloadCurrentScene));
}
场景会过1秒再加载。
失败或成功后,禁用玩家操作。
using Godot;
using System;
public partial class Player : RigidBody3D
{
// 推力 "750.0,3000.0,100.0,or_greater,or_less"
///## string(推力值)
[Export(PropertyHint.Range, "750.0,3000.0")]
public float THRUST = 1000.0f;
// 倾斜力
[Export(PropertyHint.Range, "20.0,1000.0")]
public float TORQUE_THRUST = 100.0f;
// 是否过渡中
private Boolean isTransitioning = false;
public override void _Ready()
{
}
public override void _Process(double delta)
{
// 跳跃
if (Input.IsActionPressed("跳跃"))
{
// this.Position = new Vector3(Position.X, Position.Y + (float)delta, Position.Z);
// 施加中心力,向上
this.ApplyCentralForce(Basis.Y * (float)delta * THRUST);
}
// 逆时针旋转形状
if (Input.IsActionPressed("左"))
{
// this.RotateZ((float)delta);
this.ApplyTorque(Vector3.Back * (float)delta * TORQUE_THRUST);
}
// 逆时针旋转形状
if (Input.IsActionPressed("右"))
{
// this.RotateZ(-(float)delta);
this.ApplyTorque(Vector3.Forward * (float)delta * TORQUE_THRUST);
}
}
public void onBodyEnterd(Node body)
{
if (!isTransitioning)
{
if (body.GetGroups().Contains("Goal"))
{
completeLevel(body.Get("FilePath").AsString());
}
if (body.GetGroups().Contains("Hazard"))
{
crashSequence();
}
}
}
public void crashSequence()
{
GD.Print("大爆炸!");
this.SetProcess(false);
isTransitioning = true;
Tween tween = this.GetTree().CreateTween();
;
tween.TweenInterval(1.0);
tween.TweenCallback(Callable.From(()=>this.GetTree().ReloadCurrentScene()));
}
public void completeLevel(String nextLevelFile)
{
GD.Print(nextLevelFile + ",挑战成功!");
isTransitioning = true;
Tween tween = this.GetTree().CreateTween();
tween.TweenInterval(1.0);
tween.TweenCallback(Callable.From(()=>this.GetTree().ChangeSceneToFile(nextLevelFile)));
}
}
动的障碍物
快捷创建碰撞体:
给个颜色。
可能别的地方要用到这样的移动刚体,将其创建为场景。
这个分支只有一个立方体,新增根节点脚本MovingHazard.cs。
using Godot;
using System;
public partial class MovingHazard : AnimatableBody3D
{
// 目的地
[Export]
public Vector3 destination;
// 持续时间
[Export]
public float duration=1.0f;
public override void _Ready()
{
Tween tween = this.GetTree().CreateTween();
tween.TweenProperty(this,"global_position",GlobalPosition+destination,duration);
}
public override void _Process(double delta)
{
}
}
这里用到TweenProperty( GodotObject object, NodePath property, Variant finalVal, double duration)
函数。
object 需要缓动的对象体,这里用自身。
property,要缓动改变的属性(比例、位置等)
finalVal 最终·要变化过去的值,
duration 持续时间
设置循环执行和正弦速率:
public override void _Ready()
{
Tween tween = this.GetTree().CreateTween();
// 循环执行
tween.SetLoops();
// 正弦运动,运动效果更加圆润。
tween.SetTrans(Tween.TransitionType.Sine);
tween.TweenProperty(this, "global_position", GlobalPosition + destination, duration);
tween.TweenProperty(this, "global_position", GlobalPosition, duration);
}
增加碰撞。
效果完成!
音效
这里只需要一个全局的就够用了。
加载音频,配置音量:
修改脚本
using Godot;
using System;
public partial class Player : RigidBody3D
{
private AudioStreamPlayer explosionAudio;
private AudioStreamPlayer successAudio;
// 推力 "750.0,3000.0,100.0,or_greater,or_less"
///## string(推力值)
[Export(PropertyHint.Range, "750.0,3000.0")]
public float THRUST = 1000.0f;
// 倾斜力
[Export(PropertyHint.Range, "20.0,1000.0")]
public float TORQUE_THRUST = 100.0f;
// 是否过渡中
private Boolean isTransitioning = false;
public override void _Ready()
{
explosionAudio =
this.GetNode<AudioStreamPlayer>("ExplosionAudio");
successAudio =
this.GetNode<AudioStreamPlayer>("SuccessAudio");
}
public override void _Process(double delta)
{
// 跳跃
if (Input.IsActionPressed("跳跃"))
{
// this.Position = new Vector3(Position.X, Position.Y + (float)delta, Position.Z);
// 施加中心力,向上
this.ApplyCentralForce(Basis.Y * (float)delta * THRUST);
}
// 逆时针旋转形状
if (Input.IsActionPressed("左"))
{
// this.RotateZ((float)delta);
this.ApplyTorque(Vector3.Back * (float)delta * TORQUE_THRUST);
}
// 逆时针旋转形状
if (Input.IsActionPressed("右"))
{
// this.RotateZ(-(float)delta);
this.ApplyTorque(Vector3.Forward * (float)delta * TORQUE_THRUST);
}
}
public void onBodyEnterd(Node body)
{
if (!isTransitioning)
{
if (body.GetGroups().Contains("Goal"))
{
completeLevel(body.Get("FilePath").AsString());
}
if (body.GetGroups().Contains("Hazard"))
{
crashSequence();
}
}
}
public void crashSequence()
{
isTransitioning = true;
GD.Print("大爆炸!");
this.SetProcess(false);
explosionAudio.Play();
Tween tween = this.GetTree().CreateTween();
;
tween.TweenInterval(2.5);
tween.TweenCallback(Callable.From(() => this.GetTree().ReloadCurrentScene()));
}
public void completeLevel(String nextLevelFile)
{
isTransitioning = true;
GD.Print(nextLevelFile + ",挑战成功!");
successAudio.Play();
Tween tween = this.GetTree().CreateTween();
tween.TweenInterval(1.5);
tween.TweenCallback(Callable.From(() => this.GetTree().ChangeSceneToFile(nextLevelFile)));
}
}
火箭运动音效
脚本改造
using Godot;
using System;
public partial class Player : RigidBody3D
{
......
private AudioStreamPlayer3D rocketAudio;
......
public override void _Ready()
{
......
rocketAudio =
this.GetNode<AudioStreamPlayer3D>("RocketAudio");
}
public override void _Process(double delta)
{
// 跳跃
if (Input.IsActionPressed("跳跃"))
{
// 播放声音
if (!rocketAudio.Playing)
{
rocketAudio.Play();
......
}
else
{
// 停止播放声音
if (rocketAudio.Playing)
{
rocketAudio.Stop();
}
}
......
}
......
}
粒子
准备了一个粒子的素材场景booster_particles.tscn。
修改脚本:
using Godot;
using System;
public partial class Player : RigidBody3D
{
private AudioStreamPlayer explosionAudio;
private AudioStreamPlayer successAudio;
private AudioStreamPlayer3D rocketAudio;
private GpuParticles3D boosterParticles;
private GpuParticles3D boosterParticlesRight;
private GpuParticles3D boosterParticlesLeft;
// 推力 "750.0,3000.0,100.0,or_greater,or_less"
///## string(推力值)
[Export(PropertyHint.Range, "750.0,3000.0")]
public float THRUST = 1000.0f;
// 倾斜力
[Export(PropertyHint.Range, "20.0,1000.0")]
public float TORQUE_THRUST = 100.0f;
// 是否过渡中
private Boolean isTransitioning = false;
public override void _Ready()
{
explosionAudio =
this.GetNode<AudioStreamPlayer>("ExplosionAudio");
successAudio =
this.GetNode<AudioStreamPlayer>("SuccessAudio");
rocketAudio =
this.GetNode<AudioStreamPlayer3D>("RocketAudio");
boosterParticles =
this.GetNode<GpuParticles3D>("BoosterParticles");
boosterParticlesRight =
this.GetNode<GpuParticles3D>("BoosterParticlesRight");
boosterParticlesLeft =
this.GetNode<GpuParticles3D>("BoosterParticlesLeft");
}
public override void _Process(double delta)
{
// 跳跃
if (Input.IsActionPressed("跳跃"))
{
// 开始火箭尾气喷射粒子特效
boosterParticles.Emitting = true;
// 播放声音
if (!rocketAudio.Playing)
{
rocketAudio.Play();
}
// this.Position = new Vector3(Position.X, Position.Y + (float)delta, Position.Z);
// 施加中心力,向上
this.ApplyCentralForce(Basis.Y * (float)delta * THRUST);
}
else
{
// 停止火箭尾气喷射粒子特效
boosterParticles.Emitting = false;
// 停止播放声音
if (rocketAudio.Playing)
{
rocketAudio.Stop();
}
}
// 逆时针旋转形状
if (Input.IsActionPressed("左"))
{
// 火箭尾气喷射粒子特效
boosterParticlesLeft.Emitting = true;
// this.RotateZ((float)delta);
this.ApplyTorque(Vector3.Back * (float)delta * TORQUE_THRUST);
}
else
{
// 火箭尾气喷射粒子特效
boosterParticlesLeft.Emitting = false;
}
// 逆时针旋转形状
if (Input.IsActionPressed("右"))
{
// 火箭尾气喷射粒子特效
boosterParticlesRight.Emitting = true;
// this.RotateZ(-(float)delta);
this.ApplyTorque(Vector3.Forward * (float)delta * TORQUE_THRUST);
}
else
{
// 火箭尾气喷射粒子特效
boosterParticlesRight.Emitting = false;
}
}
public void onBodyEnterd(Node body)
{
if (!isTransitioning)
{
if (body.GetGroups().Contains("Goal"))
{
completeLevel(body.Get("FilePath").AsString());
}
if (body.GetGroups().Contains("Hazard"))
{
crashSequence();
}
}
}
public void crashSequence()
{
isTransitioning = true;
GD.Print("大爆炸!");
this.SetProcess(false);
explosionAudio.Play();
Tween tween = this.GetTree().CreateTween();
;
tween.TweenInterval(2.5);
tween.TweenCallback(Callable.From(() => this.GetTree().ReloadCurrentScene()));
}
public void completeLevel(String nextLevelFile)
{
isTransitioning = true;
GD.Print(nextLevelFile + ",挑战成功!");
successAudio.Play();
Tween tween = this.GetTree().CreateTween();
tween.TweenInterval(1.5);
tween.TweenCallback(Callable.From(() => this.GetTree().ChangeSceneToFile(nextLevelFile)));
}
}
失败和成功粒子同上。
脚本如下:
using Godot;
using System;
public partial class Player : RigidBody3D
{
private AudioStreamPlayer explosionAudio;
private AudioStreamPlayer successAudio;
private AudioStreamPlayer3D rocketAudio;
private GpuParticles3D boosterParticles;
private GpuParticles3D boosterParticlesRight;
private GpuParticles3D boosterParticlesLeft;
private GpuParticles3D explosionParticles;
private GpuParticles3D successParticles;
// 推力 "750.0,3000.0,100.0,or_greater,or_less"
///## string(推力值)
[Export(PropertyHint.Range, "750.0,3000.0")]
public float THRUST = 1000.0f;
// 倾斜力
[Export(PropertyHint.Range, "20.0,1000.0")]
public float TORQUE_THRUST = 100.0f;
// 是否过渡中
private Boolean isTransitioning = false;
public override void _Ready()
{
explosionAudio =
this.GetNode<AudioStreamPlayer>("ExplosionAudio");
successAudio =
this.GetNode<AudioStreamPlayer>("SuccessAudio");
rocketAudio =
this.GetNode<AudioStreamPlayer3D>("RocketAudio");
boosterParticles =
this.GetNode<GpuParticles3D>("BoosterParticles");
boosterParticlesRight =
this.GetNode<GpuParticles3D>("BoosterParticlesRight");
boosterParticlesLeft =
this.GetNode<GpuParticles3D>("BoosterParticlesLeft");
explosionParticles =
this.GetNode<GpuParticles3D>("ExplosionParticles");
successParticles =
this.GetNode<GpuParticles3D>("SuccessParticles");
}
public override void _Process(double delta)
{
// 跳跃
if (Input.IsActionPressed("跳跃"))
{
// 开始火箭尾气喷射粒子特效
boosterParticles.Emitting = true;
// 播放声音
if (!rocketAudio.Playing)
{
rocketAudio.Play();
}
// this.Position = new Vector3(Position.X, Position.Y + (float)delta, Position.Z);
// 施加中心力,向上
this.ApplyCentralForce(Basis.Y * (float)delta * THRUST);
}
else
{
// 停止火箭尾气喷射粒子特效
boosterParticles.Emitting = false;
// 停止播放声音
if (rocketAudio.Playing)
{
rocketAudio.Stop();
}
}
// 逆时针旋转形状
if (Input.IsActionPressed("左"))
{
// 火箭尾气喷射粒子特效
boosterParticlesLeft.Emitting = true;
// this.RotateZ((float)delta);
this.ApplyTorque(Vector3.Back * (float)delta * TORQUE_THRUST);
}
else
{
// 火箭尾气喷射粒子特效
boosterParticlesLeft.Emitting = false;
}
// 逆时针旋转形状
if (Input.IsActionPressed("右"))
{
// 火箭尾气喷射粒子特效
boosterParticlesRight.Emitting = true;
// this.RotateZ(-(float)delta);
this.ApplyTorque(Vector3.Forward * (float)delta * TORQUE_THRUST);
}
else
{
// 火箭尾气喷射粒子特效
boosterParticlesRight.Emitting = false;
}
}
public void onBodyEnterd(Node body)
{
if (!isTransitioning)
{
if (body.GetGroups().Contains("Goal"))
{
completeLevel(body.Get("FilePath").AsString());
}
if (body.GetGroups().Contains("Hazard"))
{
crashSequence();
}
}
}
public void crashSequence()
{
isTransitioning = true;
explosionParticles.Emitting = true;
GD.Print("大爆炸!");
this.SetProcess(false);
explosionAudio.Play();
Tween tween = this.GetTree().CreateTween();
;
tween.TweenInterval(2.5);
tween.TweenCallback(Callable.From(() => this.GetTree().ReloadCurrentScene()));
}
public void completeLevel(String nextLevelFile)
{
isTransitioning = true;
successParticles.Emitting = true;
GD.Print(nextLevelFile + ",挑战成功!");
successAudio.Play();
Tween tween = this.GetTree().CreateTween();
tween.TweenInterval(1.5);
tween.TweenCallback(Callable.From(() => this.GetTree().ChangeSceneToFile(nextLevelFile)));
}
}
来吧火箭
最终成品。
都是用MeshInstance3D组件实现。
Body 大?。?.2,0.2,0.5),位置(0,-0.25,0)
Cockpit 大小(0,0.2,0.5),位置(0,1,0)
Midriff 大?。?.25,0.25,0.25),位置(0,0.25,0)
ThrusterMain 圆柱体, 大小(0.25,0.25,0.4),位置(0,-0.55,0)
ArmLeft 大?。?.2,0.4,0.2),位置(-0.25,-0.19,0)旋转(0 ,0,-44.5)
ThrusterAuxiliary 圆柱体,大?。?.15,0.15,0.4),位置(0.07,-0.3,0)旋转(0 ,0,-44)
ArmRight 大?。?.2,0.4,0.2),位置(0.25,-0.19,0)旋转(0 ,180,-44.5)
ThrusterAuxiliary 圆柱体,大?。?.15,0.15,0.4),位置(0.07,-0.3,0)旋转(0 ,0,-44)
BaseRing 圆环,大?。?.4,0.5),位置(0,-0.55,0)
颜色
将颜色改为#cc3820
。
另存为材质。
可以直接往模型上拖,或者选择快速加载。
背景
复制地板的组件,创建各种大小不一摆放不一的柱体即可。
然后做成地板的子节点,保存为场景Background.tscn
照明
一开始我们有默认的环境3要素,其中包括太阳光,但这个游戏上下围起来的话,需要做一个全光照明。
将环境和太阳光剪切到Backgroud.tscn场景,其他关卡都删掉。
调整参数。
环境调成自定义颜色,颜色#120b07
。
调整太阳光的角度和强度。
增加三个全域照明,就是蜡烛、白炽灯效果的光照OmniLight3D。
调整XY轴位置,光的Range和Attenuation值(强度和范围)。
游戏效果就出来了:
游戏导出
游戏导出需要导出模板,godot软件的下载国内是失败的,科学上网也没啥用。、
办法:https://github.com/godotengine/godot/releases/tag
下载完成后,再本地导入即可。
然后从文件导入,修改名字,勾上内嵌PCK(会生成exe文件),最后点击导出项目
。