Topic was automatically imported from the old Question2Answer platform.
Asked By
TempSchoolAcc#1
So in my game I have an enemy set up. When something enters the enemies attack range, if it is the player, I want the enemy to attack the player. I do this by running a function on the player which deals damage to it. However, this damage only gets applied once. To combat this, I’ve made a variable that triggers when the player enters the enemies attack range and then constantly runs every few seconds to attack the player until it leaves the enemies attack area. The issue with this is that when the while loop is activated, everything freezes.
My Code:
func _on_EnemyCollisionDetection_area_entered(area):
enemyInRange = true
if not area.is_in_group("player"):
pass
if area.is_in_group("player"):
while enemyInRange == true:
if get_node("AttackDelay").is_stopped() == true:
get_node("AttackDelay").start()
rng.randomize()
var randomNumber = rng.randf_range(2.0, 7.0)
var damageDealt = int(round(randomNumber))
area.takeDamage(damageDealt)
yield(get_tree(), "idle_frame")
func _on_EnemyCollisionDetection_area_exited(area):
enemyInRange = false
Everything works fine and I get no errors in the console, however once the while loop is activated the game and my computer freeze and the only way to get out of it (the way that I’ve discovered and seems to work) is to press ctrl+alt+delete and just cancel from there (my school computer has task manager blocked.)
I see no reason for this to happen? It is an older school computer although it should run smoothly still.
Yeah, you don’t want that while loop in there - that’s what’s hanging your system. That looks like an infinite loop. Here’s what’s happening…
You set enemyInRange to true
You enter your while enemyInRange == true: loop
Nothing inside that loop ever recalculates the value of enemyInRange
So, it’s value is always true, and you never exit the loop
Essentially, nothing else processes in your code, as you’re permanently stuck in that loop.
So, you’ll need to find a different way to process that. Instead, you probably want to wire both the area_entered and area_exited signals. Then, set a a boolean flag in the area_entered callback when your player is detected and unset the same flag when your player is exits the area (in area_exited).
Then, _process() (which fires once per frame) if your flag is true to do the things you have in your original loop, but without the while loop.
So, specifically, something like this (untested):
var enemyInRange = false
func _on_EnemyCollisionDetection_area_entered(area):
if area.is_in_group("player"):
enemyInRange = true
func _on_EnemyCollisionDetection_area_exited(area):
if area.is_in_group("player"):
enemyInRange = false
func _process(delta):
if enemyInRange:
if get_node("AttackDelay").is_stopped() == true:
get_node("AttackDelay").start()
rng.randomize()
var randomNumber = rng.randf_range(2.0, 7.0)
var damageDealt = int(round(randomNumber))
area.takeDamage(damageDealt)
yield(get_tree(), "idle_frame")
jgodfrey | 2020-11-05 03:20
Awesome! This works great, thank you. The only issue I had before was that I couldn’t transfer over the area.takeDamage function because the area variable only came with the function. For anyone following along I’ve just made another variable that the function sets its area to. If that doesn’t make sense here is the code I have now:
func _on_EnemyCollisionDetection_area_entered(area):
if not area.is_in_group("player"):
pass
if area.is_in_group("player"):
enemyInRange = true
areaExported = area
func _on_EnemyCollisionDetection_area_exited(area):
if not area.is_in_group("player"):
pass
if area.is_in_group("player"):
enemyInRange = false
areaExported = area
func _process(delta):
if enemyInRange == true:
if get_node("AttackDelay").is_stopped() == true:
get_node("AttackDelay").start()
rng.randomize()
var randomNumber = rng.randf_range(2.0, 7.0)
var damageDealt = int(round(randomNumber))
areaExported.takeDamage(damageDealt)
yield(get_tree(), "idle_frame")
Thanks for your help, Jgodfrey! Enjoy your day/night