Creating enemy programmatically makes jittery in my game

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

I am creating a simple 2D top down moving games, where different kinds of obstacles come from top, player has to avoid obstacles and move towards coins to collect. In this case I am creating obstacles programmatically and adding it to scene tree using Instance method as follows.

var enemy1 = EnemyKindOne.instance()
add_child(enemy1)

I am creating enemy for every 1 second and adding it to scene tree. At the time of creating and adding enemy there is a noticeable jerk. Because of this game is not looking smooth, How to solve this?

Could you share more of your script?

Also, what do you mean by “jerk”? Is it a framerate drop, or a visual glitch?

You might want to check the “remote” tab of your scene (see here: Overview of debugging tools — Godot Engine (stable) documentation in English) while the game is running and check that you are not spawning in more obstacles than you think.

Bernard Cloutier | 2020-09-30 13:56

This could be down to some code in the enemy’s _ready() function or possibly any nodes that can cause lag such as a particle node with preprocess set higher than 0.

Magso | 2020-09-30 13:56

Here is the code for cloning obstacles in MainScene.gd

export (PackedScene) var HoriLeft       #Obstacle type 1
export (PackedScene) var HoriLeftSmall  #Obstacle type 2
export (PackedScene) var HoriRight      #Obstacle type 3
export (PackedScene) var HoriRightSmall #Obstacle type 4

var HoriLeftIns : EnemyClass  #is a Script attached to enemy
var HoriLeftSmallIns : EnemyClass
var HoriRightIns : EnemyClass
var HoriRightSmallIns : EnemyClass

func _ready():
    HoriLeftIns = HoriLeft.instance()
    HoriLeftSmallIns  = HoriLeftSmall.instance()
    HoriRightIns  = HoriRight.instance()
    HoriRightSmallIns  = HoriRightSmall.instance()


func _on_MobTimer_timeout():
    if player:
	    var block_type = Globals.blocks_list[randi()%Globals.blocks_list.size()]
	    if block_type == "ls":
		    var enemy : EnemyClass = HoriLeftSmallIns.duplicate()
		    get_tree().get_root().call_deferred("add_child", enemy)
		    enemy.move_enemy(player.position)
	    elif block_type == "rs":
		    var enemy : EnemyClass = HoriRightSmallIns.duplicate()
		    get_tree().get_root().call_deferred("add_child", enemy)
		    enemy.move_enemy(player.position)
	    elif block_type == "lh":
		    var enemy : EnemyClass = HoriLeftIns.duplicate()
		    get_tree().get_root().call_deferred("add_child", enemy)
		    enemy.move_enemy(player.position)
	    elif block_type == "rh":
		    var enemy : EnemyClass = HoriRightIns.duplicate()
		    get_tree().get_root().call_deferred("add_child", enemy)
		    enemy.move_enemy(player.position)
	    elif block_type == "ls_rs":
		    var enemy1 : EnemyClass = HoriLeftSmallIns.duplicate()
		    get_tree().get_root().call_deferred("add_child", enemy1)
		    enemy1.move_enemy(player.position)
		    var enemy2 : EnemyClass = HoriRightSmallIns.duplicate()
		    get_tree().get_root().call_deferred("add_child", enemy2)
		    enemy2.move_enemy(player.position)
	    elif block_type == "ls_rl":
		    var enemy1 : EnemyClass = HoriLeftSmallIns.duplicate()
		    get_tree().get_root().call_deferred("add_child", enemy1)
		    enemy1.move_enemy(player.position)
		    var enemy2 : EnemyClass = HoriRightIns.duplicate()
		    get_tree().get_root().call_deferred("add_child", enemy2)
		    enemy2.move_enemy(player.position)
	    elif block_type == "rs_ll":
		    var enemy1 : EnemyClass = HoriLeftIns.duplicate()
		    get_tree().get_root().call_deferred("add_child", enemy1)
		    enemy1.move_enemy(player.position)
		    var enemy2 : EnemyClass = HoriRightSmallIns.duplicate()
		    get_tree().get_root().call_deferred("add_child", enemy2)
		    enemy2.move_enemy(player.position)

Here is a code for Obstacle Script

extends Area2D

class_name EnemyClass

var move = false
var move_position = Vector2()
var screen_size
signal enemy_killed
onready var sprite = $Sprite

func _ready():
    screen_size = get_viewport_rect().size
    sprite.modulate = Globals.enemy_color

func _process(delta):
    if move and Globals.State == Globals.GameState.Running:
	    position.y += Globals.speed * delta

func move_enemy(dest_position):
    #enemy starting position
    var randomPosition = Vector2()
    var random = RandomNumberGenerator.new()
    random.randomize()
    #Enemy moving towards player
    move_position = dest_position
    move = true

anbarasu chinna | 2020-09-30 15:27

Enemy does not have any particle effect in it.

anbarasu chinna | 2020-09-30 15:59

It may be due to the amount of elif in _on_MobTimer_timeout(). Try using a match statement so you basically use integers instead of “ls” “rs” strings. Other than that I can’t see anything else that would cause lag.

Magso | 2020-09-30 19:03

Give some time, I will check and write my feedback.

anbarasu chinna | 2020-10-03 06:47

Thanks, Some improvements are there when replacing elif with match statement, but still noticeable lag is there.

anbarasu chinna | 2020-10-03 13:03

Have you tried the profiler? Debugger panel — Godot Engine (stable) documentation in English

Start the profiler, get some enemies to spawn, then stop it. You can then scroll down the list of functions and see if maybe some of your functions take up more time than expected.

Bernard Cloutier | 2020-10-03 14:30

Can anyone give me best example for cloning and adding enemy node into scene tree. Because I tried loading all me enemy scenes and instancing those under the auto load class of GDScript. But jittery motion is still there?

Here is the video of my issue

Note : I am getting this issue only while running on android device.

anbarasu chinna | 2020-10-06 06:59

Finally I have profiled my game and taken screen shot of it. Can you find out the cause of issue. Thanks in advance.

Screen shot here

anbarasu chinna | 2020-10-06 07:41

The profiling result looks normal. Since it occurs only on Android, have you tried using GLES2 as a renderer?

Bernard Cloutier | 2020-10-06 13:51

Am using GLES3.

anbarasu chinna | 2020-10-06 17:05

Have you tried using GLES2. You can select it in the top right of the editor.

Bernard Cloutier | 2020-10-06 19:02

Tried that also. Not working. Finally I found solution for the jittery problem. I have removed all floating point value assigned for properties like Collision2D,Texture Scalling, and for Visibility notifier, now everything works fine with int value. Seems if fast moving object assigned with floating point value(3.463) for Collision2D,Visibility notifier and texture makes jittery. Better use rounded int value(3).

Thanks for the discussion on my post. Finaly I wasted 3 days of time just for floating point value. But worth it.

anbarasu chinna | 2020-10-06 19:20