Godot 4.2.1
I am currently working on my small card game, and I recently watched a video of someone recreating Balatro’s card effects, movement, shaders, and swapping mechanics. Among these features, I am particularly interested in adding the swapping mechanism to my game, which will allow users to organize their hand by swapping the positions of cards.
The problem is that I have no clue where to start with this idea. If anyone could provide guidance on how to implement this feature, it would be wonderful. Thank you!
Here’s the video(timestamp 1:46-2:09): https://youtu.be/I1dAZuWurw4
My game(currently):
#Hand Code#
extends Control
var card_size = Vector2(24,40)
@export var hand_curve: Curve
@export var rotation_curve: Curve
@export var max_rotation_degrees : int
@export var x_sep : int
@export var y_min : int
@export var y_max : int
func _process(_delta):
_update_cards()
func _update_cards() -> void:
var cards = get_child_count()
var all_cards_size = card_size.x * cards + x_sep * (cards - 1)
var final_x_sep = x_sep
if all_cards_size > size.x:
final_x_sep = (size.x - card_size.x * cards) / (cards - 1)
all_cards_size = size.x
var offset = (size.x - all_cards_size) / 2
for i in cards:
var card := get_child(i)
var y_multiplier := hand_curve.sample(1.0 / (cards-1) * i)
var rot_multiplier := rotation_curve.sample(1.0 / (cards-1) * i)
if cards == 1:
y_multiplier = 0.0
rot_multiplier = 0.0
var final_x: float = offset + card_size.x * i + final_x_sep * i
var final_y: float = y_min + y_max * y_multiplier
card.position = Vector2(final_x, final_y)
card.rotation_degrees = max_rotation_degrees * rot_multiplier
func _on_mouse_entered():
Game.mouse_on_hand = true
func _on_mouse_exited():
Game.mouse_on_hand = false
#Basic Card movement and dragging code#
extends Control
@export var angle_x_max: float = 25.0
@export var angle_y_max: float = 25.0
var is_selected : bool = false
var following_mouse : bool = false
var is_placed : bool = false
var is_on_slot : bool = false
var tween_hover : Tween
var initial_pos : Vector2 = Vector2.ZERO
func _ready():
pass
func _process(_delta):
if following_mouse:
global_position = get_global_mouse_position()
#if is_selected:
# fake_3d()
func _gui_input(event):
if event is InputEventMouseButton and event.button_index == 1:
if event.button_mask == 1 and is_selected:
Game.card_scene = load("res://Cards/Scenes/ace_c.tscn")
Game.card_name = name
initial_pos = position
following_mouse = true
if event.button_mask == 0:
var hand = get_tree().get_root().get_child(1).get_child(1).get_child(0)
if Game.mouse_on_hand and is_on_slot:
add_card_to_hand(hand)
if Game.mouse_on_slot:
var slot = get_tree().get_root().get_child(1).get_child(0).find_child(Game.slot_name)
if not slot.has_card:
place_card_on_slot(slot)
else:
cancel_card_move()
else:
cancel_card_move()
reset_card_selection()
func add_card_to_hand(hand):
var temp_card = Game.card_scene.instantiate()
hand.add_child(temp_card)
Game.cards_in_hand += 1
queue_free()
func place_card_on_slot(slot):
var temp_card = Game.card_scene.instantiate()
slot.add_child(temp_card)
if not is_on_slot:
Game.cards_in_hand -= 1
temp_card.is_on_slot = true
queue_free()
func cancel_card_move():
following_mouse = false
is_selected = false
position = initial_pos
func reset_card_selection():
Game.card_scene = null
Game.card_name = null
is_selected = false
following_mouse = false
func fake_3d():
var mouse_pos: Vector2 = get_local_mouse_position()
var diff: Vector2 = (position + size) - mouse_pos
var lerp_val_x: float = remap(mouse_pos.x, 0.0, size.x, 0, 1)
var lerp_val_y: float = remap(mouse_pos.y, 0.0, size.y, 0, 1)
var rot_x: float = rad_to_deg(lerp_angle(-angle_x_max, angle_x_max, lerp_val_x))
var rot_y: float = rad_to_deg(lerp_angle(angle_y_max, -angle_y_max, lerp_val_y))
$Texture.material.set_shader_parameter("x_rot", rot_y)
$Texture.material.set_shader_parameter("y_rot", rot_x)
func _on_mouse_entered():
is_selected = true
if tween_hover and tween_hover.is_running():
tween_hover.kill()
tween_hover = create_tween().set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_ELASTIC)
tween_hover.tween_property(self, "scale", Vector2(2.15, 2.15), 0.5)
func _on_mouse_exited():
if not following_mouse:
is_selected = false
if tween_hover and tween_hover.is_running():
tween_hover.kill()
tween_hover = create_tween().set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_ELASTIC)
tween_hover.tween_property(self, "scale", Vector2(2,2), 0.55)
Board Node Structure:
Card Node Structure: