2dsprite texture not changing :(

Godot Version

4.6.2

Question

Hello everyone! I am trying to make a fishtank game with multiple scenes. I have a scene for “maintank”, one for “inventory” and one for “iteminfo”. The idea is that you buy tanks from the shop, they add to your inventory (via a dictionary in a script called Global), and then you can place those tanks into your room (maintank scene) via a use button that pops up when you click on your inventory and then “use” the desired tank (iteminfo). In the game you start of with a plastic bag, and then you can update your tank → therefore in the maintank you start off with a baggy sprite2d that would hopefully change texture to the icon of the tank you “use” and everything in my script indicates that the texture should change… but it isn’t.

I have followed many tutorials and have asked AI, read forums etc - overall I have tried very hard to fix this issue on my own but as a beginner I am now totally lost. Below are all the relevant scripts that I believe are responsible for this failure to change the texture.

As for the scene tree. Main tank is the ‘parent’ with Placeditem (the sprite2d that I want to change) as a child and Inventory attached to that. Inventory is then a parent of “iteminfo” and “inventorygrid”. Inventory has no script attached to itself.

Let me know if you need any other info from me!! Really appreciate any help :slight_smile:

Main tank script

extends Control


@onready var placeditem: Sprite2D = %Placeditem

var ItemName = ""
var ItemDes = ""
var ItemCost = 0
var ItemCount = 0
var CurrItem = 0
var select = 0 


# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	$inventory.hide()
	Global.item_changed_globally.connect(_thissomeshit)



func _thissomeshit(item_index: int) -> void:
	var item_data = Global.inventory[item_index]
	print("watch dis SPACE")
	print(item_data["icon"])
	%Placeditem.texture = item_data.icon
	%Placeditem.scale = Vector2(1, 1)           # Ensure it's not tiny
	%Placeditem.z_index = 100                  # Ensure it's on top
	%Placeditem.show()                         # Ensure it's not hidden
	%Placeditem.position = Vector2(500, 300) 
	print("Placed: ", item_data.Name)
	print("Texture should now be: ", item_data["Name"])

func _on_button_pressed() -> void:
	get_tree().change_scene_to_file("res://scenes/leave_house.tscn")
	

func _on_add_pressed() -> void:
	hide()
	$inventory.show()


Global script:


extends Node
signal item_changed_globally(new_index)

var gold = 1000
var tanks = {
	0: {
		"Name": "Baggy",
		"Des": "Start here brokie!",
		"Cost": 5,
		"icon": preload("res://562b27c8-54ea-49fe-9ae5-2f7052fe8b55.png")
	},
	1: {
		"Name": "Bowl",
		"Des": "An upgrade! You can now start adding more fish... don't add too much though",
		"Cost": 50,
		"icon": preload("res://Screenshot 2026-04-20 005228.png"),
	},
	2: {
		"Name": "Large Tank", 
		"Des": "This is a large tank. Suitable for more fish.",
		"Cost": 200,
		"icon": preload("res://Screenshot 2026-04-20 005223.png"),
	},
}

var feesh = {
	0: {
		"Name": "Betta",
		"Des": "Also known as the Siamese fighting fish, the betta is a freshwater tropical fish native to Southeast Asia. They were initially bred for aggression and subject to gambling matches akin to cockfighting.",
		"Cost": 10,
		"icon": preload("res://HM_Orange_M_Sarawut.jpg")
	},
	1: {
		"Name": "Goldfish",
		"Des": "The goldfish - a fresh cold-water fish native to China - have become an invasive pest in parts of Australia. Goldfish breeds vary greatly in size, body shape, fin configuration and coloration.",
		"Cost": 10, 
		"icon": preload("res://Gold_fish1.jpg")
	}
}
	
var inventory = {
	0: {
		"Name": "Baggy",
		"Des": "Start here brokie!",
		"Cost": 5,
		"icon": preload("res://562b27c8-54ea-49fe-9ae5-2f7052fe8b55.png"),
		"Count": 1,
		}
}


Iteminfo script:


extends CanvasLayer

signal item_changed_globally(new_index)

var ItemName = ""
var ItemDes = ""
var ItemCost = 0
var ItemCount = 0
var CurrItem = 0
var select = 0 
var current_selected_index : int = 0 


func _process(_delta):
	pass


# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	pass

# Called every frame. 'delta' is the elapsed time since the previous frame.


func updateInfo():
	get_node("title").text = ItemName
	get_node("des").text = ItemDes + "\nCost" + str(ItemCost)
	current_selected_index = CurrItem
	

func _on_use_pressed() -> void:
	for i in Global.inventory: 
		if Global.inventory[i]["Name"] == ItemName:
			print("Emitting Index: ", i)
			Global.item_changed_globally.emit(i)
			ItemCount -=1 
			if ItemCount == 0: 
				var tempDic = {}
				for x in Global.inventory:
					if x > i: 
						tempDic[x-1] = Global.inventory[x]
					elif x < i: 
						tempDic[x] = Global.inventory[x]
				Global.inventory.clear()
				Global.inventory = tempDic
				_on_close_pressed()
			else:
				Global.inventory[i]["Count"] -=1
			get_node("../inventorycontainer").fillInventorySlots()
			

func _on_close_pressed() -> void:
	get_tree().change_scene_to_file("res://scenes/inventory.tscn")


And finally Inventorygrid container script:


extends GridContainer


@onready var item = preload("res://scenes/slot.tscn")
var invSize = 24



func _ready():
	#load slots in
	for i in invSize:
		var ItemTemp = item.instantiate()
		add_child(ItemTemp)
	
	fillInventorySlots()
	
func fillInventorySlots():
	for i in invSize: 
		get_child(i).ItemName = ""
		get_child(i).ItemDes = ""
		get_child(i).ItemCost = 0
		get_child(i).ItemCount = 0
		get_child(i).hasItem = false
	#fills in inventory == slots
	for i in Global.inventory:
		get_child(i).ItemName = Global.inventory[i]["Name"]
		get_child(i).ItemDes = Global.inventory[i]["Des"]
		get_child(i).ItemCost = Global.inventory[i]["Cost"]
		get_child(i).ItemCount = Global.inventory[i]["Count"]
		get_child(i).get_node("count").text = str(Global.inventory[i]["Count"])
		get_child(i).get_node("icon").texture = Global.inventory[i]["icon"]
		get_child(i).hasItem = true

```

Seems like you only have the Baggy as an item in your inventory, with the same texture preloaded too. Are you replacing the Baggy with the Baggy? Have you tried adding more items?

change_scene_to_file will delete all nodes in the current scene, this seems to include placeditem, so leaving the house may reset your progress. You could keep some of this information in a global which are not reset upon change_scene_to_file then update the scene on _ready based on the global’s data.

Hi! Yes, I have three items and have tried buying multiple of them and adding them all to the inventory. When I run the script after “buying” and “using” bowl, the script with all of the print visibility measures I put in actually tells me that the texture should be that of Bowl:

Emitting Index: 1
watch dis SPACE
(res://Screenshot 2026-04-20 005228.png):<CompressedTexture2D#-9223372002125937212>
Placed: Bowl
Texture should now be: Bowl

I have checked the screenshot name and it matches that of bowl. It just doesn’t visually do anything :confused:

Oh!! How would I do that - I am basically a complete beginner outside the 12 tutorials I’ve watched!! I thought I was already adding the items to Global. I think I left out another portion of script that might be helpful - the shop script (my bad!):

I have three shop scripts - one for fish, tanks and a master shop that houses directions to both those previous shops. This is the script from my tank shop (virtually the same as fish shop):

extends Control



var currItem = 0 
var select = 0 

func switchItem(select): 
	for i in range(Global.tanks.size()):
		if select == i:
			currItem = select
			print(Global.tanks[currItem])
			get_node("Name").text = Global.tanks[currItem]["Name"]
			get_node("description").text = Global.tanks[currItem]["Des"]
			get_node("description").text += "\nCost: " + str(Global.tanks[currItem]["Cost"])
			get_node("image").texture = Global.tanks[currItem]["icon"]


func _on_next_pressed() -> void:
	switchItem(currItem+1)


func _on_prev_pressed() -> void:
	switchItem(currItem-1)


func _on_purchase_pressed() -> void:
	var item_name = Global.tanks[currItem]["Name"]
	var found = false
	if Global.gold > Global.tanks[currItem]["Cost"]:	
		for key in Global.inventory:
			if Global.inventory[key]["Name"] == item_name:
				Global.inventory[key]["Count"] += 1
				found = true
				break
		if not found:
			var new_item = Global.tanks[currItem].duplicate()
			new_item["Count"] = 1
			Global.inventory[Global.inventory.size()] = new_item
		Global.gold -= Global.tanks[currItem]["Cost"]
		Golld.text = str(Global.gold)
	print(Global.inventory)

func _ready() -> void:
	switchItem(0)
	Golld.text = str(Global.gold)

func _on_exit_pressed() -> void:
	get_tree().change_scene_to_file("res://scenes/mastershop.tscn")

Based on the prints it should work, what does your scene tree look like?

Seems like you are adding items to the global, maybe not the ‘placed’ items though? It’s a little tough since it’s all dictionaries, you may have a better time creating resources to store data and using Arrays of those custom resources

## new file feesh_data.gd
extends Resource
class_name FeeshData

@export var name: String
@export_multiline var description: String
@export var cost: int = 10
@export var icon: Texture2D

## Now you can make fish as files via "New Resource > FeeshData"

## then your global can use
var feesh: Array[FeeshData] = [load("res://betta_fish.tres")]
# and later
feesh.append(load("res://goldfish.tres"))

But this is getting off-topic

Here is the scene tree for main tank! The screenshot202604… is the background picture. I really should organise all of these!

Then under Inventory there is an inventorygridcontainer, some labels and iteminfo (which is a canvas layer)

Sorry that the last two don’t have pictures -I am in Australia and am now tucked into bed but I can post those after work tomorrow!

1 Like

Still seems it should work, Placeditem is a scene, does it have any children? As your maintank is a Control node for user interfaces maybe you should change the type of your image from Sprite2D to TextureRect, those work better (but shouldn’t fix the issue) with Control type parents and still have a .texture property.

In the future I would suggest using sprite sheets for your fish tanks. Switching between frames in an image is trivial.

For now, take a look at this line of code from _thissomeshit:

%Placeditem.position = Vector2(500, 300) 

The item already has a position on your screen. Why are you changing it? Odds are you will not be drawing the new image where the old one was.

If that isn’t the issue, try using this to force an update:

%Placeditem.queue_redraw()

Morning!! Sorry, that was an old screenshot. I since deleted it and remade it so its not its own scene. I tried the TextureRect solution just then but it doesn’t seem to be solving it :frowning:

Yes I will go back and make sprite sheets! That was a chatgpt last hope fix - I have since deleted it but it does not change anything.

I just tried the .queue.redraw() and doesn’t seem to work :frowning: Just confirming the script should look like this?



func _thissomeshit(item_index: int) -> void:
	var item_data = Global.inventory[item_index]
	print("watch dis SPACE")
	print(item_data["icon"])
	%Placeditem.texture = item_data["icon"]
	%Placeditem.scale = Vector2(1, 1)           # Ensure it's not tiny
	%Placeditem.z_index = 100                  # Ensure it's on top
	%Placeditem.show()                         # Ensure it's not hidden
	%Placeditem.queue_redraw()
	print("Placed: ", item_data.Name)
	print("Texture should now be: ", item_data["Name"])