diff options
Diffstat (limited to 'src/player_controller/playercontroller.cpp')
| -rw-r--r-- | src/player_controller/playercontroller.cpp | 325 |
1 files changed, 325 insertions, 0 deletions
diff --git a/src/player_controller/playercontroller.cpp b/src/player_controller/playercontroller.cpp new file mode 100644 index 0000000..6ea5544 --- /dev/null +++ b/src/player_controller/playercontroller.cpp @@ -0,0 +1,325 @@ +#include "playercontroller.h" +#include <ResourceLoader.hpp> +#include <PackedScene.hpp> +#include <Input.hpp> + +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 = Math::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")); + useray = get_node<RayCast>(NodePath("Neck/Head/UseRay")); + nametag = get_node<Label3D>(NodePath("Nametag")); + nav = get_node<NavigationAgent>(NodePath("NavigationAgent")); + Ref<PackedScene> p = ResourceLoader::get_singleton()->load("res://scenes/weapons/w_Rockets.tscn"); + weapon = (Node *)p->instance(); + add_child(weapon); + world = get_tree()->get_root()->get_node<Spatial>("GAMEWORLD"); + cam = (PlayerCam *)world->call("get_cam"); +} + +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]]); + nametag->set_text(init_info["nametag"]); +} + +void PlayerController::set_phys_transform(Transform trfrm, Vector3 lvel) { + set_transform(trfrm); + set_linear_velocity(lvel); +} + +void PlayerController::_process(float _delta) { + const Input *input_singleton = Input::get_singleton(); + if(is_player && !world->call("is_chatting_f")){ + if(input_singleton->is_action_just_pressed("use")) + initiate_use(); + if(controlling_machine) { + if(input_singleton->is_action_just_pressed("fire"))machine->call("attack1"); + if(input_singleton->is_action_just_pressed("fire2"))machine->call("attack2"); + } + } +} + +void PlayerController::initiate_use() { + if(controlling_machine){machine->call("relinquish_control"); return; } + if(ladder_m != nullptr) { leave_ladder(); return; } + if(useray->is_colliding()){ + const Node *area_c = (Node *) useray->get_collider(); + if(area_c->get_name() == "SteerArea") + world->rpc_id(1, "_call_on_server", "_client_request_control_vehicle", Dictionary::make("id", world->call("get_client_id"), "machine_path", area_c->get_parent()->get_path(), "char_name", get_name())); + else if(area_c->get_name() == "LadderArea") + mount_ladder((Spatial *)area_c->get_parent()); + else if(area_c->get_name() == "TugArea")return; + else if(area_c->get_name() == "PickupArea")return; + } +} + +void PlayerController::set_net_owner(int owner_id) { + nametag->set_text(""); + set_network_master(owner_id); + if(owner_id != 1) + nametag->set_text(String(world->call("get_players_info")[owner_id][0])); + if(get_tree()->get_network_unique_id() != 1){ + if(owner_id == (int)world->call("get_client_id")){ + nametag->set_visible(false); + world->call("set_player_char", this); + is_player = true; + cam->attach(this, "FIRSTPERSON", "./Neck/Head"); + }else{ + nametag->set_visible(true); + is_player = false; + } + world->get_node("HUD")->call("update_characters"); + } +} + +void PlayerController::deselect_character() { + if(is_network_master()){ + world->call("set_player_char", nullptr); + if((int)world->call("get_client_id") != 1)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())cam->attach(this, "FIRSTPERSON", "./Neck/Head"); + controlling_machine = false; + machine = nullptr; +} + +void 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, String("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); + add_central_force(-100*linear_velocity); +// #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) { + Spatial *ladder_tracker = Spatial::new(); + ladder_tracker->name = get_name(); + target_ladder->add_child(ladder_tracker); + ladder_tracker->set_transform(target_ladder->get_node<Spatial>("BOTTOM")->get_transform(); + + ladder_tracker->set_global_transform( Transform(target_ladder->call("get_nearest_point_to_route", get_global_transform().origin), ladder_tracker->get_global_transform().basis ) ); + look_at(get_global_transform().origin + target_ladder->get_global_transform().basis.x, target_ladder->get_global_transform().basis.y) + + ladder_m = ladder_tracker; + Transform t = ladder_m->get_global_transform(); + set_global_transform( Transform(t.origin, t.basis.orthonormalized())); + set_linear_velocity(Vector3::ZERO); + set_gravity_scale(0.0); +} + +void PlayerController::climb_ladder(float delta) { + Vector3 new_ladder_pos = ladder_m->get_global_transform().origin + ladder_m->get_global_transform().basis.y.normalized() * move_axis.x * delta * climb_speed; + float prog = ladder_m->get_parent()->call("get_climb_scalar", new_ladder_pos) + if(prog >= 0.0 and && <= 1.0) + ladder_m->set_global_transform(Transform(new_ladder_pos, ladder_m->get_global_transform().basis)); + Transform t = ladder_m->get_global_transform(); + set_global_transform( Transform(t.origin, t.basis.orthonormalized())); +} + +void PlayerController::leave_ladder() { + if((ladder_m->get_parent()->get_node<Spatial>("TOP")->global_transform.origin - get_global_transform().origin).length_squared() < 0.01) + apply_central_impulse(-400*ladder_m->get_global_transform().basis.z); + Transform t = get_global_transform(); + t.basis = world->get_global_transform().basis; + set_global_transform(t); + set_gravity_scale(1.0); + ladder_m->queue_free(); + ladder_m = nullptr; +} + +void PlayerController::damage(int dmg_amt, String _type, Array shooter, String extra = ".") { + health -= dmg_amt; + int shooter_id = shooter[0]; + String shooter_text = shooter[1]; + if(health <= 0 && is_network_master()){ + if(shooter_id != get_network_master() && shooter_id != 1) world->rpc_id(shooter_id, "game_killsound"); + if(get_network_master() == 1) + world->call("_call_on_server", "_character_death", Dictionary::make("killer_id", shooter_id, "killer", shooter_text, "victim_mp_id", get_network_master(), "victim", get_name(), "extra", extra)); + else + world->rpc_id(1, "_call_on_server", "_character_death", Dictionary::make("killer_id", shooter_id, "killer", shooter_text, "victim_mp_id", get_network_master(), "victim", get_name(), "extra", extra)); + } else if( is_network_master()) + if(shooter_id != get_network_master() && shooter_id != 1) world->rpc_id(shooter_id, "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); +} + + |
