godot - 我如何将其他类型的动作(状态效果、治疗、属性提升、派对切换)添加到基于回合的系统中
问题描述
我目前正在尝试实现一些不同的动作而不是攻击,但我想专注于派对功能,看起来像这样,我可以弄清楚我想要的动作类型,但我想改变战斗功能以适应可以接受多个动作而不仅仅是攻击的角色
func change_party(inventory,index): # Inventory being if enemy or player
if inventory[index].fainted == false: # Checks if the monster is not dead
var hold = inventory[0] # Holds the first slot and then applys it later to the selected slot
inventory[0] = inventory[index]
inventory[index] = hold
这改变了由按钮输入的索引并将其与数组中的第一个插槽交换这是因为第一个插槽是首先显示的怪物,我也有这个战斗功能:
func _battle():
participants = [player_inventory[0],enemy_inventory[0]]
participants.sort_custom(self, "check_speed")
for attacker in participants:
var player_move = player_inventory[0].move_slot[action_index]
var random_move = randi() % 3 + 1
var enemy_move = attacker.move_slot[0] # Use random_move currently 0
var target = _choose_target(attacker, participants)
if attacker == player_inventory[0]:
yield(attack(attacker, target, player_move), "completed")
else:
yield(attack(attacker, target, enemy_move), "completed")
if player_inventory[0].current_hp <= 0:
player_inventory[0].current_hp = 0
player_inventory[0].fainted = true
Battle_Ui_Updater()
self.current_state = GameState.LOST
return
if enemy_inventory[0].current_hp <= 0:
enemy_inventory[0].current_hp = 0
enemy_inventory[0].fainted = true
Battle_Ui_Updater()
self.current_state = GameState.WON
return
self.current_state = GameState.ACTION
我想到的一个解决方案是尝试将所有操作放在一个数组中,然后根据输入调用我想要的操作,但我不知道如何使它看起来可读或没有错误
在这个功能中,它是如何根据速度决定谁轮到谁的,但有时我希望玩家先走,例如当我想更换队伍成员时,当玩家更换时,我希望敌人开始攻击,但是我正在为如何让它改变动作而摸不着头脑,我知道如果我想让它做其他事情就应该改变攻击功能,但我也希望能够根据什么类型的动作来控制谁的回合用过,如果没有解释清楚,请见谅,希望大家理解,我不想重复自己做另一个类似战斗的功能,那么如何在做自己想做的事情的同时避免重复呢?
战斗脚本:
func attack(attacker, target, move):
print(str(attacker.name) + " used " + str(move.name) + " " + str((move)))
var new_text = (attacker.name + " attacked with " + move.name)
text_scroller(new_text)
var data = recieve_damage(move,attacker,target)
#var data = target.take_damage(move,attacker) # Calls the function to take damage
yield(get_tree().create_timer(2), "timeout") #Wait for 2 seconds
Battle_Ui_Updater()
if data:
yield(critical_hit(attacker),"completed")
func critical_hit(attacker):
var new_text = (attacker.name + " has landed a critical hit! ")
text_scroller(new_text)
print(attacker.name + " has landed a critical hit!")
yield(get_tree().create_timer(2.5), "timeout")
func Get_effectiveness(attack_type,defence_type):
if attack_type == TypeData.types.none or defence_type == TypeData.types.none:
return 1
print("row : " + str(attack_type))
print("col : " + str(defence_type))
return TypeData.chart[attack_type][defence_type]
func recieve_damage(action,attacker,defender):
var critical = 1
var critical_chance = randi() % 100 + 1
if critical_chance <= 6.25:
critical = 2
var attack_mode
var defence_mode
if action.is_special == true:
attack_mode = attacker.special_attack
defence_mode = defender.special_defence
else:
attack_mode = attacker.attack
defence_mode = defender.defence
var type : float = Get_effectiveness(action.type,defender.type_1) * Get_effectiveness(action.type,defender.type_2)
var modifier : float = rand_range(0.85,1.0) * type * critical
var a : float = (2.0 * attacker.level / 5.0 + 2.0)
var b : float = (a * attack_mode * action.power / defence_mode) / 50.0
var c : float = (b + 2.0) * modifier
var damage = int(c)
defender.current_hp -= damage
print(str(attacker.name) + " = " + str(damage))
return critical > 1
用当前成员交换党员:
func change_party(inventory,index):
if inventory[index].fainted == false:
var hold = inventory[0]
inventory[0] = inventory[index]
inventory[index] = hold
print(inventory[0].hp)
Battle_Ui_Updater()
move_ui_updater(player_inventory[0])
yield(get_tree().create_timer(2),"timeout")
解决方案
我想出了这个:
class_name Task
class Skipper:
signal skip
func emit() -> void:
emit_signal("skip")
var _instance:Object
var _method:String
var _parameters:Array
var _result = null
func _init(instance:Object, method:String, parameters:Array = []) -> void:
_instance = instance
_method = method
_parameters = parameters
func execute():
var instance = _instance
var parameters = _parameters
if instance != null and instance.has_method(_method):
_instance = null
_parameters = []
_result = instance.callv(_method, parameters)
if _result is GDScriptFunctionState && _result.is_valid():
_result = yield(_result, "completed")
return _result
var skipper = Skipper.new()
skipper.call_deferred("emit")
yield(skipper, "skip")
return _result
这就是你初始化它的方式:
var parameters = [player_inventory[0], enemy_inventory[0], player_inventory[0].move_slot[action_index]]
player_action = Task.new(self, "attack", parameters)
这就是你使用它的方式:
yield(player_action.execute(), "completed")
这个类的新特性是无论它调用的方法是否是异步的,它都是异步的(所以你不必担心它调用的方法是否会产生)。无论哪种方式,它都会在它调用的方法完成后完成。它甚至返回(如果它调用的内容不返回,则返回 null)!
注意:此代码将记住结果,并删除它链接到的参数和实例。随后的执行调用将简单地返回记忆的结果。这样它就不会不必要地持有引用。
我们如何做到这一点?
好吧,首先,我们使用callv
的是通过名称调用带有参数数组的方法。Godot 中有一个类FuncRef
可以以类似的方式使用。但是,不使用它会更方便。
其次,调用异步的东西会是yield(..., "completed")
,但我们不知道我们所调用的是否是异步的。所以我们检查。如何?如果它是异步的,它实际上将它离开执行的状态返回为 a GDScriptFunctionState
,所以我们检查一下。
如果是GDScriptFunctionState
,那么我们可以使用yield(..., "completed")
它。
如果不是。我们需要以某种方式使函数异步。我们将通过发出一个带有 的信号来做到这一点call_deferred
。我决定把它变成一个内部类,这样它就不会暴露在脚本之外。
另请注意,代码会检查实例是否不为空并且方法是否已通过。但如果没有,它只会返回它存储的结果。这是记忆机制的一部分,但是,这也意味着如果您传递了错误的实例,方法名称写错了,您将没有反馈。
最后,它应该适用于以下版本_battle
:
func _battle():
participants = [player_inventory[0],enemy_inventory[0]]
participants.sort_custom(self, "check_speed")
for current_participant in participants:
if current_participant == player_inventory[0]:
yield(player_action.execute(), "completed")
else:
yield(enemy_action.execute(), "completed")
var state = decide_battle_state()
if state != GameState.BATTLE:
self.current_state = state
return
self.current_state = GameState.ACTION
func decide_battle_state():
if check_fainted(player_inventory[0]):
return GameState.LOST
if check_fainted(enemy_inventory[0]):
return GameState.WON
return GameState.BATTLE
func check_fainted(participant) -> bool:
if participant.current_hp > 0:
return false
participant.current_hp = 0
participant.fainted = true
Battle_Ui_Updater()
return true
你可以Task
用speed
:
class_name BattleAction extends Task
# warning-ignore:unused_class_variable
var speed
func _init(instance:Object, method:String, parameters:Array = []).(instance, method, parameters) -> void:
pass
然后像这样使用:
var parameters = [player_inventory[0], enemy_inventory[0], player_inventory[0].move_slot[action_index]]
player_action = BattleAction.new(self, "attack", parameters)
player_action.speed = player_inventory[0].speed
最后_battle
看起来像这样:
使用您的BattleAction
which has speed
,您可以执行以下操作:
func _battle():
actions = [player_action, enemy_action]
actions.sort_custom(self, "check_speed")
for action in actions:
yield(action.execute(), "completed")
var state = decide_battle_state()
if state != GameState.BATTLE:
self.current_state = state
return
self.current_state = GameState.ACTION
推荐阅读
- android - 即使我提供了 64 位 apk,Google Play 64 位要求问题
- javascript - CSRF 攻击和 Websocket
- javascript - EXIF-JS 数据在方法之外变得未定义
- mysql - 登录用户时奇怪的nodejs行为
- php - 编写代码以检查数据库并插入不同的表时遇到问题
- java - 如何修复线程“main”org.openqa.selenium.WebDriverException中的异常?
- python - 在 python 中使用 reduce() 序列化字符串
- python - Check a dict key using assert from unit test
- python - 多个while循环
- bash - Doing a "one vs others" iteration through Bash script arguments