如何解决我如何为我的回合制系统增加速度,以便如果怪物速度更快,它会先攻击
我做了一个函数来比较玩家和敌人两个怪物的速度,但我不知道如何让他们进行攻击然后回到玩家可以再次按下按钮的状态,此时此刻如果我将按钮更改为 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,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,BATTLE,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,"completed")
if player_scene.current_health == 0:
self.current_state = GameState.LOST
else:
yield(attack(player_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
上的输赢条件,也不必从 _update_view
调用 attack
。
最后,我们可以编写一个将它们放入数组的版本:
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,"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")
原因是一个产生结果的函数返回一个 GDScriptFunctionState
。
关于 GDScriptFunctionState
的文档:
在函数内调用@GDScript.yield 将导致该函数作为该类型的对象屈服并返回其当前状态
这里我使用了 "completed"
的 GDScriptFunctionState
信号,如关于 Coroutines & signals 的文档中所建议的:
如果你不确定一个函数是否可以让步,或者它是否可以多次让步,你可以有条件地让步到完成的信号
现在,让“速度”工作的最简单方法是将速度视为转弯顺序。类似于 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
只会返回 P_team.monster_invetory[0].speed > enemy_scene.speed
。见Functions。
我们也可以这样写:
func _on_Attack_button_pressed():
# ...
if player_speed() > enemy_speed():
yield(player_attack(),"completed")
其中 player_speed
和 enemy_speed
是返回适当值的函数。
如果您需要三个参与者,您可以想象一下代码 (something like this)。
但是,您的代码将受益于使用具有 speed
属性和 attack
方法的对象(这些对象可能是也可能不是节点,请参阅 Classes)。
如果你有对象,支持更多参与者会更容易:
- 将参与者放在一个数组中。
- 按
speed
和sort_custom
对它们进行排序。 - 遍历数组,并对每个数组调用
attack
。
另一种方法是使用 get_next
函数返回下一个要调用 attack
的对象。然后循环调用 get_next
。您将有一个变量来跟踪玩家是否进行了攻击(通过检查您从 get_next
获得的内容是否是玩家对象),并在循环玩家攻击两次之前停止(因为用户应该按下按钮再次攻击)
使用 get_next
函数可以实现更复杂的逻辑。例如,让参与者根据其 speed
进行多次攻击。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。