- Edited
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:
(This video uses the gravity scale method)