![]() |
Attention | Topic was automatically imported from the old Question2Answer platform. |
![]() |
Asked By | BigBadWouf |
Hello,
I have simple scene with Spatial as root, StaticBody as ground, and Area as Marker.
The goal of Marker is to check overlapping with other Areas in the scene.
What i try to making is spawn multiple node (Brick) while left mouse button is pressed, but preventing spawn if another area is under the mouse. That work at one exception :
The brick spawn twice before marker detect overlapping. I trying some (stupid) things, but i dont understand why…
Code of root node :
extends Spatial
export (NodePath) var marker_node
var pointer : Vector3
var marker : Node
var clic : bool = false
var hit : Dictionary = {}
onready var camera = $View/Arm/Camera
func _ready():
marker = get_node(marker_node)
func _unhandled_input(event):
if event is InputEventMouseMotion:
var from = camera.project_ray_origin(event.position)
var to = from + camera.project_ray_normal(event.position) * 1000;
var space_state = get_world().get_direct_space_state()
hit = space_state.intersect_ray( from, to )
if Input.is_action_pressed("primary"):
clic = true
if Input.is_action_just_released("primary"):
clic = false
func _physics_process(delta):
if not hit.empty():
pointer = Vector3(floor(hit.position.x) + .5, 0.01, floor(hit.position.z) + .5)
marker.global_transform.origin = pointer
if clic and marker.get_overlapping_areas().empty():
var brick = Brick.new()
brick.global_transform.origin = pointer
add_child(brick)
Code of the Brick.gd :
extends Area
class_name Brick
var mesh = PlaneMesh.new()
var mi = MeshInstance.new()
var cs = CollisionShape.new()
var shape = BoxShape.new()
func _init():
mesh.size = Vector2(1,1)
shape.extents = Vector3(0.499, 1, 0.499)
cs.shape = shape
mi.mesh = mesh
add_child(cs)
add_child(mi)
The Marker is just Area with CollisionShape (BosShape).
If i press mouse left button, Brick spawn twice. If i press and drag,
Brick spawn 4 or 5 time…
For now, i use Godot Beta 3.5. But have tested in Godot 3.4, with same result.
I’m not sure at first glance what would be wrong, but here are some notes:
if Input.is_action_pressed("primary"):
Keep in mind _unhandled_input
is called for every input event. That means it will be called when you put the button down, and also when you release the button. And also each time you move the mouse. Which is why usually, it is kinda suspicious to see Input.something
inside an _input*
function, since you should only rely on the event that’s being passed to you. Try using event.is_action_pressed
or event.is_action_release
instead. Might not solve your issue but would be cleaner: InputEvent — Godot Engine (stable) documentation in English
From what I see in your code, until _unhandled_input
is called, your clic
variable will remain true
until you release your mouse. I would not call it clic
, but instead place_brick_action
, and then set it to false
once the action is consumed inside _physics_process
. This, assuming you also do the change I mentionned above about not using Input
(otherwise clic
could come back to true
randomly just because some other input event occured like a key press while your mouse button is still down or whatever).
Then, something you could try is verify when your area detects the brick if you let it run. I suspect you’ll find out it starts being detected 2 physic frames later (depending on the physics engine you use), which could explain the issue. If that is the case I’m not sure how you could solve it, apart from waiting two physic frames maybe.
If it is still not detected after that, perhaps your collision layers or collision shapes or area monitoring are not being setup correctly?
Zylann | 2022-02-02 13:52
Thank you for the Input precision.
I have tried to set the boolean to false after consuming action in _physics_process
. Same result.
According to the doc, problem is probably linked to :
For performance reasons (collisions are all processed at the same
time) this list is modified once during the physics step, not
immediately after objects are moved. Consider using signals instead.
Like you said, it take two frame to detect the collision. Cause when i add child, the collider list is updated next frame, and after consuming event second time.
So, what i find for now, delta of _physics_process
is fixe, so i add a variable to hold delta and consume the event only if my variable is equal to delta * 2.
So, wait one more frame to check overlapping. But it seem very ugly solution.
func _physics_process(delta):
time += delta
if clic and marker.get_overlapping_areas().empty() and time == delta * 2:
var brick = Brick.new()
brick.transform.origin = marker.transform.origin
add_child(brick)
if time == delta * 2:
time = 0
Edit : clic
stay true, it’s what i want. I want to be able to drop multiple brick when i move mouse.
BigBadWouf | 2022-02-02 14:58