Help with camera offset my drag tower texture preview attached to mouse

Godot Version

4.3

Question

Im attempting to make a 2d tower defense in godot 4.3, and I have a camera2D for wasd movement in game. I also have a drag tower preview attached to the mouse so the player can see where it will be built if clicked. However whenever I move the camera in game, it offsets the drag tower preview texture by that much rather than it staying on the mouse like it should. I cant seem to figure it out.

here the script attached to my UI:

extends CanvasLayer
func set_tower_preview(tower_type, mouse_position):
var drag_tower = load(“res://Scenes/Towers/” + tower_type + “.tscn”).instantiate()
drag_tower.set_name(“DragTower”)
drag_tower.modulate = Color(“ad54ff3c”)

var control = Control.new()
control.add_child(drag_tower, true)
control.set_position(mouse_position)
control.set_name("TowerPreview")
add_child(control, true)
move_child(get_node("TowerPreview"), 0)

func update_tower_preview(new_position, color):
get_node(“TowerPreview”).set_position(new_position)
if get_node(“TowerPreview/DragTower”).modulate != Color(color):
get_node(“TowerPreview/DragTower”).modulate = Color(color)

and heres the game scene script:

extends Node2D
var map_node
var game_speed = 1.0
var fast_forward_speed = 2.0
var mage_tower_cost = 100
var cannon_tower_cost = 160
var is_paused = false
var build_mode = false
var build_valid = false
var build_location
var build_type
var build_tile
@onready var mouse_pos = get_global_mouse_position()
@onready var ui = $HUD/UI
@onready var mage_label = $HUD/UI/M/BuildBar/M/PC/HB/MageTowerButtonPanel/mage/MagePrice
@onready var cannon_label = $HUD/UI/M/BuildBar/M/PC/HB/CannonTowerButtonPanel/cannon/CannonPrice
@onready var gold_label = %GoldLabel
@onready var health_label = %HealthLabel
func _ready():
map_node = get_node(“Map1”)
gold_label.text = str(GameData.gold)
health_label.text = str(GameData.health)
for i in get_tree().get_nodes_in_group(“build_buttons”):
i.pressed.connect(initiate_build_mode.bind(i.name))

func _process(delta: float) → void:
if build_mode:
update_tower_preview()

gold_label.text = "Gold: " + str(GameData.gold)

func _unhandled_input(event: InputEvent) → void:
if event.is_action_released(“cancel”) and build_mode == true:
cancel_build_mode()
if event.is_action_released(“click”) and build_mode == true:
verify_and_build()
cancel_build_mode()

func initiate_build_mode(tower_type):
if build_mode:
cancel_build_mode()
build_type = tower_type + “_tower”
build_mode = true
ui.set_tower_preview(build_type, get_global_mouse_position())

func update_tower_preview():
var tower_exclusion = map_node.get_node(“TowerExclusion”)
var mouse_position = get_global_mouse_position()
var current_tile = tower_exclusion.local_to_map(mouse_position)
var tile_position = tower_exclusion.map_to_local(current_tile)

if tower_exclusion.get_cell_source_id(current_tile) == -1:
	ui.update_tower_preview(tile_position, "ad54ff3c")
	build_valid = true
	build_location = tile_position
	build_tile = current_tile
	print(mouse_position)
else:
	ui.update_tower_preview(tile_position, "adff4545")
	build_valid = false

func cancel_build_mode():
build_mode = false
build_valid = false

get_node("HUD/UI/TowerPreview").free()

func verify_and_build():
if build_valid and build_type == “mage_tower”:
if GameData.gold >= mage_tower_cost:
var mage_tower_instance = load(“res://Scenes/Towers/mage_tower.tscn”)
var new_mage_tower = mage_tower_instance.instantiate()
new_mage_tower.position = build_location
map_node.get_node(“Towers”).add_child(new_mage_tower, true)
map_node.get_node(“TowerExclusion”).set_cell(build_tile, 5, Vector2(1, 0))
GameData.gold -= mage_tower_cost
gold_label.text = str(GameData.gold)
else:
print(“Not Enough Gold”)
elif build_valid and build_type == “cannon_tower”:
if GameData.gold >= cannon_tower_cost:
var cannon_tower_instance = load(“res://Scenes/Towers/cannon_tower.tscn”)
var new_cannon_tower = cannon_tower_instance.instantiate()
new_cannon_tower.position = build_location
map_node.get_node(“Towers”).add_child(new_cannon_tower, true)
map_node.get_node(“TowerExclusion”).set_cell(build_tile, 5, Vector2(1, 0))
GameData.gold -= cannon_tower_cost
gold_label.text = str(GameData.gold)
else:
print(“Not Enough Gold”)

func take_damage():
pass

func game_over():
pass

if someone could assist me in solving this issue I would be most grateful.
Thank you!

I assume that I need to subtract the cameras position from the mouse position somewhere and I tried various areas of the script to do that but it just made the tower preview disappear completely every time iirc. I’m only about a week into learning game development so i’d welcome any help at this point lol

The tower may be offset from it’s origin in it’s own scene. Make sure not to move scene children from their 0,0 position. Could you share the tower’s scene 2d view?

Also please format code pastes

Thank you, your 2d scene look great!

Maybe you are crossing too many coordinate systems, have you tried making tile_position in global space?

# in game_scene's update_tower_preview and verify_and_build
var current_tile: Vector2i = tower_exclusion.local_to_map(mouse_position)
var tile_position: Vector2 = tower_exclusion.to_global(tower_exclusion.map_to_local(current_tile))

# in ui's update_tower_preview
func update_tower_preview(new_position, color):
	$TowerPreview.global_position = new_position

well unfortunately I wasn’t insightful enough to make a backup of my project at the peak of its working condition, and now after all my attempted fixes I’ve made it worse lol, even though I’ve reverted the script to what should’ve been the best working build thus far, yet the tower preview isn’t showing at all that I can see, I’ve checked all the reference material I used to code it and I can’t find anything different. Thank you for your help up until now, I’ll make a copy of you’re suggested solution to the issue and save it in my new project. At this point since I am new to programming and development altogether, I think it will be beneficial to just start from scratch and work on keep my code clean and organized, far better than this project was at least. The only way to learn is to keep experimenting with different ideas and figuring out what works and what doesn’t. I’ll go ahead and close this post for now since my project is no longer in a state that I can viably test anyone’s potential solutions to the original post’s problem. Thanks again!

well idk how to delete the post lol maybe a mod has to

I found a solution for the problem in some comments on youtube with someone having the same issue.

The solution is to create a new canvas layer for the drag preview and enable follow viewport for this canvas layer.

here is what the person posted:

“I added camera movement by mouse in map due to map size. Although the camera movement is doing well, the drag preview is moving along with the camera movement instead of sticking with the mouse position. I’d like to know how to fix the drag preview to stick with the mouse position while camera is moving. If I don’t use camera, the drag preview is doing properly. Thanks advance for your help.”

then they said:

“I found a solution. I make a new Canvas Layer for drag preview and enable follow viewport for this layer. Now the drag preview is moving according to mouse position.”

1 Like