IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> 【Godot】SkillNode 技能节点 -> 正文阅读

[游戏开发]【Godot】SkillNode 技能节点

Godot 3.4.2

角色的功能逻辑,按照攻击、施放技能时的阶段的逻辑执行功能。

下载后打开 TestSkill.tscn 场景,按下空格进行施放技能


注意节点设置了施放的时间间隔等属性


分为以下几个阶段:

  1. 准备阶段,开始抬手执行功能
  2. 开始功能阶段
  3. 持续阶段
  4. 功能结束阶段,开始放手
  5. 完全结束
  6. 功能冷却阶段
  7. 刷新可使用

每次执行都会发出一个信号,通过连接这个信号去执行不同阶段的功能,即实现了角色的功能逻辑


为了有些不想下载查看的,代码贴入如下(比较长)

Skill.gd

施放瞬间性的技能(非持续性技能)

#==================================================
#	Skill
#==================================================
#  非持续性技能
# * 调用 control 方法进行施放
# * 自己扩展脚本时重写 execute() 方法进行添加施放效果
# * 连接此节点的信号进行不同阶段功能的施放
#============================================================
# * 建议使用连接信号的方式进行功能的增减,因为如果不了解功能
#    逻辑时,最好不要重写修改里面的代码
#==================================================
# @path: res://addons/function_tree/src/base/function/skills/Skill.gd
# @datetime: 2021-12-12 11:52:07
#==================================================
extends Node


## 准备执行 (执行技能前摇)
signal ready_execute
## 执行了技能 (技能发出)
signal executed
## 技能执行完成 (后摇结束)
signal execute_finished
## 技能状态刷新了(冷却时间结束了)
signal status_refreshed
## 技能停止(调用 stop 方法时发出这个信号)
signal stopped
## 中断技能(调用 interrupt 方法中断成功时发出这个信号)
signal interrupted


## 中断执行结果
enum InterruptResult {
	OK = OK,
	NO_CASTING,		# 技能没有在施放
	NO_EXECUTE,		# 还没有执行其中的中断功能
}


## 技能前摇(准备技能的时间)
export var before_shake : float = 0.0 setget set_before_shake
## 技能后摇(结束技能的时间)
export var after_shake : float = 0.0 setget set_after_shake
## 施放间隔时间
export var interval : float = 1.0 setget set_interval


## 刷新间隔时间计时器
var __refresh_timer__ := Timer.new()
## 技能前后摇计时器
var __skill_timer__ := SkillTimer.new(self)
## 技能状态
var __state__ : SkillStatus = SkillStatus.new()
## 中断技能时的状态
var __interrupt_status__ = SkillStatus.Status.CAN_CAST


#==================================================
#   Set/Get
#==================================================
##  技能是否可用 
## @return  
func is_enabled() -> bool:
	return (
		__state__.is_can_cast()
		&& __refresh_timer__.is_stopped()
	)

func set_interrupt_state(value):
	__interrupt_status__ = value

func get_interrupt_state():
	return __interrupt_status__

## 设置前摇
func set_before_shake(value: float) -> void:
	before_shake = value
	__skill_timer__.before_time = value

func set_after_shake(value: float) -> void:
	after_shake = value
	__skill_timer__.after_time = value

func set_interval(value: float) -> void:
	interval = value
	if __refresh_timer__ == null:
		yield(self, "tree_entered")
	__refresh_timer__.wait_time = max(0.005, value)

##  可攻击的剩余时间
## @return  
func attack_time_left() -> float:
	return __refresh_timer__.time_left



#============================================================
#   内置
#============================================================
func _ready():
	__skill_timer__.set_before(before_shake, "_execute")
	__skill_timer__.set_after(after_shake, "_execute_finish")
	
	# 间隔时间结束,则调用 refresh() 方法
	__refresh_timer__.one_shot = true
	__refresh_timer__.autostart = false
	__refresh_timer__.wait_time = max(0.01, interval)
	__refresh_timer__.connect("timeout", self, "refresh")
	self.add_child(__refresh_timer__)



#==================================================
#   Skill 方法
#==================================================
##  开始执行技能
## @_data  执行所需数据
## @return  返回是否可以执行
func control(_data = null) -> bool:
	if is_enabled():
		emit_signal("ready_execute")
		__state__.ready()
		# 开始施法前摇
		__skill_timer__.start_before_shake()
		return true
	
	# 没有执行成功
	return false


##  执行(开始准备执行)
func _execute() -> void:
	# 施放中时 return 
	if __state__.is_casting():
		return
	# 开始间隔倒计时
	__refresh_timer__.start(interval)
	# 开始执行具体功能
	cast()


