当我尝试在碰撞后产生实例时,是什么原因导致游戏落后?
我正在制作一个系统,该系统在子弹击中敌人后催生8个新弹丸(Area2d触摸另一个区域2D)。但是,在这些弹丸产卵之后,该游戏在片刻中输掉了大约10 fps。
注意:我试图使用不同的触发器(计时器和过程功能)使弹丸产卵,并且它们都没有导致性能下降。
这是我为敌人使用的代码:
func _ready():
shooter.projectile = preload("res://Projectiles/Planet/LavaBall/LavaBall.tscn")
func _on_Planet_area_entered(area):
if("PlayerProjectile" in area.name):
if (randi() % 100 > 30):
shoot_burst()
func shoot_burst():
fire_projectile_burst(8, 30)
func fire_projectile_burst(projectile, amount: int, spread: int):
var begin_direction = fire_angle
fire_angle = fire_angle - ceil(spread/2)
for i in range(amount):
fire_projectile(projectile)
fire_angle += (spread/amount)
fire_angle = begin_direction
func fire_projectile(projectile):
var projectile_ins = projectile.instance()
projectile_ins.position = position
var rad_fire_angle = deg2rad(fire_angle)
projectile_ins.direction = Vector2(cos(rad_fire_angle),sin(rad_fire_angle))
get_tree().get_root().add_child(projectile_ins)
弹丸的代码:
var speed: float = 500
var direction : Vector2 = Vector2.ZERO
func _ready():
speed = 300
func _on_Projectile_area_entered(area):
if (area.name == "Player"):
area.take_damage(2)
self.queue_free()
func _physics_process(delta):
position += (direction * delta * speed)
func _on_DeleteDelay_timeout():
self.queue_free()
发生了什么原因?
I am working on a system which spawns 8 new projectiles after a bullet hits an enemy (an area2D touches another area2D). However, the game loses about 10 FPS for a moment after these projectiles spawn.
Note: I have tried to make the projectiles spawn using different triggers (Timers and process functions), and none of them have resulted in any drops in performance.
This is the code I use for the enemy:
func _ready():
shooter.projectile = preload("res://Projectiles/Planet/LavaBall/LavaBall.tscn")
func _on_Planet_area_entered(area):
if("PlayerProjectile" in area.name):
if (randi() % 100 > 30):
shoot_burst()
func shoot_burst():
fire_projectile_burst(8, 30)
func fire_projectile_burst(projectile, amount: int, spread: int):
var begin_direction = fire_angle
fire_angle = fire_angle - ceil(spread/2)
for i in range(amount):
fire_projectile(projectile)
fire_angle += (spread/amount)
fire_angle = begin_direction
func fire_projectile(projectile):
var projectile_ins = projectile.instance()
projectile_ins.position = position
var rad_fire_angle = deg2rad(fire_angle)
projectile_ins.direction = Vector2(cos(rad_fire_angle),sin(rad_fire_angle))
get_tree().get_root().add_child(projectile_ins)
The code for the projectile:
var speed: float = 500
var direction : Vector2 = Vector2.ZERO
func _ready():
speed = 300
func _on_Projectile_area_entered(area):
if (area.name == "Player"):
area.take_damage(2)
self.queue_free()
func _physics_process(delta):
position += (direction * delta * speed)
func _on_DeleteDelay_timeout():
self.queue_free()
What causes this to happen?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我本来建议使用粒子系统的问题的方式。但是,有了代码,我看到您正在尝试产生可能造成损坏的弹丸……
在进一步前进之前,我应该将您指向您的Profiler,这可能会使您对实际发生的事情有所了解。您可以在“配置文件”选项卡上从编辑器的底部面板的底部面板启用调试器剖面。启用后开始游戏。 Profiler将制作图形(您可以在左侧选择图形),向您显示需要更多时间的时间。您可能还对“监视器”选项卡上的图形感兴趣。然后,您将重现有问题的情况,然后查看更多的时间(您会在代码产生弹丸时突然升起的一些图表)。
我不知道这是什么,但是我可以做出一些有根据的猜测,并就如何处理它们提供一些建议。
您可能会失去框架的原因之一是着色器加载和编译。
您可以通过检查这是否仅在您第一次产生弹丸时才会诊断此问题。着色器已经第二次已经加载和编译,因此由于此原因不会落下框架。
这也告诉您如何解决这个问题:先前加载着着色器和可见的东西。同样,请尝试重复使用您的着色器。
无论如何,我认为着色器不是问题所在。罪魁祸首更有可能是物理学:当弹丸产卵时,它拦截了其他区域,并且多个弹丸相互拦截。您将使用
collision_layer
和Collision_mask
来解决这个问题。在理想的情况下,您甚至根本不需要此检查:
相反,您将拥有自己的层。这些
afore2d
具有仅与该层相撞的掩码。这样一来,戈多甚至都不会检查弹丸与玩家以外的其他事物之间的碰撞。可以缓解上述问题的其他方法是传播实例。
顺便说一句,如果问题如果弹丸场景很重可以实例化,除了试图使其变得不那么重(较小的纹理,更简单的形状,更便宜的着色器……),您还可以尝试传播实例化。
最简单的方法是在您的循环中插入这条线:
或者物理框架更好:
该线将使Godot停止执行,直到框架(或物理框架)通过,然后Godot恢复在下一行上执行代码。
同样,如果实例化是昂贵的(或者问题是正在创建大量实例(似乎并非如此)),则可以汇总实例。
在您的情况下,这可能不是必需的……无论如何,这个想法是两个折:
queue_free
它们,而是从场景中删除它们(带有emove> remove_child
)并将它们添加回阵列以重复使用。The way the question was originally written, I would have suggested to use a particle system. However, with the code, I see you are trying to spawn projectiles that can cause damage…
Before going further, I should point you to the profiler, which might give you some insight in what is actually happening. You can enable the Debugger profiler from the bottom panel of the editor, on the profile tab. Once enabled start the game. The profiler will make graphs (you can select what to graph on the left) showing you what takes more time. You may also be interested on the graphs on the Monitors tab. Then you would reproduce the problematic situation, and see what is eating more time (you would looking for some graph suddenly rising around the time your code spawns the projectiles).
I don't know what it is for sure, but I can make some educated guesses and give you some advice on how to handle them.
One of the reasons you might lose frames is shaders loading and compiling.
You can diagnose this problem by checking if this only happens the first time you spawn your projectiles. For the second time the shaders would have already been loaded and compiled, so there would be no frames drops due to this.
That also tells you how to address this: have something with the shader loaded and visible beforehand. On a similar note, try to reuse your shaders.
Anyway, I don't think shaders is the problem. A more likely culprit is physics: When the projectile spawns, it intercepts the other areas, and the multiple projectiles intercept each other. You would address that with
collision_layer
andcollision_mask
.In an ideal scenario, you would not even need this check at all:
Instead you would have the player on its own layer. And these
Area2D
have a mask that have only collide with that layer. That way Godot will not even check for collisions between the projectiles and something other than the player.Something else that will ease the above issue is to spread the instantiations.
By the way, if the issue if that the projectile scene is just that heavy to instantiate, aside from trying to making it less heavy (smaller textures, simpler shapes, less expensive shaders…), you can also try spreading the instantiations.
The easiest way to do that is to insert this line in your loop:
Or perhaps physics frame is better:
This line will have the Godot halt execution until a frame (or physics frame) passes, then Godot resumes the execution of the code on the next line.
Similarly, if instantiating is expensive (or if the problem were a large number of instances being created, which does not seem to be the case), you could pool the instances.
This is probably not necessary in your case... Anyway, the idea is two fold:
queue_free
them, instead remove them from the scene (withremove_child
) and add them back to the array to be reused.