Godot Version
v4.3.stable.official [77dcf97d8]
Question
I’m trying to add the ability for blocks (frozen RigidBody2Ds) to be hard-dropped instantly (they get placed on the closest surface directly below them) But I’m having trouble with it. Many of the methods I have tried to accomplish hard-dropping (specifically surface detection) are very slow (they have a noticeable delay). Even after a surface is detected, the block might sometimes end up being placed partially in the floor, not directly on top of it.
Can anyone help me figure out what I’m doing wrong or link me to an answer for reference? I’ve looked around but couldn’t find anything.
Here are some methods I’ve tried:
- Using raycasts (either a noticeable delay or it goes too fast for the raycast to check for collisions)
- Using Area2Ds (same issue as raycasts)
- Unfreezing the blocks, applying a high gravity scale, and freezing them shortly afterward
=====
- Here’s my code:
extends RigidBody2D
# for i & for j loops start at top-right, go up, go back down and move left, and repeat for the whole square.
@onready var tiles: TileMapLayer = $TileMapLayer
@onready var tile_start: Marker2D = $Marker2D
@onready var collision_polygon: CollisionPolygon2D = $CollisionPolygon2D
@onready var ray_cast_floor: RayCast2D = $RayCastFloor
@onready var detect_area: Area2D = $DetectArea
@onready var detect_polygon: CollisionPolygon2D = $DetectArea/DetectPolygon
@export var piece_type = -1 as int
var detect_moving = true
var movable = true
var drop_y = null
var rng = RandomNumberGenerator.new()
var piece_data = [
"NULL/NULL/NULL/NULL/(2, 3)/(2, 2)/(2, 2)/(2, 1)/NULL/NULL/NULL/NULL/NULL/NULL/NULL/NULL/=(16, -64)/(16, 64)/(-16, 64)/(-16, -64)=(16, 0)=(0, 16)", # I, 0
"NULL/NULL/NULL/NULL/NULL/(6, 2)/(6, 1)/NULL/NULL/(5, 2)/(5, 1)/NULL/NULL/NULL/NULL/NULL/=(32, -32)/(32, 32)/(-32, 32)/(-32, -32)=(0, 0)=(0, 16)", # O, 1
"NULL/(4, 0)/NULL/NULL/(5, 0)/(3, 0)/NULL/NULL/NULL/(2, 0)/NULL/NULL/NULL/NULL/NULL/NULL/=(-48, -32)/(48, -32)/(48, 0)/(16, 0)/(16, 32)/(-16, 32)/(-16, 0)/(-48, 0)=(16, 32)=(0, 16)", # T, 2
"NULL/NULL/NULL/NULL/NULL/(8, 0)/(9, 1)/(9, 0)/NULL/(6, 0)/NULL/NULL/NULL/NULL/NULL/NULL/=(32, -32)/(32, 64)/(-32, 64)/(-32, 32)/(0, 32)/(0, -32)=(0, -32)=(0, 16)", # J, 3
"NULL/NULL/NULL/NULL/NULL/(8, 0)/NULL/NULL/NULL/(6, 0)/(9, 1)/(9, 0)/NULL/NULL/NULL/NULL/=(32, 32)/(32, 64)/(-32, 64)/(-32, -32)/(0, -32)/(0, 32)=(0, -32)=(0, 16)", # L, 4
"NULL/NULL/NULL/NULL/NULL/NULL/(1, 0)/NULL/NULL/(1, 0)/(1, 0)/NULL/NULL/(1, 0)/NULL/NULL/=(32, -32)/(32, 0)/(0, 0)/(0, 32)/(-64, 32)/(-64, 0)/(-32, 0)/(-32, -32)=(0, 0)=(0, 16)", # S, 5
"NULL/NULL/NULL/NULL/NULL/(1, 0)/NULL/NULL/NULL/(1, 0)/(1, 0)/NULL/NULL/NULL/(1, 0)/NULL/=(32, 0)/(32, 32)/(-32, 32)/(-32, 0)/(-64, 0)/(-64, -32)/(0, -32)/(0, 0)=(0, 0)=(0, 16)", # Z, 6
"NULL/(4, 0)/NULL/NULL/NULL/(3, 0)/NULL/NULL/NULL/(3, 0)/NULL/NULL/NULL/(2, 0)/(1, 0)/NULL/=(-32, -32)/(-32, 0)/(64, 0)/(64, 32)/(-64, 32)/(-64, -32)=(0, 0)=(0, 16)", # Long sideways J, 7
"NULL/NULL/NULL/NULL/NULL/(4, 1)/NULL/NULL/NULL/(3, 1)/NULL/NULL/NULL/NULL/NULL/NULL/=(-32, -16)/(32, -16)/(32, 16)/(-32, 16)=(0, 16)=(0, 16)", # Small horizontal 2-long, 8
"NULL/NULL/NULL/NULL/(4, 0)/NULL/NULL/NULL/(3, 0)/(1, 1)/NULL/NULL/(2, 0)/(0, 1)/NULL/NULL/=(-48, -32)/(16, -32)/(16, 0)/(48, 0)/(48, 32)/(-48, 32)/(-48, 0)=(-16, 32)=(0, 16)", # O with a block right of bottom-right, 9
]
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
#freeze_mode = 1
tiles.tile_set.setup_local_to_scene()
var picked_piece
if piece_type < 0:
picked_piece = piece_data.pick_random()
else:
picked_piece = piece_data[piece_type]
#print(picked_piece)
var piece_tile_string = picked_piece.get_slice("=", 0)
#print(piece_tile_string)
var piece_tile_array = piece_tile_string.split("/", true)
var piece_tile_array_vec2 = []
piece_tile_array_vec2.resize(piece_tile_array.size())
for entry in piece_tile_array.size():
var coord_string = piece_tile_array[entry]
if coord_string == "":
piece_tile_array_vec2.remove_at(entry)
elif coord_string == "NULL":
piece_tile_array_vec2[entry] = Vector2(-1, -1)
else:
coord_string = coord_string.replace("(", "")
coord_string = coord_string.replace(")", "")
coord_string = coord_string.replace(" ", "")
var coord_vec2 = Vector2(float(coord_string.get_slice(",", 0)), float(coord_string.get_slice(",", 1)))
piece_tile_array_vec2[entry] = coord_vec2
#print("tile array vector2")
#print(piece_tile_array_vec2)
var piece_col_string = picked_piece.get_slice("=", 1)
#print(piece_col_string)
var piece_col_array = piece_col_string.split("/", true)
#print(piece_col_array)
var piece_col_array_vec2 = []
piece_col_array_vec2.resize(piece_col_array.size())
for entry in piece_col_array.size():
var coord_string = piece_col_array[entry]
if coord_string == "":
piece_col_array.remove_at(entry)
elif coord_string == "NULL":
piece_col_array_vec2[entry] = Vector2(-1, -1)
else:
coord_string = coord_string.replace("(", "")
coord_string = coord_string.replace(")", "")
coord_string = coord_string.replace(" ", "")
#print(coord_string)
var coord_vec2 = Vector2(float(coord_string.get_slice(",", 0)), float(coord_string.get_slice(",", 1)))
#print(coord_vec2)
#print(" ")
piece_col_array_vec2[entry] = coord_vec2
#print("coord array vector2")
#print(piece_col_array_vec2)
var tile_select = 0
for i in 4:
for j in 4:
#print(str(i * 32) + ", " + str(j * 32))
var tile_used = 1 #rng.randi_range(0, 1) # 0 == Y, 1 == N
var tile_pos = tiles.local_to_map(Vector2(tile_start.position.x - (32 * i), tile_start.position.y - (32 * j)))
if piece_tile_array_vec2[tile_select] != Vector2(-1, -1):
tiles.set_cell(tile_pos, 1, piece_tile_array_vec2[tile_select])
#var adjacent_array = []
#if tiles.get_cell_tile_data(Vector2i(tile_pos.x + 32, tile_pos.y)) == null:
#tiles.erase_cell(tile_pos)
else:
tiles.erase_cell(tile_pos)
tile_select += 1
collision_polygon.set_polygon(piece_col_array_vec2)
detect_polygon.set_polygon(piece_col_array_vec2)
var col_position_string = picked_piece.get_slice("=", 2)
col_position_string = col_position_string.replace("(", "")
col_position_string = col_position_string.replace(")", "")
col_position_string = col_position_string.replace(" ", "")
collision_polygon.position = Vector2(float(col_position_string.get_slice(",", 0)), float(col_position_string.get_slice(",", 1)))
print(collision_polygon.position)
#var ray_cast_string = picked_piece.get_slice("=", 3)
#ray_cast_string = ray_cast_string.replace("(", "")
#ray_cast_string = ray_cast_string.replace(")", "")
#ray_cast_string = ray_cast_string.replace(" ", "")
#ray_cast_floor.position = Vector2(float(ray_cast_string.get_slice(",", 0)), float(ray_cast_string.get_slice(",", 1)))
#print(ray_cast_floor.position)
global_rotation_degrees = rng.randi_range(0, 3) * 90
ray_cast_floor.global_rotation_degrees = 0
detect_area.global_rotation_degrees = 0
detect_polygon.global_rotation_degrees = global_rotation_degrees
ray_cast_floor.position = Vector2(0, 0)
#extend_raycast()
check_collisions()
func extend_raycast():
ray_cast_floor.position.y -= 32
while not ray_cast_floor.is_colliding():
ray_cast_floor.target_position.y += 32
await get_tree().create_timer(0.2).timeout
func check_collisions():
drop_y = null
detect_area.global_position = collision_polygon.global_position
if GameManager.game_phase == "calm" and movable == true:
detect_area.global_position.y = 1
await get_tree().create_timer(0.05).timeout
while not detect_area.has_overlapping_bodies():
detect_area.global_position.y += 32
await get_tree().create_timer(0.05).timeout
#ray_cast_floor.target_position.y = 33
#while not ray_cast_floor.is_colliding():
#ray_cast_floor.target_position.y += 32
#detect_area.global_position.y += 32
#await get_tree().create_timer(0.05).timeout
# ray_cast_floor.target_position.y -= 1
drop_y = ray_cast_floor.get_collision_point().y
print(drop_y)
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _physics_process(delta: float) -> void:
if GameManager.game_phase == "calm" and movable == true:
freeze = true
if Input.is_action_just_pressed("move_left"):
global_position.x -= 32
check_collisions()
elif Input.is_action_just_pressed("move_right"):
global_position.x += 32
check_collisions()
elif Input.is_action_just_pressed("move_down"):
print("GO DOWN")
movable = false
#freeze_mode = 1
gravity_scale = 300
freeze = false
await get_tree().create_timer(0.05).timeout
freeze = true
gravity_scale = 1
-
Here’s my block scene dock:
-
Here’s a short video I uploaded of my running game: hard dropping via gravity scale...nope.mp4 - Google Drive (This video uses the gravity scale method)