##  施放技能
func cast():
	__state__.cast()
	_cast()
	# 施放后
	_executed()


## (重写这个方法)
func _cast():
	execute()


## 执行功能(实施技能效果)
func execute():
	pass


##  功能施放后
## (这个是在技能发出瞬间之后进行处理的)
func _executed() -> void:
	__state__.casted()
	__skill_timer__.start_after_shake()
	emit_signal("executed")


##  执行完成
func _execute_finish() -> void:
	__state__.finish()
	emit_signal("execute_finished")


## 停止
func stop():
	_stop()


# (重写这个方法)
func _stop() -> bool:
	# 还没开始执行就停止时
	if __state__.is_ready():
		__state__.refresh()
	# 如果是在施放技能的状态
	if not __state__.is_no_cast():
		__state__.casted()
		__skill_timer__.stop()
		emit_signal("stopped")
		return true
	return false


##  中断,结束持续
#(提前结束执行技能,比如正准备施放时中断,执行时中断)
#(不要重写这个方法)
func interrupt():
	if _interrupt() == InterruptResult.OK:
		# 开始后摇
		__skill_timer__.start_after_shake()
		emit_signal("interrupted")


## (重写这个方法,对继承后的脚本功能进行扩展)
func _interrupt() -> int:
	if __state__.is_no_cast():
		if __state__.is_ready():
			__skill_timer__.stop_before_shake()
			set_interrupt_state(Function.Skills.Signals.ReadyExecute)
			return InterruptResult.OK
		return InterruptResult.NO_EXECUTE
	return InterruptResult.NO_CASTING


##  技能刷新
func refresh() -> void:
	_refresh()


## (重写这个方法)
func _refresh():
	__refresh_timer__.stop()
	__state__.refresh()
	emit_signal("status_refreshed")



#==================================================
#   施放动作计时器
#==================================================
class SkillTimer:
	const MIN_TIME = 0.03
	
	var host : Node
	var before := Timer.new()
	var after := Timer.new()
	
	var before_time : float = 0.0 
	var after_time : float = 0.0 
	
	func _init(host: Node):
		self.host = host
	
	## 前摇动作
	func set_before(wait_time: float, method: String, binds: Array = []):
		before_time = wait_time
		before.wait_time =  max(MIN_TIME, wait_time)
		before.one_shot = true
		before.autostart = false
		before.connect("timeout", host, method, binds)
		if not host.is_inside_tree():
			yield(host, "tree_entered")
		host.add_child(before)
	
	# 后摇动作
	func set_after(wait_time: float, method: String, binds: Array = []):
		after_time = wait_time
		after.wait_time = max(MIN_TIME, wait_time)
		after.one_shot = true
		after.autostart = false
		after.connect("timeout", host, method, binds)
		if not host.is_inside_tree():
			yield(host, "tree_entered")
		host.add_child(after)
	
	# 前摇动作
	func start_before_shake():
		# (必须加计时器时间,因为在准备施放时要至少有一帧的等待时间
		# 没有这个时间则会有方法执行顺序的问题,所以设置 MIN_TIME)
		before.start(max(before_time, MIN_TIME))
	
	# 后摇动作
	func start_after_shake():
		after.start(max(after_time, MIN_TIME))
	
	func stop():
		before.stop()
		after.stop()
	
	func stop_before_shake():
		before.stop()
	
	func stop_after_shake():
		after.stop()



#==================================================
#   技能状态
#==================================================
class SkillStatus:
	
	enum Status {
		CAN_CAST,	# 可使用
		READY,		# 开始准备施放(前摇)
		CASTING,	# 施放中
		CASTED,		# 施放后(开始后摇)
		FINISHED,	# 施放结束(开始冷却)
	}
	
	var __state__ = Status.CAN_CAST
	
	func get_state():
		return __state__
	
	func set_state(value) -> void:
		# 防止中断、停止之类的功能造成状态切换错误
		if (__state__ == Status.CAN_CAST
			and value != Status.READY
		):
			# 如果可施放时不是切换到准备状态,则 return
			# 因为“可施放”状态只能切换到“准备”状态,否则逻辑错误
			# 总不能还没准备施放就到达其他状态了
			return
		__state__ = value
	
	func is_casting():
		return __state__ == Status.CASTING
	
	func is_ready():
		return __state__ == Status.READY
	
	# 是否可以施放
	func is_can_cast():
		return __state__ == Status.CAN_CAST
	
	func is_casted():
		return __state__ == Status.CASTED
	
	# 没有在施放技能
	func is_no_cast():
		return (
			__state__ == Status.CAN_CAST
			or __state__ == Status.FINISHED
		)
	
	func ready():
		set_state(Status.READY)
	
	func cast():
		set_state(Status.CASTING)
	
	func casted():
		set_state(Status.CASTED)
	
	func finish():
		set_state(Status.FINISHED)
	
	func refresh():
		set_state(Status.CAN_CAST)

