#include "playercontroller.h" #include #include #include 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("team", &PlayerController::team, String("RED")); register_property("health", &PlayerController::health, int(100)); register_property("mouse_sensitivity", &PlayerController::mouse_sensitivity, float(12.0)); register_property("FOV", &PlayerController::FOV, float(90.0)); register_property("jump_height", &PlayerController::jump_height, float(300.0)); register_property("is_player", &PlayerController::is_player, bool(false)); register_property("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(NodePath("Neck/Head")); neck = get_node(NodePath("Neck")); useray = get_node(NodePath("Neck/Head/UseRay")); nametag = get_node(NodePath("Nametag")); nav = get_node(NodePath("NavigationAgent")); Ref 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("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("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", "NULL"); 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("Feet"); if(feet->is_colliding()){ is_on_floor = true; floor_normal = Vector3::UP; floorspeed = feet->get_collider()->has_method("get_linear_velocity") ? ((RigidBody *)(feet->get_collider()))->get_linear_velocity() : Vector3::ZERO; return true; } if(player_state){ 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) { 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); //Godot::yield(get_tree().create_timer(0.05),"timeout"); can_jump = true; } void PlayerController::swim(float _delta) { // #drag and buoyancy add_central_force(Vector3::UP*get_weight()); add_central_force(-100*get_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->set_name(get_name()); target_ladder->add_child(ladder_tracker); ladder_tracker->set_transform(target_ladder->get_node("BOTTOM")->get_transform()); ladder_tracker->set_global_transform( Transform( ladder_tracker->get_global_transform().basis, (Vector3)target_ladder->call("get_nearest_point_to_route", get_global_transform().origin)) ); 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.basis.orthonormalized(), t.origin)); 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 && prog <= 1.0) ladder_m->set_global_transform(Transform(ladder_m->get_global_transform().basis, new_ladder_pos)); Transform t = ladder_m->get_global_transform(); set_global_transform( Transform(t.basis.orthonormalized(), t.origin )); } void PlayerController::leave_ladder() { if((ladder_m->get_parent()->get_node("TOP")->get_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); }