otherworldly_simulation/scene/test/character.gd
2024-11-01 23:23:07 +08:00

336 lines
8.5 KiB
GDScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

extends CharacterBody2D
class_name Unit
#这里暂时使用中文键debug方便调试后会更改
var action_emoji:Dictionary={
"生气":"🤯",
"愤怒":"🤬",
"指责":"👈🤯",
"伤害":"😡🔪",
"友好":"🥰",
"被指责":"😟",
"受伤":"😭💔",
"饥饿":"🍽︎",
"好吃":"😋"
}
#角色数据
@export var unit_data:Dictionary={
}
##背包数据
@export var bag_data:Array=[]
#允许的状态队列
var state_value_array:Array=["hungry","fatigue","rage","tensity","panic","pressure","hp_max","hp","atk"]
#设置状态值
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:
if state_value_name in state_value_array:
#对每种属性更改进行特殊设置
match state_value_name:
"hp":
if value<=0:
dead()
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)
func get_atk():
return get_state_value("atk")
func set_atk(value):
return set_state_value("atk",value)
##单位的独特ID
@export var unit_id:String="default"
##单位所属族群
@export var unit_type:String="default"
@export var unit_data_from_id: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
##行为感知范围
@export var sense_area:Area2D
#攻击范围
@export var attack_sense_area:Area2D
#攻击检测
@export var attack_area:Area2D
#攻击模组
var attack_scene:AttackModel
#使用数据进行初始化角色
func init_from_data():
Global.set_unit_instance(get_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)
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])
animation=new_sprite_animation
#攻击模式场景
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
Global.unit_instance_dic[get_unit_id()]=self
#改变攻击模式
func change_attack():
pass
#var hungry:float=0:
#set(val):
#hungry=val
#if %hungry!=null:
#%hungry.text="饥饿值:"+str(val)
func _ready() -> void:
init_from_data()
pass
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()
#判断单位是否再攻击范围内
func is_unit_instance_in_attack_area(instance:Node):
#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:
return false
else:
return attack_scene.is_unit_instance_in_attack_area(instance)
#指责(口角)
func accuse(unit_id:String):
show_action("指责")
var instance=Global.get_unit_instance(unit_id)
if instance is UnitOther:
instance.accused(self.get_unit_id())
pass
#被指责,调用
func accused(by_unit_id:String):
show_action("被指责")
Global.set_unit_favour(get_unit_id(),by_unit_id,Global.get_unit_favour(get_unit_id(),by_unit_id)-10)
pass
@export var attack_frames:int=2
#攻击
func attack():
#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()
#func frame_changed():
#if animation.animation in [&"up_attack",&"down_attack",&"left_right_attack"] and animation.frame==attack_frames:
#use_attack_damage()
func is_attack_finished():
#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:
return true
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()
else:
return false
##在固定帧使用攻击
#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()
func attacked(by_unit_id:String,damage:float):
show_action("受伤")
Global.set_unit_favour(get_unit_id(),by_unit_id,Global.get_unit_favour(get_unit_id(),by_unit_id)-20)
set_state_value("hp",get_state_value("hp")-damage)
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():
set_hungry(clamp(get_hungry()+1,0,100))
unit_data["position"]=[self.global_position.x,self.global_position.y]
unit_data["map"]=Global.now_map_id
pass
func eat(food:Food):
print("")
show_action("好吃")
set_hungry(clamp(get_hungry()-food.hungry,0,100))
food.eated()
pass
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(get_unit_id())
queue_free()
pass