Avoid FPS drops generating coins

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Repertix

So, I’m making a coin generator that only generates coins inside a CollisionShape2D, I’m using preload() to load the coins and then add them in the scene and a Timer so it will generate coins every 10 seconds. I have a problem with the code, cause each 10 seconds when the node generates coins it causes FPS drops.

This is how the code looks:

extends Area2D


func _ready():
	$Timer.connect("timeout", self, "_checkGenerate")

func _checkGenerate():
	_generateCandy(1)

func _generateCandy(amount):
	for i in amount:
		var cnd = preload("res://objects/candy.tscn")#I tried to put this line and the one below in _ready so it will do use the preload just one time, but stills causing FPS drops
		var cn = cnd.instance()
		var dk = $CollisionShape2D.shape.extents
		cn.position = Vector2(randi()%(int(dk.x)*2)-int(dk.x), randi()%(int(dk.y)*2)-int(dk.y))
		self.add_child(cn)

There’s a better method that doesn’t cause FPS drops?

Why are you repeatedly preloading the resource…?

psear | 2021-01-21 20:59

I tried to preload one time by just using preload in the ready function, but that didn’t work either.

Repertix | 2021-01-21 21:18

Can you share the code with the loading in _ready()?

psear | 2021-01-21 22:34

:bust_in_silhouette: Reply From: psear

First, when you are loading a resource inside function running in your script you use load(), not preload()

Second, loading resources is an expensive task, which is why you normally do it before the game runs. Have something like this

extends Area2D

var cnd = preload("pathtoresource")

func _ready():
    #rest of your code

The code still causing FPS drops, tried replacing preload with load, and didn’t work.

Repertix | 2021-01-21 21:59

You are trying to load a resource every 10 seconds, don’t do that. Load the resource at the start of the code and use it with the variable you assign it.

psear | 2021-01-21 22:16

Like using one-time cnd.instance() and in the function running the rest of the code to generate the coin?

Repertix | 2021-01-21 22:45

I would need to see your code with the loading under _ready() to have a better idea what the issue was.

psear | 2021-01-21 22:53

Actually I have the code like this. Is the entire code.

extends Area2D
onready var cnd = preload("res://objects/candy.tscn")
onready var cn = cnd.instance()
func _ready():
	$Timer.connect("timeout", self, "_checkGenerate")
func _checkGenerate():
	_generateCandy(10)
	print("test")

func _generateCandy(amount):
	for i in amount:
		var dk = $CollisionShape2D.shape.extents
		cn.position = Vector2(randi()%(int(dk.x)*2)-int(dk.x), randi()%(int(dk.y)*2)-int(dk.y))
		self.add_child(cn)

Repertix | 2021-01-21 23:27

instance() and duplicate() also seems to be expensive calls when used this way
so try using self.call_deferred("add_child", cnd.instance()) in your loop

Wakatta | 2021-01-22 01:07

Ok, but still having a problem with the FPS drop :confused:

Repertix | 2021-01-22 02:31

:bust_in_silhouette: Reply From: Wakatta

Ok, but still having a problem with the FPS drop :confused:

Hmm i noticed that in your example you’re not freeing those generated coins
No judgement, its just that 10x10x6 = 600 coins per minute added to your scene, Yikes!!!

so i’d recommend to generate the maximum amount of coins you’ll ever need displayed in your _ready() function add them to a list and when you need to show them use the_generateCandy() function to add them to the scene and after you’ve finished using them remove them from the scene using removeCandy(amount)

extends Area2D
onready var cnd = preload("res://objects/candy.tscn")
var generated_coins = Array()

func _ready():
    addCandy(10)
    $Timer.connect("timeout", self, "_checkGenerate")

func addCandy(amount):
    for i in amount:
        generated_coins.append(cnd.instance())

func _generateCandy(amount):
    if amount <= generated_coins.size():
        for i in amount:
            if not generated_coins[i].is_inside_tree():
                self.call_deferred("add_child", generated_coins[i])

func removeCandy(amount):
    if amount <= generated_coins.size():
        for i in amount:
            if generated_coins[i].is_inside_tree():
                self.call_deferred("remove_child", generated_coins[i])