634 lines
19 KiB
GDScript
634 lines
19 KiB
GDScript
extends Characters_
|
|
|
|
onready var female = preload("res://characters/vroid1-female.tscn")
|
|
onready var male = preload("res://characters/vroid1-man.tscn")
|
|
onready var face_ctrl = preload("res://scenes/face/head_comtrol.tscn")
|
|
onready var modules = {
|
|
# "physics": load("res://scripts/modules/character_physics.gd"),
|
|
"cmdq": preload("res://scripts/modules/cmdq.gd"),
|
|
"marker": preload("res://scripts/modules/npc_marker.gd"),
|
|
"sacrifice": preload("res://scripts/modules/npc_sacrifice.gd"),
|
|
"nun": preload("res://scripts/modules/npc_nun.gd"),
|
|
"mystress": preload("res://scripts/modules/npc_mystress.gd"),
|
|
"player": preload("res://scripts/modules/player_controls.gd"),
|
|
"player_clothes": preload("res://scripts/modules/player_clothes.gd"),
|
|
"hurtboxes": preload("res://scripts/modules/character_hurtboxes.gd"),
|
|
"student": preload("res://scripts/modules/npc_student.gd"),
|
|
"bandit": preload("res://scripts/modules/npc_bandit.gd")
|
|
}
|
|
|
|
var face_data_path = "res://scenes/face/"
|
|
var hair_data_path = "res://scenes/hair/"
|
|
var female_faces = []
|
|
var mesh_female_faces = {}
|
|
var male_faces = []
|
|
var mesh_male_faces = {}
|
|
var female_hairs = []
|
|
var mesh_female_hairs = {}
|
|
var male_hairs = []
|
|
var mesh_male_hairs = {}
|
|
var hair_materials = []
|
|
var data_hair_materials = {}
|
|
|
|
var name_data = {}
|
|
var rnd
|
|
|
|
var roommates = {}
|
|
|
|
#var _crowd: DetourCrowdManager
|
|
|
|
func _ready():
|
|
var capsule_male = CapsuleShape.new()
|
|
capsule_male.radius = 0.3
|
|
capsule_male.height = 1.2
|
|
capsule_male.margin = 0.05
|
|
var capsule_female = CapsuleShape.new()
|
|
capsule_female.radius = 0.2
|
|
capsule_female.height = 1.1
|
|
capsule_female.margin = 0.05
|
|
CharacterSystemWorld.add_character_scene(female, {}, "female")
|
|
CharacterSystemWorld.add_character_scene(male, {}, "male")
|
|
for k in modules.keys():
|
|
CharacterSystemWorld.add_module(k, modules[k])
|
|
CharacterSystemWorld.set_face_ctrl_scene(face_ctrl)
|
|
CharacterSystemWorld.add_character_shape(capsule_female, Transform(Basis().rotated(Vector3(1, 0, 0), -PI/2.0), Vector3(0, 0.751, 0)), "female")
|
|
CharacterSystemWorld.add_character_shape(capsule_male, Transform(Basis().rotated(Vector3(1, 0, 0), -PI/2.0), Vector3(0, 0.899, 0)), "male")
|
|
set_root_motion_mod(Transform())
|
|
var fd = File.new()
|
|
fd.open("res://data/names.json", File.READ)
|
|
var names = fd.get_as_text()
|
|
var result = JSON.parse(names)
|
|
name_data = result.result
|
|
rnd = RandomNumberGenerator.new()
|
|
var data_fd: = File.new()
|
|
for g in ["male", "female"]:
|
|
var fp = face_data_path + g + "-face.tscn"
|
|
if data_fd.file_exists(fp):
|
|
match g:
|
|
"female":
|
|
female_faces.push_back(fp)
|
|
mesh_female_faces[fp] = load(fp)
|
|
CharacterSystemWorld.add_face_scene(mesh_female_faces[fp], "female")
|
|
|
|
"male":
|
|
male_faces.push_back(fp)
|
|
mesh_male_faces[fp] = load(fp)
|
|
CharacterSystemWorld.add_face_scene(mesh_male_faces[fp], "male")
|
|
for id in range(10000):
|
|
var fp_m = face_data_path + "male-face" + str(id) + ".tscn"
|
|
var fp_f = face_data_path + "female-face" + str(id) + ".tscn"
|
|
var hp_m = hair_data_path + "male-hair" + str(id) + ".tscn"
|
|
var hp_f = hair_data_path + "female-hair" + str(id) + ".tscn"
|
|
var mat = hair_data_path + "hair" + str(id) + ".tres"
|
|
if data_fd.file_exists(fp_m):
|
|
male_faces.push_back(fp_m)
|
|
mesh_male_faces[fp_m] = load(fp_m)
|
|
CharacterSystemWorld.add_face_scene(mesh_male_faces[fp_m], "male")
|
|
if data_fd.file_exists(fp_f):
|
|
female_faces.push_back(fp_f)
|
|
mesh_female_faces[fp_f] = load(fp_f)
|
|
CharacterSystemWorld.add_face_scene(mesh_female_faces[fp_f], "female")
|
|
if data_fd.file_exists(hp_m):
|
|
male_hairs.push_back(hp_m)
|
|
mesh_male_hairs[hp_m] = load(hp_m)
|
|
CharacterSystemWorld.add_hair_scene(mesh_male_hairs[hp_m], "male")
|
|
if data_fd.file_exists(hp_f):
|
|
female_hairs.push_back(hp_f)
|
|
mesh_female_hairs[hp_f] = load(hp_f)
|
|
CharacterSystemWorld.add_hair_scene(mesh_female_hairs[hp_f], "female")
|
|
if data_fd.file_exists(mat):
|
|
hair_materials.push_back(mat)
|
|
data_hair_materials[mat] = load(mat)
|
|
CharacterSystemWorld.add_hair_material(data_hair_materials[mat], "male")
|
|
CharacterSystemWorld.add_hair_material(data_hair_materials[mat], "female")
|
|
assert(male_faces.size() > 0)
|
|
assert(female_faces.size() > 0)
|
|
assert(male_hairs.size() > 0)
|
|
assert(female_hairs.size() > 0)
|
|
assert(hair_materials.size() > 0)
|
|
|
|
func get_relationship(obj1, obj2, s) -> int:
|
|
var stats1 = {}
|
|
var stats2 = {}
|
|
if obj1.has_meta("stats"):
|
|
stats1 = obj1.get_meta("stats")
|
|
if obj2.has_meta("stats"):
|
|
stats2 = obj2.get_meta("stats")
|
|
if !stats2.has("relationships"):
|
|
return 0
|
|
var rel = stats2.relationships
|
|
var cid = stats1.firstname + stats1.lastname
|
|
if !rel.has(cid):
|
|
return 0
|
|
var rel_data = rel[cid]
|
|
if rel_data.has(s):
|
|
return rel_data[s]
|
|
return 0
|
|
func set_relationships(obj1, obj2, s, v: int) -> void:
|
|
assert(obj1)
|
|
assert(obj2)
|
|
var stats1 = {}
|
|
var stats2 = {}
|
|
if obj1.has_meta("stats"):
|
|
stats1 = obj1.get_meta("stats")
|
|
if obj2.has_meta("stats"):
|
|
stats2 = obj2.get_meta("stats")
|
|
if !stats2.has("relationships"):
|
|
stats2.relationships = {}
|
|
var rel = stats2.relationships
|
|
var cid = stats1.firstname + stats1.lastname
|
|
if !rel.has(cid):
|
|
rel[cid] = {}
|
|
rel[cid][s] = v
|
|
print(stats2)
|
|
obj2.set_meta("stats", stats2)
|
|
func get_face_node(sc: Node) -> Node:
|
|
var face_node_paths = ["skeleton/Skeleton/head/face", "Skeleton/head/face"]
|
|
for e in face_node_paths:
|
|
if sc.has_node(e):
|
|
print("face node: ", e)
|
|
return sc.get_node(e)
|
|
assert(0)
|
|
return null
|
|
|
|
func get_hair_node(sc: Node) -> Node:
|
|
var hair_node_paths = ["skeleton/Skeleton/head/hair", "Skeleton/head/hair"]
|
|
for e in hair_node_paths:
|
|
if sc.has_node(e):
|
|
print("hair node: ", e)
|
|
return sc.get_node(e)
|
|
assert(0)
|
|
return null
|
|
func compose_kinematic_character(g, enable_modules = [], face = -1, hair = -1, hair_mat = -1):
|
|
return CharacterSystemWorld.create_character(g, enable_modules, face, hair, hair_mat)
|
|
var body = KinematicBody.new()
|
|
var cshape = CollisionShape.new()
|
|
body.add_child(cshape)
|
|
var capsule = CapsuleShape.new()
|
|
var character_data = {
|
|
"sex": g,
|
|
"modules": enable_modules
|
|
}
|
|
var face_scene: PackedScene
|
|
var hair_scene: PackedScene
|
|
var face_i: Node
|
|
var hair_i: Node
|
|
var face_node: Node
|
|
var hair_node: Node
|
|
match g:
|
|
"female":
|
|
if face == -1:
|
|
face = rnd.randi() % female_faces.size()
|
|
if hair == -1:
|
|
hair = rnd.randi() % female_hairs.size()
|
|
face_scene = mesh_female_faces[female_faces[face]]
|
|
hair_scene = mesh_female_hairs[female_hairs[hair]]
|
|
capsule.radius = 0.2
|
|
capsule.height = 1.1
|
|
capsule.margin = 0.05
|
|
cshape.translation.x = 0
|
|
cshape.translation.y = 0.751
|
|
cshape.translation.z = 0
|
|
cshape.rotation = Vector3(-PI/2.0, 0, 0)
|
|
var i = female.instance()
|
|
body.add_child(i)
|
|
i.transform = Transform()
|
|
face_node = get_face_node(i)
|
|
hair_node = get_hair_node(i)
|
|
"male":
|
|
if face == -1:
|
|
face = rnd.randi() % male_faces.size()
|
|
if hair == -1:
|
|
hair = rnd.randi() % male_hairs.size()
|
|
face_scene = mesh_male_faces[male_faces[face]]
|
|
hair_scene = mesh_male_hairs[male_hairs[hair]]
|
|
capsule.radius = 0.3
|
|
capsule.height = 1.2
|
|
capsule.margin = 0.05
|
|
cshape.translation.x = 0
|
|
cshape.translation.y = 0.899
|
|
cshape.translation.z = 0
|
|
cshape.rotation = Vector3(-PI/2.0, 0, 0)
|
|
var i = male.instance()
|
|
body.add_child(i)
|
|
i.transform = Transform()
|
|
face_node = get_face_node(i)
|
|
hair_node = get_hair_node(i)
|
|
assert(face_node)
|
|
face_i = face_scene.instance()
|
|
face_i.add_to_group("face")
|
|
prepare_extra_skeleton(face_i, "face")
|
|
hair_i = hair_scene.instance()
|
|
hair_i.add_to_group("hair")
|
|
prepare_extra_skeleton(hair_i, "hair")
|
|
if hair_mat == -1:
|
|
hair_mat = rnd.randi() % hair_materials.size()
|
|
var hmat = data_hair_materials[hair_materials[hair_mat]]
|
|
assert(hmat)
|
|
set_hair_material(hair_i, hmat)
|
|
for e in face_node.get_children():
|
|
e.queue_free()
|
|
for e in hair_node.get_children():
|
|
e.queue_free()
|
|
face_node.add_child(face_i)
|
|
hair_node.add_child(hair_i)
|
|
var face_ctrl_i = face_ctrl.instance()
|
|
face_ctrl_i.active = true
|
|
face_i.add_child(face_ctrl_i)
|
|
face_i.set_meta("body", body)
|
|
body.set_meta("face_control", face_ctrl_i)
|
|
body.set_meta("face_playback", "parameters/state/playback")
|
|
face_ctrl_i.add_to_group("face")
|
|
face_i.transform = Transform()
|
|
character_data.face = face
|
|
character_data.hair = hair
|
|
character_data.hair_mat = hair_mat
|
|
cshape.shape = capsule
|
|
body.set_meta("character_data", character_data)
|
|
for e in enable_modules:
|
|
assert(modules.has(e))
|
|
if modules.has(e):
|
|
assert(modules[e])
|
|
var obj = modules[e].new()
|
|
body.add_child(obj)
|
|
setup_character_physics(body)
|
|
body.add_to_group("character")
|
|
return body
|
|
|
|
func replace_character(obj, g, enable_modules = [], face = -1, hair = -1, hair_mat = -1):
|
|
assert(obj)
|
|
var xform = obj.global_transform
|
|
var p = obj.get_parent()
|
|
obj.queue_free()
|
|
# var body = compose_kinematic_character(g, enable_modules, face, hair, hair_mat)
|
|
var body = CharacterSystemWorld.create_character(g, enable_modules, face, hair, hair_mat)
|
|
p.add_child(body)
|
|
body.global_transform = xform
|
|
var orientation = Transform()
|
|
orientation.basis = xform.basis
|
|
body.set_meta("orientation", orientation)
|
|
return body
|
|
const basedir = "res://scenes/clothes/"
|
|
#func prepare_extra_skeleton(obj, g):
|
|
# var queue = [obj]
|
|
# while queue.size() > 0:
|
|
# var item = queue.pop_front()
|
|
# if item is Skeleton:
|
|
# item.add_to_group(g)
|
|
# break
|
|
# for g in item.get_children():
|
|
# queue.push_back(g)
|
|
func set_hair_material(hair, mat: Material):
|
|
assert(mat)
|
|
var queue = [hair]
|
|
while queue.size() > 0:
|
|
var item = queue.pop_front()
|
|
if item is MeshInstance:
|
|
item.set_surface_material(0, mat)
|
|
break
|
|
for g in item.get_children():
|
|
queue.push_back(g)
|
|
func setup_garments(obj, garments, garments_head, material):
|
|
var skel = obj.get_meta("skeleton")
|
|
assert(skel)
|
|
var hair_skel = obj.get_meta("hair_skeleton")
|
|
assert(hair_skel)
|
|
|
|
if obj.has_meta("garments"):
|
|
print("Can remove garments")
|
|
var d = obj.get_meta("garments")
|
|
var db = d.body_data
|
|
var dh = d.head_data
|
|
for e in db + dh:
|
|
print("remove: ", e)
|
|
# obj.remove_child(e)
|
|
if e.get_parent() == obj:
|
|
obj.remove_child(e)
|
|
e.queue_free()
|
|
var gdata_body = []
|
|
for g in garments:
|
|
var m: MeshInstance = MeshInstance.new()
|
|
m.name = g
|
|
print("loading: ", basedir + g + ".mesh")
|
|
var geo: ArrayMesh = load(basedir + g + ".mesh")
|
|
assert(geo)
|
|
print("mesh: ", geo, "mat: ", material)
|
|
geo.surface_set_material(0, material)
|
|
m.mesh = geo
|
|
# m.skeleton = m.get_path_to(root.get_meta("skeleton"))
|
|
# = root.get_meta("skeleton")
|
|
skel.add_child(m)
|
|
m.transform = Transform()
|
|
gdata_body.push_back(m)
|
|
var gdata_head = []
|
|
for g in garments_head:
|
|
var m: MeshInstance = MeshInstance.new()
|
|
m.name = g
|
|
var geo: ArrayMesh = load(basedir + g + ".mesh")
|
|
print("mesh: ", geo, "mat: ", material)
|
|
geo.surface_set_material(0, material)
|
|
m.mesh = geo
|
|
# m.skeleton = m.get_path_to(root.get_meta("skeleton"))
|
|
# = root.get_meta("skeleton")
|
|
hair_skel.add_child(m)
|
|
m.transform = Transform()
|
|
gdata_head.push_back(m)
|
|
var gdata = {
|
|
"body": garments,
|
|
"head": garments_head,
|
|
"material": material,
|
|
"body_data": gdata_body,
|
|
"head_data": gdata_head
|
|
}
|
|
obj.set_meta("garments", gdata)
|
|
|
|
func lastname():
|
|
var lastnames = name_data.lastname
|
|
var d = lastnames.size()
|
|
return lastnames[rnd.randi() % d].to_lower().capitalize()
|
|
|
|
func firstname(g):
|
|
var firstnames = name_data[g].firstname
|
|
var d = firstnames.size()
|
|
return firstnames[rnd.randi() % d].to_lower().capitalize()
|
|
|
|
func generate_stats(npc: Node):
|
|
var stats = npc.get_meta("stats")
|
|
var strength = 10 + rnd.randi() % 100
|
|
var max_health = 10 + rnd.randi() % 100
|
|
var max_stamina = 10 + rnd.randi() % 100
|
|
stats.tiredness = 0.0
|
|
stats.hunger = 0.0
|
|
stats.thirst = 0.0
|
|
stats.libido = 0.0
|
|
stats.toilet = 0.0
|
|
stats.stress = 0.0
|
|
stats.health = max_health
|
|
stats.stamina = max_stamina
|
|
stats.max_health = max_health
|
|
stats.max_stamina = max_stamina
|
|
stats.violence = rnd.randi() % (int(strength * 0.5))
|
|
stats.xp = 0
|
|
npc.set_meta("stats", stats)
|
|
var stat_changes = {
|
|
"sleep":{
|
|
"tiredness": -0.3,
|
|
"stress": -0.03
|
|
},
|
|
"eating": {
|
|
"hunger": -0.9,
|
|
"stress": -0.01
|
|
},
|
|
"drinking": {
|
|
"thirst": -2.8,
|
|
"stress": -0.01
|
|
},
|
|
"use_tap": {
|
|
"thirst": -2.8,
|
|
"stress": -0.01
|
|
},
|
|
"locomotion": {
|
|
"tiredness": 0.0015,
|
|
"hunger": 0.025,
|
|
"thirst": 0.045,
|
|
"stress": 0.0001,
|
|
"libido": 0.00015,
|
|
"toilet": 0.0002
|
|
}
|
|
}
|
|
func update_stats(npc: Node):
|
|
var stats = npc.get_meta("stats")
|
|
if stats.tiredness < 10.0:
|
|
if stats.stamina < stats.max_stamina:
|
|
stats.stamina += 0.1
|
|
stats.stamina = clamp(stats.stamina, 0, stats.max_stamina)
|
|
var animtree = npc.get_meta("animation_tree")
|
|
var state = animtree["parameters/state/playback"].get_current_node()
|
|
if state in stat_changes.keys():
|
|
for s in stat_changes[state].keys():
|
|
stats[s] += stat_changes[state][s]
|
|
if stats[s] < 0:
|
|
stats[s] = 0.0
|
|
npc.set_meta("stats", stats)
|
|
|
|
# Action part should be integrated into SmartObjectManager
|
|
func check_leave_smart(npc: Node):
|
|
return
|
|
if !npc.has_meta("smart_object"):
|
|
return
|
|
var sm = npc.get_meta("smart_object")
|
|
var new_goal = calculate_goal(npc)
|
|
if !sm.is_in_group(new_goal):
|
|
# var animtree = npc.get_meta("animation_tree")
|
|
# animtree["parameters/state/playback"].travel("locomotion")
|
|
npc.remove_meta("smart_object")
|
|
|
|
func calculate_goal(npc: Node):
|
|
var utility = {
|
|
"sleep": ["tiredness", 900],
|
|
"hungry": ["hunger", 1000],
|
|
"thirsty": ["thirst", 1300],
|
|
"relieve_stress": ["stress", 800],
|
|
"have_sex": ["libido", 500],
|
|
"idle": ["", 600]
|
|
}
|
|
var stats = npc.get_meta("stats")
|
|
var rutility = -10000
|
|
var goal = "idle"
|
|
var last_goal = ""
|
|
var last_utility = -1
|
|
if npc.has_meta("last_goal"):
|
|
last_goal = npc.get_meta("last_goal")
|
|
goal = npc.get_meta("last_goal")
|
|
if npc.has_meta("last_utility"):
|
|
last_utility = int(npc.get_meta("last_utility"))
|
|
rutility = int(npc.get_meta("last_utility") * 2.0)
|
|
for k in utility.keys():
|
|
var st = 1.0
|
|
if utility[k][0] != "":
|
|
st = stats[utility[k][0]]
|
|
var mul = utility[k][1]
|
|
var cutil = int(st * mul)
|
|
if rutility < cutil:
|
|
rutility = cutil
|
|
goal = k
|
|
npc.set_meta("last_goal", goal)
|
|
if goal == last_goal:
|
|
npc.set_meta("last_utility", last_utility)
|
|
else:
|
|
npc.set_meta("last_utility", rutility)
|
|
|
|
return goal
|
|
|
|
var cooldown = 0.0
|
|
|
|
var close_groups = {}
|
|
|
|
func walkto_(npc, target):
|
|
assert(npc.has_meta("agent_id"))
|
|
if npc.has_mete("agent_id"):
|
|
walkto_agent(npc, target)
|
|
# if npc.has_meta("_target"):
|
|
# var otarget = npc.get_meta("_target")
|
|
# if target == otarget:
|
|
# return
|
|
# assert(npc.has_meta("agent_id"))
|
|
# npc.set_meta("_target", target)
|
|
## print("walk to ", target)
|
|
## print("walk to ", target)
|
|
## print("walk to ", target)
|
|
# var agent_id = npc.get_meta("agent_id")
|
|
# if target is Spatial:
|
|
# get_crowd().set_agent_target_position(agent_id, target.global_transform.origin)
|
|
# elif target is Vector3:
|
|
# get_crowd().set_agent_target_position(agent_id, target)
|
|
|
|
#func update_to_agent(root):
|
|
# if !_crowd:
|
|
# return
|
|
# if !root.has_meta("agent_id"):
|
|
# _crowd.add_agent(root, 0, false, PoolRealArray([0.2, 1.5, 0.3, 3.0]))
|
|
# if !root.has_meta("agent_id"):
|
|
# return
|
|
# if !root.has_meta("_target"):
|
|
# return
|
|
# var velocity = root.get_meta("agent_velocity")
|
|
# if velocity.length() == 0:
|
|
# characters.set_walk_speed(root, 0, 0)
|
|
# else:
|
|
## print("agent_velocity=", velocity)
|
|
# var vel1 = velocity
|
|
# vel1.y = 0
|
|
# var xform: = Transform().looking_at(vel1, Vector3.UP)
|
|
# xform = xform.orthonormalized()
|
|
# var orientation = root.get_meta("orientation")
|
|
# orientation.basis = orientation.basis.slerp(xform.basis, get_physics_process_delta_time())
|
|
# root.set_meta("orientation", orientation)
|
|
# characters.set_walk_speed(root, clamp(vel1.length() / 6.5, 0.0, 1.0), 0)
|
|
#
|
|
#func character_physics(root):
|
|
# var delta = get_physics_process_delta_time()
|
|
# var animtree = root.get_meta("animation_tree")
|
|
# var orientation = root.get_meta("orientation")
|
|
# var root_motion = animtree.get_root_motion_transform()
|
|
# orientation *= root_motion
|
|
# var h_velocity = orientation.origin / delta
|
|
# var velocity: = Vector3()
|
|
# velocity.x = h_velocity.x
|
|
# velocity.z = h_velocity.z
|
|
# velocity.y = h_velocity.y
|
|
## if root.has_meta("climb"):
|
|
## print("has climb meta")
|
|
## if root.has_meta("cmdqueue"):
|
|
## print("+has cmdqueue")
|
|
# if !root.has_meta("vehicle") && !root.has_meta("cmdqueue"):
|
|
# if root is KinematicBody:
|
|
# if !root.is_on_floor():
|
|
# velocity += Vector3(0, -9.8, 0)
|
|
# velocity = root.move_and_slide(velocity, Vector3.UP, true, 4, 0.785, false)
|
|
# elif root.has_meta("cmdqueue") && root.has_meta("cmdq_walk"):
|
|
# if root is KinematicBody:
|
|
# if !root.is_on_floor() && !root.has_meta("climb"):
|
|
# velocity += Vector3(0, -9.8, 0)
|
|
# velocity = root.move_and_slide(velocity, Vector3.UP, true, 4, 0.785, false)
|
|
# elif root.has_meta("cmdqueue") && root.has_meta("climb"):
|
|
# if root is KinematicBody:
|
|
# velocity.y = h_velocity.y
|
|
# velocity = root.move_and_slide(velocity, Vector3.UP, true, 4, 0.785, false)
|
|
# orientation.origin = Vector3()
|
|
# orientation = orientation.orthonormalized()
|
|
# root.global_transform.basis = orientation.basis
|
|
# root.set_meta("orientation", orientation)
|
|
# if root.has_meta("vehicle"):
|
|
# var vehicle: VehicleBody = get_meta("vehicle")
|
|
# if has_meta("vehicle_offset"):
|
|
# var xform = get_meta("vehicle_offset")
|
|
# root.global_transform = vehicle.global_transform * xform
|
|
# if root.has_node("blackboard"):
|
|
# var bb = root.get_node("blackboard")
|
|
# bb.set("velocity", velocity)
|
|
# update_to_agent(root)
|
|
|
|
func check_main_animtree(item):
|
|
if !item is AnimationTree:
|
|
return false
|
|
for g in ["hair", "face"]:
|
|
if item.is_in_group(g):
|
|
return false
|
|
return true
|
|
|
|
func check_main_skeleton(item):
|
|
if !item is Skeleton:
|
|
return false
|
|
for g in ["hair", "face"]:
|
|
if item.is_in_group(g):
|
|
return false
|
|
return true
|
|
|
|
func setup_character_physics(root):
|
|
var queue = [root]
|
|
while queue.size() > 0:
|
|
var item = queue.pop_front()
|
|
if check_main_animtree(item):
|
|
root.set_meta("animation_tree", item)
|
|
if check_main_skeleton(item):
|
|
root.set_meta("skeleton", item)
|
|
if item is Skeleton && item.is_in_group("hair"):
|
|
root.set_meta("hair_skeleton", item)
|
|
if item is Skeleton && item.is_in_group("face"):
|
|
root.set_meta("face_skeleton", item)
|
|
for e in item.get_children():
|
|
queue.push_back(e)
|
|
# var velocity = Vector3()
|
|
var orientation = Transform()
|
|
if root.is_inside_tree():
|
|
orientation = root.global_transform
|
|
orientation.origin = Vector3()
|
|
root.set_meta("orientation", orientation)
|
|
|
|
func _process(delta):
|
|
if cooldown > 0.0:
|
|
cooldown -= delta
|
|
return
|
|
for e in get_tree().get_nodes_in_group("character"):
|
|
var gr = []
|
|
for o in get_tree().get_nodes_in_group("character"):
|
|
if e == o:
|
|
continue
|
|
var e_org = e.global_transform.origin
|
|
var o_org = o.global_transform.origin
|
|
if e_org.distance_to(o_org) < 1.2:
|
|
gr.push_back(o)
|
|
close_groups[e] = gr
|
|
if e.has_meta("animation_tree"):
|
|
var animtree = e.get_meta("animation_tree")
|
|
var state = animtree["parameters/state/playback"].get_current_node()
|
|
var face_playback = e.get_meta("face_playback")
|
|
var face_ctrl = e.get_meta("face_control")
|
|
var p = face_ctrl[face_playback]
|
|
if state == "sleeping":
|
|
if p.get_current_node() != "sleeping":
|
|
p.travel("sleeping")
|
|
else:
|
|
if p.get_current_node() != "locomotion":
|
|
p.travel("locomotion")
|
|
cooldown = 0.2
|
|
func get_player():
|
|
var c = get_viewport().get_camera()
|
|
if !c:
|
|
return null
|
|
if !c.has_meta("player"):
|
|
return null
|
|
var player = c.get_meta("player")
|
|
if !player:
|
|
return null
|
|
return player
|
|
|
|
func _physics_process(delta):
|
|
var player = get_player()
|
|
if !player:
|
|
return
|
|
if player.has_meta("animation_tree") && !player.has_meta("vehicle"):
|
|
if streaming.can_spawn:
|
|
character_physics(player)
|