如何为我的回合制系统增加速度,以便如果怪物速度更快,它会先攻击
How do I add speed to my turn based system so if a monster has more speed it attacks first
我制作了一个功能来比较玩家和敌人两个怪物的速度,但我不知道如何让他们进行攻击然后回到玩家可以再次按下按钮的状态,在如果我将按钮更改为check_speed,那么玩家攻击然后敌人攻击而速度不是一个因素的那一刻它变成了一个无限循环
这是代码:
func check_speed(): # Gonna make it so speed becomes a factor
if P_team.monster_invetory[0].speed > enemy_scene.speed:
player_attack()
else:
enemy_attack()
func player_attack(): # Attacks the enemy
print("Player attacking")
enemy_scene.take_damage(P_team.monster_invetory[0].attack) # Calls the function to take damage
yield(get_tree().create_timer(2), "timeout") #Wait for 2 seconds
Enemy_battle_scene(enemy_scene) #This updates the display values
var is_dead = enemy_scene.take_damage(P_team.monster_invetory[0].attack) # Checks if dead
if is_dead:
current_state = GameState.WON
elif !is_dead:
current_state = GameState.ENEMYTURN
enemy_attack() # Here is where the enemy decides what to do, for now it only attacks
func enemy_attack(): # Attacks the player
print("Enemy attacking")
P_team.monster_invetory[0].take_damage(enemy_scene.attack) # Calls the function to take damage
yield(get_tree().create_timer(2), "timeout") #Wait for 2 seconds
Player_battle_scene(P_team.monster_invetory[0]) #This updates the display values
var is_dead = P_team.monster_invetory[0].take_damage(enemy_scene.attack) # Checks if dead
if is_dead:
current_state = GameState.LOST
elif !is_dead:
current_state = GameState.PLAYERTURN
#player_attack()
func _on_Attack_button_pressed():
if current_state != GameState.PLAYERTURN:
return
player_attack()
#check_speed()
新答案
任何其他名称的状态机。
你有状态:
enum GameState {START, CHOICE, PLAYERTURN, ENEMYTURN, WON, LOST, CAPTURE}
var current_state = GameState.START
我们可以通过将 current_state
变成 属性 并添加 "state_changed"
信号来使其更有用:
signal state_changed()
enum GameState {START, CHOICE, PLAYERTURN, ENEMYTURN,WON, LOST, CAPTURE}
var current_state setget set_current_state
func set_current_state(new_value):
current_state = new_value
emit_signal("state_changed")
现在,我们每次设置self.current_state
,都会触发信号。当然我们可以连接到它。
所以我们可以这样做:
func _ready():
self.connect("state_changed", self, "_on_state_changed")
self.current_state = GameState.START
func _on_state_changed():
match current_state:
GameState.START:
_start()
GameState.CHOICE:
_choice()
GameState.PLAYERTURN:
_player_turn()
GameState.ENEMYTURN:
_enemy_turn()
GameState.LOST:
_lost()
GameState.CAPTURE:
_capture()
为什么不把_on_state_changed
直接放在set_current_state
里呢?因为信号是异步的。 此外,您不必在此脚本中处理所有这些问题。您甚至可以为每个州准备一个脚本。
好的,让我们开始制作这些函数:
开始:
func _start():
# initalization stuff
self.current_state = GameState.CHOICE
选择:
func _choice():
# We have to wait for the button press, we do nothing here
pass
func _on_Attack_button_pressed():
if current_state != GameState.CHOICE:
return
if _player_speed() > _enemy_speed(): # Checks which monster is faster
self.current_state = GameState.PLAYERTURN
else:
self.current_state = GameState.ENEMYTURN
具有 _player_speed
和 _enemy_speed
的一些定义。
PLAYER_TURN 和 ENEMY_TURN:
var enemy_attk = false
var player_attk = false
func _player_turn():
yield(_player_attack(), "completed")
if _enemy_is_dead():
self.current_state = GameState.WON
else:
if enemy_attk:
player_attk = false
enemy_attk = false
self.current_state = GameState.CHOICE
else:
player_attk = true
self.current_state = GameState.ENEMYTURN
func _enemy_turn():
yield(_enemy_attack(), "completed")
if _player_is_dead():
self.current_state = GameState.LOST
else:
if player_attk:
player_attk = false
enemy_attk = false
self.current_state = GameState.CHOICE
else:
enemy_attk = true
self.current_state = GameState.PLAYERTURN
具有 _player_is_dead
、_enemy_is_dead
、_player_attack
和 _enemy_attack
的一些定义。
获胜、失败和捕获:
func _lost():
# whatever happens
pass
func _won():
# whatever happens
pass
func _capture():
# whatever happens
pass
我不知道。
现在,让我们将 PLAYERTURN、ENEMYTURN 合并到一个新的 BATTLE 状态。更新枚举:
enum GameState {START, CHOICE, BATTLE, WON, LOST, CAPTURE}
更新匹配语句:
func _on_state_changed():
match current_state:
GameState.START:
_start()
GameState.CHOICE:
_choice()
GameState.BATTLE:
_battle()
GameState.LOST:
_lost()
GameState.CAPTURE:
_capture()
当按下按钮时,我们只需更改为 BATTLE:
func _on_Attack_button_pressed():
if current_state != GameState.CHOICE:
return
self.current_state = GameState.BATTLE
现在是重头戏:
func _battle():
if _player_speed() > _enemy_speed(): # Checks which monster is faster
yield(_player_attack(), "completed")
if _enemy_is_dead():
self.current_state = GameState.WON
else:
yield(_enemy_attack(), "completed")
if _player_is_dead():
self.current_state = GameState.LOST
else:
self.current_state = GameState.CHOICE
else:
yield(_enemy_attack(), "completed")
if _player_is_dead():
self.current_state = GameState.LOST
else:
yield(_player_attack(), "completed")
if _enemy_is_dead():
self.current_state = GameState.WON
else:
self.current_state = GameState.CHOICE
让我们谈谈使用对象。首先,参考它们。您已经拥有 enemy_scene
,让我们使用它。我们需要添加一个计数器部分 player_scene
.
onready var player_scene = P_team.monster_invetory[0]
顺便说一下,如果我是你,我会在 EnemyPos
和 PlayerPos
中添加一个脚本,这样我就可以这样做:
$EnemyPos.update_view(enemy_scene)
$PlayerPos.update_view(player_scene)
现在,START 可以如下所示:
func _start():
_update_view()
print("Battle started")
yield(get_tree().create_timer(0.2), "timeout")
self.current_state = GameState.CHOICE
func _update_view():
$PlayerPos.update(player_scene)
$EnemyPos.update(enemy_scene)
建议:给那些场景加一个“health_changed”信号,分别接在$PlayerPos
或$EnemyPos
上,这样就可以自动更新了。 事实上,当怪物死亡时,我们可以使用该信号来处理。
攻击是个问题,因为这些对象不知道它们的目标。以后会担心的。
现在更新 BATTLE 以使用 player_scene
和 enemy_scene
:
func _battle():
if player_scene.speed > enemy_scene.speed:
yield(attack(player_scene, enemy_scene), "completed")
if enemy_scene.current_health == 0:
self.current_state = GameState.WON
else:
yield(attack(enemy_scene, player_scene), "completed")
if player_scene.current_health == 0:
self.current_state = GameState.LOST
else:
self.current_state = GameState.CHOICE
else:
yield(attack(enemy_scene, player_scene), "completed")
if player_scene.current_health == 0:
self.current_state = GameState.LOST
else:
yield(attack(player_scene, enemy_scene), "completed")
if enemy_scene.current_health == 0:
self.current_state = GameState.WON
else:
self.current_state = GameState.CHOICE
func attack(attacker, target):
print(attacker.name, " attacking")
target.take_damage(attacker.attack) # Calls the function to take damage
yield(get_tree().create_timer(2), "timeout") #Wait for 2 seconds
_update_view()
请注意,使用“health_changed”信号,这段代码要简单得多。因为您不必在 _battle
上处理输赢条件,也不必从 attack
调用 _update_view
。
最后,我们可以编写一个将它们放在数组中的版本:
func _battle():
var participants = [player_scene, enemy_scene]
participants.sort_custom(self, "check_speed")
for attacker in participants:
var target = _choose_target(attacker, participants)
yield(attack(attacker, target), "completed")
if player_scene.current_health == 0:
self.current_state = GameState.LOST
return
if enemy_scene.current_health == 0:
self.current_state = GameState.WON
return
self.current_state = GameState.CHOICE
func check_speed(a, b):
return a.speed > b.speed:
func _choose_target(attacker, participants):
for participant in participants:
if participant == attacker:
continue
return participant
同样,使用“health_changed”信号会更简单。
这仍然需要一些修改才能完全支持两个以上的怪物:
- 要赢得它会检查是否所有敌方怪物都死了,而不仅仅是一个。
- 失去它会检查所有盟友怪物是否都死了,而不仅仅是一个。
- 选择目标时,请确保它选择了考虑到攻击者的合适团队。 您也可以考虑让玩家控制选择目标。
当然,您可以将数组保留在 _battle
之外,并在参与者死亡时将其移除。然后检查是否所有敌方怪物都死了,实际上是检查所有剩余的怪物是否都是盟友(反之亦然)。你可以通过计算那里有多少盟友或敌方怪物,并在它们死亡时减少它来做到这一点。 你可以连接到“health_changed”信号。
啊,对了,一个可以让怪物根据速度进行多次攻击的版本。您将需要这些场景的新属性。我叫它exhaustion
,战斗开始时应该是0
。
func _battle():
var participants = [player_scene, enemy_scene]
var player_attacked = false
while (true):
var attacker = get_next(participants)
if player_scene == attacker:
if player_attacked:
# It is time for the player to attack again.
# Return control to the player.
self.current_state = GameState.CHOICE
return
else:
player_attacked = true
var target = _choose_target(attacker, participants)
yield(attack(attacker, target), "completed")
attacker.exhaustion += 1.0 / attacker.speed # <--
if player_scene.current_health == 0:
self.current_state = GameState.LOST
return
if enemy_scene.current_health == 0:
self.current_state = GameState.WON
return
func get_next(participants):
participants.sort_custom(self, "check_order")
return participants[0]
func check_order(a, b):
if a.exhaustion < b.exhaustion:
return true
if a.exhaustion == b.exhaustion:
return a.speed > b.speed:
return false
如你所见,规则是exhaustion
少的怪物先出。如果两只怪物的 exhaustion
相同,则 speed
多的先出。每次怪物攻击时,它的 exhaustion
都会增加。多少? speed
的倒数。因此 speed
少的怪物耗尽得更快,而 speed
多的怪物耗尽得慢。因此,如果一个怪物的 speed
多于另一个,它最终会像第一个怪物一样对每个怪物进行多次攻击。
注意:我称其为“耗尽”只是为了让您对值如何变化有一些直觉。但是,重要的是这不是一场又一场的战斗,它必须重置为 0
。如果你想象一个筋疲力尽的怪物与一个没有筋疲力尽的怪物,没有筋疲力尽的人会在另一个人做任何事情之前得到很多攻击。
我们需要跟踪玩家是否进行了攻击,正如我在原始答案中提到的那样,以打破循环。
原回答
这取决于您希望 Speed 的具体工作方式,我只会展示最简单的方法。但首先让我们从基线开始。
这么说吧,不管速度,玩家攻击,然后怪物攻击,然后等待下一次输入。
这意味着像这样做:
func _on_Attack_button_pressed():
# ...
player_attack()
enemy_attack()
除了那些函数yield
。所以我们需要这个:
func _on_Attack_button_pressed():
# ...
yield(player_attack(), "completed")
yield(enemy_attack(), "completed")
原因是产生 returns 的函数是 GDScriptFunctionState
。
文档说 GDScriptFunctionState
:
Calling @GDScript.yield within a function will cause that function to yield and return its current state as an object of this type
这里我使用 GDScriptFunctionState
的 "completed"
信号,正如 Coroutines & signals:
文档中所建议的
If you're unsure whether a function may yield or not, or whether it may yield multiple times, you can yield to the completed signal conditionally
现在,让“速度”发挥作用的最简单方法是将速度视为回合顺序。类似于 D&D 计划。这意味着我们所做的就是根据速度对这些操作进行排序。所以你做这样的事情:
func _on_Attack_button_pressed():
# ...
if player_goes_first():
yield(player_attack(), "completed")
yield(enemy_attack(), "completed")
else:
yield(enemy_attack(), "completed")
yield(player_attack(), "completed")
根据您的代码,我猜 player_goes_first
只会 return P_team.monster_invetory[0].speed > enemy_scene.speed
。参见 Functions。
我们也可以这样写:
func _on_Attack_button_pressed():
# ...
if player_speed() > enemy_speed():
yield(player_attack(), "completed")
yield(enemy_attack(), "completed")
else:
yield(enemy_attack(), "completed")
yield(player_attack(), "completed")
其中 player_speed
和 enemy_speed
是 return 适当值的函数。
如果你需要三个参与者,你可以想象代码(something like this)。
但是,您的代码将受益于使用具有 speed
属性 和 attack
方法的对象(这些对象可能是也可能不是节点,请参阅 Classes ).
如果你有对象,支持更多的参与者会更容易:
- 将参与者放在一个数组中。
- 按
speed
排序,sort_custom
。
- 遍历数组,并对每个数组调用
attack
。
另一种方法是使用 get_next
函数,return 调用 attack
的下一个对象。然后循环调用 get_next
。您将有一个变量来跟踪玩家是否进行了攻击(通过检查您从 get_next
获得的内容是否是玩家对象),并在循环播放器攻击两次之前停止(因为用户应该按下按钮再次攻击)。
使用 get_next
函数可以实现更复杂的逻辑。例如,让参与者根据其 speed
.
进行多次攻击
我制作了一个功能来比较玩家和敌人两个怪物的速度,但我不知道如何让他们进行攻击然后回到玩家可以再次按下按钮的状态,在如果我将按钮更改为check_speed,那么玩家攻击然后敌人攻击而速度不是一个因素的那一刻它变成了一个无限循环
这是代码:
func check_speed(): # Gonna make it so speed becomes a factor
if P_team.monster_invetory[0].speed > enemy_scene.speed:
player_attack()
else:
enemy_attack()
func player_attack(): # Attacks the enemy
print("Player attacking")
enemy_scene.take_damage(P_team.monster_invetory[0].attack) # Calls the function to take damage
yield(get_tree().create_timer(2), "timeout") #Wait for 2 seconds
Enemy_battle_scene(enemy_scene) #This updates the display values
var is_dead = enemy_scene.take_damage(P_team.monster_invetory[0].attack) # Checks if dead
if is_dead:
current_state = GameState.WON
elif !is_dead:
current_state = GameState.ENEMYTURN
enemy_attack() # Here is where the enemy decides what to do, for now it only attacks
func enemy_attack(): # Attacks the player
print("Enemy attacking")
P_team.monster_invetory[0].take_damage(enemy_scene.attack) # Calls the function to take damage
yield(get_tree().create_timer(2), "timeout") #Wait for 2 seconds
Player_battle_scene(P_team.monster_invetory[0]) #This updates the display values
var is_dead = P_team.monster_invetory[0].take_damage(enemy_scene.attack) # Checks if dead
if is_dead:
current_state = GameState.LOST
elif !is_dead:
current_state = GameState.PLAYERTURN
#player_attack()
func _on_Attack_button_pressed():
if current_state != GameState.PLAYERTURN:
return
player_attack()
#check_speed()
新答案
任何其他名称的状态机。
你有状态:
enum GameState {START, CHOICE, PLAYERTURN, ENEMYTURN, WON, LOST, CAPTURE}
var current_state = GameState.START
我们可以通过将 current_state
变成 属性 并添加 "state_changed"
信号来使其更有用:
signal state_changed()
enum GameState {START, CHOICE, PLAYERTURN, ENEMYTURN,WON, LOST, CAPTURE}
var current_state setget set_current_state
func set_current_state(new_value):
current_state = new_value
emit_signal("state_changed")
现在,我们每次设置self.current_state
,都会触发信号。当然我们可以连接到它。
所以我们可以这样做:
func _ready():
self.connect("state_changed", self, "_on_state_changed")
self.current_state = GameState.START
func _on_state_changed():
match current_state:
GameState.START:
_start()
GameState.CHOICE:
_choice()
GameState.PLAYERTURN:
_player_turn()
GameState.ENEMYTURN:
_enemy_turn()
GameState.LOST:
_lost()
GameState.CAPTURE:
_capture()
为什么不把_on_state_changed
直接放在set_current_state
里呢?因为信号是异步的。 此外,您不必在此脚本中处理所有这些问题。您甚至可以为每个州准备一个脚本。
好的,让我们开始制作这些函数:
开始:
func _start():
# initalization stuff
self.current_state = GameState.CHOICE
选择:
func _choice():
# We have to wait for the button press, we do nothing here
pass
func _on_Attack_button_pressed():
if current_state != GameState.CHOICE:
return
if _player_speed() > _enemy_speed(): # Checks which monster is faster
self.current_state = GameState.PLAYERTURN
else:
self.current_state = GameState.ENEMYTURN
具有 _player_speed
和 _enemy_speed
的一些定义。
PLAYER_TURN 和 ENEMY_TURN:
var enemy_attk = false
var player_attk = false
func _player_turn():
yield(_player_attack(), "completed")
if _enemy_is_dead():
self.current_state = GameState.WON
else:
if enemy_attk:
player_attk = false
enemy_attk = false
self.current_state = GameState.CHOICE
else:
player_attk = true
self.current_state = GameState.ENEMYTURN
func _enemy_turn():
yield(_enemy_attack(), "completed")
if _player_is_dead():
self.current_state = GameState.LOST
else:
if player_attk:
player_attk = false
enemy_attk = false
self.current_state = GameState.CHOICE
else:
enemy_attk = true
self.current_state = GameState.PLAYERTURN
具有 _player_is_dead
、_enemy_is_dead
、_player_attack
和 _enemy_attack
的一些定义。
获胜、失败和捕获:
func _lost():
# whatever happens
pass
func _won():
# whatever happens
pass
func _capture():
# whatever happens
pass
我不知道。
现在,让我们将 PLAYERTURN、ENEMYTURN 合并到一个新的 BATTLE 状态。更新枚举:
enum GameState {START, CHOICE, BATTLE, WON, LOST, CAPTURE}
更新匹配语句:
func _on_state_changed():
match current_state:
GameState.START:
_start()
GameState.CHOICE:
_choice()
GameState.BATTLE:
_battle()
GameState.LOST:
_lost()
GameState.CAPTURE:
_capture()
当按下按钮时,我们只需更改为 BATTLE:
func _on_Attack_button_pressed():
if current_state != GameState.CHOICE:
return
self.current_state = GameState.BATTLE
现在是重头戏:
func _battle():
if _player_speed() > _enemy_speed(): # Checks which monster is faster
yield(_player_attack(), "completed")
if _enemy_is_dead():
self.current_state = GameState.WON
else:
yield(_enemy_attack(), "completed")
if _player_is_dead():
self.current_state = GameState.LOST
else:
self.current_state = GameState.CHOICE
else:
yield(_enemy_attack(), "completed")
if _player_is_dead():
self.current_state = GameState.LOST
else:
yield(_player_attack(), "completed")
if _enemy_is_dead():
self.current_state = GameState.WON
else:
self.current_state = GameState.CHOICE
让我们谈谈使用对象。首先,参考它们。您已经拥有 enemy_scene
,让我们使用它。我们需要添加一个计数器部分 player_scene
.
onready var player_scene = P_team.monster_invetory[0]
顺便说一下,如果我是你,我会在 EnemyPos
和 PlayerPos
中添加一个脚本,这样我就可以这样做:
$EnemyPos.update_view(enemy_scene)
$PlayerPos.update_view(player_scene)
现在,START 可以如下所示:
func _start():
_update_view()
print("Battle started")
yield(get_tree().create_timer(0.2), "timeout")
self.current_state = GameState.CHOICE
func _update_view():
$PlayerPos.update(player_scene)
$EnemyPos.update(enemy_scene)
建议:给那些场景加一个“health_changed”信号,分别接在$PlayerPos
或$EnemyPos
上,这样就可以自动更新了。 事实上,当怪物死亡时,我们可以使用该信号来处理。
攻击是个问题,因为这些对象不知道它们的目标。以后会担心的。
现在更新 BATTLE 以使用 player_scene
和 enemy_scene
:
func _battle():
if player_scene.speed > enemy_scene.speed:
yield(attack(player_scene, enemy_scene), "completed")
if enemy_scene.current_health == 0:
self.current_state = GameState.WON
else:
yield(attack(enemy_scene, player_scene), "completed")
if player_scene.current_health == 0:
self.current_state = GameState.LOST
else:
self.current_state = GameState.CHOICE
else:
yield(attack(enemy_scene, player_scene), "completed")
if player_scene.current_health == 0:
self.current_state = GameState.LOST
else:
yield(attack(player_scene, enemy_scene), "completed")
if enemy_scene.current_health == 0:
self.current_state = GameState.WON
else:
self.current_state = GameState.CHOICE
func attack(attacker, target):
print(attacker.name, " attacking")
target.take_damage(attacker.attack) # Calls the function to take damage
yield(get_tree().create_timer(2), "timeout") #Wait for 2 seconds
_update_view()
请注意,使用“health_changed”信号,这段代码要简单得多。因为您不必在 _battle
上处理输赢条件,也不必从 attack
调用 _update_view
。
最后,我们可以编写一个将它们放在数组中的版本:
func _battle():
var participants = [player_scene, enemy_scene]
participants.sort_custom(self, "check_speed")
for attacker in participants:
var target = _choose_target(attacker, participants)
yield(attack(attacker, target), "completed")
if player_scene.current_health == 0:
self.current_state = GameState.LOST
return
if enemy_scene.current_health == 0:
self.current_state = GameState.WON
return
self.current_state = GameState.CHOICE
func check_speed(a, b):
return a.speed > b.speed:
func _choose_target(attacker, participants):
for participant in participants:
if participant == attacker:
continue
return participant
同样,使用“health_changed”信号会更简单。
这仍然需要一些修改才能完全支持两个以上的怪物:
- 要赢得它会检查是否所有敌方怪物都死了,而不仅仅是一个。
- 失去它会检查所有盟友怪物是否都死了,而不仅仅是一个。
- 选择目标时,请确保它选择了考虑到攻击者的合适团队。 您也可以考虑让玩家控制选择目标。
当然,您可以将数组保留在 _battle
之外,并在参与者死亡时将其移除。然后检查是否所有敌方怪物都死了,实际上是检查所有剩余的怪物是否都是盟友(反之亦然)。你可以通过计算那里有多少盟友或敌方怪物,并在它们死亡时减少它来做到这一点。 你可以连接到“health_changed”信号。
啊,对了,一个可以让怪物根据速度进行多次攻击的版本。您将需要这些场景的新属性。我叫它exhaustion
,战斗开始时应该是0
。
func _battle():
var participants = [player_scene, enemy_scene]
var player_attacked = false
while (true):
var attacker = get_next(participants)
if player_scene == attacker:
if player_attacked:
# It is time for the player to attack again.
# Return control to the player.
self.current_state = GameState.CHOICE
return
else:
player_attacked = true
var target = _choose_target(attacker, participants)
yield(attack(attacker, target), "completed")
attacker.exhaustion += 1.0 / attacker.speed # <--
if player_scene.current_health == 0:
self.current_state = GameState.LOST
return
if enemy_scene.current_health == 0:
self.current_state = GameState.WON
return
func get_next(participants):
participants.sort_custom(self, "check_order")
return participants[0]
func check_order(a, b):
if a.exhaustion < b.exhaustion:
return true
if a.exhaustion == b.exhaustion:
return a.speed > b.speed:
return false
如你所见,规则是exhaustion
少的怪物先出。如果两只怪物的 exhaustion
相同,则 speed
多的先出。每次怪物攻击时,它的 exhaustion
都会增加。多少? speed
的倒数。因此 speed
少的怪物耗尽得更快,而 speed
多的怪物耗尽得慢。因此,如果一个怪物的 speed
多于另一个,它最终会像第一个怪物一样对每个怪物进行多次攻击。
注意:我称其为“耗尽”只是为了让您对值如何变化有一些直觉。但是,重要的是这不是一场又一场的战斗,它必须重置为 0
。如果你想象一个筋疲力尽的怪物与一个没有筋疲力尽的怪物,没有筋疲力尽的人会在另一个人做任何事情之前得到很多攻击。
我们需要跟踪玩家是否进行了攻击,正如我在原始答案中提到的那样,以打破循环。
原回答
这取决于您希望 Speed 的具体工作方式,我只会展示最简单的方法。但首先让我们从基线开始。
这么说吧,不管速度,玩家攻击,然后怪物攻击,然后等待下一次输入。
这意味着像这样做:
func _on_Attack_button_pressed():
# ...
player_attack()
enemy_attack()
除了那些函数yield
。所以我们需要这个:
func _on_Attack_button_pressed():
# ...
yield(player_attack(), "completed")
yield(enemy_attack(), "completed")
原因是产生 returns 的函数是 GDScriptFunctionState
。
文档说 GDScriptFunctionState
:
Calling @GDScript.yield within a function will cause that function to yield and return its current state as an object of this type
这里我使用 GDScriptFunctionState
的 "completed"
信号,正如 Coroutines & signals:
If you're unsure whether a function may yield or not, or whether it may yield multiple times, you can yield to the completed signal conditionally
现在,让“速度”发挥作用的最简单方法是将速度视为回合顺序。类似于 D&D 计划。这意味着我们所做的就是根据速度对这些操作进行排序。所以你做这样的事情:
func _on_Attack_button_pressed():
# ...
if player_goes_first():
yield(player_attack(), "completed")
yield(enemy_attack(), "completed")
else:
yield(enemy_attack(), "completed")
yield(player_attack(), "completed")
根据您的代码,我猜 player_goes_first
只会 return P_team.monster_invetory[0].speed > enemy_scene.speed
。参见 Functions。
我们也可以这样写:
func _on_Attack_button_pressed():
# ...
if player_speed() > enemy_speed():
yield(player_attack(), "completed")
yield(enemy_attack(), "completed")
else:
yield(enemy_attack(), "completed")
yield(player_attack(), "completed")
其中 player_speed
和 enemy_speed
是 return 适当值的函数。
如果你需要三个参与者,你可以想象代码(something like this)。
但是,您的代码将受益于使用具有 speed
属性 和 attack
方法的对象(这些对象可能是也可能不是节点,请参阅 Classes ).
如果你有对象,支持更多的参与者会更容易:
- 将参与者放在一个数组中。
- 按
speed
排序,sort_custom
。 - 遍历数组,并对每个数组调用
attack
。
另一种方法是使用 get_next
函数,return 调用 attack
的下一个对象。然后循环调用 get_next
。您将有一个变量来跟踪玩家是否进行了攻击(通过检查您从 get_next
获得的内容是否是玩家对象),并在循环播放器攻击两次之前停止(因为用户应该按下按钮再次攻击)。
使用 get_next
函数可以实现更复杂的逻辑。例如,让参与者根据其 speed
.