圈数限制
为了驱动玩家向下一个圆圈跳跃,所以我们限制圆圈上转的圈数,圈数结束后游戏结束
为Circle
添加一个Label
节点
选择合适字体及文字大小,并使其内容以及布局均为居中
circle.gd
中编写脚本
enum MODES {STATIC, LIMITED} # 两种状态的圆圈
var mode = MODES.STATIC
var num_orbits = 3 # 圈数计数
var current_orbits = 0 # 完成圈数
var orbit_start = null # 轨道起始位置
设置圆圈的模式
func set_mode(_mode):
mode = _mode
match mode:
MODES.STATIC:
$Label.hide()
MODES.LIMITED:
current_orbits = num_orbits
$Label.text = str(orbits_left)
$Label.show()
初始化圆圈模式
func init(_position, _radius=radius, _mode=MODES.LIMITED):
set_mode(_mode)
删除jumper.gd
中的这句
target.get_node("Pivot").rotation = (position - target.position).angle()
circle.gd
func capture(target):
jumper=target
$AnimationPlayer.play("capture")
$Pivot.rotation = (jumper.position-position).angle()
orbit_start = $Pivot.rotation
Main.gd
中传入参数
func _on_Jumper_captured(object):
$Camera2D.position = object.position
object.capture(player)
call_deferred("spawn_circle")
circle.gd
func _process(delta):
$Pivot.rotation += rotation_speed * delta
if mode == MODES.LIMITED and jumper:
check_orbits()
func check_orbits():
# 检测是否经过一圈
if abs($Pivot.rotation - orbit_start) > 2 * PI:
current_orbits -= 1
$Label.text = str(current_orbits)
if orbits_left <= 0:
jumper.die()
jumper = null
implode()
orbit_start = $Pivot.rotation
为Jumper
下的VisibilityNotifier2D
节点添加screen_eited()
信号
当玩家死亡、不在轨道上且跳出屏幕
func die():
target = null
queue_free()
func _on_VisibilityNotifier2D_screen_exited():
if !target:
die()
测试1
当圈数为0时玩家和圆圈都会消失
圈数效果
给圈数计数添加一个雷达扫描的效果
关于2d绘图的官方文档https://docs.godotengine.org/zh_CN/stable/tutorials/2d/custom_drawing_in_2d.html
circle.gd
func _draw():
if jumper:
var r = ((radius - 50) / num_orbits) * (1 + num_orbits - current_orbits)
draw_circle_arc_poly(Vector2.ZERO, r, orbit_start + PI/2,$Pivot.rotation + PI/2, Color(1, 0, 0))
func draw_circle_arc_poly(center, radius, angle_from, angle_to, color):
var nb_points = 32
var points_arc = PoolVector2Array()
points_arc.push_back(center)
var colors = PoolColorArray([color])
for i in range(nb_points + 1):
var angle_point = angle_from + i * (angle_to - angle_from) / nb_points - PI/2
points_arc.push_back(center + Vector2(cos(angle_point), sin(angle_point)) * radius)
draw_polygon(points_arc, colors)
然后在_process()
中调用update()
func _process(delta):
$Pivot.rotation += rotation_speed * delta
if mode == MODES.LIMITED and jumper:
check_orbits()
update()
测试2
菜单
场景框架
新建一个场景BaseScreen.tscn
,这是一个基本的UI框架,保存在UI文件夹中,节点如下
CanvasLayer
(BaseScreen)
MarginContainer
VBoxContainer
Label
HBoxContainer
(Buttons)HBoxContainer
(Buttons2)
Tween
MarginContainer
布局选择整个矩形
适当修改外边距,让其距离四周有一定距离
将BaseScreen
的offset x
修改为500
然后新建BaseScreen,gd
脚本,为场景添加动画
extends CanvasLayer
onready var tween = $Tween
func appear():
tween.interpolate_property(self, "offset:x", 500, 0,0.5, Tween.TRANS_BACK, Tween.EASE_IN_OUT)
tween.start()
func disappear():
tween.interpolate_property(self, "offset:x", 0, 500,0.4, Tween.TRANS_BACK, Tween.EASE_IN_OUT)
tween.start()
开始场景
完成基本框架后,场景->新建继承场景
,选择刚才的BaseScreen
场景
新建一个TitleScreen
场景,在Buttons
下添加TextureButton
把按钮添加到buttons
组中
这时修改初始场景的属性便可修改该场景的子场景
修改VBoxContainer
的Separation
属性让控件间距增大
设置场景
同上,新建SettingsScreen
场景,并添加按钮
结束场景
同上,新建SettingsScreen
场景,并添加按钮
场景管理
新建Screens场景,三个UI场景为Node
的子节点
**
添加Screens.gd
脚本
extends Node
# 开始游戏的信号
signal start_game
# 当前的UI界面
var current_screen = null
func _ready():
register_buttons()
change_screen($TitleScreen)
# 注册按钮
func register_buttons():
# 获取buttons组
var buttons = get_tree().get_nodes_in_group("buttons")
# 按钮连接信号
for button in buttons:
button.connect("pressed", self, "_on_button_pressed", [button.name])
func _on_button_pressed(name):
match name:
"Return","Home":
change_screen($TitleScreen)
"Play":
change_screen(null)
yield(get_tree().create_timer(0.5), "timeout")
emit_signal("start_game")
"Settings":
change_screen($SettingsScreen)
# 改变UI界面
func change_screen(new_screen):
if current_screen:
current_screen.disappear()
yield(current_screen.tween, "tween_completed")
current_screen = new_screen
if new_screen:
current_screen.appear()
yield(current_screen.tween, "tween_completed")
func game_over():
change_screen($GameOverScreen)
回到Main
场景,将Screens
添加到Main
中,并为其连接信号
并在Main.gd
中的_ready()
函数中删去new_game()
为玩家失败添加信号
# 死亡信号
signal died
func die():
emit_signal("died")
target = null
queue_free()
在Main.gd
中连接信号并将Circle
添加到circles
的分组中
func new_game():
# 连接信号
player.connect("captured", self, "_on_Jumper_captured")
player.connect("died",self,"_on_Jumper_died")
func _on_Jumper_died():
get_tree().call_group("circles", "implode")
$Screens.game_over()