giants-godot/entities/character.gd

288 lines
7.0 KiB
GDScript3
Raw Normal View History

2021-09-22 18:04:03 +02:00
extends KinematicBody
2021-09-08 18:36:41 +02:00
class_name Character
enum States {
Alive,
Dead
}
2021-09-22 18:04:03 +02:00
enum GroundType {
DIRT,
WATER,
2021-10-01 15:50:16 +02:00
WOOD,
METAL,
SAND,
GRASS
2021-09-22 18:04:03 +02:00
}
2021-10-01 15:50:16 +02:00
signal health_changed
signal died
signal changed_weapon
signal fired(projectile)
signal pickup_weapon
signal jumped
2021-09-22 18:04:03 +02:00
export var max_weapons: int = 5
2021-09-23 21:19:11 +02:00
var weapons: Array = []
var current_weapon: Weapon
2021-09-22 18:04:03 +02:00
var is_in_water: bool = false
2021-09-23 21:19:11 +02:00
export var weapon_refpt_right: NodePath
export var weapon_refpt_left: NodePath
export var water_splash_sound: AudioStreamSample
var animation_blend_vector = Vector2.ZERO
export var animation_tree_path: NodePath
var animation_tree: AnimationTree
2021-10-15 23:42:06 +02:00
export var back_camera_path: NodePath
onready var back_camera = get_node(back_camera_path)
export var head_path: NodePath
2021-10-19 00:20:29 +02:00
onready var head: Spatial = get_node(head_path)
var marker: MeshInstance
2021-09-23 21:19:11 +02:00
# Move
var velocity := Vector3()
var move_axis: Vector3 = Vector3.ZERO
var can_sprint := true
var sprinting := false
const FLOOR_NORMAL := Vector3.UP
export var sprint_speed := 16.0
export var acceleration := 8
export var deacceleration := 6
2021-10-01 15:50:16 +02:00
export(float, 0.0, 1.0, 0.00001) var air_control := 0.001
export var can_jump = true
2021-09-23 21:19:11 +02:00
export var jump_height := 5
2021-10-01 15:50:16 +02:00
export var floor_max_angle := 90.0
2021-09-23 21:19:11 +02:00
export var gravity: float = 40.0
export var walk_speed: float = 2.0
2021-10-01 15:50:16 +02:00
export var ground_friction: float = 3.0
2021-10-15 23:42:06 +02:00
export var animation_blend_speed: float = 10
var ground_snap = Vector3.DOWN
2021-10-19 00:20:29 +02:00
export var has_marker: bool = false
2021-09-22 18:04:03 +02:00
var ground_type = GroundType.DIRT
2021-10-01 15:50:16 +02:00
var footstep_sounds = {}
2021-09-22 18:04:03 +02:00
2021-10-12 23:11:23 +02:00
export var max_health = 100
2021-09-22 18:04:03 +02:00
export var health = 100
var state = States.Alive
var shoot_delay: float = 0
2021-09-22 18:04:03 +02:00
func has_weapon(weapon: Weapon) -> bool:
if get_similar_weapon(weapon):
return true
else:
return false
func get_similar_weapon(weapon: Weapon) -> Weapon:
for weap in weapons:
if weap.name == weapon.name:
return weap
return null
2021-09-08 18:36:41 +02:00
2021-09-22 18:04:03 +02:00
func can_pickup_weapon(weapon: Weapon) -> bool:
return has_weapon(weapon) or len(weapons) < max_weapons
2021-10-19 00:20:29 +02:00
func can_see(other_character: Character) -> bool:
var ray = RayCast.new()
ray.translation = head.translation
ray.cast_to(other_character.head)
var collider = ray.get_collider()
return collider == other_character.head
2021-09-08 18:36:41 +02:00
func can_shoot_delay() -> bool:
# returns true if the character has not shot a bullet recently
return shoot_delay <= 0
2021-09-23 21:19:11 +02:00
func pickup_weapon(weapon: Weapon) -> Weapon:
2021-09-22 18:04:03 +02:00
var similar = get_similar_weapon(weapon)
if similar:
similar.current_ammo = clamp(similar.current_ammo + weapon.current_ammo, 0, weapon.max_ammo)
2021-09-23 21:19:11 +02:00
return similar
2021-09-22 18:04:03 +02:00
else:
2021-09-23 21:19:11 +02:00
# add new weapon
2021-09-22 18:04:03 +02:00
weapons.append(weapon)
2021-09-23 21:19:11 +02:00
weapon.holder = self
weapon.visible = false
if weapon.held_hand == Weapon.WeaponHeld.Left:
get_node(weapon_refpt_left).add_child(weapon)
else:
get_node(weapon_refpt_right).add_child(weapon)
return weapon
2021-09-22 18:04:03 +02:00
func take_damage(hitpts: float):
2021-10-12 23:11:23 +02:00
if state == States.Alive:
health -= hitpts
emit_signal("health_changed")
if health <= 0:
die()
2021-09-22 18:04:03 +02:00
2021-09-23 21:19:11 +02:00
func get_current_weapon():
return current_weapon
2021-09-22 18:04:03 +02:00
func die():
state = States.Dead
2021-10-01 15:50:16 +02:00
emit_signal("died")
2021-10-12 23:11:23 +02:00
print("Me ded")
2021-09-23 21:19:11 +02:00
func set_weapon_slot(slot: int):
if current_weapon:
current_weapon.visible = false
current_weapon.disconnect("fired", self, "weapon_fired")
2021-09-23 21:19:11 +02:00
var newweapon = weapons[slot]
current_weapon = newweapon
current_weapon.visible = true
current_weapon.play_switch_sound()
current_weapon.connect("fired", self, "weapon_fired")
2021-09-08 18:36:41 +02:00
2021-09-22 18:04:03 +02:00
func play_footstep():
2021-10-01 15:50:16 +02:00
if ground_type in footstep_sounds:
var sound = footstep_sounds[ground_type][randi() % len(footstep_sounds[ground_type])]
Globals.play_sound(sound, Globals.Bus.Sounds, self)
2021-09-23 21:19:11 +02:00
func get_current_weapon_slot():
return get_weapon_slot(current_weapon)
func get_weapon_slot(weapon: Weapon):
var i = 0
for weap in weapons:
if weap == weapon:
return i
i+=1
return i
func create_weapon(weapon_scene: PackedScene):
var weapon = weapon_scene.instance()
if weapon is Weapon:
return weapon
else:
weapon.queue_free()
return null
func get_next_weapon_slot():
var current = get_current_weapon_slot()
if current + 1 < len(weapons):
return current + 1
else:
return 0
2021-09-23 21:19:11 +02:00
func switch_next_weapon_slot():
var next_slot = get_next_weapon_slot()
if next_slot == get_current_weapon_slot():
return
set_weapon_slot(next_slot)
2021-09-23 21:19:11 +02:00
func enter_water(force: float):
is_in_water = true
2021-10-01 15:50:16 +02:00
ground_type = GroundType.WATER
2021-09-23 21:19:11 +02:00
if abs(force) >= 50:
Globals.play_sound(water_splash_sound, Globals.Bus.Sounds, self)
func exit_water(force: float):
is_in_water = false
2021-10-01 15:50:16 +02:00
ground_type = GroundType.GRASS
2021-09-23 21:19:11 +02:00
func _ready():
if animation_tree_path:
animation_tree = get_node(animation_tree_path)
2021-10-19 00:20:29 +02:00
if has_marker:
marker = preload("res://ui/player_marker.tscn").instance()
head.add_child(marker)
marker.transform.origin = Vector3(0, 0.337, 0)
marker.mesh.size = Vector2.ONE * 5
func _process(delta):
if shoot_delay > 0:
shoot_delay -= delta
2021-09-23 21:19:11 +02:00
func _physics_process(delta):
if Engine.editor_hint:
return
walk(delta)
if not animation_tree:
return
2021-10-15 23:42:06 +02:00
2021-09-23 21:19:11 +02:00
# Blend nicely between animations
2021-10-15 23:42:06 +02:00
var anim_vector = Vector2(move_axis.y, move_axis.x)
var res = animation_blend_vector.linear_interpolate(anim_vector, delta*animation_blend_speed)
2021-09-23 21:19:11 +02:00
animation_tree.set("parameters/movement/blend_position", res)
animation_blend_vector = res
func fire_pressed():
if current_weapon and can_shoot_delay():
2021-10-15 23:42:06 +02:00
current_weapon.activate(Globals.target_position["position"])
2021-09-23 21:19:11 +02:00
func fire_released():
2021-10-15 23:42:06 +02:00
if current_weapon:
current_weapon.deactivate(Globals.target_position["position"])
func jump():
if can_jump and is_on_floor():
velocity.y = jump_height
emit_signal("jumped")
func set_sprint(sprint_state: bool):
2021-10-15 23:42:06 +02:00
if can_sprint:
sprinting = sprint_state
func weapon_fired():
shoot_delay = current_weapon.repeat_time
2021-09-23 21:19:11 +02:00
func walk(delta: float) -> void:
# Input
var direction = Vector3()
var aim: Basis = get_global_transform().basis
if move_axis.x >= 0.5:
direction -= aim.z
if move_axis.x <= -0.5:
direction += aim.z
if move_axis.y <= -0.5:
direction -= aim.x
if move_axis.y >= 0.5:
direction += aim.x
direction.y = 0
direction = direction.normalized()
# Apply Gravity
velocity.y -= gravity * delta
# if is_in_water:
# velocity.y = 0
# Sprint
var _speed: float
2021-10-15 23:42:06 +02:00
if sprinting:
# if can_sprint and move_axis.x == 1:
2021-09-23 21:19:11 +02:00
_speed = sprint_speed
else:
_speed = walk_speed
# Acceleration and Deacceleration
# where would the player go
var _temp_vel: Vector3 = velocity
_temp_vel.y = 0
var _target: Vector3 = direction * _speed
var _temp_accel: float
if direction.dot(_temp_vel) > 0:
_temp_accel = acceleration
else:
_temp_accel = deacceleration
if not is_on_floor():
_temp_accel *= air_control
# interpolation
_temp_vel = _temp_vel.linear_interpolate(_target, _temp_accel * delta)
velocity.x = _temp_vel.x
velocity.z = _temp_vel.z
# clamping (to stop on slopes)
if direction.dot(velocity) == 0:
2021-10-01 15:50:16 +02:00
var _vel_clamp := 1
2021-09-23 21:19:11 +02:00
if velocity.x < _vel_clamp and velocity.x > -_vel_clamp:
velocity.x = 0
if velocity.z < _vel_clamp and velocity.z > -_vel_clamp:
velocity.z = 0
# Move
2021-10-01 15:50:16 +02:00
velocity = move_and_slide(velocity, FLOOR_NORMAL, true, 4, deg2rad(floor_max_angle))
# velocity.y = move_and_slide_with_snap(velocity, _snap, FLOOR_NORMAL, true, 4, deg2rad(floor_max_angle)).y