Duration.gd

施放持续性的技能

#==================================================
#	Duration.gd
#==================================================
#  持续性技能
# * 调用 control 方法进行施放
# * 扩展脚本时重写此脚本的 _process_duration 方法
#    进行添加持续性的功能
# * 调用 interrupt 方法提前中断技能,变为施放完成,和 
#    stop 方法的停止不同,stop 是强行中断正在施放的技能,
#    而 interrupt 则判定为技能已经施放完成了。
# * [ 请查看继承的 Skill.gd 的脚本的描述 ]
#==================================================
# @datetime: 2021-12-12 11:51:53
#==================================================

extends "Skill.gd"


## 开始执行持续技能
signal execute_duration


## 技能持续时间
export var duration : float = 1.0 setget set_duration


## 开始持续技能
var __executing__ : bool = false setget set_executing
## 持续时间计时器
var __duration_timer__ : Timer = Timer.new()



#==================================================
#   Set/Get
#==================================================
#(override)
func is_enabled() -> bool:
	return (.is_enabled()
		&& not __executing__
	)

##  设置持续时间
## @value  
func set_duration(value: float) -> void:
	duration = max(0.001, value)
	__duration_timer__.wait_time = duration

## 是否正在执行
func is_executing():
	return __executing__

func set_executing(value: bool):
	__executing__ = value
	set_physics_process(__executing__)



#==================================================
#   内置
#==================================================
func _ready():
	# 持续时间
	__duration_timer__.wait_time = duration
	__duration_timer__.one_shot = true
	__duration_timer__.autostart = false
	__duration_timer__.connect("timeout", self, "_duration_finished")
	self.add_child(__duration_timer__)


func _physics_process(delta):
	if __executing__:
		_process_duration(delta)



#==================================================
#   Skill 方法
#==================================================
#(override)
func _cast():
	._cast()
	__duration_timer__.stop()
	__duration_timer__.start(duration)
	__executing__ = true
	# 持续技能
	emit_signal("execute_duration")


#(override)
func _stop() -> bool:
	if ._stop():
		__duration_timer__.stop()
		__executing__ = false
		return true
	return false


#(override)
func _interrupt() -> int:
	if not __state__.is_no_cast():
		# 如果正在执行,则进行
		if __state__.is_casting():
			set_interrupt_state(Function.Skills.Signals.ExecuteDuration)
			_duration_finished()
			__duration_timer__.stop()
			__state__.casted()
			return InterruptResult.OK
		else:
			return ._interrupt()
	return InterruptResult.NO_EXECUTE


# ========================= [ 新添加 ] 

##  持续线程 
## @delta  帧时间
func _process_duration(_delta: float) -> void:
	pass


#(override)
func _executed():
	# 这个是在技能发出瞬间后进行处理的
	# 持续性施放之后的处理在 _duration_finished() 里进行
	pass


## 持续技能结束
func _duration_finished() -> void:
	__duration_timer__.stop()
	__executing__ = false
	if __refresh_timer__.is_stopped():
		__refresh_timer__.start()
	# 调用父类中的 executed (执行完成)方法 
	._executed()

func.gd

#============================================================
#	Function
#============================================================
#  Function 全局功能
# * 方便使用,不用手动输入字符串,防止出错
#============================================================
# @datetime: 2022-2-5 14:33:48
#============================================================

class_name Function
extends Reference

# ========================= [ 常量 ] 

const Skills = {
	Signals = {
		ReadyExecute = 'ready_execute',			# 准备执行功能,开始执行前摇
		ExecuteDuration = 'execute_duration',	# 前摇执行结束,执行功能
		Executed = 'executed',					# 功能执行完成,开始执行后摇
		ExecuteFinished = 'execute_finished',	# 后摇执行结束,动作完全结束
		StatusRefreshed = 'status_refreshed',	# 功能冷却完成,可再次使用
		Interrupted = "interrupted",			# 技能被中断时发出
		Stopped = 'stopped',					# 停止执行功能时发出
	},
	Propertys = {
		BeforeShake = "before_shake",
		AfterShake = 'after_shake',
		Interval = 'interval',
		Duration = 'duration',
	}
}

static func get_skill_signal_list() -> Array:
	return Skills.Signals.values()

static func get_skill_property_list() -> Array:
	return Skills.Propertys.values()

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-02-16 13:27:57  更:2022-02-16 13:29:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 16:35:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码