Godot Version
Godot Engine v4.4.1.stable.mono.official.49a5bc7b6
Question
I’m trying create a cup with bubble tea pearls inside of it. I’m using StaticBody2D as walls for the cup and RigidBody2D for the pearls.
With the current setup, it works slightly well but if I move the cup too fast, the tunneling issue happens where the pearls fall outside of the cup.
Since forum does not allow new user to attach stuff so here is the link to the demo
Note: I found that increasing the size of the collision shapes help a bit but if I move much faster, the issue occurs again. I tried searching it up but couldn’t find the right keywords.
Current setup:
pearl.tscn
[gd_scene load_steps=5 format=3 uid="uid://bk45ipognydds"]
[ext_resource type="Script" uid="uid://dft8j6nqkphck" path="res://prototype/topping/pearl/pearl.gd" id="1_25gxw"]
[ext_resource type="Texture2D" uid="uid://j6gewbxp3f05" path="res://prototype/topping/pearl/assets/pearl.webp" id="1_pxne4"]
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_25gxw"]
friction = 0.7
bounce = 0.3
[sub_resource type="CircleShape2D" id="CircleShape2D_tdk6r"]
radius = 7.0
[node name="Pearl" type="RigidBody2D"]
collision_layer = 8
collision_mask = 12
physics_material_override = SubResource("PhysicsMaterial_25gxw")
can_sleep = false
continuous_cd = 2
script = ExtResource("1_25gxw")
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
shape = SubResource("CircleShape2D_tdk6r")
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="."]
visible = false
position = Vector2(-2.84217e-14, -1)
scale = Vector2(0.0622407, 0.0622407)
polygon = PackedVector2Array(23, -92.4, -8, -93.6, -8, -92.1, -30.1, -86.5, -33.5, -86.5, -55.5, -73.5, -57.8, -73.5, -79.8, -52.5, -81.2, -52.5, -94.1, -29.5, -95.6, -29.5, -101.5, -4.5, -103, -4.5, -103, 30.8, -94, 55.9, -94, 58.2, -75, 83.1, -75, 85.4, -52, 104.4, -52, 105.8, -30, 114.9, -30, 116.2, -9, 119.2, -9, 120.5, -6.8, 120.5, 26.2, 117.5, 30.5, 117.5, 57.5, 103.5, 59.7, 103.5, 81.7, 84.5, 83.1, 84.5, 99.1, 60.5, 100.5, 60.5, 108.5, 29.5, 110, 29.5, 110, 2.2, 107, -8.5, 107, -14, 94, -40, 94, -42.3, 85, -52.3, 85, -54.4, 67, -70.4, 67, -71.7, 39, -85.8, 39, -87.1, 23, -91.1)
disabled = true
[node name="Sprite2D" type="Sprite2D" parent="."]
position = Vector2(-2.84217e-14, -1)
scale = Vector2(0.0622407, 0.0622407)
texture = ExtResource("1_pxne4")
cup.tscn
[gd_scene load_steps=9 format=3 uid="uid://dy0majlmfkegw"]
[ext_resource type="Script" uid="uid://vl5vran0r25f" path="res://prototype/cup/cup.gd" id="1_ponjl"]
[ext_resource type="Texture2D" uid="uid://oqow1s2an4aa" path="res://icon.svg" id="2_cmrwc"]
[ext_resource type="PackedScene" uid="uid://bk45ipognydds" path="res://prototype/topping/pearl/pearl.tscn" id="3_qi7ja"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_msvy8"]
size = Vector2(80, 192)
[sub_resource type="RectangleShape2D" id="RectangleShape2D_kssxt"]
size = Vector2(16, 192)
[sub_resource type="RectangleShape2D" id="RectangleShape2D_qi7ja"]
size = Vector2(112, 11.5)
[sub_resource type="RectangleShape2D" id="RectangleShape2D_sqg1t"]
size = Vector2(16, 192)
[sub_resource type="RectangleShape2D" id="RectangleShape2D_u3gmq"]
size = Vector2(112, 16)
[node name="Cup" type="Area2D" groups=["cups"]]
collision_mask = 0
script = ExtResource("1_ponjl")
[node name="FillingTimer" type="Timer" parent="."]
[node name="Polygon2D" type="Polygon2D" parent="."]
color = Color(0.337255, 0.164706, 1, 0.905882)
polygon = PackedVector2Array(-40, -96, 40, -96, 40, 96, -40, 96)
uv = PackedVector2Array(-40, -96, 40, -96, 40, 96, -40, 96)
[node name="Label" type="Label" parent="."]
offset_left = -40.0
offset_top = -96.0
offset_right = 40.0
offset_bottom = 96.0
text = "Cup"
horizontal_alignment = 1
vertical_alignment = 1
metadata/_edit_use_anchors_ = true
[node name="Liquid" type="TextureProgressBar" parent="."]
offset_left = -40.0
offset_top = -96.0
offset_right = 40.0
offset_bottom = 96.0
fill_mode = 3
nine_patch_stretch = true
texture_progress = ExtResource("2_cmrwc")
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
shape = SubResource("RectangleShape2D_msvy8")
[node name="Walls" type="CharacterBody2D" parent="."]
z_index = 1
collision_layer = 4
collision_mask = 8
[node name="Left" type="CollisionShape2D" parent="Walls" groups=["cup_walls"]]
position = Vector2(-48, 0)
shape = SubResource("RectangleShape2D_kssxt")
one_way_collision_margin = 10.0
debug_color = Color(0.852554, 0.303196, 0.551431, 0.42)
[node name="Bottom" type="CollisionShape2D" parent="Walls"]
position = Vector2(0, 101.75)
shape = SubResource("RectangleShape2D_qi7ja")
one_way_collision_margin = 10.0
debug_color = Color(0.852554, 0.303196, 0.551431, 0.42)
[node name="Right" type="CollisionShape2D" parent="Walls" groups=["cup_walls"]]
position = Vector2(48, 0)
shape = SubResource("RectangleShape2D_sqg1t")
one_way_collision_margin = 10.0
debug_color = Color(0.824591, 0.331672, 0.57583, 0.42)
[node name="Top" type="CollisionShape2D" parent="Walls"]
position = Vector2(-3.49691e-07, -104)
rotation = -3.14159
shape = SubResource("RectangleShape2D_u3gmq")
one_way_collision = true
debug_color = Color(0.852554, 0.303196, 0.551431, 0.42)
[node name="Pearl" parent="." instance=ExtResource("3_qi7ja")]
position = Vector2(16, 48)
[connection signal="input_event" from="." to="." method="_on_input_event"]
[connection signal="timeout" from="FillingTimer" to="Walls" method="fill_liquid"]
cup.gd
class_name Cup
extends Area2D
var dragging: bool = false
var offset: Vector2
var fill_percentage = 10
var in_area = false
@onready var liquid: TextureProgressBar = $Liquid
@export var drag_speed = 10
func _ready() -> void:
pass
func _on_input_event(_viewport: Node, event: InputEvent, _shape_idx: int) -> void:
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
if event.is_pressed():
dragging = true
offset = global_position - event.position
else:
stop_dragging()
func _physics_process(_delta: float) -> void:
if dragging:
var new_position = get_global_mouse_position() + offset
position = new_position
func fill_liquid() -> void:
if !in_area:
print('Please place the cup in the area first!')
return
if liquid.value < 100:
liquid.value += fill_percentage
elif liquid.value <= 110:
print('Please stop pouring!')
else:
print('Pleaseeeeeeeeeeeeee')
func stop_dragging() -> void:
dragging = false