Godot Tutorial: Creating a physics based point & click mechanic


This is a step by step guide for how to recreate the physics based click and drag mechanic seen in my game.

Tutorial

Step 1: setup a global script with variables var is_dragging = false and var hovering = false in which will track whether you're actively dragging an object. Set that script in the project settings in the "autoload" settings.

Step 2: In project settings under "Input Map" add a new action called "click" that corresponds to left click

Step 3: Create your draggable RigidBody2d, make sure to add an Area2d called "clickable_area" and add a collision shape that covers everything you want to be draggable.

Step 4: Create the script for your draggable object and then go back to your Area2d, "clickable_area" and connect the following signals to your object script:

  • body_entered(body:Node2d)

  • body_exited(body:Node2d)

Step 5: Now the signals section of the Object script will have the following code: (replace > with tabs)

var draggable = false  
func _on_area_2d_mouse_entered(): 
> if not global.is_dragging: 
>> draggable = true #notes that this object can be dragged 
>> global.hovering = true #prevents clicking on multiple objects at the same time 
>> add_to_group("hovered") #prevents clicking on multiple objects at the same time 
>> scale = Vector2(1.05, 1.05) #shows which objects can be clicked by increasing size  
func _on_area_2d_mouse_exited(): 
> if not global.is_dragging: 
>> draggable = false 
>> global.hovering = false 
>> remove_from_group("hovered") 
>> scale = Vector2(1, 1)

Step 6: Next we'll go back the global script and add the logic for handling hovering:

...  
var hovered : Array 
var hovered_size 
var top_hovered  
func _process(delta): 
> if hovering and not is_dragging:  
>> hovered = get_tree().get_nodes_in_group("hovered") 
>> hovered_size = get_tree().get_nodes_in_group("hovered").size()-1 
>> if hovered_size >= 0:  
>>> top_hovered = hovered[hovered_size] 
>> else: 
>>> hovering = false

Step 7: now we'll add a StaticBody2d named "mouse null" to your main scene with a child PinJoint2d make sure to set the Node A in the PinJoint2d reference your StaticBody2d

Step 8: Add a script to your StaticBody2d, "mouse null":

func _physics_process(delta): 
>global_position = lerp(global_position, get_global_mouse_position(), 60*delta) #make StaticBody2d follow mouse 
>if Input.is_action_pressed("click"): >>if global.is_dragging == true: 
>>$PinJoint2D.node_b = global.top_hovered.get_path() #get attached the PinJoint2d to the top object 
>elif Input.is_action_just_released("click"): 
>>$PinJoint2D.node_b = ""

Step 9: We'll go back to your object script, and add to the _physics_process:

func _physics_process(delta):  
> if draggable and global.top_hovered == self: #this is determined by the "clickable area" with signals & logic checking an array of overlapping objects  
>> if Input.is_action_just_pressed("click"): 
>>>self.collision_mask = 2 #keeps you from interacting with other objects while dragging remove if undesired 
>>>self.collision_layer = 2 #keeps you from interacting with other objects while dragging remove if undesired 
>>>global.is_dragging = true #keeps you from picking up multiple objects  
>>if Input.is_action_pressed("click"): 
>>>global.is_dragging = true  
>>elif Input.is_action_just_released("click"): 
>>>self.collision_mask = 1 
>>>self.collision_layer = 1 
>>>global.is_dragging = false  
>>>draggable = false  
>>>self.angular_velocity = 0.0 #reset any momentum when released to avoid physics glitches 
>>>self.linear_velocity = Vector2(0,0) #reset any momentum when released to avoid physics glitches

Now it should work! Have fun!

Get Voynich Cafe

Leave a comment

Log in with itch.io to leave a comment.