oh my god let's try this again
This commit is contained in:
179
scripts/Character_Hazmat.gd
Normal file
179
scripts/Character_Hazmat.gd
Normal file
@@ -0,0 +1,179 @@
|
||||
extends CharacterBody3D
|
||||
|
||||
var gravity : float = ProjectSettings.get_setting("physics/3d/default_gravity")
|
||||
|
||||
var grabbable : bool = false
|
||||
var shootable : bool = true
|
||||
var weakpoint : bool = false
|
||||
var rootnode : bool = true
|
||||
var waitingfor : int = 0
|
||||
|
||||
@export var HP : float = 3
|
||||
@export var weakpoint_damage : float = 5.0
|
||||
@export var runner : bool = false
|
||||
@export var physics_push_force : float = 1.5
|
||||
|
||||
var movement_speed: float = 8.0
|
||||
var movement_delta: float
|
||||
var path_point_margin: float = 1
|
||||
|
||||
var current_path_index: int = 0
|
||||
var current_path_point: Vector3
|
||||
var current_path: PackedVector3Array
|
||||
@onready var default_3d_map_rid: RID = get_world_3d().get_navigation_map()
|
||||
var startpos : Vector3
|
||||
var forth : bool = false
|
||||
|
||||
var headoffset : Vector3
|
||||
var headbone : int
|
||||
|
||||
var pissed : bool = false
|
||||
@export var min_player_distance : float = 4.0
|
||||
@export var min_ally_distance : float = 6.0
|
||||
var runtarget : Vector3
|
||||
@export var player : Node
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
headoffset = Vector3(0,0.2,0)
|
||||
headbone = $CharacterArmature/Skeleton3D.find_bone("Head")
|
||||
|
||||
$CharacterArmature.rotation_degrees.y = 180
|
||||
|
||||
rotation_degrees.y += 180
|
||||
|
||||
player.enemies.append(self)
|
||||
|
||||
$AnimationPlayer.play("Idle")
|
||||
|
||||
pissed = true
|
||||
|
||||
|
||||
|
||||
func _physics_process(delta):
|
||||
if pissed and player.global_transform.origin.distance_to(runtarget) > 4:
|
||||
runtarget = player.global_transform.origin
|
||||
|
||||
if current_path.is_empty() and NavigationServer3D.map_is_active(default_3d_map_rid):
|
||||
if runner:
|
||||
set_movement_target($waypoint.global_transform.origin)
|
||||
elif pissed and global_transform.origin.distance_to(runtarget) > 4:
|
||||
set_movement_target(runtarget)
|
||||
$chase_timer.start(1.5)
|
||||
|
||||
move_and_slide()
|
||||
|
||||
for i in get_slide_collision_count():
|
||||
var slaminto = get_slide_collision(i)
|
||||
if slaminto.get_collider() is RigidBody3D:
|
||||
slaminto.get_collider().apply_central_impulse(-slaminto.get_normal() * physics_push_force)
|
||||
|
||||
if !current_path.is_empty():
|
||||
if !runner and global_transform.origin.distance_to(player.global_transform.origin) <= min_player_distance:
|
||||
clearpath()
|
||||
$chase_timer.start(1.5)
|
||||
|
||||
if global_transform.origin.distance_to(current_path_point) <= path_point_margin:
|
||||
current_path_index += 1
|
||||
if current_path_index >= current_path.size():
|
||||
clearpath()
|
||||
if runner:
|
||||
if !forth:
|
||||
set_movement_target(startpos)
|
||||
forth = true
|
||||
elif forth:
|
||||
set_movement_target($waypoint.global_transform.origin)
|
||||
forth = false
|
||||
else:
|
||||
$chase_timer.start(1.5)
|
||||
|
||||
"""for bud in player.enemies:
|
||||
if bud.get_instance_id() != get_instance_id() and bud.global_position.distance_to(global_position) <= min_ally_distance and bud.global_position.distance_to(player.global_position) < global_position.distance_to(player.global_position):
|
||||
clearpath()
|
||||
$queue_timer.start(3)"""
|
||||
|
||||
if !current_path.is_empty() and HP > 0:
|
||||
$Head.position = headoffset + $CharacterArmature/Skeleton3D.get_bone_global_pose(headbone).origin
|
||||
|
||||
if len(current_path) > 0:
|
||||
current_path_point = current_path[current_path_index]
|
||||
|
||||
var direction = global_transform.origin.direction_to(current_path_point)
|
||||
var acceleration = 8.0
|
||||
|
||||
velocity.x = lerp(velocity.x, direction.x * movement_speed, acceleration * delta)
|
||||
velocity.z = lerp(velocity.z, direction.z * movement_speed, acceleration * delta)
|
||||
|
||||
global_transform = global_transform.interpolate_with(global_transform.looking_at(Vector3(current_path_point.x,global_position.y,current_path_point.z)), 0.2)
|
||||
|
||||
elif current_path.is_empty() or waitingfor != 0:
|
||||
velocity.x = 0
|
||||
velocity.z = 0
|
||||
|
||||
if HP > 0:
|
||||
var velocityclamp = 0.25
|
||||
if abs(velocity.x) + abs(velocity.z) > (velocityclamp * 2):
|
||||
$AnimationPlayer.play("Run")
|
||||
else:
|
||||
$AnimationPlayer.play("Idle")
|
||||
else:
|
||||
velocity = Vector3(0,0,0)
|
||||
|
||||
if not is_on_floor():
|
||||
velocity.y -= gravity * delta
|
||||
|
||||
|
||||
func deal_damage(damage):
|
||||
print(str(damage)+" damage taken, "+str(HP)+" HP left")
|
||||
HP = HP - damage
|
||||
if HP <= 0:
|
||||
print("death")
|
||||
$AnimationPlayer.play("Death")
|
||||
|
||||
|
||||
func set_movement_target(target_position: Vector3):
|
||||
var start_position: Vector3 = global_transform.origin
|
||||
|
||||
current_path = NavigationServer3D.map_get_path(
|
||||
default_3d_map_rid,
|
||||
start_position,
|
||||
target_position,
|
||||
true
|
||||
)
|
||||
|
||||
if not current_path.is_empty():
|
||||
current_path_index = 0
|
||||
current_path_point = current_path[0]
|
||||
|
||||
func clearpath():
|
||||
current_path = []
|
||||
current_path_index = 0
|
||||
current_path_point = global_transform.origin
|
||||
|
||||
func _on_animation_player_animation_finished(anim_name):
|
||||
if anim_name == "Idle":
|
||||
$AnimationPlayer.play("Idle")
|
||||
if anim_name == "Run":
|
||||
$AnimationPlayer.play("Run")
|
||||
if anim_name == "Death":
|
||||
delete_me()
|
||||
"""set_collision_layer_value(1, false)
|
||||
$Head.set_collision_layer_value(1, false)"""
|
||||
|
||||
func delete_me():
|
||||
player.enemies.erase(self)
|
||||
get_parent().remove_child(self)
|
||||
queue_free()
|
||||
|
||||
func _on_chase_timer_timeout():
|
||||
if player.global_transform.origin.distance_to(runtarget) > 4:
|
||||
runtarget = player.global_transform.origin
|
||||
if global_transform.origin.distance_to(runtarget) > 4:
|
||||
set_movement_target(runtarget)
|
||||
print("updating runtarget to "+str(runtarget))
|
||||
$chase_timer.start(1.5)
|
||||
|
||||
|
||||
func _on_queue_timer_timeout():
|
||||
$queue_timer.stop()
|
||||
_on_chase_timer_timeout()
|
||||
1
scripts/Character_Hazmat.gd.uid
Normal file
1
scripts/Character_Hazmat.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dgpehgcv4487d
|
||||
437
scripts/character.gd
Normal file
437
scripts/character.gd
Normal file
@@ -0,0 +1,437 @@
|
||||
extends CharacterBody3D
|
||||
|
||||
# TODO: Add descriptions for each value
|
||||
|
||||
@export_category("Character")
|
||||
|
||||
@export var start_rotation : float = 0
|
||||
var start_rotated : bool = false
|
||||
|
||||
@export var max_health : float = 100.0
|
||||
var hp : float
|
||||
|
||||
var playerallied : bool = true
|
||||
|
||||
var currentgun : String = "pistol"
|
||||
|
||||
@export var base_speed : float = 10.0
|
||||
@export var sprint_speed : float = 6.0
|
||||
@export var crouch_speed : float = 6.0
|
||||
|
||||
@export var acceleration : float = 10.0
|
||||
@export var jump_velocity : float = 6.0
|
||||
@export var mouse_sensitivity : float = 0.1
|
||||
|
||||
@export var walljump_cooldown : float = 0.75
|
||||
@export var wallbounce_multiplier : float = 0.3
|
||||
|
||||
@export var aircontrol_multiplier : float = 0.5
|
||||
@export var aircontrol_delay : float = 0.5
|
||||
|
||||
@export var coyotetime : float = 0.3
|
||||
var coyotechance : bool = false
|
||||
|
||||
@export var dash_cooldown : float = 2.0
|
||||
@export var dash_speedmultiplier : float = 3.0
|
||||
@export var dash_distance : float = 5.0
|
||||
var dash_spent : bool = false
|
||||
var dash_active : bool = false
|
||||
var dash_startpos : Vector3 = Vector3(0, 0, 0)
|
||||
|
||||
@export var physics_push_force : float = 1.0
|
||||
|
||||
var holding_object : bool = false
|
||||
var held_object : RigidBody3D
|
||||
@export var object_hurl_force : float = 40.0
|
||||
@export var object_grab_distance : float = 8.0
|
||||
@export var object_hold_height : float = 1.0
|
||||
|
||||
@export var gun_damage : float = 6
|
||||
@export var gun_firedelay : float = 0.2
|
||||
@export var gun_physics_nudge_multiplier : float = 5
|
||||
|
||||
var stomping : bool = false
|
||||
var stomp_startingheight : float
|
||||
var stomp_speed : float = 25
|
||||
var stomp_radius : float = 6
|
||||
var stomp_radiusthreshold : float = 2
|
||||
var stomp_radiusincrement : float = 1
|
||||
var stomp_maxradius : float = 12
|
||||
var stomp_damagepermeter : float = 3
|
||||
var stomp_mindamage : float = 4
|
||||
var stomp_maxdamage : float = 16
|
||||
|
||||
@export_group("Nodes")
|
||||
@export var HEAD : Node3D
|
||||
@export var CAMERA : Camera3D
|
||||
@export var CAMERA_ANIMATION : AnimationPlayer
|
||||
|
||||
@export_group("Controls")
|
||||
# We are using UI controls because they are built into Godot Engine so they can be used right away
|
||||
@export var JUMP : String = "move_jump"
|
||||
@export var LEFT : String = "move_left"
|
||||
@export var RIGHT : String = "move_right"
|
||||
@export var FORWARD : String = "move_forward"
|
||||
@export var BACKWARD : String = "move_backward"
|
||||
@export var PAUSE : String = "ui_cancel"
|
||||
@export var CROUCH : String = "move_crouch"
|
||||
@export var DASH : String = "move_dash"
|
||||
@export var TELEK : String = "action_telekinesis"
|
||||
@export var SHOOT : String = "action_shoot"
|
||||
|
||||
@export var SPRINT : String
|
||||
|
||||
@export_group("Feature Settings")
|
||||
@export var immobile : bool = false
|
||||
@export var jumping_enabled : bool = true
|
||||
@export var in_air_momentum : bool = true
|
||||
@export var motion_smoothing : bool = true
|
||||
@export var sprint_enabled : bool = false
|
||||
@export var crouch_enabled : bool = true
|
||||
@export_enum("Hold to Crouch", "Toggle Crouch") var crouch_mode : int = 0
|
||||
@export_enum("Hold to Sprint", "Toggle Sprint") var sprint_mode : int = 0
|
||||
@export var dynamic_fov : bool = false
|
||||
@export var continuous_jumping : bool = false
|
||||
@export var view_bobbing : bool = false
|
||||
|
||||
# Member variables
|
||||
var speed : float = base_speed
|
||||
var is_crouching : bool = false
|
||||
var is_sprinting : bool = false
|
||||
var walljump_ready : bool = true
|
||||
|
||||
var enemies : Array[Node] = []
|
||||
|
||||
# Get the gravity from the project settings to be synced with RigidBody nodes
|
||||
var gravity : float = ProjectSettings.get_setting("physics/3d/default_gravity") # Don't set this as a const, see the gravity section in _physics_process
|
||||
|
||||
const tex_pistol_neutral = preload("res://sprites/fpguns/pistol_neutral.png")
|
||||
const tex_pistol_recoil = preload("res://sprites/fpguns/pistol_recoil.png")
|
||||
const tex_telehand_grip = preload("res://sprites/fpguns/telehand_grip.png")
|
||||
const tex_telehand_pull = preload("res://sprites/fpguns/telehand_pull.png")
|
||||
const tex_telehand_throw = preload("res://sprites/fpguns/telehand_throw.png")
|
||||
|
||||
func _ready():
|
||||
HEAD = $Head
|
||||
CAMERA = $Head/Camera
|
||||
CAMERA_ANIMATION = $Head/camera_animation
|
||||
|
||||
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||
|
||||
$Head/Camera/Ray.target_position.z -= 1024
|
||||
$Head/TelekinesisPoint.position.z -= object_grab_distance / 2
|
||||
$Head/TelekinesisPoint.position.y += object_hold_height
|
||||
|
||||
hp = max_health
|
||||
|
||||
$UserInterface/Telehand.visible = false
|
||||
|
||||
$stomparea.scale = Vector3(stomp_radius, stomp_radius, stomp_radius)
|
||||
|
||||
|
||||
func _physics_process(delta):
|
||||
if Input.is_action_just_pressed("exit"):
|
||||
get_tree().quit()
|
||||
|
||||
$UserInterface/HUDContainer/HUDText.update(self,$walljump_timer,$dash_timer)
|
||||
|
||||
if !start_rotated:
|
||||
HEAD.rotation_degrees.y += start_rotation
|
||||
start_rotated = true
|
||||
|
||||
# Add some debug data
|
||||
$UserInterface/DebugPanel.add_property("Movement Speed", speed, 1)
|
||||
$UserInterface/DebugPanel.add_property("Velocity", get_real_velocity(), 2)
|
||||
|
||||
# Gravity
|
||||
#gravity = ProjectSettings.get_setting("physics/3d/default_gravity") # If the gravity changes during your game, uncomment this code
|
||||
if not is_on_floor():
|
||||
if velocity.y >= gravity:
|
||||
velocity.y = gravity
|
||||
velocity.y -= gravity * delta
|
||||
|
||||
handle_jumping()
|
||||
|
||||
var input_dir = Vector2.ZERO
|
||||
if !immobile:
|
||||
input_dir = Input.get_vector(LEFT, RIGHT, FORWARD, BACKWARD)
|
||||
|
||||
handle_movement(delta, input_dir)
|
||||
|
||||
handle_stomp()
|
||||
|
||||
handle_telekinesis()
|
||||
|
||||
handle_gunshoot()
|
||||
|
||||
# toggle_crouch()
|
||||
toggle_sprint(input_dir)
|
||||
if Input.is_action_just_pressed(DASH) and !dash_spent:
|
||||
dash_spent = true
|
||||
dash_startpos = position
|
||||
dash_active = true
|
||||
$dash_timer.start(dash_cooldown)
|
||||
$aircontrol_timer.stop()
|
||||
|
||||
if dash_active and dash_startpos.distance_to(position) > dash_distance:
|
||||
dash_active = false
|
||||
|
||||
if dash_active and input_dir.x == 0 and input_dir.y == 0:
|
||||
dash_active = false
|
||||
|
||||
if dash_active:
|
||||
speed = base_speed * dash_speedmultiplier
|
||||
elif is_crouching:
|
||||
speed = crouch_speed
|
||||
elif is_sprinting:
|
||||
speed = sprint_speed
|
||||
else:
|
||||
speed = base_speed
|
||||
|
||||
|
||||
if view_bobbing:
|
||||
headbob_animation(input_dir)
|
||||
|
||||
|
||||
for i in get_slide_collision_count():
|
||||
var slaminto = get_slide_collision(i)
|
||||
if slaminto.get_collider() is RigidBody3D:
|
||||
slaminto.get_collider().apply_central_impulse(-slaminto.get_normal() * physics_push_force)
|
||||
|
||||
|
||||
func handle_jumping():
|
||||
if jumping_enabled:
|
||||
if !coyotechance and !is_on_floor():
|
||||
$coyote_timer.start(coyotetime)
|
||||
coyotechance = true
|
||||
|
||||
if continuous_jumping:
|
||||
if Input.is_action_pressed(JUMP) and is_on_floor():
|
||||
velocity.y += jump_velocity
|
||||
else:
|
||||
if Input.is_action_just_pressed(JUMP):
|
||||
if is_on_floor() or (coyotechance and !$coyote_timer.is_stopped()):
|
||||
velocity.y += jump_velocity
|
||||
$aircontrol_timer.start(aircontrol_delay)
|
||||
|
||||
if walljump_ready and Input.is_action_just_pressed(JUMP) and !is_on_floor() and is_on_wall():
|
||||
velocity.x = velocity.x + ((position.bounce(get_slide_collision(0).get_normal()).x) * wallbounce_multiplier)
|
||||
velocity.z = velocity.z + ((position.bounce(get_slide_collision(0).get_normal()).z) * wallbounce_multiplier)
|
||||
velocity.y += jump_velocity
|
||||
walljump_ready = false
|
||||
$walljump_timer.start(walljump_cooldown)
|
||||
$aircontrol_timer.start(aircontrol_delay)
|
||||
print("walljump timer started")
|
||||
|
||||
func handle_movement(delta, input_dir):
|
||||
|
||||
var direction = input_dir.rotated(-HEAD.rotation.y)
|
||||
direction = Vector3(direction.x, 0, direction.y)
|
||||
|
||||
move_and_slide()
|
||||
|
||||
if in_air_momentum:
|
||||
if is_on_floor(): # Don't lerp y movement
|
||||
if motion_smoothing:
|
||||
velocity.x = lerp(velocity.x, direction.x * speed, acceleration * delta)
|
||||
velocity.z = lerp(velocity.z, direction.z * speed, acceleration * delta)
|
||||
else:
|
||||
velocity.x = direction.x * speed
|
||||
velocity.z = direction.z * speed
|
||||
else:
|
||||
if direction.x != 0 and direction.z != 0 and $aircontrol_timer.is_stopped():
|
||||
if motion_smoothing:
|
||||
velocity.x = lerp(velocity.x, direction.x * speed, acceleration * delta)
|
||||
velocity.z = lerp(velocity.z, direction.z * speed, acceleration * delta)
|
||||
else:
|
||||
if motion_smoothing:
|
||||
velocity.x = lerp(velocity.x, direction.x * speed, acceleration * delta)
|
||||
velocity.z = lerp(velocity.z, direction.z * speed, acceleration * delta)
|
||||
else:
|
||||
velocity.x = direction.x * speed
|
||||
velocity.z = direction.z * speed
|
||||
|
||||
|
||||
func _process(delta):
|
||||
|
||||
$UserInterface/DebugPanel.add_property("FPS", 1.0/delta, 0)
|
||||
|
||||
if Input.is_action_just_pressed(PAUSE):
|
||||
if Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
|
||||
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||
elif Input.mouse_mode == Input.MOUSE_MODE_VISIBLE:
|
||||
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||
|
||||
|
||||
func _unhandled_input(event):
|
||||
if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
|
||||
HEAD.rotation_degrees.y -= event.relative.x * mouse_sensitivity
|
||||
HEAD.rotation_degrees.x -= event.relative.y * mouse_sensitivity
|
||||
HEAD.rotation.x = clamp(HEAD.rotation.x, deg_to_rad(-90), deg_to_rad(90))
|
||||
|
||||
|
||||
"""func toggle_crouch():
|
||||
if crouch_enabled:
|
||||
if crouch_mode == 0:
|
||||
is_crouching = Input.is_action_pressed(CROUCH)
|
||||
elif crouch_mode == 1:
|
||||
if Input.is_action_just_pressed(CROUCH):
|
||||
is_crouching = !is_crouching
|
||||
|
||||
# Replace with your own crouch animation code
|
||||
if is_crouching:
|
||||
$Collision.scale.y = lerp($Collision.scale.y, 0.75, 0.2)
|
||||
else:
|
||||
$Collision.scale.y = lerp($Collision.scale.y, 1.0, 0.2)"""
|
||||
|
||||
|
||||
func toggle_sprint(moving):
|
||||
if sprint_enabled:
|
||||
if sprint_mode == 0:
|
||||
if !is_crouching: # Crouching takes priority over sprinting
|
||||
is_sprinting = Input.is_action_pressed(SPRINT)
|
||||
else:
|
||||
is_sprinting = false # Fix a bug where if you are sprinting and then crouch then let go of the sprinting button you keep sprinting
|
||||
elif sprint_mode == 1:
|
||||
if Input.is_action_just_pressed(SPRINT):
|
||||
if !is_crouching:
|
||||
is_sprinting = !is_sprinting
|
||||
else:
|
||||
is_sprinting = false
|
||||
|
||||
if dynamic_fov:
|
||||
if is_sprinting and moving:
|
||||
CAMERA.fov = lerp(CAMERA.fov, 85.0, 0.3)
|
||||
else:
|
||||
CAMERA.fov = lerp(CAMERA.fov, 75.0, 0.3)
|
||||
|
||||
|
||||
func headbob_animation(moving):
|
||||
if moving and is_on_floor():
|
||||
CAMERA_ANIMATION.play("headbob")
|
||||
CAMERA_ANIMATION.speed_scale = speed / base_speed
|
||||
else:
|
||||
CAMERA_ANIMATION.play("RESET")
|
||||
|
||||
func handle_telekinesis():
|
||||
if holding_object:
|
||||
held_object.global_position = held_object.global_position.lerp($Head/TelekinesisPoint.global_position, 0.3)
|
||||
if $UserInterface/Telehand.texture == tex_telehand_pull and held_object.global_position.distance_to($Head/TelekinesisPoint.global_position) < 0.1:
|
||||
$UserInterface/Telehand.texture = tex_telehand_grip
|
||||
|
||||
if Input.is_action_just_pressed(CROUCH) and holding_object:
|
||||
holding_object = false
|
||||
held_object.gravity_scale = 1.0
|
||||
$UserInterface/Telehand.texture = tex_telehand_throw
|
||||
$telehand_timer.start(0.6)
|
||||
elif Input.is_action_just_pressed(TELEK):
|
||||
if !holding_object:
|
||||
var object = $Head/Camera/Ray.get_collider()
|
||||
if object != null and ($Head/Camera/Ray.get_collision_point().distance_to(position) <= object_grab_distance) and object.get("grabbable") == true:
|
||||
holding_object = true
|
||||
held_object = object
|
||||
held_object.gravity_scale = 0.0
|
||||
$UserInterface/Telehand.texture = tex_telehand_pull
|
||||
$UserInterface/Telehand.visible = true
|
||||
$telehand_timer.stop()
|
||||
$telehand_timer.start(0.5)
|
||||
else:
|
||||
held_object.apply_central_impulse($Head/Camera/Ray.global_position.direction_to(held_object.global_position - Vector3(0,object_hold_height,0)) * Vector3(object_hurl_force, object_hurl_force, object_hurl_force))
|
||||
holding_object = false
|
||||
held_object.gravity_scale = 1.0
|
||||
$UserInterface/Telehand.texture = tex_telehand_throw
|
||||
$telehand_timer.start(0.5)
|
||||
|
||||
func handle_gunshoot():
|
||||
if Input.is_action_just_pressed(SHOOT) and $gunfire_timer.is_stopped():
|
||||
$gunfire_timer.start(gun_firedelay)
|
||||
$gunflash_timer.start(0.08)
|
||||
$UserInterface/Gun.texture = tex_pistol_recoil
|
||||
|
||||
var object = $Head/Camera/Ray.get_collider()
|
||||
if object != null:
|
||||
if object.get("shootable") == true:
|
||||
var multiplier : float = 1.0
|
||||
if object.get("weakpoint") == true:
|
||||
if object.rootnode:
|
||||
multiplier = object.weakpoint_damage
|
||||
else:
|
||||
multiplier = object.owner.weakpoint_damage
|
||||
if object.rootnode:
|
||||
object.deal_damage(gun_damage * multiplier)
|
||||
else:
|
||||
object.owner.deal_damage(gun_damage * multiplier)
|
||||
elif object.get("grabbable") == true:
|
||||
var shootforce = gun_damage * gun_physics_nudge_multiplier
|
||||
object.apply_central_impulse($Head/Camera/Ray.global_position.direction_to(object.global_position) * Vector3(shootforce, shootforce, shootforce))
|
||||
if object == held_object:
|
||||
holding_object = false
|
||||
held_object.gravity_scale = 1.0
|
||||
$UserInterface/Telehand.visible = false
|
||||
$telehand_timer.stop
|
||||
|
||||
func handle_stomp():
|
||||
if !stomping and !is_on_floor() and !holding_object and Input.is_action_just_pressed(CROUCH):
|
||||
stomping = true
|
||||
stomp_startingheight = global_position.y
|
||||
$stomparea.monitoring = true
|
||||
if stomping:
|
||||
if !is_on_floor():
|
||||
velocity.y = -stomp_speed
|
||||
var stompheight = stomp_startingheight - global_position.y
|
||||
if stompheight >= stomp_radiusthreshold:
|
||||
var newradius = clamp(stomp_radius + (stomp_radiusincrement * (stompheight - stomp_radiusthreshold)), stomp_radius, stomp_maxradius)
|
||||
$stomparea.scale = Vector3(newradius, newradius, newradius)
|
||||
else:
|
||||
stomping = false
|
||||
var damage = clamp(stomp_damagepermeter * (stomp_startingheight - global_position.y), stomp_mindamage, stomp_maxdamage)
|
||||
for body in $stomparea.get_overlapping_bodies():
|
||||
if body is RigidBody3D:
|
||||
body.apply_central_impulse(global_position.direction_to(body.global_position) * Vector3(damage*2, damage*4, damage*2))
|
||||
if body is CharacterBody3D and body.get("playerallied") == false:
|
||||
body.deal_damage(damage)
|
||||
body.global_position.y += 0.2
|
||||
body.velocity = global_position.direction_to(body.global_position) * Vector3(damage*20, damage*40, damage*20)
|
||||
$stomparea.scale = Vector3(stomp_radius, stomp_radius, stomp_radius)
|
||||
$stomparea.monitoring = false
|
||||
|
||||
func deal_damage(damage):
|
||||
print("player takes "+ str(damage)+" damage, leaving "+str(hp)+" HP left")
|
||||
hp = hp - damage
|
||||
if hp <= 0:
|
||||
print("player died! oh no!")
|
||||
|
||||
func _on_walljump_timer_timeout():
|
||||
walljump_ready = true
|
||||
$walljump_timer.stop()
|
||||
|
||||
|
||||
func _on_aircontrol_timer_timeout():
|
||||
$aircontrol_timer.stop()
|
||||
|
||||
|
||||
func _on_coyote_timer_timeout():
|
||||
$coyote_timer.stop()
|
||||
|
||||
|
||||
func _on_dash_timer_timeout():
|
||||
dash_spent = false
|
||||
$dash_timer.stop()
|
||||
pass # Replace with function body.
|
||||
|
||||
|
||||
func _on_gunfire_timer_timeout():
|
||||
$gunfire_timer.stop()
|
||||
|
||||
|
||||
func _on_gunflash_timer_timeout():
|
||||
$UserInterface/Gun.texture = tex_pistol_neutral
|
||||
$gunflash_timer.stop()
|
||||
|
||||
|
||||
func _on_telehand_timer_timeout():
|
||||
if $UserInterface/Telehand.texture == tex_telehand_pull:
|
||||
$UserInterface/Telehand.texture = tex_telehand_grip
|
||||
elif $UserInterface/Telehand.texture == tex_telehand_throw:
|
||||
$UserInterface/Telehand.visible = false
|
||||
$telehand_timer.stop()
|
||||
1
scripts/character.gd.uid
Normal file
1
scripts/character.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bvykx45u8uuv3
|
||||
298
scripts/enemy_chompyboy.gd
Normal file
298
scripts/enemy_chompyboy.gd
Normal file
@@ -0,0 +1,298 @@
|
||||
extends CharacterBody3D
|
||||
|
||||
var gravity : float = ProjectSettings.get_setting("physics/3d/default_gravity")
|
||||
|
||||
var grabbable : bool = false
|
||||
var shootable : bool = true
|
||||
var weakpoint : bool = false
|
||||
var playerallied : bool = false
|
||||
var rootnode : bool = true
|
||||
var waitingfor : int = 0
|
||||
|
||||
var perception_refreshinterval : float = 0.6
|
||||
var perception_radius : float = 32
|
||||
var perception_giveuptime : float = 6
|
||||
|
||||
var path_refreshinterval : float = 1.5
|
||||
|
||||
@export var hp : float = 8
|
||||
@export var physics_push_force : float = 1.5
|
||||
var lunge_startdistance : float = 6
|
||||
var lunge_pausetime : float = 0.1
|
||||
var lunge_traveldistance : float = 12
|
||||
var lunge_travelheight : float = 0.3
|
||||
var lunge_velocity : float = 18
|
||||
var lunge_upwardvelocity : float = 4
|
||||
var lunge_damage : float = 8
|
||||
var lunge_recovery : float = 0.4
|
||||
|
||||
var currentlunge_angle : Vector3
|
||||
var currentlunge_startpos : Vector3
|
||||
var currentlunge_apex : float
|
||||
var currentlunge_lethal : bool = true
|
||||
|
||||
var state : String = "idle"
|
||||
|
||||
var movement_speed: float = 8
|
||||
var movement_delta: float
|
||||
var path_point_margin: float = 1
|
||||
|
||||
var current_path_index: int = 0
|
||||
var current_path_point: Vector3
|
||||
var current_path: PackedVector3Array
|
||||
@onready var default_3d_map_rid: RID = get_world_3d().get_navigation_map()
|
||||
var startpos : Vector3
|
||||
var forth : bool = false
|
||||
|
||||
@export var min_player_distance : float = 2.0
|
||||
@export var min_ally_distance : float = 6.0
|
||||
var runtarget : Vector3
|
||||
@export var player : Node
|
||||
|
||||
const sprite_front1 = preload("res://sprites/enemies/chompyboy_front1.png")
|
||||
const sprite_left1 = preload("res://sprites/enemies/chompyboy_left1.png")
|
||||
const sprite_right1 = preload("res://sprites/enemies/chompyboy_right1.png")
|
||||
const sprite_back1 = preload("res://sprites/enemies/chompyboy_back1.png")
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
rotation_degrees.y += 180
|
||||
|
||||
player.enemies.append(self)
|
||||
|
||||
$perception_timer.start(perception_refreshinterval)
|
||||
|
||||
|
||||
|
||||
func _physics_process(delta):
|
||||
sprite_angle()
|
||||
ai_process()
|
||||
|
||||
if state == "chasing" and player.global_transform.origin.distance_to(runtarget) > 4:
|
||||
runtarget = player.global_transform.origin
|
||||
|
||||
if current_path.is_empty() and NavigationServer3D.map_is_active(default_3d_map_rid):
|
||||
if state == "chasing" and global_transform.origin.distance_to(runtarget) > 4:
|
||||
set_movement_target(runtarget)
|
||||
$chase_timer.start(path_refreshinterval)
|
||||
|
||||
move_and_slide()
|
||||
|
||||
if velocity.y > 3:
|
||||
print("hey! stop that! current state "+state+" current velocity "+str(velocity.y)+"current motion mode "+str(get_motion_mode()))
|
||||
velocity.y = 3
|
||||
|
||||
for i in get_slide_collision_count():
|
||||
var slaminto = get_slide_collision(i)
|
||||
if slaminto.get_collider() is RigidBody3D:
|
||||
slaminto.get_collider().apply_central_impulse(-slaminto.get_normal() * physics_push_force)
|
||||
elif slaminto.get_collider() is CharacterBody3D:
|
||||
slaminto.get_collider().velocity += (-slaminto.get_normal() * movement_speed)
|
||||
if (state == "lunge_rise" or state == "lunge_descend") and slaminto.get_collider().get("playerallied") == true and currentlunge_lethal == true and slaminto.get_collider().get("hp") > 0:
|
||||
slaminto.get_collider().deal_damage(lunge_damage)
|
||||
currentlunge_lethal = false
|
||||
|
||||
if !current_path.is_empty():
|
||||
if global_transform.origin.distance_to(player.global_transform.origin) <= min_player_distance:
|
||||
clearpath()
|
||||
$chase_timer.start(path_refreshinterval)
|
||||
|
||||
if global_transform.origin.distance_to(current_path_point) <= path_point_margin:
|
||||
current_path_index += 1
|
||||
if current_path_index >= current_path.size():
|
||||
clearpath()
|
||||
$chase_timer.start(path_refreshinterval)
|
||||
|
||||
|
||||
if state == "chasing" and is_on_floor() and !current_path.is_empty() and hp > 0:
|
||||
if len(current_path) > 0:
|
||||
current_path_point = current_path[current_path_index]
|
||||
|
||||
var direction = global_transform.origin.direction_to(current_path_point)
|
||||
var acceleration = 8.0
|
||||
|
||||
velocity.x = lerp(velocity.x, direction.x * movement_speed, acceleration * delta)
|
||||
velocity.z = lerp(velocity.z, direction.z * movement_speed, acceleration * delta)
|
||||
|
||||
# global_transform = global_transform.interpolate_with(global_transform.looking_at(Vector3(current_path_point.x,global_position.y,current_path_point.z)), 0.4)
|
||||
global_transform = global_transform.looking_at(Vector3(current_path_point.x,global_position.y,current_path_point.z))
|
||||
|
||||
elif state == "lunge_start":
|
||||
currentlunge_startpos = global_transform.origin
|
||||
currentlunge_angle = global_transform.origin.direction_to(player.global_transform.origin)
|
||||
currentlunge_apex = player.global_transform.origin.y + lunge_travelheight
|
||||
global_transform = global_transform.looking_at(Vector3(player.global_transform.origin.x,global_position.y,player.global_transform.origin.z))
|
||||
state = "lunge_rise"
|
||||
motion_mode = 1
|
||||
|
||||
elif state == "lunge_rise":
|
||||
var acceleration = 8.0
|
||||
velocity.x = lerp(velocity.x, currentlunge_angle.x * lunge_velocity, acceleration * delta)
|
||||
velocity.z = lerp(velocity.z, currentlunge_angle.z * lunge_velocity, acceleration * delta)
|
||||
|
||||
if currentlunge_startpos.distance_to(global_transform.origin) >= lunge_traveldistance:
|
||||
state = "lunge_startrecovery"
|
||||
elif global_transform.origin.y < currentlunge_apex:
|
||||
velocity.y = lerp(velocity.y, lunge_upwardvelocity, acceleration * delta)
|
||||
else:
|
||||
motion_mode = 0
|
||||
state = "lunge_descend"
|
||||
|
||||
if get_real_velocity().x == 0 and get_real_velocity().z == 0 and $ai_timer.is_stopped():
|
||||
$ai_timer.start(1)
|
||||
|
||||
elif state == "lunge_descend":
|
||||
var acceleration = 8.0
|
||||
velocity.x = lerp(velocity.x, currentlunge_angle.x * lunge_velocity, acceleration * delta)
|
||||
velocity.z = lerp(velocity.z, currentlunge_angle.z * lunge_velocity, acceleration * delta)
|
||||
|
||||
if currentlunge_startpos.distance_to(global_transform.origin) >= lunge_traveldistance:
|
||||
state = "lunge_startrecovery"
|
||||
|
||||
if get_real_velocity().x == 0 and get_real_velocity().z == 0 and $ai_timer.is_stopped():
|
||||
$ai_timer.start(1)
|
||||
|
||||
elif state == "lunge_recovering":
|
||||
var acceleration = 8.0
|
||||
velocity.x = lerp(velocity.x, 0.0, acceleration * delta)
|
||||
velocity.z = lerp(velocity.z, 0.0, acceleration * delta)
|
||||
|
||||
elif current_path.is_empty() or waitingfor != 0:
|
||||
velocity.x = 0
|
||||
velocity.z = 0
|
||||
|
||||
if hp > 0:
|
||||
var velocityclamp = 0.25
|
||||
if abs(velocity.x) + abs(velocity.z) > (velocityclamp * 2):
|
||||
# $AnimationPlayer.play("Run")
|
||||
pass
|
||||
else:
|
||||
# $AnimationPlayer.play("Idle")
|
||||
pass
|
||||
else:
|
||||
velocity = Vector3(0,0,0)
|
||||
|
||||
if not is_on_floor():
|
||||
velocity.y -= gravity * delta
|
||||
|
||||
func ai_process():
|
||||
if state == "chasing" and global_transform.origin.distance_to(player.global_transform.origin) <= lunge_startdistance:
|
||||
state = "lunge_charge"
|
||||
$ai_timer.start(lunge_pausetime)
|
||||
elif state == "lunge_startrecovery":
|
||||
motion_mode = 0
|
||||
state = "lunge_recovering"
|
||||
$ai_timer.start(lunge_recovery)
|
||||
elif state == "goidle":
|
||||
$ai_timer.stop()
|
||||
clearpath()
|
||||
state = "idle"
|
||||
pass
|
||||
|
||||
func deal_damage(damage):
|
||||
print(str(damage)+" damage taken, "+str(hp)+" HP left")
|
||||
hp = hp - damage
|
||||
if hp <= 0:
|
||||
print("death")
|
||||
delete_me()
|
||||
|
||||
|
||||
func set_movement_target(target_position: Vector3):
|
||||
var start_position: Vector3 = global_transform.origin
|
||||
|
||||
current_path = NavigationServer3D.map_get_path(
|
||||
default_3d_map_rid,
|
||||
start_position,
|
||||
target_position,
|
||||
true
|
||||
)
|
||||
|
||||
if not current_path.is_empty():
|
||||
current_path_index = 0
|
||||
current_path_point = current_path[0]
|
||||
|
||||
func clearpath():
|
||||
current_path = []
|
||||
current_path_index = 0
|
||||
current_path_point = global_transform.origin
|
||||
|
||||
'''func _on_animation_player_animation_finished(anim_name):
|
||||
if anim_name == "Idle":
|
||||
# $AnimationPlayer.play("Idle")
|
||||
pass
|
||||
if anim_name == "Run":
|
||||
# $AnimationPlayer.play("Run")
|
||||
pass
|
||||
if anim_name == "Death":
|
||||
delete_me()
|
||||
"""set_collision_layer_value(1, false)
|
||||
$Head.set_collision_layer_value(1, false)"""'''
|
||||
|
||||
func delete_me():
|
||||
player.enemies.erase(self)
|
||||
get_parent().remove_child(self)
|
||||
queue_free()
|
||||
|
||||
func sprite_angle():
|
||||
var playerpos = Vector2(player.global_position.x, player.global_position.z)
|
||||
var spritepos = Vector2(global_position.x, global_position.z)
|
||||
var directiontoplayer = rad_to_deg((playerpos - spritepos).angle())
|
||||
var selfangle = rad_to_deg(global_rotation.y)
|
||||
var spriteangle = fposmod((directiontoplayer + selfangle) + 90, 359)
|
||||
'''print("playerdirection "+str(directiontoplayer)+", angle "+str(selfangle)+", sprite "+str(spriteangle))'''
|
||||
|
||||
if spriteangle < 45 and $Sprite.texture != sprite_front1:
|
||||
$Sprite.texture = sprite_front1
|
||||
elif spriteangle >= 45 and spriteangle < 135 and $Sprite.texture != sprite_right1:
|
||||
$Sprite.texture = sprite_right1
|
||||
elif spriteangle >= 135 and spriteangle < 225 and $Sprite.texture != sprite_back1:
|
||||
$Sprite.texture = sprite_back1
|
||||
elif spriteangle >= 225 and spriteangle < 315 and $Sprite.texture != sprite_left1:
|
||||
$Sprite.texture = sprite_left1
|
||||
elif spriteangle >= 315 and spriteangle < 360 and $Sprite.texture != sprite_front1:
|
||||
$Sprite.texture = sprite_front1
|
||||
|
||||
func _on_chase_timer_timeout():
|
||||
if player.global_transform.origin.distance_to(runtarget) > 4:
|
||||
runtarget = player.global_transform.origin
|
||||
if global_transform.origin.distance_to(runtarget) > 4:
|
||||
set_movement_target(runtarget)
|
||||
$chase_timer.start(path_refreshinterval)
|
||||
|
||||
|
||||
func _on_ai_timer_timeout():
|
||||
$ai_timer.stop()
|
||||
if state == "lunge_charge":
|
||||
state = "lunge_start"
|
||||
currentlunge_lethal = true
|
||||
elif state == "lunge_recovering":
|
||||
state = "chasing"
|
||||
# halt lunge when stuck in same position for too long
|
||||
elif state == "lunge_rise" and get_real_velocity().x == 0 and get_real_velocity().z == 0:
|
||||
state = "lunge_startrecovery"
|
||||
elif state == "lunge_descend" and get_real_velocity().x == 0 and get_real_velocity().z == 0:
|
||||
state = "lunge_startrecovery"
|
||||
# go idle when chasing player that has been out of sight for too long
|
||||
elif state == "chasing":
|
||||
state = "goidle"
|
||||
print("player gone, giving up...")
|
||||
|
||||
|
||||
func _on_perception_timer_timeout():
|
||||
$perception_timer.stop()
|
||||
$sightchecker.target_position = to_local(player.global_transform.origin)
|
||||
$sightchecker.force_raycast_update()
|
||||
|
||||
if global_transform.origin.distance_to(player.global_transform.origin) <= perception_radius and $sightchecker.get_collider() == player:
|
||||
if state == "idle":
|
||||
state = "chasing"
|
||||
print("player sighted!")
|
||||
elif state == "chasing" and !$ai_timer.is_stopped():
|
||||
$ai_timer.stop()
|
||||
elif state == "chasing" and $ai_timer.is_stopped():
|
||||
$ai_timer.start(perception_giveuptime)
|
||||
$perception_timer.start(perception_refreshinterval)
|
||||
|
||||
|
||||
func _on_hitflash_timer_timeout():
|
||||
pass # Replace with function body.
|
||||
1
scripts/enemy_chompyboy.gd.uid
Normal file
1
scripts/enemy_chompyboy.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cl5e3d87p1xm0
|
||||
26
scripts/hud_text.gd
Normal file
26
scripts/hud_text.gd
Normal file
@@ -0,0 +1,26 @@
|
||||
extends Label
|
||||
|
||||
var hud_scaling : float = 1.0
|
||||
|
||||
func update(player, walljump_timer, dash_timer):
|
||||
var hp = "Health: " + str(player.hp)
|
||||
var walljump_ready = "Walljump Ready"
|
||||
var dash_ready = "Dash Ready"
|
||||
|
||||
if get_viewport_rect().size.x > 1280 and hud_scaling == 1.0:
|
||||
hud_scaling = (get_viewport_rect().size.x / 1280)
|
||||
|
||||
get_parent().size = get_viewport_rect().size
|
||||
get_parent().add_theme_constant_override("margin_top", 600 * hud_scaling)
|
||||
get_parent().add_theme_constant_override("margin_right", 1000 * hud_scaling)
|
||||
get_parent().add_theme_constant_override("margin_bottom", 20 * hud_scaling)
|
||||
get_parent().add_theme_constant_override("margin_left", 20 * hud_scaling)
|
||||
label_settings.font_size = int(25 * hud_scaling)
|
||||
label_settings.outline_size = int(3 * hud_scaling)
|
||||
|
||||
if !player.walljump_ready:
|
||||
walljump_ready = "Walljump in " + str("%.1f" % walljump_timer.time_left)
|
||||
if player.dash_spent:
|
||||
dash_ready = "Dash in " + str("%.1f" % dash_timer.time_left)
|
||||
|
||||
text = hp + "\n" + walljump_ready + "\n" + dash_ready
|
||||
1
scripts/hud_text.gd.uid
Normal file
1
scripts/hud_text.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bs0cc5wulparn
|
||||
21
scripts/telekinesis_object.gd
Normal file
21
scripts/telekinesis_object.gd
Normal file
@@ -0,0 +1,21 @@
|
||||
extends RigidBody3D
|
||||
|
||||
var grabbable : bool = true
|
||||
@export var damage : float = 6.0
|
||||
@export var min_damaging_velocity : float = 1.0
|
||||
|
||||
func _ready():
|
||||
contact_monitor = true
|
||||
max_contacts_reported = 2
|
||||
set_collision_mask_value(2, true)
|
||||
body_entered.connect(_on_body_entered)
|
||||
|
||||
func _on_body_entered(body):
|
||||
if body.get("shootable") == true:
|
||||
var totalvelocity = abs(angular_velocity.x + angular_velocity.y + angular_velocity.z)
|
||||
if totalvelocity > (3 * min_damaging_velocity):
|
||||
if body.get("rootnode") == true:
|
||||
body.deal_damage(totalvelocity * damage)
|
||||
else:
|
||||
body.owner.deal_damage(totalvelocity * damage)
|
||||
apply_central_impulse(body.position.direction_to(position) * -3.0)
|
||||
1
scripts/telekinesis_object.gd.uid
Normal file
1
scripts/telekinesis_object.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://13fip1bbanaw
|
||||
Reference in New Issue
Block a user