![]() |
Attention | Topic was automatically imported from the old Question2Answer platform. |
![]() |
Asked By | mikefrom1974 |
UPDATE: removing github ling as it’s no longer needed and the solution is apparent in the pasted code.
Newish godot user here (some experience with 3.5 but waited for 4.0 to deep dive).
I have a simple 2D scene set up from a tutorial. I like to extend tutorials so that I break stuff and have to fix it because let’s be honest that’s where the real learning happens.
I have a player node and a mob node that both work fine with moving, jumping, and killing each other… I decided to create a spawner and try to get multiple mobs involved. However, when I spawn multiple mobs the die() function seems to stop working properly. If I instance only one mob all works as expected, but if I set a timer to instance multiple mobs it stops working.
When working (single spawned mob):
Player jumps on mob, mob explodes and goes away.
When not working (multiple spawning mobs):
Player jumps on mob, mob stops moving, resumes idle, doesn’t go away.
Main question: Is there something I am missing when spawning multiple instances of nodes that would make the scripting conflict?
Goal: I know I could wipe and start over, or code around it… but I want to understand WHY this is happening, so I can learn from it and prevent mistakes in the future.
Player script:
extends CharacterBody2D
const SPEED = 300.0
const JUMP_VELOCITY = -400.0
@onready var anim = $AnimationPlayer
@onready var sprite = $AnimatedSprite2D
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")
var alive = true
func _physics_process(delta):
if alive:
var direction = Input.get_axis("ui_left", "ui_right")
var crouch = Input.get_axis("ui_down", "ui_up")
if direction:
velocity.x = direction * SPEED
sprite.flip_h = velocity.x < 0
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
if not is_on_floor():
velocity.y += gravity * delta
if velocity.y < 0:
anim.play("jump")
else:
anim.play("fall")
else:
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
if direction:
anim.play("run")
elif crouch < 0:
anim.play("crouch")
else:
anim.play("idle")
move_and_slide()
func die():
alive = false
anim.play("death")
await anim.animation_finished
get_tree().change_scene_to_file("res://scenes/main.tscn")
mob script:
extends CharacterBody2D
const JUMP_SPEED = 110
const JUMP_DELAY = 0.6
@export var player: CharacterBody2D
@onready var sprite = $Sprite
@onready var my_collision = $Collision
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")
var last_jump = JUMP_DELAY
var alive = true
var loop_timer = 0
func initialize(spawn_position):
alive = true
self.global_position = spawn_position
func _ready():
player = get_tree().get_first_node_in_group("players")
sprite.play("idle")
func _physics_process(delta):
loop_timer += 1 * delta
if loop_timer > 3:
alive = true
if alive:
if not is_on_floor():
velocity.y += gravity * delta
if velocity.y < 0:
sprite.play("jump")
else:
sprite.play("fall")
else:
velocity.x = 0
sprite.play("idle")
if player:
var h_dir = 1
var direction = (self.global_position - player.global_position).normalized()
if direction.x < 0:
sprite.flip_h = true
else:
sprite.flip_h = false
h_dir = -1
if is_on_floor() && last_jump >= JUMP_DELAY:
last_jump = 0
velocity.y = -JUMP_SPEED
velocity.x = JUMP_SPEED * h_dir
else:
last_jump += 1 * delta
move_and_slide()
func die():
alive = false
player = null
sprite.play("death")
await sprite.animation_finished
self.queue_free()
func _on_head_area_body_entered(body):
if body.is_in_group("players"):
body.velocity.y = body.JUMP_VELOCITY * .8
self.die()
func _on_body_area_body_entered(body):
if alive:
if body.is_in_group("players"):
player = null
body.die()
world script:
extends Node2D
const MAX_FROG_SPAWN_DELAY = 5
const MIN_FROG_SPAWN_DELAY = 1
@export var frog_scene: PackedScene
@onready var timer = $Timer
var timer_length = MAX_FROG_SPAWN_DELAY
var frog_num = 0
func _ready():
timer.wait_time = randi_range(MIN_FROG_SPAWN_DELAY, MAX_FROG_SPAWN_DELAY)
timer.start()
func _on_timer_timeout():
spawn_frog()
var yaynay = randi_range(1, 10)
if yaynay > 5:
timer_length -= 1
if timer_length < MIN_FROG_SPAWN_DELAY:
timer_length = MIN_FROG_SPAWN_DELAY
timer.wait_time = timer_length
timer.start()
func spawn_frog():
frog_num += 1
var spawn_position = get_node("FrogSpawn").global_position
var frog = frog_scene.duplicate().instantiate()
frog.initialize(spawn_position)
add_child(frog)
Layout:
World
|- Player
|- FrogSpawn
|- Timer
The only thing that looks a bit weird is in the spawn_frog() method where the frog_scene is duplicated before instantiated. You should be able to simply call instantiate.
However, I doubt that’s the issue if spawning a single frog once with the same method works. (I’m assuming you don’t just add the mob child scene to the game level scene when you say “single spawned mob”.)
Are there any errors in the console? If so, what are they?
You may need to share your project on github or something and let us know. It’s WAY easier to debug as I doubt I could duplicate everything from GDScript alone.
tuon | 2023-06-26 18:13
@tuon you are correct, the duplicate doesn’t make a difference. I just added it during troubleshooting.
The single spawned frog is spawned once with the script, not manually added.
No errors in console.
I am editing the original Q with a github link.
mikefrom1974 | 2023-06-26 20:31