2024-10-25 15:41:39 +08:00
|
|
|
|
extends CharacterBody2D
|
|
|
|
|
class_name Unit
|
|
|
|
|
#这里暂时使用中文键debug,方便调试,后会更改
|
|
|
|
|
var action_emoji:Dictionary={
|
|
|
|
|
"生气":"🤯",
|
|
|
|
|
"愤怒":"🤬",
|
|
|
|
|
"指责":"👈🤯",
|
|
|
|
|
"伤害":"😡🔪",
|
|
|
|
|
"友好":"🥰",
|
|
|
|
|
"被指责":"😟",
|
|
|
|
|
"受伤":"😭💔",
|
|
|
|
|
"饥饿":"🍽︎",
|
|
|
|
|
"好吃":"😋"
|
|
|
|
|
}
|
|
|
|
|
@export var unit_data:Dictionary={
|
|
|
|
|
"unit_id":"default",
|
|
|
|
|
"unit_type":"default",
|
|
|
|
|
#动画资源
|
|
|
|
|
"sprite_frames":"res://res/animation/other_character_default.tres",
|
|
|
|
|
#动画偏移
|
|
|
|
|
"sprite_offset":Vector2(0,-80),
|
|
|
|
|
#动画缩放
|
|
|
|
|
"sprite_scale":Vector2(5,5),
|
|
|
|
|
#基础属性
|
|
|
|
|
"hp_base":100,
|
|
|
|
|
"atk_base":10,
|
|
|
|
|
"speed_base":1,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#攻击方式
|
|
|
|
|
"attack_type":"base",
|
|
|
|
|
|
|
|
|
|
#下面是临时生成的动态数据
|
|
|
|
|
|
|
|
|
|
#状态值
|
|
|
|
|
#饥饿,疲劳,怒气,紧张,恐慌,压力
|
|
|
|
|
}
|
|
|
|
|
#允许的状态队列
|
2024-10-25 17:45:08 +08:00
|
|
|
|
var state_value_array:Array=["hungry","fatigue","rage","tensity","panic","pressure","hp_max","hp","atk"]
|
2024-10-25 15:41:39 +08:00
|
|
|
|
#设置状态值
|
|
|
|
|
func get_state_value(state_value_name:String):
|
|
|
|
|
if state_value_name in state_value_array:
|
|
|
|
|
return unit_data[state_value_name]
|
|
|
|
|
else:
|
|
|
|
|
return null
|
|
|
|
|
#状态值改变时发出信号
|
|
|
|
|
signal state_value_changed(state_value_name:String,value)
|
|
|
|
|
#设置状态值
|
|
|
|
|
func set_state_value(state_value_name:String,value)->bool:
|
2024-10-25 17:45:08 +08:00
|
|
|
|
|
2024-10-25 15:41:39 +08:00
|
|
|
|
if state_value_name in state_value_array:
|
2024-10-25 17:45:08 +08:00
|
|
|
|
#对每种属性更改进行特殊设置
|
|
|
|
|
match state_value_name:
|
|
|
|
|
"hp":
|
|
|
|
|
if value<=0:
|
|
|
|
|
dead()
|
2024-10-25 15:41:39 +08:00
|
|
|
|
unit_data[state_value_name]=value
|
|
|
|
|
state_value_changed.emit(state_value_name,value)
|
|
|
|
|
return true
|
|
|
|
|
else:
|
|
|
|
|
return false
|
|
|
|
|
#获取单位ID
|
|
|
|
|
func get_unit_id():
|
|
|
|
|
return unit_data["unit_id"]
|
|
|
|
|
#获取单位类型
|
|
|
|
|
func get_unit_type():
|
|
|
|
|
return unit_data["unit_type"]
|
|
|
|
|
|
|
|
|
|
#快捷获取
|
|
|
|
|
func get_hungry():
|
|
|
|
|
return get_state_value("hungry")
|
|
|
|
|
func set_hungry(value):
|
|
|
|
|
return set_state_value("hungry",value)
|
|
|
|
|
|
|
|
|
|
|
2024-10-25 17:45:08 +08:00
|
|
|
|
func get_atk():
|
|
|
|
|
return get_state_value("atk")
|
|
|
|
|
func set_atk(value):
|
|
|
|
|
return set_state_value("atk",value)
|
2024-10-25 15:41:39 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
##单位的独特ID
|
|
|
|
|
@export var unit_id:String="default"
|
|
|
|
|
##单位所属族群
|
|
|
|
|
@export var unit_type:String="default"
|
|
|
|
|
##每秒触发的timer,用于计算饥饿值积累等
|
|
|
|
|
var second_timer:Timer
|
|
|
|
|
@export var animation:AnimatedSprite2D
|
|
|
|
|
const unit_speed = 300.0
|
|
|
|
|
const JUMP_VELOCITY = -400.0
|
|
|
|
|
@export var agent: NavigationAgent2D
|
|
|
|
|
@export var state_machine: StateMachine
|
|
|
|
|
#旋转中心轴
|
|
|
|
|
@export var rotate: Node2D
|
|
|
|
|
|
|
|
|
|
##与其他单位交互的范围,目标进入此范围内才进行交互
|
|
|
|
|
@export var touch_area:Area2D
|
2024-10-26 22:17:29 +08:00
|
|
|
|
##行为感知范围
|
2024-10-25 15:41:39 +08:00
|
|
|
|
@export var sense_area:Area2D
|
2024-10-26 22:17:29 +08:00
|
|
|
|
#攻击范围
|
|
|
|
|
@export var attack_sense_area:Area2D
|
|
|
|
|
#攻击检测
|
2024-10-25 15:41:39 +08:00
|
|
|
|
@export var attack_area:Area2D
|
2024-10-26 22:17:29 +08:00
|
|
|
|
#攻击模组
|
|
|
|
|
var attack_scene:AttackModel
|
2024-10-25 15:41:39 +08:00
|
|
|
|
|
|
|
|
|
|
2024-10-26 22:17:29 +08:00
|
|
|
|
#使用数据进行初始化角色
|
|
|
|
|
func init_from_data():
|
2024-10-25 15:41:39 +08:00
|
|
|
|
Global.set_unit_instance(unit_id,self)
|
|
|
|
|
agent.max_speed=unit_speed
|
|
|
|
|
agent.velocity_computed.connect(safe_speed)
|
|
|
|
|
second_timer=Timer.new()
|
|
|
|
|
second_timer.autostart=true
|
|
|
|
|
second_timer.one_shot=false
|
|
|
|
|
second_timer.wait_time=1
|
|
|
|
|
second_timer.timeout.connect(second_timer_time_out)
|
|
|
|
|
add_child(second_timer)
|
|
|
|
|
|
|
|
|
|
var new_sprite_animation:AnimatedSprite2D=AnimatedSprite2D.new()
|
|
|
|
|
new_sprite_animation.sprite_frames=load(unit_data["sprite_frames"])
|
|
|
|
|
|
|
|
|
|
add_child(new_sprite_animation)
|
2024-10-26 22:17:29 +08:00
|
|
|
|
|
|
|
|
|
new_sprite_animation.position=Vector2(unit_data["sprite_offset"][0],unit_data["sprite_offset"][1])
|
|
|
|
|
new_sprite_animation.scale=Vector2(unit_data["sprite_scale"][0],unit_data["sprite_scale"][1])
|
2024-10-25 15:41:39 +08:00
|
|
|
|
animation=new_sprite_animation
|
2024-10-26 22:17:29 +08:00
|
|
|
|
if unit_data.has("attack_scene"):
|
|
|
|
|
if %rotate!=null:
|
|
|
|
|
var new_attack_scene=load(unit_data["attack_scene"]).instantiate()
|
|
|
|
|
%rotate.add_child(new_attack_scene)
|
|
|
|
|
attack_scene=new_attack_scene
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#var hungry:float=0:
|
|
|
|
|
#set(val):
|
|
|
|
|
#hungry=val
|
|
|
|
|
#if %hungry!=null:
|
|
|
|
|
#%hungry.text="饥饿值:"+str(val)
|
|
|
|
|
func _ready() -> void:
|
|
|
|
|
unit_data=Database.get_unit_data("test_character_ranged")
|
|
|
|
|
init_from_data()
|
|
|
|
|
pass
|
2024-10-25 15:41:39 +08:00
|
|
|
|
func set_target_pos(target:Vector2):
|
|
|
|
|
agent.target_position=target
|
|
|
|
|
|
|
|
|
|
func _physics_process(delta: float) -> void:
|
|
|
|
|
if agent!=null and not is_move_finished():
|
|
|
|
|
var current_pos:Vector2=global_position
|
|
|
|
|
var next_pos:Vector2=agent.get_next_path_position()
|
|
|
|
|
var new_velocity=current_pos.direction_to(next_pos)*unit_speed
|
|
|
|
|
if agent.avoidance_enabled:
|
|
|
|
|
agent.set_velocity(new_velocity)
|
|
|
|
|
rotate.rotation=velocity.angle()
|
|
|
|
|
else:
|
|
|
|
|
safe_speed(new_velocity)
|
|
|
|
|
rotate.rotation=velocity.angle()
|
|
|
|
|
if is_move_finished():
|
|
|
|
|
velocity=Vector2.ZERO
|
|
|
|
|
else:
|
|
|
|
|
cache_velicity=velocity
|
|
|
|
|
if animation!=null:
|
|
|
|
|
if velocity.x>0:
|
|
|
|
|
animation.flip_h=false
|
|
|
|
|
if velocity.x<0:
|
|
|
|
|
animation.flip_h=true
|
|
|
|
|
|
|
|
|
|
move_and_slide()
|
|
|
|
|
|
|
|
|
|
func safe_speed(safe_velocity):
|
|
|
|
|
velocity=safe_velocity
|
|
|
|
|
|
|
|
|
|
func stop_move():
|
|
|
|
|
set_target_pos(self.global_position)
|
|
|
|
|
|
|
|
|
|
func is_move_finished():
|
|
|
|
|
#return agent.is_target_reached()
|
|
|
|
|
return agent.is_navigation_finished()
|
|
|
|
|
|
|
|
|
|
func sent_message(type:String,value):
|
|
|
|
|
state_machine.send_message(type,value)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#判断unit实例在不在交互范围内
|
|
|
|
|
func is_unit_instance_in_touch_area(instance:Node):
|
|
|
|
|
if touch_area==null:
|
|
|
|
|
return false
|
|
|
|
|
else:
|
|
|
|
|
if instance is PhysicsBody2D:
|
|
|
|
|
return instance in touch_area.get_overlapping_bodies()
|
|
|
|
|
if instance is Area2D:
|
|
|
|
|
return instance in touch_area.get_overlapping_areas()
|
2024-10-25 17:45:08 +08:00
|
|
|
|
|
|
|
|
|
#判断单位是否再攻击范围内
|
|
|
|
|
func is_unit_instance_in_attack_area(instance:Node):
|
2024-10-26 22:17:29 +08:00
|
|
|
|
#if attack_sense_area==null:
|
|
|
|
|
#return false
|
|
|
|
|
#else:
|
|
|
|
|
#if instance is PhysicsBody2D:
|
|
|
|
|
#return instance in attack_sense_area.get_overlapping_bodies()
|
|
|
|
|
#if instance is Area2D:
|
|
|
|
|
#return instance in attack_sense_area.get_overlapping_areas()
|
|
|
|
|
#
|
|
|
|
|
#pass
|
|
|
|
|
if attack_scene==null:
|
2024-10-25 17:45:08 +08:00
|
|
|
|
return false
|
|
|
|
|
else:
|
2024-10-26 22:17:29 +08:00
|
|
|
|
return attack_scene.is_unit_instance_in_attack_area(instance)
|
2024-10-25 15:41:39 +08:00
|
|
|
|
#指责(口角)
|
|
|
|
|
func accuse(unit_id:String):
|
|
|
|
|
show_action("指责")
|
|
|
|
|
var instance=Global.get_unit_instance(unit_id)
|
|
|
|
|
if instance is UnitOther:
|
|
|
|
|
instance.accused(self.unit_id)
|
|
|
|
|
pass
|
|
|
|
|
#被指责,调用
|
|
|
|
|
func accused(by_unit_id:String):
|
|
|
|
|
show_action("被指责")
|
|
|
|
|
Global.set_unit_favour(unit_id,by_unit_id,Global.get_unit_favour(unit_id,by_unit_id)-10)
|
|
|
|
|
pass
|
|
|
|
|
@export var attack_frames:int=2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#攻击
|
|
|
|
|
func attack():
|
2024-10-26 22:17:29 +08:00
|
|
|
|
#show_action("伤害")
|
|
|
|
|
#match get_dir():
|
|
|
|
|
#0:
|
|
|
|
|
#play_animation("up_attack")
|
|
|
|
|
#1:
|
|
|
|
|
#play_animation("down_attack")
|
|
|
|
|
#2:
|
|
|
|
|
#play_animation("left_right_attack")
|
|
|
|
|
#3:
|
|
|
|
|
#play_animation("left_right_attack")
|
|
|
|
|
#pass
|
|
|
|
|
if attack_scene:
|
|
|
|
|
print("攻击")
|
|
|
|
|
attack_scene.attack()
|
2024-10-25 15:41:39 +08:00
|
|
|
|
|
2024-10-26 22:17:29 +08:00
|
|
|
|
#func frame_changed():
|
|
|
|
|
#if animation.animation in [&"up_attack",&"down_attack",&"left_right_attack"] and animation.frame==attack_frames:
|
|
|
|
|
#use_attack_damage()
|
2024-10-25 15:41:39 +08:00
|
|
|
|
func is_attack_finished():
|
2024-10-26 22:17:29 +08:00
|
|
|
|
#if animation.animation in [&"up_attack",&"down_attack",&"left_right_attack"] and not animation.is_playing():
|
|
|
|
|
#return true
|
|
|
|
|
#else:
|
|
|
|
|
#return false
|
|
|
|
|
if attack_scene is AttackModel:
|
|
|
|
|
return attack_scene.is_attack_finished()
|
|
|
|
|
else:
|
2024-10-25 15:41:39 +08:00
|
|
|
|
return true
|
2024-10-26 22:17:29 +08:00
|
|
|
|
func is_attacking():
|
|
|
|
|
#return animation.animation in [&"up_attack",&"down_attack",&"left_right_attack"] and animation.is_playing()
|
|
|
|
|
if attack_scene is AttackModel:
|
|
|
|
|
return attack_scene.is_attacking()
|
2024-10-25 15:41:39 +08:00
|
|
|
|
else:
|
|
|
|
|
return false
|
2024-10-26 22:17:29 +08:00
|
|
|
|
##在固定帧使用攻击
|
|
|
|
|
#func use_attack_damage():
|
|
|
|
|
#print("使用攻击")
|
|
|
|
|
#for i in attack_area.get_overlapping_bodies():
|
|
|
|
|
#if i is Unit and i!=self:
|
|
|
|
|
#i.attacked(unit_id,get_atk())
|
|
|
|
|
#
|
|
|
|
|
#pass
|
|
|
|
|
func attack_reset():
|
|
|
|
|
if attack_scene:
|
|
|
|
|
attack_scene.attack_reset()
|
2024-10-25 17:45:08 +08:00
|
|
|
|
func attacked(by_unit_id:String,damage:float):
|
2024-10-25 15:41:39 +08:00
|
|
|
|
show_action("受伤")
|
|
|
|
|
Global.set_unit_favour(unit_id,by_unit_id,Global.get_unit_favour(unit_id,by_unit_id)-20)
|
2024-10-25 17:45:08 +08:00
|
|
|
|
set_state_value("hp",get_state_value("hp")-damage)
|
2024-10-25 15:41:39 +08:00
|
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
func set_target(global_pos:Vector2):
|
|
|
|
|
cache_velicity=global_pos-self.global_position
|
|
|
|
|
rotate.look_at(global_pos)
|
|
|
|
|
if cache_velicity.x>0:
|
|
|
|
|
animation.flip_h=false
|
|
|
|
|
if cache_velicity.x<0:
|
|
|
|
|
animation.flip_h=true
|
|
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
func show_action(type:String):
|
|
|
|
|
print(type)
|
|
|
|
|
if action_emoji.has(type):
|
|
|
|
|
%action_show.text=action_emoji[type]
|
|
|
|
|
if %action_animation.is_playing():
|
|
|
|
|
%action_animation.stop()
|
|
|
|
|
%action_animation.play("show")
|
|
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
func play_animation(animation_name:String):
|
|
|
|
|
if animation !=null:
|
|
|
|
|
animation.play(animation_name)
|
|
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
var cache_velicity:Vector2=Vector2(1,0)
|
|
|
|
|
#0上,1下,2左,3右
|
|
|
|
|
func get_dir()->int:
|
|
|
|
|
if abs(cache_velicity.y)>abs(cache_velicity.x):
|
|
|
|
|
|
|
|
|
|
if cache_velicity.y>0:
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
if cache_velicity.x>0:
|
|
|
|
|
return 3
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
return 2
|
|
|
|
|
pass
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
func second_timer_time_out():
|
|
|
|
|
|
2024-10-25 17:45:08 +08:00
|
|
|
|
set_hungry(clamp(get_hungry()+1,0,100))
|
2024-10-25 15:41:39 +08:00
|
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
func eat(food:Food):
|
|
|
|
|
print("吃")
|
|
|
|
|
show_action("好吃")
|
|
|
|
|
set_hungry(clamp(get_hungry()-food.hungry,0,100))
|
|
|
|
|
food.eated()
|
|
|
|
|
pass
|
2024-10-25 17:45:08 +08:00
|
|
|
|
|
|
|
|
|
const DEAD_SCENE = preload("res://scene/character/dead_scene_sprite/dead_scene.tscn")
|
|
|
|
|
func dead():
|
|
|
|
|
var new_dead_scene=DEAD_SCENE.instantiate()
|
|
|
|
|
new_dead_scene.sprite_frames=animation.sprite_frames
|
|
|
|
|
new_dead_scene.global_position=animation.global_position
|
|
|
|
|
new_dead_scene.scale=animation.scale
|
|
|
|
|
get_parent().add_child(new_dead_scene)
|
|
|
|
|
Global.delete_unit_instance(unit_id)
|
|
|
|
|
queue_free()
|
|
|
|
|
pass
|