在第三十四节我实现了来回无限滚动的伤害铁刺球,这一节我准备实现一个圆形移动或扇形移动,并带有链条的铁球。效果如下:
一、实现原理
绕一点做圆周运动,简单的说就是: 每一帧根据旋转的角度计算出下一个位置的坐标 。因此我们需要两个数值: 旋转角度(偏移量)、距离(半径) 。这样每一帧都根据计算的坐标来更新平台的位置,实现平台绕中心点做圆周运动。这么怎么才能计算出移动的位置呢?这需要我们初中学的一些数学知识。给你一个坐标系,以原点为圆心,画一个半径为r的圆,若果我们知道圆上任意一点A的旋转角度为α,那么如何求得A点坐标呢?
初中知识,我们从A点分别向X轴,Y轴做垂线,分别交于a点和b点,我们可以得到两个直接三角形,一个是三角形Abo,一个是三角形Aao。已知条件是半径r,和旋转角度a,在直角三角形中sin等于对边比上斜边;cos等于临边比上斜边,也就是说Aa/r等于rsin(a),oa/r=cos(a),以我们可以求出ob=rsin(a),oa=rcos(a),所以A点坐标是(rcos(a),r*sin(a))。
还记得角的表示方法有两种吗?一种是角度制,一种是弧度制。在godot中常用的是角度制,也就是a的取值为0到2π,2π对应着360度。以上就是圆周运动的基础理论。
还记得角的表示方法有两种吗?一种是角度制,一种是弧度制。在godot中常用的是角度制,也就是a的取值为0到2π,2π对应着360度。以上就是圆周运动的基础理论。
二、节点配置
新建node2场景,命名为RotateBall,保存在Scenes目录文件下。为根节点添加Sprite2D节点命名为MovingSpikes,将Texture设置为为我们的链球图片。
节点结构非常简单。
三、编写代码
为根节点RotateBall添加代码,编写如下代码:
extends Node2D
@onready var moving_spikes = $MovingSpikes #获取滚动小球
var angle_offset = 0 #旋转角度
var radius = 50 #旋转半径
var startPoin: = Vector2(0.0,0.0) #旋转中心
var line #定义line节点用来表示旋转链球的链条
@export var speed :=2.0 #旋转速度
@export var startPI = PI #旋转开始角度
@export var EndPI = PI #选择结束角度
func _ready():
angle_offset = startPI #设置旋转角度等于初始角度
moving_spikes.position = startPoin + Vector2(cos(angle_offset) * radius,sin(angle_offset) * radius) #计算初始位置,等于旋转中心+新的位置
draw_linemy(startPoin,moving_spikes.position) #画出链条
#画链条,第一个参数为半径起点,第二个参数为半径中点
func draw_linemy(startpoint:Vector2,endpoind:Vector2):
if not line:#判断链条是否存在,如果不存在
line = Line2D.new() #新建Line2D节点
line.width=2 #链条宽度设为2
line.show_behind_parent=true #设置链条在底部显示,目的是刺球挡住半径看起来更美观
line.default_color = Color.DARK_SLATE_BLUE #设置链条颜色
add_child(line) #将连线添加到场景
line.points = PackedVector2Array([startPoin, endpoind])#设置链条的长度
func _physics_process(delta):
rotateBall(delta) #调用链球位置
#链球位置计算
func rotateBall(delta:float):
if startPI==EndPI: #如果起始角度和节结束角度相等,做圆周运动
angle_offset += delta * speed #旋转角度等于速度*时间
else:#如果起始角度和结束角度不同,做钟摆运动
if absf(angle_offset)>absf(EndPI) or abs(angle_offset)<absf(startPI):
#如果旋转角度大于结束角度,旋转方向向相反方向旋转了
speed = -1 * speed
angle_offset += delta*speed #计算角度
# 计算下一个位置
moving_spikes.position = startPoin + Vector2(cos(angle_offset) * radius,sin(angle_offset) * radius) #加上旋转中心
draw_linemy(startPoin,moving_spikes.position)
四、主场景调用
在主场景实例化2个RotateBall场景。
第一个场景speed设置为2,start pi设置为-0.2,end pi设置为-2.9,这样是个逆时针摇摆的链球,如果顺时针摇摆,start pi和end pi只需要设置正数即可。
第2个场景speed设置为5,start pi和end pi均设置为3.14,这样是个圆周运动的链球。
看一下预览效果: