Topic was automatically imported from the old Question2Answer platform.
Asked By
billyshears
Started my first godot project and have now gotten stuck …
The main scene is a room, I spawn a box (kinematicbody2d) with add_child. The box falls to the floor of the room and stops. This part works fine. I then need to detect a mouse click inside the box.
I tried adding _input(event) function to detect a left mouse click inside the box. This kind worked or so I thought, unfortunately the problem is it doesn’t matter if I click in or outside of the box, _input(event) treats it the same, as long as I left click somewhere in the room.
I was then informed that I should use _input_event() to detect inside the box and make the kinematicbody2d pickable. Then check if event type is InputEventMouseButton and event is pressed. I’ve tried this but it doesn’t detect any mouse click, never gets into the method when I click anyway.
It was also suggested I add an area2d with a collisionshape as a child to the parent kinematicbody2d. I tried this and still couldn’t get the mouse click to fire off the input_event(). I didn’t like having a collisionshape for the kinematicbody2d and a duplicate for the area2d anyway but would do this if I had to. Not sure if I did that part correctly.
I am only getting a result from _input(). I added print(event) in that function and it does print InputEventMouseButton … just doesn’t ever get to _input_event() when I try to use that instead with left mouse click.
It was also suggested I use _unhandled_input(event) but I do not even no where to start with that one.
So, as a beginner I am failing miserably somewhere.
Any idea what I am missing here? Could it have something to do with main scene add_child? Any suggestions what to try next?
Also, more boxes could fall and they should collide with the box below it. With that in mind and the fact I need to detect a click inside each box, is kinematicbody2d the correct node to start with?
Hi billyshears,
I have created this very basic scene setup. Follow the instructions and there should be no problems. From what you described I would say you forget to do the signals connection (11-14), but I don’t know. Do you know how signals work? It’s well explained here. For me it works.
Use Godot 3.1
Create a new 2D Scene.
Create a new PhysicsBody2D. I used a RigidBody2D because I didn’t wanted to write the gravity but you can use a KinematicBody2D too. Name it Box.
Add a Sprite as a child of your Box node.
Set a texture to that Sprite.
Add a CollisionShape2D to as a child of your Box node.
Create a new shape by clicking into the CollisionShapes shape property.
Scale it so it fits to your sprite.
Select your Box node and add a script to it.
In the inspector set the pickable property to true.
Now head over to the signals tab (same place as the inspector).
Under CollisionObject2D double click input_event(bababa).
In the Popup box select your Box node, leave everything else untouched and click Connect.
The Script editor should have opened. There should be a function called _on_Box_input_event(viewport, event, shape_idx)
Delete the pass and type in
if event is InputEventMouseButton and event.pressed and event.button_index == BUTTON_LEFT:
print("lol it works")
queue_free()
Hope it helps. Good luck!
Still not working for me … but I have more info.
I run the main scene and the Box drops to the floor, I click and still get nothing.
However, when I run the Box scene by itself it works!!! I can click the box and see “lol” in the Output before it drops off screen.
So does this have something to with how I am spawning from the main scene? Here is my code:
onready var box = preload("res://Scenes/box.tscn")
func _ready():
new_box()
func new_box():
var new_box = box.instance()
add_child(new_box)
billyshears | 2019-05-28 19:23
Also, thanks so much for your steps to follow. I got too excited when it worked on it’s own that I forgot my manners.
The API provides for detecting clicks on any CollisionObject2D:
As the doc suggests, connect the input_event signal and you’ll be able to detect mouse events. The input_pickable property enables/disables this functionality.
The other input handling methods you listed are more general - they detect inputs but are not tied to the object’s shape, so you would get a click event from anywhere on the screen.
For example, I have the following code on a RigidBody2D that I want the player to be able to click to pick up:
func _input_event(viewport, event, shape_idx):
if event is InputEventMouseButton:
if event.button_index == BUTTON_LEFT and event.pressed:
print("clicked")
Don’t forget to connect the signal.
Thanks for the info, I was able to get this working on the scene itself. However, when I instance from my main scene, it no longer detects click inside.
I couldn’t get an elegant solution to work with _unhandled_input, so I’m using this function:
I’m using a singleton named Globals to get a reference to the camera.
func is_point_inside_collision_shape(point: Vector2, cs:CollisionShape2D):
var r = RectangleShape2D.new()
r.extents = Vector2(1,1)
var cam = Globals.get("currentCamera")
return cs.shape.collide(cs.get_global_transform(), r,
Transform2D(0, point + cam.get_global_transform().get_origin()))
I then use this function inside _unhandled_input with event.position and a collision shape as arguments
if is_point_inside_collision_shape(event.position, collision_shape):
# do something
This is exactly what I ended up doing.
I’d love to know if there’s a better way to handle _unhandled_input, as it seems like something that should be handled by the engine more cleanly, but it works for me, thanks