0 votes

First sorry for poor English.

I am beginner in Godot and game development. I make a brick breaker 2d game with 7 level for android. Everything is OK But my problem is memory usage.

When i run my game (for test in Windows 7, Godot 2.1.4) and open Windows Task Manager (Performance tab), level after level increases memory and game will be lagging.

What can i do?

asked Jan 14 in Projects by hashak (25 points)

That sounds like a very small game, so my guess is you're doing something very wrong. However, nobody can really give you advice unless you provide more information about how your game is set up. What is your scene/node setup? Your code? Have you tried narrowing down the problem?

Scene setup image
My scene setup image direct link

Thanks for you answer. Can you tell what causes it to increase memory (For example a checklist)

It is my scene setup and i repeat these in other level. Level by level some object (like bricks) and animation are increase.

"audio" have several sound (StreamPlayer type).

"camera" have a code for shaking when ball is lose. (I learn this code from Angega Studios youtube user)

"Player" and "enemy" have 2 animation and i set those to play random when finished animation.

func _ready():
    anim.connect("finished", self, "_random_animation")

func _random_animation():
    var randNum = randi() % 2
    if randNum == 0: anim.play("idle")
    else: anim.play("ready")

"brick container" have 24 bricks, and level by level these will be increase.

"ball" have a for loop condition for collision check and bricks queue_free, play sound when contact to object. and a condition for check ball that when ball get out at scene, reset ball position for new game.

func _fixed_process(delta):
    if _global.is_ball_play && self.get_global_pos().x <= 0:
        self.set_sleeping(true)
        self.set_pos(Vector2(220, 190))
        _global.is_ball_play = false
        container.add_child(fade_white.instance())
        _global.player_life -= 1
        camera.shake(8, 0.2)
        ballSpeed = BALL_SPEED

        if _global.is_sfx:
            snd_ball_gone.play()

    # Colliding ball
    var collision = get_colliding_bodies()
    for i in collision:
        ballSpeed += 3
        ballSpeed = clamp(ballSpeed, BALL_SPEED, BALL_SPEED*2)

        # Ball sound
        if _global.is_sfx:
            snd_ball.play()

        if i.is_in_group("g_brick"):
            i.queue_free()

        # Change direction ball by hit
        if i.get_name() == "hit_player":
            var p = i.get_node("position2D").get_global_pos()
            var changPos = self.get_global_pos() - p
            var velocity = changPos.normalized() * ballSpeed
            self.set_linear_velocity(Vector2(velocity.x, velocity.y))

"container" is a place for add "white fade-out animation" when ball is lose and "hit shape" for change direction ball (like a paddle), and after finished animation these will be queue_free.

"ui" is a simple menu for go to next level, close or restart game.

I hope these information be enough

How are you loading new levels? I notice that you've named that scene "level_1" so I assume you have a scene for each level. Is it possible that you are not removing the scene for the previous level when the player continues?

Thanks for your answer.

I add a global variable called "levelnumber" in AutoLoad. If player win in this level, a window will be open and there is "Next level button" inside that, If user click on that i add 1 to "levelnumber". And change scene to next level with this:

func _on_pressed_next_level():
    _global.level_number += 1
    _global.is_ball_play = false
    if _global.level_number < 8:
        get_tree().change_scene("res://stages/level_%s.tscn" % str(_global.level_number))
    else:
        get_tree().change_scene("res://stages/level_end.tscn")
    pass

1 Answer

+1 vote
Best answer

You forgetting to free current scene.

We use this SceneManager from one of demo projects:

extends Node


# @var  SceneTree
var _tree

# @var  Viewport
var _root

# @var  Node
var _currentScene = null


func _init():
    _tree = get_tree()
    _root = _tree.get_root()
    _currentScene = _root.get_child( _root.get_child_count() - 1 )


# Go to scene
# @param  string  path
func goto(path):  # bool
    var f = File.new()
    if !f.file_exists(path):
        print('SceneManager: goto: Scene doesn\'t exist: ' + str(path))
        return false

    # This function will usually be called from a signal callback,
    # or some other function from the running scene.
    # Deleting the current scene at this point might be
    # a bad idea, because it may be inside of a callback or function of it.
    # The worst case will be a crash or unexpected behavior.

    # The way around this is deferring the load to a later time, when
    # it is ensured that no code from the current scene is running:

    call_deferred('_deferredGoto', path)
    return true


# @param  string  path
func _deferredGoto(path):  # void
    # Immediately free the current scene,   
    # there is no risk here.
    _currentScene.free()

    # Load new scene
    var s = ResourceLoader.load(path)

    # Instance the new scene
    _currentScene = s.instance()

    # Add it to the active scene, as child of root
    _root.add_child(_currentScene)

    # optional, to make it compatible with the SceneTree.change_scene() API
    _tree.set_current_scene(_currentScene)

Add it to autoload and use it like this:

SceneManager.goto("res://stages/level_%s.tscn" % str(_global.level_number))
answered Feb 11 by QuentinCaffeino (50 points)
selected Feb 17 by hashak
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.