Corrente de juntas
Doze elos presos uns nos outros e um peso na ponta. Clique para empurrar a corrente e veja ela se acomodar.
O editor acima está rodando este projeto. Mude uma linha e ele recarrega.
Classes do Godot usadas
PinJoint2DRigidBody2DStaticBody2D
O código
scripts/main.gd
extends Node
const LINKS: int = 12
const LINK_SIZE: Vector2 = Vector2(18, 44)
const WEIGHT_RADIUS: float = 34.0
var weight: RigidBody2D
func _ready() -> void:
_add_background()
var view: Vector2 = get_viewport().get_visible_rect().size
var top: Vector2 = Vector2(view.x * 0.5, view.y * 0.18)
var anchor: StaticBody2D = StaticBody2D.new()
anchor.position = top
anchor.add_child(_make_rect(Vector2(60, 18), Color('#2a2f3d')))
add_child(anchor)
var previous: PhysicsBody2D = anchor
for i in LINKS:
var at: Vector2 = top + Vector2(0, LINK_SIZE.y * (i + 1))
var link: RigidBody2D = _add_link(at, i == LINKS - 1)
_pin(previous, link, at - Vector2(0, LINK_SIZE.y * 0.5))
previous = link
weight = previous as RigidBody2D
weight.apply_impulse(Vector2(900, 0))
print('the last link is heavier, click to push the chain again')
func _unhandled_input(event: InputEvent) -> void:
if event is InputEventMouseButton and event.pressed and is_instance_valid(weight):
weight.apply_impulse(Vector2(randf_range(-900, 900), -200))
func _add_link(at: Vector2, is_weight: bool) -> RigidBody2D:
var body: RigidBody2D = RigidBody2D.new()
body.position = at
if is_weight:
body.mass = 6.0
var circle: CircleShape2D = CircleShape2D.new()
circle.radius = WEIGHT_RADIUS
var collision: CollisionShape2D = CollisionShape2D.new()
collision.shape = circle
body.add_child(_make_circle(WEIGHT_RADIUS, Color('#fc7f7f')))
body.add_child(collision)
else:
var shape: RectangleShape2D = RectangleShape2D.new()
shape.size = LINK_SIZE
var collision: CollisionShape2D = CollisionShape2D.new()
collision.shape = shape
body.add_child(_make_rect(LINK_SIZE, Color('#8da5f3')))
body.add_child(collision)
add_child(body)
return body
func _pin(a: PhysicsBody2D, b: PhysicsBody2D, at: Vector2) -> void:
var joint: PinJoint2D = PinJoint2D.new()
joint.position = at
add_child(joint)
joint.node_a = a.get_path()
joint.node_b = b.get_path()
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 _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
func _add_background() -> void:
var background: ColorRect = ColorRect.new()
background.color = Color('#12141a')
add_child(background)
# ColorRect defaults to MOUSE_FILTER_STOP and would eat the click before _unhandled_input
background.mouse_filter = Control.MOUSE_FILTER_IGNORE
background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)