When i run my game the collision shape moves far from the sprite

Godot Version

4.2

Question

I am making a city builder for android. i got it so the camera will move with swipe. a menu to build buildings with a button to spawn the building.

now I’m trying to get it so that when you tap on the spawned building it will allow you to drag to a new position. but the area necessary to tap moves.

if you run the game and don’t move the camera and spawn a building it will spawn it in the middle of the screen like it should but then if you try to click it you have to click in the top left corner of the screen (almost like it’s inheriting the ui anchor point of the parent node) but if you move the camera at all before this it moves somewhere else i cant always find
I will try to upload the a video here for this.

also you can see the red debug square is wrong when i spawn the building…

I can copy paste my scripts if that’ll help too.
( can i not upload a godot game file here?)

Unless you are moving the CollisionShape directly in the scripts it would be more helpful to see your building scene and/or that video with “Debug > Visible collision shapes” turned on.

It is turned on. the red fading is caused by a debug setting and the blue box around the gold mine is the collision shape (only the half sphere shape will be visible in game). I guess technically the shape isn’t moving visually but the detection for it is

Ah I see now. Paste the script it should be easier to tell what is going on with that. Make sure to use the </> formatting button on a new line like so

```
type or paste code here
```

The </> button is in forum editing panel. It creates three ticks for you to paste your code.

this the starting three ticks
```

now your code goes here

```
the ending three ticks

You end up with this:

now your code goes here

You can also write the three ticks yourself with the (`~) key

there are 3 scripts
This is the building resource that gets spawned but is handling the touch input for the sprite:

type or paste code here

extends Node2D

@export var buildTime: int =1
@export var resourceRate: int =1
@onready var main_sprite = $MainSprite
@onready var collision_shape_2d = $CollisionShape2D


# Called when the node enters the scene tree for the first time.
func _ready():
	pass # Replace with function body.


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
	pass


func _input(event):
	if event is InputEventScreenTouch:
		if main_sprite.get_rect().has_point(to_local(event.position)):
			print("You clicked on Sprite!")

this one is the ui that spawns the building:

extends Control

var goldmine = preload("res://Buildings/Goldmine.tscn")
var sawmill = preload("res://Buildings/sawmill.tscn")
@onready var wood_cost_amount_text = $CanvasLayer/Panel/GridContainer2/WoodCostAmountText
@onready var gold_cost_amount_text = $CanvasLayer/Panel/GridContainer2/GoldCostAmountText

@onready var panel = $CanvasLayer/Panel
var selectedBuilding:String =""

var buildingDictionary={"goldmine":goldmine,"sawmill":sawmill}

signal stop_camera_movement(state)


func _ready():
	panel.visible= false


func _on_button_button_up():
	panel.visible = true
	stop_camera_movement.emit(false)


func _on_button_3_pressed():
	panel.visible = false
	stop_camera_movement.emit(true)


func _on_goldmine_button_pressed():
	gold_cost_amount_text.text = str(250)
	wood_cost_amount_text.text = str(250)
	selectedBuilding = "goldmine"
	


func _on_saw_mill_button_pressed():
	gold_cost_amount_text.text = str(150)
	wood_cost_amount_text.text = str(150)
	selectedBuilding = 'sawmill'


func _on_build_confirm_button_pressed():
	panel.visible = false
	
	#for i in buildingDictionary():
	var newBuilding= buildingDictionary[selectedBuilding].instantiate()
	newBuilding.position = Globals.camera_pos
	add_child(newBuilding)
	stop_camera_movement.emit(true)
	print("built")

this last one is the camera. not sure its useful they all kinda communicate tho

textends Camera2D
@onready var camera_2d = $"."
var min_zoom:float = 0.5
var max_zoom:float = 2

var zoom_sensitivity: int = 10 
var zoom_speed: float = 0.05

var events= {}
var last_drag_distance = 0
var can_move: bool = true




func _ready():
	print(Globals.camera_pos)
	

func _process(delta):
	#Globals.camera_pos = $".".get_screen_center_position()
	#print(Globals.camera_pos)
	pass

# hand camera movement
func _unhandled_input(event):
	if event is InputEventScreenTouch and can_move:
		if event.is_pressed():
			events[event.index] = event
			Globals.camera_pos=camera_2d.get_screen_center_position()
			print(Globals.camera_pos)
			
		else:
			events.erase(event.index)
	if event is InputEventScreenDrag and can_move:
		events[event.index]= event
		if events.size() == 1:
			position -= event.relative 
			my_get_center_screen()
		elif events.size() == 2:
			var drag_distance = events[0].position.distance_to(events[1].position)
			if abs(drag_distance - last_drag_distance) > zoom_sensitivity:
				var new_zoom = (1 + zoom_speed) if drag_distance < last_drag_distance else (1 - zoom_speed)
				new_zoom = clamp(zoom.x * new_zoom, min_zoom, max_zoom)
				zoom = Vector2.ONE * new_zoom
				last_drag_distance = drag_distance
				#following code gets center of screen when it moves so we don't 
				#have to use do it every frame
				my_get_center_screen()
				

#stop camera movement when in build mode
func _on_ui_stop_camera_movement(state):
	can_move=state

func my_get_center_screen():
	Globals.camera_pos=camera_2d.get_screen_center_position()
	print(Globals.camera_pos)

thanks for your help with the formatting lol

Pretty sure it’s going to be from this coordinate conversion. This also isn’t using a collision shape, it uses the sprite’s size.

To make this work you need to convert event.position to world space before using to_local, you will need to add the camera position (not the center position like is used in Globals.camera_pos).

You could use your static bodies input_event signal instead. As long as it is set to input_pickable

I’ll give this a go. Thanks!