虚拟摇杆
一个被限制在圆环内的摇杆,驱动一个圆点移动。在手机上同样的代码响应触摸。
上方的编辑器正在运行这个项目。改一行代码,它就会重新加载。
用到的 Godot 类
PanelStyleBoxFlatInputEventMouseMotion
代码
scripts/main.gd
extends Node
const BASE_RADIUS: float = 90.0
const KNOB_RADIUS: float = 38.0
const SPEED: float = 420.0
var base: Panel
var knob: Panel
var runner: Polygon2D
var readout: Label
var origin: Vector2
var direction: Vector2 = Vector2.ZERO
var dragging: bool = false
func _ready() -> void:
var background: ColorRect = ColorRect.new()
background.color = Color('#12141a')
add_child(background)
background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
var view: Vector2 = get_viewport().get_visible_rect().size
origin = Vector2(BASE_RADIUS + 60, view.y - BASE_RADIUS - 60)
runner = _make_circle(30.0, Color('#8eef97'))
runner.position = view * 0.5
add_child(runner)
base = _make_disc(BASE_RADIUS, Color(0.55, 0.65, 0.95, 0.12), Color('#2a2f3d'))
base.position = origin - Vector2(BASE_RADIUS, BASE_RADIUS)
add_child(base)
knob = _make_disc(KNOB_RADIUS, Color('#8da5f3'), Color('#8da5f3'))
add_child(knob)
_move_knob(origin)
readout = Label.new()
readout.position = Vector2(40, 40)
readout.add_theme_color_override('font_color', Color('#999999'))
add_child(readout)
print('drag inside the ring, on a phone the same code answers to touch')
func _unhandled_input(event: InputEvent) -> void:
if event is InputEventMouseButton:
var press: InputEventMouseButton = event
if press.pressed and press.position.distance_to(origin) <= BASE_RADIUS * 1.6:
dragging = true
elif not press.pressed:
dragging = false
direction = Vector2.ZERO
_move_knob(origin)
if event is InputEventMouseMotion and dragging:
var offset: Vector2 = ((event as InputEventMouseMotion).position - origin).limit_length(BASE_RADIUS)
direction = offset / BASE_RADIUS
_move_knob(origin + offset)
func _process(delta: float) -> void:
var view: Vector2 = get_viewport().get_visible_rect().size
runner.position += direction * SPEED * delta
runner.position = runner.position.clamp(Vector2(30, 30), view - Vector2(30, 30))
readout.text = 'direction %.2f, %.2f' % [direction.x, direction.y]
func _move_knob(at: Vector2) -> void:
knob.position = at - Vector2(KNOB_RADIUS, KNOB_RADIUS)
func _make_disc(radius: float, fill: Color, border: Color) -> Panel:
var style: StyleBoxFlat = StyleBoxFlat.new()
style.bg_color = fill
style.border_color = border
style.set_border_width_all(2)
style.set_corner_radius_all(int(radius))
var disc: Panel = Panel.new()
disc.size = Vector2(radius * 2, radius * 2)
disc.add_theme_stylebox_override('panel', style)
# a Control eats the drag before _unhandled_input and the stick would never move
disc.mouse_filter = Control.MOUSE_FILTER_IGNORE
return disc
func _make_circle(radius: float, color: Color) -> Polygon2D:
var points: PackedVector2Array = PackedVector2Array()
for i in 24:
points.append(Vector2(cos(TAU * i / 24.0), sin(TAU * i / 24.0)) * radius)
var circle: Polygon2D = Polygon2D.new()
circle.polygon = points
circle.color = color
return circle