summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAnson Bridges <bridges.anson@gmail.com>2022-09-19 17:44:22 -0400
committerAnson Bridges <bridges.anson@gmail.com>2022-09-19 17:44:22 -0400
commit1d347e770fddcdd051890cdf070fd2779ab113bf (patch)
tree6501fb000509819b7ba58df15c9a831c8bdc44fb /src
parent2fd755132f526c48fed2c1867530526971e1cf19 (diff)
problems: player controller perf, boat perf, NAVSERVER PERF
Diffstat (limited to 'src')
-rw-r--r--src/PlayerController.gd297
-rw-r--r--src/camera_controller/.sconsign.dblitebin0 -> 25088 bytes
-rw-r--r--src/camera_controller/PlayerCam.gd79
-rw-r--r--src/camera_controller/SConstruct109
-rw-r--r--src/camera_controller/gdlibrary.cpp15
-rw-r--r--src/camera_controller/gdlibrary.osbin0 -> 185848 bytes
-rw-r--r--src/camera_controller/playercam.cpp107
-rw-r--r--src/camera_controller/playercam.h43
-rw-r--r--src/camera_controller/playercam.osbin0 -> 248864 bytes
-rw-r--r--src/playercontroller.cpp313
-rw-r--r--src/playercontroller.h83
-rw-r--r--src/script_to_header.py2
12 files changed, 1047 insertions, 1 deletions
diff --git a/src/PlayerController.gd b/src/PlayerController.gd
new file mode 100644
index 0000000..241cbe0
--- /dev/null
+++ b/src/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)
diff --git a/src/camera_controller/.sconsign.dblite b/src/camera_controller/.sconsign.dblite
new file mode 100644
index 0000000..f7491e9
--- /dev/null
+++ b/src/camera_controller/.sconsign.dblite
Binary files differ
diff --git a/src/camera_controller/PlayerCam.gd b/src/camera_controller/PlayerCam.gd
new file mode 100644
index 0000000..382ec06
--- /dev/null
+++ b/src/camera_controller/PlayerCam.gd
@@ -0,0 +1,79 @@
+extends ClippedCamera
+
+var _modes: PoolStringArray = ["STATIC", "FIRSTPERSON", "THIRDPERSON", "ARM", "FREECAM"]
+var mode: String = "STATIC" #STATIC, FIRSTPERSON, THIRDPERSON, ARM, FREECAM
+
+#first/third person variables
+var head: Spatial = null
+var neck: Spatial = null
+var player: RigidBody = null
+
+#third person/arm variables
+var arm: SpringArm = null
+
+var mouse_axis: Vector2
+var mouse_sensitivity: float = 12.0
+
+func _ready():
+ Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
+ current = true
+
+func _input(event: InputEvent):
+ if event is InputEventMouseMotion and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
+ mouse_axis = event.relative
+ match mode:
+ "FIRSTPERSON":
+ mouse_firstperson()
+ "THIRDPERSON":
+ mouse_thirdperson()
+ "STATIC":
+ pass
+ "ARM":
+ mouse_arm()
+ "FREECAM":
+ mouse_freecam()
+ _:
+ pass
+
+func attach(new_parent: Node, c_mode: String, extra_path: String = "."):
+ if get_parent():
+ get_parent().remove_child(self)
+ if c_mode in _modes:
+ mode = c_mode
+ if mode == "FIRSTPERSON":
+ head = new_parent.head; neck = new_parent.neck;
+ arm = null;
+ elif mode == "THIRDPERSON":
+ head = new_parent.head; neck = new_parent.neck;
+ arm = new_parent.arm
+ elif mode == "ARM":
+ head = null; neck = null;
+ arm = new_parent.arm
+ else:
+ head = null; neck = null; arm = null;
+ new_parent.get_node(extra_path).add_child(self)
+ transform = Transform.IDENTITY
+
+func mouse_firstperson() -> void:
+ if mouse_axis.length_squared() > 0:
+ var horizontal: float = -mouse_axis.x * (mouse_sensitivity / 100)
+ var vertical: float = -mouse_axis.y * (mouse_sensitivity / 100)
+
+ neck.rotate_y(deg2rad(horizontal))
+ head.rotate_x(deg2rad(vertical))
+
+ #vertical clamp
+ head.rotation_degrees.x = clamp(head.rotation_degrees.x, -90, 90)
+
+func mouse_thirdperson() -> void:
+ arm.rotation_degrees.x = clamp(rotation_degrees.x-mouse_axis.y*(mouse_sensitivity / 100),-90,90)
+ arm.rotation_degrees.y -= mouse_axis.x*(mouse_sensitivity / 100)
+ head.rotation_degrees.x = arm.rotation_degrees.x
+ neck.rotation_degrees.y = arm.rotation_degrees.y
+
+func mouse_arm() -> void:
+ arm.rotation_degrees.x = clamp(rotation_degrees.x-mouse_axis.y*(mouse_sensitivity / 100),-70,70)
+ arm.rotation_degrees.y -= mouse_axis.x*(mouse_sensitivity / 100)
+
+func mouse_freecam() -> void:
+ pass
diff --git a/src/camera_controller/SConstruct b/src/camera_controller/SConstruct
new file mode 100644
index 0000000..d68c103
--- /dev/null
+++ b/src/camera_controller/SConstruct
@@ -0,0 +1,109 @@
+#!python
+import os
+
+opts = Variables([], ARGUMENTS)
+
+# Gets the standard flags CC, CCX, etc.
+env = DefaultEnvironment()
+
+# Define our options
+opts.Add(EnumVariable('target', "Compilation target", 'debug', ['d', 'debug', 'r', 'release']))
+opts.Add(EnumVariable('platform', "Compilation platform", '', ['', 'windows', 'x11', 'linux', 'osx']))
+opts.Add(EnumVariable('p', "Compilation target, alias for 'platform'", '', ['', 'windows', 'x11', 'linux', 'osx']))
+opts.Add(BoolVariable('use_llvm', "Use the LLVM / Clang compiler", 'no'))
+opts.Add(PathVariable('target_path', 'The path where the lib is installed.', '../../godot/bin/'))
+opts.Add(PathVariable('target_name', 'The library name.', 'libplayercam', PathVariable.PathAccept))
+
+# Local dependency paths, adapt them to your setup
+godot_headers_path = "../../godot-cpp/godot-headers/"
+cpp_bindings_path = "../../godot-cpp/"
+cpp_library = "libgodot-cpp"
+
+# only support 64 at this time..
+bits = 64
+
+# Updates the environment with the option variables.
+opts.Update(env)
+
+# Process some arguments
+if env['use_llvm']:
+ env['CC'] = 'clang'
+ env['CXX'] = 'clang++'
+
+if env['p'] != '':
+ env['platform'] = env['p']
+
+if env['platform'] == '':
+ print("No valid target platform selected.")
+ quit();
+
+# For the reference:
+# - CCFLAGS are compilation flags shared between C and C++
+# - CFLAGS are for C-specific compilation flags
+# - CXXFLAGS are for C++-specific compilation flags
+# - CPPFLAGS are for pre-processor flags
+# - CPPDEFINES are for pre-processor defines
+# - LINKFLAGS are for linking flags
+
+# Check our platform specifics
+if env['platform'] == "osx":
+ env['target_path'] += 'osx/'
+ cpp_library += '.osx'
+ env.Append(CCFLAGS=['-arch', 'x86_64'])
+ env.Append(CXXFLAGS=['-std=c++17'])
+ env.Append(LINKFLAGS=['-arch', 'x86_64'])
+ if env['target'] in ('debug', 'd'):
+ env.Append(CCFLAGS=['-g', '-O2'])
+ else:
+ env.Append(CCFLAGS=['-g', '-O3'])
+
+elif env['platform'] in ('x11', 'linux'):
+ env['target_path'] += 'x11/'
+ cpp_library += '.linux'
+ env.Append(CCFLAGS=['-fPIC'])
+ env.Append(CXXFLAGS=['-std=c++17'])
+ if env['target'] in ('debug', 'd'):
+ env.Append(CCFLAGS=['-g3', '-Og'])
+ else:
+ env.Append(CCFLAGS=['-g', '-O3'])
+
+elif env['platform'] == "windows":
+ env['target_path'] += 'win64/'
+ cpp_library += '.windows'
+ # This makes sure to keep the session environment variables on windows,
+ # that way you can run scons in a vs 2017 prompt and it will find all the required tools
+ env.Append(ENV=os.environ)
+
+ env.Append(CPPDEFINES=['WIN32', '_WIN32', '_WINDOWS', '_CRT_SECURE_NO_WARNINGS'])
+ env.Append(CCFLAGS=['-W3', '-GR'])
+ env.Append(CXXFLAGS='/std:c++17')
+ if env['target'] in ('debug', 'd'):
+ env.Append(CPPDEFINES=['_DEBUG'])
+ env.Append(CCFLAGS=['-EHsc', '-MDd', '-ZI'])
+ env.Append(LINKFLAGS=['-DEBUG'])
+ else:
+ env.Append(CPPDEFINES=['NDEBUG'])
+ env.Append(CCFLAGS=['-O2', '-EHsc', '-MD'])
+
+if env['target'] in ('debug', 'd'):
+ cpp_library += '.debug'
+else:
+ cpp_library += '.release'
+
+cpp_library += '.' + str(bits)
+
+# make sure our binding library is properly includes
+env.Append(CPPPATH=['.', godot_headers_path, cpp_bindings_path + 'include/', cpp_bindings_path + 'include/core/', cpp_bindings_path + 'include/gen/'])
+env.Append(LIBPATH=[cpp_bindings_path + 'bin/'])
+env.Append(LIBS=[cpp_library])
+
+# tweak this if you want to use different folders, or more folders, to store your source code in.
+env.Append(CPPPATH=['./'])
+sources = Glob('*.cpp')
+
+library = env.SharedLibrary(target=env['target_path'] + env['target_name'] , source=sources)
+
+Default(library)
+
+# Generates help for the -h scons option.
+Help(opts.GenerateHelpText(env))
diff --git a/src/camera_controller/gdlibrary.cpp b/src/camera_controller/gdlibrary.cpp
new file mode 100644
index 0000000..3311441
--- /dev/null
+++ b/src/camera_controller/gdlibrary.cpp
@@ -0,0 +1,15 @@
+#include "playercam.h"
+
+extern "C" void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o) {
+ godot::Godot::gdnative_init(o);
+}
+
+extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *o) {
+ godot::Godot::gdnative_terminate(o);
+}
+
+extern "C" void GDN_EXPORT godot_nativescript_init(void *handle) {
+ godot::Godot::nativescript_init(handle);
+
+ godot::register_class<godot::PlayerCam>();
+}
diff --git a/src/camera_controller/gdlibrary.os b/src/camera_controller/gdlibrary.os
new file mode 100644
index 0000000..ade72b5
--- /dev/null
+++ b/src/camera_controller/gdlibrary.os
Binary files differ
diff --git a/src/camera_controller/playercam.cpp b/src/camera_controller/playercam.cpp
new file mode 100644
index 0000000..f321c09
--- /dev/null
+++ b/src/camera_controller/playercam.cpp
@@ -0,0 +1,107 @@
+#include "playercam.h"
+#include "InputEventMouseMotion.hpp"
+
+
+using namespace godot;
+
+PlayerCam::PlayerCam () { }
+PlayerCam::~PlayerCam () { }
+
+void PlayerCam::_register_methods() {
+ register_method("_ready", &PlayerCam::_ready);
+ register_method("_input", &PlayerCam::_input);
+ register_method("attach", &PlayerCam::attach);
+ register_method("mouse_firstperson", &PlayerCam::mouse_firstperson);
+ register_method("mouse_thirdperson", &PlayerCam::mouse_thirdperson);
+ register_method("mouse_arm", &PlayerCam::mouse_arm);
+ register_method("mouse_freecam", &PlayerCam::mouse_freecam);
+}
+
+void PlayerCam::_init() {
+ mode = String("STATIC");
+ head = nullptr;
+ neck = nullptr;
+ player = nullptr;
+ arm = nullptr;
+ mouse_axis = Vector2::ZERO;
+ mouse_sensitivity = 12.0;
+}
+
+void PlayerCam::_ready() {
+ Input *input_singleton = Input::get_singleton();
+ input_singleton->set_mouse_mode(Input::MOUSE_MODE_CAPTURED);
+ set_current(true);
+}
+
+void PlayerCam::_input(const Ref<InputEvent> event) {
+ Input const *input_singleton = Input::get_singleton();
+ Ref<InputEventMouseMotion> event_m(event);
+ if(event_m.is_valid() && input_singleton->get_mouse_mode() == Input::MOUSE_MODE_CAPTURED){
+ mouse_axis = event_m->get_relative();
+ if(mode == "FIRSTPERSON")mouse_firstperson();
+ else if(mode == "THIRDPERSON")mouse_thirdperson();
+ else if(mode == "STATIC");
+ else if(mode == "ARM")mouse_arm();
+ else if(mode == "FREECAM")mouse_freecam();
+ }
+}
+
+void PlayerCam::attach(Node* new_parent, String c_mode, String extra_path) {
+ if(get_parent() != nullptr)
+ get_parent()->remove_child(this);
+ if(c_mode == "FIRSTPERSON") {
+ head = (Spatial*)new_parent->find_node("Head", true, false); neck = (Spatial*)new_parent->find_node("Neck", true, false);
+ arm = nullptr; mode = c_mode;
+ }
+ else if (c_mode == "THIRDPERSON") {
+ head = (Spatial*)new_parent->find_node("Head", true, false); neck = (Spatial*)new_parent->find_node("Neck", true, false);
+ arm = (SpringArm*)new_parent->find_node("SpringArm", true, false); mode = c_mode;
+ }
+ else if(c_mode == "ARM") {
+ head = nullptr; neck = nullptr;
+ arm = (SpringArm*)new_parent->find_node("SpringArm", true, false); mode = c_mode;
+ }
+ else {
+ head = nullptr; neck = nullptr; arm = nullptr;
+ }
+ new_parent->get_node(NodePath(extra_path))->add_child(this);
+ set_transform(Transform::IDENTITY);
+}
+
+void PlayerCam::mouse_firstperson() {
+ if(mouse_axis.length_squared() > 0.0){
+ float horizontal = -mouse_axis.x * (mouse_sensitivity / 100.0);
+ float vertical = -mouse_axis.y * (mouse_sensitivity / 100.0);
+
+ neck->rotate_y(Math::deg2rad(horizontal));
+ head->rotate_x(Math::deg2rad(vertical));
+
+ //vertical clamp
+ Vector3 new_rot = head->get_rotation_degrees();
+ new_rot.x = Math::clamp((double)new_rot.x, -90.0, 90.0);
+ head->set_rotation_degrees(new_rot);
+ }
+}
+
+void PlayerCam::mouse_thirdperson() {
+ Vector3 new_arm_rot = arm->get_rotation_degrees();
+ new_arm_rot.x = Math::clamp((double)(get_rotation_degrees().x-mouse_axis.y*(mouse_sensitivity / 100)),-90.0,90.0);
+ new_arm_rot.y -= mouse_axis.x*(mouse_sensitivity / 100.0);
+ arm->set_rotation_degrees(new_arm_rot);
+ Vector3 new_head_rot = Vector3(arm->get_rotation_degrees().x, 0, 0);
+ Vector3 new_neck_rot = Vector3(0, arm->get_rotation_degrees().y, 0);
+
+ head->set_rotation_degrees(new_head_rot);
+ neck->set_rotation_degrees(new_neck_rot);
+}
+
+void PlayerCam::mouse_arm() {
+ //arm->rotation_degrees.x = Math::clamp(rotation_degrees.x-mouse_axis.y*(mouse_sensitivity / 100),-70,70);
+ //arm->rotation_degrees.y -= mouse_axis.x*(mouse_sensitivity / 100);
+}
+
+void PlayerCam::mouse_freecam() {
+// pass
+}
+
+
diff --git a/src/camera_controller/playercam.h b/src/camera_controller/playercam.h
new file mode 100644
index 0000000..dd089de
--- /dev/null
+++ b/src/camera_controller/playercam.h
@@ -0,0 +1,43 @@
+#ifndef PLAYERCAMGDS_H
+#define PLAYERCAMGDS_H
+
+#include <Godot.hpp>
+#include <ClippedCamera.hpp>
+#include <RigidBody.hpp>
+#include <SpringArm.hpp>
+#include <Input.hpp>
+
+namespace godot {
+
+class PlayerCam : public ClippedCamera {
+ GODOT_CLASS(PlayerCam, ClippedCamera)
+
+private:
+ String mode;
+ Spatial* head;
+ Spatial* neck;
+ RigidBody* player;
+ SpringArm* arm;
+ Vector2 mouse_axis;
+ float mouse_sensitivity;
+
+public:
+ static void _register_methods();
+
+ PlayerCam();
+ ~PlayerCam();
+
+ void _init();
+
+ void _ready();
+ void _input(const Ref<InputEvent> event);
+ void attach(Node* new_parent, String c_mode, String extra_path = ".");
+ void mouse_firstperson();
+ void mouse_thirdperson();
+ void mouse_arm();
+ void mouse_freecam();
+
+};
+
+}
+#endif
diff --git a/src/camera_controller/playercam.os b/src/camera_controller/playercam.os
new file mode 100644
index 0000000..29ea3c4
--- /dev/null
+++ b/src/camera_controller/playercam.os
Binary files differ
diff --git a/src/playercontroller.cpp b/src/playercontroller.cpp
new file mode 100644
index 0000000..edf85be
--- /dev/null
+++ b/src/playercontroller.cpp
@@ -0,0 +1,313 @@
+#include "playercontroller.h"
+
+using namespace godot;
+
+PlayerController::PlayerController () { }
+PlayerController::~PlayerController () { }
+
+void PlayerController::_register_methods() {
+ register_method("_ready", &PlayerController::_ready);
+ register_method("get_init_info", &PlayerController::get_init_info);
+ register_method("mp_init", &PlayerController::mp_init);
+ register_method("set_phys_transform", &PlayerController::set_phys_transform, GODOT_METHOD_RPC_MODE_REMOTE);
+ register_method("_process", &PlayerController::_process);
+ register_method("initiate_use", &PlayerController::initiate_use);
+ register_method("set_net_owner", &PlayerController::set_net_owner, GODOT_METHOD_RPC_MODE_REMOTESYNC);
+ register_method("deselect_character", &PlayerController::deselect_character);
+ register_method("take_control_of_machine", &PlayerController::take_control_of_machine);
+ register_method("lose_machine", &PlayerController::lose_machine);
+ register_method("_physics_process", &PlayerController::_physics_process);
+ register_method("on_floor_test", &PlayerController::on_floor_test);
+ register_method("_integrate_forces", &PlayerController::_integrate_forces);
+ register_method("walk", &PlayerController::walk);
+ register_method("jump", &PlayerController::jump);
+ register_method("swim", &PlayerController::swim);
+ register_method("enter_water", &PlayerController::enter_water);
+ register_method("exit_water", &PlayerController::exit_water);
+ register_method("mount_ladder", &PlayerController::mount_ladder);
+ register_method("climb_ladder", &PlayerController::climb_ladder);
+ register_method("leave_ladder", &PlayerController::leave_ladder);
+ register_method("damage", &PlayerController::damage, GODOT_METHOD_RPC_MODE_REMOTESYNC);
+ register_method("remove_dead_character", &PlayerController::remove_dead_character, GODOT_METHOD_RPC_MODE_REMOTESYNC);
+ register_method("net_apply_impulse", &PlayerController::net_apply_impulse, GODOT_METHOD_RPC_MODE_REMOTESYNC);
+
+ register_property<PlayerController, String>("team", &PlayerController::team, String("RED"));
+ register_property<PlayerController, int>("health", &PlayerController::health, int(100));
+ register_property<PlayerController, float>("mouse_sensitivity", &PlayerController::mouse_sensitivity, float(12.0));
+ register_property<PlayerController, float>("FOV", &PlayerController::FOV, float(90.0));
+ register_property<PlayerController, float>("jump_height", &PlayerController::jump_height, float(300.0));
+ register_property<PlayerController, bool>("is_player", &PlayerController::is_player, bool(false));
+ register_property<PlayerController, float>("walk_speed", &PlayerController::walk_speed, float(5.0));
+}
+
+void PlayerController::_init() {
+ weapon = nullptr;
+ world = nullptr;
+ mouse_axis = Vector2::ZERO;
+ velocity = Vector3::ZERO;
+ direction = Vector3::ZERO;
+ move_axis = Vector2::ZERO;
+ floorspeed = Vector3::ZERO;
+ jumping = false;
+ can_jump = true;
+ FLOOR_MAX_ANGLE = deg2rad(46.0);
+ in_water = false;
+ swim_speed = 450.0;
+ climb_speed = 5.0;
+ controlling_machine = false;
+ machine = nullptr;
+ ladder_m = nullptr;
+ player_state = nullptr;
+ is_on_floor = false;
+ floor_normal = Vector3::UP;
+ acceleration = 80.0;
+ c_friction = 4.0;
+ air_control = 0.3;
+}
+
+void PlayerController::_ready() {
+ head = get_node<Spatial>(NodePath("Neck/Head"));
+ neck = get_node<Spatial>(NodePath("Neck"));
+ nav = get_node<NavigationAgent>(NodePath("NavigationAgent"));
+ weapon = (Node *)ResourceLoader::get_singleton()->load("res://scenes/weapons/w_Rockets.tscn")->instance()
+ add_child(weapon)
+ world = get_tree()->get_root()->get_node("GAMEWORLD")
+}
+
+Dictionary PlayerController::get_init_info() {
+ return Dictionary::make("linear_velocity", get_linear_velocity(), "angular_velocity", get_angular_velocity(), "controlling_machine", controlling_machine, "team", team, "health", health, "nametag", get_node<Label3D>("Nametag")->get_text());
+}
+
+void PlayerController::mp_init(Dictionary init_info) {
+ for(int i = 0; i < init_info.keys().size(); i++)
+ set(init_info.keys()[i], init_info[init_info.keys()[i]]);
+ get_node<Label3D>("Nametag")->set_text(init_info["nametag"]);
+}
+
+void PlayerController::set_phys_transform(Transform trfrm, Vector3 lvel) {
+ set_transform(trfrm);
+ set_linear_velocity(lvel);
+}
+
+PlayerController::_process(float _delta) {
+// if is_player and !world.is_chatting:
+// if Input.is_action_just_pressed("use"):
+// initiate_use()
+}
+
+void PlayerController::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
+}
+
+void PlayerController::set_net_owner(int owner_id) {
+// $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()
+}
+
+void PlayerController::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)
+}
+
+void PlayerController::take_control_of_machine(RigidBody *slave_machine) {
+ machine = slave_machine;
+ controlling_machine = true;
+}
+
+void PlayerController::lose_machine() {
+ if is_network_master()world.cam.attach(self, "FIRSTPERSON", "./Neck/Head");
+ controlling_machine = false;
+ machine = nullptr;
+}
+
+PlayerController::_physics_process(float delta) {
+ if(is_network_master()) {
+ if (ladder_m != nullptr)
+ climb_ladder(delta);
+ else if( !on_floor_test() && in_water)
+ swim(delta);
+ else
+ walk(delta);
+ is_on_floor = false;// #reset whether is on floor in between frames
+ }
+}
+
+bool PlayerController::on_floor_test() {
+ const RayCast *feet = get_node<RayCast>("Feet");
+ if(feet->is_colliding()){
+ is_on_floor = true;
+ floor_normal = Vector3::UP;
+ floorspeed = feet->get_collider()->has_method("get_linear_velocity") ? feet->get_collider()->get_linear_velocity() : Vector3::ZERO;
+ return true;
+ }
+ if(player_state){
+ for(int i = 0;i< player_state->get_contact_count()) {
+ float contact_angle_from_up = 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;
+}
+
+void PlayerController::_integrate_forces(PhysicsDirectBodyState *state) {
+ if(!is_network_master()) return;
+ player_state = state;
+ velocity = state->get_linear_velocity();
+ for(int i=0; i < player_state->get_contact_count(); i++) {
+ float contact_angle_from_up = Vector3::UP.angle_to(player_state->get_contact_local_normal(i));
+ if(contact_angle_from_up > FLOOR_MAX_ANGLE && !is_on_floor){
+ set_friction(0);
+ break;
+ }
+ if(i == player_state.get_contact_count() - 1)
+ set_friction(1);
+ }
+ rpc("set_phys_transform", get_transform(), get_linear_velocity());
+ if(get_global_transform().origin.y < -30)
+ rpc("damage", 500000, "drown", Array::make(1, "Davy Jones"]);
+}
+
+void PlayerController::walk(float _delta) {
+// # 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
+}
+
+void PlayerController::jump() {
+ can_jump = false;
+ apply_central_impulse(Vector3.UP*jump_height);
+ yield(get_tree().create_timer(0.05),"timeout");
+ can_jump = true;
+}
+
+void PlayerController::swim(float _delta) {
+// #drag and buoyancy
+ add_central_force(Vector3.UP*weight*1.0);
+ add_central_force(-1*linear_velocity*100);
+// #controls
+ Basis dir = head->get_global_transform().basis;
+ Vector3 m_dir = -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*get_weight()*0.5);
+}
+
+void PlayerController::enter_water() {
+ in_water = true;
+}
+
+void PlayerController::exit_water() {
+ in_water = false;
+}
+
+void PlayerController::mount_ladder(Spatial target_ladder) {
+// 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)
+}
+
+void PlayerController::climb_ladder(float delta) {
+// 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()
+}
+
+void PlayerController::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
+}
+
+void PlayerController::damage(int dmg_amt, String _type, Array shooter, String extra = ".") {
+ 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")
+}
+
+void PlayerController::remove_dead_character() {
+ if(is_network_master() && machine != nullptr)
+ machine->call("relinquish_control");
+ deselect_character();
+ queue_free();
+}
+
+void PlayerController::net_apply_impulse(Vector3 impulse_v) {
+ apply_central_impulse(impulse_v);
+}
+
+
diff --git a/src/playercontroller.h b/src/playercontroller.h
new file mode 100644
index 0000000..388de3f
--- /dev/null
+++ b/src/playercontroller.h
@@ -0,0 +1,83 @@
+#ifndef PLAYERCONTROLLER_H
+#define PLAYERCONTROLLER_H
+
+#include <Godot.hpp>
+#include <RigidBody.hpp>
+
+namespace godot {
+
+class PlayerController : public RigidBody {
+ GODOT_CLASS(PlayerController, RigidBody)
+
+private:
+ String team;
+ int health;
+ Node *weapon;
+ Spatial *world;
+ float mouse_sensitivity;
+ float FOV;
+ Vector2 mouse_axis;
+ Spatial *head;
+ Spatial *neck;
+ Vector3 velocity;
+ Vector3 direction;
+ Vector3 move_axis;
+ Vector3 floorspeed;
+ bool jumping;
+ bool can_jump;
+ NavigationAgent nav;
+ float FLOOR_MAX_ANGLE;
+ float jump_height;
+ bool in_water;
+ float swim_speed;
+ float climb_speed;
+ bool controlling_machine;
+ RigidBody *machine;
+ bool is_player;
+ Spatial *ladder_m;
+ PhysicsDirectBodyState *player_state;
+ bool is_on_floor;
+ Vector3 floor_normal;
+ float acceleration;
+ float walk_speed;
+ float c_friction;
+ float air_control;
+
+
+public:
+ static void _register_methods();
+
+ PlayerController();
+ ~PlayerController();
+
+ void _init();
+
+ void _ready();
+ Dictionary get_init_info();
+ void mp_init(Dictionary init_info);
+ void set_phys_transform(Transform trfrm, Vector3 lvel);
+ void _process(float _delta);
+ void initiate_use();
+ void set_net_owner(int owner_id);
+ void deselect_character();
+ void take_control_of_machine(RigidBody slave_machine);
+ void lose_machine();
+ void _physics_process(float delta);
+ bool on_floor_test();
+ void _integrate_forces(PhysicsDirectBodyState *state);
+ void walk(float _delta);
+ void jump();
+ void swim(float _delta);
+ void enter_water();
+ void exit_water();
+ void mount_ladder(Spatial target_ladder);
+ void climb_ladder(float delta);
+ void leave_ladder();
+ void damage(int dmg_amt, String _type, Array shooter, String extra);
+ void remove_dead_character();
+ void net_apply_impulse(Vector3 impulse_v);
+
+};
+
+}
+#endif
diff --git a/src/script_to_header.py b/src/script_to_header.py
index 452a09d..e62984e 100644
--- a/src/script_to_header.py
+++ b/src/script_to_header.py
@@ -43,7 +43,7 @@ def script_to_gdn(filename):
returntype = "void"
if "->" in line:
- returntype = line[line.index("->"+1),line.index(":").strip()]
+ returntype = line[line.index("->")+1:line.index(":")].strip()
funcname = line[ line[0:line.index("(")].rindex(" ") : int(line.index("(")) ].strip()