summaryrefslogtreecommitdiff
path: root/src/player_controller/PlayerController.gd
diff options
context:
space:
mode:
Diffstat (limited to 'src/player_controller/PlayerController.gd')
-rw-r--r--src/player_controller/PlayerController.gd297
1 files changed, 297 insertions, 0 deletions
diff --git a/src/player_controller/PlayerController.gd b/src/player_controller/PlayerController.gd
new file mode 100644
index 0000000..241cbe0
--- /dev/null
+++ b/src/player_controller/PlayerController.gd
@@ -0,0 +1,297 @@
+extends RigidBody
+
+# Game
+export var team: String = "RED"
+export var health: int = 100
+var weapon: Node = null
+var world: Spatial = null
+
+# Camera
+export var mouse_sensitivity:float = 12.0
+export var FOV:float = 90.0
+var mouse_axis: Vector2 = Vector2.ZERO
+onready var head: Spatial = $Neck/Head
+onready var neck: Spatial = $Neck
+
+# Move
+var velocity := Vector3()
+var direction := Vector3()
+var move_axis := Vector2()
+var floorspeed := Vector3()
+var jumping:bool = false
+var can_jump:bool = true
+onready var nav: NavigationAgent = $NavigationAgent
+
+# Walk
+const FLOOR_MAX_ANGLE: float = deg2rad(46.0)
+export var jump_height: float = 300.0
+var in_water : bool = false
+var swim_speed : float = 450.0
+var climb_speed : float = 5.0
+
+# Control
+var controlling_machine: bool = false #whether character is riding/controlling something
+var machine : RigidBody = null
+export var is_player: bool = false #whether character is currently controlled by a player
+var ladder_m: Spatial = null
+
+#physics
+var player_state: PhysicsDirectBodyState = null
+var is_on_floor:bool
+var floor_normal : Vector3 = Vector3.UP
+var acceleration:float = 80.0
+export var walk_speed:float = 5.0
+var c_friction:float = 4.0
+var air_control:float = 0.3
+
+# Called when the node enters the scene tree
+func _ready() -> void:
+ weapon = preload("res://scenes/weapons/w_Rockets.tscn").instance()
+ add_child(weapon)
+ world = get_tree().get_root().get_node("GAMEWORLD")
+
+ $"%UseRay".add_exception(self)
+ $"%MeleeRay".add_exception(self)
+ $"%UseRay".add_exception($AreaDetect)
+ $"%MeleeRay".add_exception($AreaDetect)
+
+func get_init_info() -> Dictionary:
+ return {"linear_velocity" : linear_velocity, "angular_velocity" : angular_velocity, "controlling_machine" : controlling_machine, "team" : team, "health" : health, "nametag" : $Nametag.text}
+
+func mp_init(init_info: Dictionary):
+ for variable in init_info.keys():
+ set(variable, init_info[variable])
+ $Nametag.text = init_info["nametag"]
+
+remote func set_phys_transform(trfrm: Transform, lvel: Vector3):
+ transform = trfrm
+ linear_velocity = lvel
+
+# Called every frame. 'delta' is the elapsed time since the previous frame
+func _process(_delta: float) -> void:
+ if is_player and !world.is_chatting:
+ if Input.is_action_just_pressed("use"):
+ initiate_use()
+
+ if controlling_machine:
+ if Input.is_action_just_pressed("fire"):
+ machine.attack1()
+ if Input.is_action_just_pressed("fire2"):
+ machine.attack2()
+ machine.direction_input(Input.get_action_strength("move_forward"),Input.get_action_strength("move_backward"), Input.get_action_strength("move_right"),Input.get_action_strength("move_left"), Input.get_action_strength("alt_right"),Input.get_action_strength("alt_left"))
+ machine.misc_input(Input.get_action_strength("move_duck"),Input.get_action_strength("move_jump"),Input.get_action_strength("move_walk"))
+ machine.mouse_input(Input.get_action_strength("fire"), Input.get_action_strength("fire3"),Input.get_action_strength("fire2"))
+ else:
+ jumping = Input.get_action_strength("move_jump")
+ if Input.is_action_just_pressed("fire"):
+ weapon.attack1()
+ move_axis.x = Input.get_action_strength("move_forward") - Input.get_action_strength("move_backward")
+ move_axis.y = Input.get_action_strength("move_right") - Input.get_action_strength("move_left")
+
+
+func initiate_use():
+ if controlling_machine:
+ machine.relinquish_control()
+ return
+ if ladder_m != null:
+ leave_ladder()
+ return
+ if $"%UseRay".is_colliding():
+ var area_c = $"%UseRay".get_collider()
+ match area_c.name:
+ "SteerArea":
+ world.rpc_id(1, "_call_on_server", "_client_request_control_vehicle", {"id" : world.client_id, "machine_path" : area_c.get_parent().get_path(), "char_name" : name})
+ "LadderArea":
+ mount_ladder(area_c.get_parent())
+ "TugArea":
+ pass
+ "PickupArea":
+ pass
+ _:
+ pass
+
+remotesync func set_net_owner(owner_id: int):
+ $Nametag.text = ""
+ set_network_master(owner_id)
+ if owner_id != 1:
+ $Nametag.text = world.players_info[owner_id][0]
+ if get_tree().get_network_unique_id() != 1:
+ if owner_id == world.client_id:
+ $Nametag.visible = false
+ world.player_char = self
+ is_player = true
+ world.cam.attach(self, "FIRSTPERSON", "./Neck/Head")
+ else:
+ $Nametag.visible = true
+ is_player = false
+ world.get_node("HUD").update_characters()
+
+func deselect_character():
+ if is_network_master():
+ world.player_char = null
+ if world.client_id != 1: world.cam.attach(world, "STATIC", "./DEFAULTCAM")
+ rpc("set_net_owner", 1)
+
+func take_control_of_machine(slave_machine: RigidBody):
+ machine = slave_machine
+ controlling_machine = true
+
+func lose_machine():
+ if is_network_master(): world.cam.attach(self, "FIRSTPERSON", "./Neck/Head")
+ controlling_machine = false
+ machine = null
+
+# Called every physics tick. 'delta' is constant
+func _physics_process(delta: float) -> void:
+ if is_network_master():
+ if ladder_m != null:
+ climb_ladder(delta)
+ elif !on_floor_test() and in_water:
+ swim(delta)
+ else:
+ walk(delta)
+ is_on_floor = false #reset whether is on floor in between frames
+
+# called each physics frame
+func on_floor_test() -> bool:
+ if $Feet.is_colliding():
+ is_on_floor = true
+ floor_normal = Vector3.UP
+ floorspeed = $Feet.get_collider().get_linear_velocity() if $Feet.get_collider().has_method("get_linear_velocity") else Vector3.ZERO
+ return true
+ if player_state:
+ for i in range(player_state.get_contact_count()):
+ var contact_angle_from_up : float = Vector3.UP.angle_to(player_state.get_contact_local_normal(i))
+ if contact_angle_from_up < FLOOR_MAX_ANGLE:
+ floor_normal = player_state.get_contact_local_normal(i)
+ is_on_floor = true
+ return true
+ return false
+
+#modify simulated physics results
+func _integrate_forces(state: PhysicsDirectBodyState) -> void:
+ if !is_network_master():
+ return
+ player_state = state
+ velocity = state.get_linear_velocity()
+ $normal_vis.look_at($normal_vis.global_transform.origin + global_transform.basis.z, floor_normal)
+ for i in range(player_state.get_contact_count()):
+ var contact_angle_from_up : float = Vector3.UP.angle_to(player_state.get_contact_local_normal(i))
+ if contact_angle_from_up > FLOOR_MAX_ANGLE and !is_on_floor:
+ friction = 0
+ break
+ if i == player_state.get_contact_count() - 1:
+ friction = 1
+
+ rpc("set_phys_transform", transform, linear_velocity)
+ if global_transform.origin.y < -30:
+ rpc("damage", 500000, "drown", [1, "Davy Jones"])
+
+func walk(_delta: float) -> void:
+ # Input
+ direction = Vector3()
+ var aim: Basis = head.get_global_transform().basis
+ direction += -move_axis.x * aim.z + move_axis.y * aim.x
+ direction.y = 0
+ direction = direction.normalized()
+
+ if floor_normal != Vector3.UP: direction = direction.rotated(floor_normal.cross(Vector3.UP).normalized(), Vector3.UP.angle_to(floor_normal))
+
+ # Jump
+ if is_player and jumping and is_on_floor and can_jump:
+ jump()
+
+ #max walk speed
+ var _speed = walk_speed
+ var _temp_accel: float = acceleration
+ var _cspeed = sqrt(pow(velocity.x-floorspeed.x,2)+pow(velocity.z-floorspeed.z,2))
+
+ if not is_on_floor:
+ _temp_accel *= air_control
+
+ var projVel = Vector2(velocity.x-floorspeed.x,velocity.z-floorspeed.z).dot(Vector2(direction.x,direction.z))
+
+ if is_on_floor:
+ add_central_force(-mass*_cspeed*linear_velocity.normalized()*c_friction)#friction
+ if _speed - _cspeed > 0:
+ add_central_force (mass*Vector3(direction.x*_temp_accel, 0, direction.z*_temp_accel))#velocity.x += direction.x*_temp_accel
+ else:
+ add_central_force(mass*Vector3(direction.x*(_speed-projVel), 0, direction.z*(_speed-projVel)))
+ elif 1.0 - projVel > 0:
+ add_central_force (mass*Vector3(direction.x*_temp_accel, 0, direction.z*_temp_accel))
+
+func jump():
+ can_jump = false
+ apply_central_impulse(Vector3.UP*jump_height)
+ yield(get_tree().create_timer(0.05),"timeout")
+ can_jump = true
+
+func swim(_delta: float):
+ #drag and buoyancy
+ add_central_force(Vector3.UP*weight*1.0)
+ add_central_force(-1*linear_velocity*100)
+ #controls
+ var dir: Basis = head.get_global_transform().basis
+ var m_dir: Vector3 = -move_axis.x * dir.z + move_axis.y * dir.x
+ m_dir = m_dir.normalized()
+ add_central_force(swim_speed*m_dir)
+ if jumping:
+ add_central_force(Vector3.UP*weight*0.5)
+
+func enter_water():
+ in_water = true
+
+func exit_water():
+ in_water = false
+
+func mount_ladder(target_ladder: Spatial):
+ var ladder_tracker = Spatial.new()
+ ladder_tracker.name = name
+ target_ladder.add_child(ladder_tracker)
+ ladder_tracker.transform = target_ladder.bottom.transform
+
+ ladder_tracker.global_transform.origin = target_ladder.get_nearest_point_to_route(global_transform.origin)
+ look_at(global_transform.origin + target_ladder.global_transform.basis.x, target_ladder.global_transform.basis.y)
+
+ ladder_m = ladder_tracker
+ global_transform.origin = ladder_m.global_transform.origin
+ global_transform.basis = ladder_m.global_transform.basis.orthonormalized()
+ linear_velocity = Vector3.ZERO
+ set_gravity_scale(0.0)
+
+#called each frame while climbing ladder
+func climb_ladder(delta: float):
+ var new_ladder_pos = ladder_m.global_transform.origin + ladder_m.global_transform.basis.y.normalized() * move_axis.x * delta * climb_speed
+ var prog = ladder_m.get_parent().get_climb_scalar(new_ladder_pos)
+ if prog >= 0.0 and prog <= 1.0:
+ ladder_m.global_transform.origin = new_ladder_pos
+ global_transform.origin = ladder_m.global_transform.origin
+ global_transform.basis = ladder_m.global_transform.basis.orthonormalized()
+
+func leave_ladder():
+ if (ladder_m.get_parent().top.global_transform.origin - global_transform.origin).length_squared() < 0.01:
+ apply_central_impulse(-400*ladder_m.global_transform.basis.z)
+ global_transform.basis = world.global_transform.basis
+ set_gravity_scale(1.0)
+ ladder_m.queue_free()
+ ladder_m = null
+
+remotesync func damage(dmg_amt: int, _type: String, shooter: Array, extra: String):
+ health -= dmg_amt
+ if health <= 0 and is_network_master():
+ if shooter[0] != get_network_master() and shooter[0] != 1: world.rpc_id(shooter[0], "game_killsound")
+ if get_network_master() == 1:
+ world._call_on_server("_character_death", {"killer_id" : shooter[0], "killer" : shooter[1], "victim_mp_id" : get_network_master(), "victim" : name, "extra" : extra})
+ else:
+ world.rpc_id(1, "_call_on_server", "_character_death", {"killer_id" : shooter[0], "killer" : shooter[1], "victim_mp_id" : get_network_master(), "victim" : name, "extra" : extra})
+ elif is_network_master():
+ if shooter[0] != get_network_master() and shooter[0] != 1: world.rpc_id(shooter[0], "game_hitsound")
+
+remotesync func remove_dead_character():
+ if is_network_master() and machine != null:
+ machine.relinquish_control()
+ deselect_character()
+ queue_free()
+
+remotesync func net_apply_impulse(impulse_v: Vector3):
+ apply_central_impulse(impulse_v)