形状投射

一个方块在移动前先问自己会停在哪里。那个虚影就是投射返回的安全比例。

上方的编辑器正在运行这个项目。改一行代码,它就会重新加载。

用到的 Godot 类

ShapeCast2DPolygon2DStaticBody2D

代码

scripts/main.gd
extends Node

const PROBE_SIZE: Vector2 = Vector2(70, 70)
const REACH: float = 420.0

var probe: Polygon2D
var ghost: Polygon2D
var cast: ShapeCast2D
var path: Line2D
var origin: Vector2


func _ready() -> void:
	_add_background()

	var view: Vector2 = get_viewport().get_visible_rect().size
	origin = Vector2(view.x * 0.2, view.y * 0.5)

	for at in [Vector2(view.x * 0.6, view.y * 0.35), Vector2(view.x * 0.75, view.y * 0.7)]:
		_add_wall(at, Vector2(50, 260))

	var shape: RectangleShape2D = RectangleShape2D.new()
	shape.size = PROBE_SIZE

	cast = ShapeCast2D.new()
	cast.shape = shape
	cast.position = origin
	add_child(cast)

	path = Line2D.new()
	path.width = 2.0
	path.default_color = Color(0.55, 0.65, 0.95, 0.3)
	add_child(path)

	ghost = _make_rect(PROBE_SIZE, Color(0.98, 0.5, 0.5, 0.35))
	add_child(ghost)

	probe = _make_rect(PROBE_SIZE, Color('#8da5f3'))
	probe.position = origin
	add_child(probe)

	print('the ghost is where the box would stop, computed before moving')


func _physics_process(_delta: float) -> void:
	var target: Vector2 = get_viewport().get_mouse_position()
	var to: Vector2 = (target - origin).limit_length(REACH)

	cast.target_position = to
	cast.force_shapecast_update()

	var fraction: float = cast.get_closest_collision_safe_fraction() if cast.is_colliding() else 1.0

	ghost.position = origin + to * fraction
	ghost.color = Color(0.98, 0.5, 0.5, 0.35) if cast.is_colliding() else Color(0.55, 0.94, 0.6, 0.25)
	path.points = PackedVector2Array([origin, origin + to])


func _add_wall(center: Vector2, size: Vector2) -> void:
	var shape: RectangleShape2D = RectangleShape2D.new()
	shape.size = size

	var collision: CollisionShape2D = CollisionShape2D.new()
	collision.shape = shape

	var wall: StaticBody2D = StaticBody2D.new()
	wall.position = center
	wall.add_child(_make_rect(size, Color('#2a2f3d')))
	wall.add_child(collision)
	add_child(wall)


func _make_rect(size: Vector2, color: Color) -> Polygon2D:
	var rect: Polygon2D = Polygon2D.new()
	rect.polygon = PackedVector2Array([-size * 0.5, Vector2(size.x, -size.y) * 0.5, size * 0.5, Vector2(-size.x, size.y) * 0.5])
	rect.color = color

	return rect


func _add_background() -> void:
	var background: ColorRect = ColorRect.new()
	background.color = Color('#12141a')
	add_child(background)
	background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)

更多物理示例