extends RigidBody # Game export var team = "RED" export (int) var health = 100 var weapon = null var world # Camera export(float) var mouse_sensitivity = 12.0 export(float) var FOV = 90.0 var mouse_axis := Vector2() onready var head: Spatial = $Head onready var cam: Camera = $Head/Camera # Move var velocity := Vector3() var direction := Vector3() var move_axis := Vector2() var floorspeed := Vector3() onready var nav = $NavigationAgent # Walk const FLOOR_MAX_ANGLE: float = deg2rad(46.0) export(float) var jump_height = 400 # Control var controlling_machine = false #whether character is riding/controlling something var machine = null export var is_player = false #whether character is currently controlled by a player var should_move = false #physics var player_state : PhysicsDirectBodyState var is_on_floor:bool export(float) var acceleration = 80.0 export(int) var walk_speed = 6 export(float) var c_friction = 4.0 export(float) var _airspeed_cap = 1.0 export(float) var air_control = 1.0 # 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") if is_player: cam.current = true $Head/Camera/UseRay.add_exception(self) $Head/Camera/MeleeRay.add_exception(self) $Head/Camera/LongRay.add_exception(self) Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) cam.fov = FOV func get_init_info(): 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): for variable in init_info.keys(): set(variable, init_info[variable]) $Nametag.text = init_info["nametag"] remote func set_phys_transform(trfrm, lvel): 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")) else: 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() machine = null controlling_machine = false if is_player: cam.current = true return if $Head/Camera/UseRay.is_colliding(): var type = $Head/Camera/UseRay.get_collider().name match type: "SteerArea": controlling_machine = true machine = $Head/Camera/UseRay.get_collider().get_parent().take_control(self) var gt = global_transform.origin velocity = Vector3.ZERO global_transform.origin = gt _: pass remotesync func set_owner(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: world.player_char = self is_player = true cam.current = true else: cam.current = false is_player = false world.get_node("HUD").update_characters() func deselect_character(): if is_network_master(): world.player_char = null world.get_node("DEFAULTCAM").current = true rpc("set_owner", 1) func regain_control(_gt): controlling_machine = false machine = null # Called every physics tick. 'delta' is constant func _physics_process(delta: float) -> void: walk(delta) if is_network_master(): rpc("set_phys_transform", transform, linear_velocity) # called by signal when character is collided with func on_floor_test() -> void: if $Feet.is_colliding(): is_on_floor = true if $Feet.get_collider().has_method("get_linear_velocity"): floorspeed = $Feet.get_collider().get_linear_velocity() else: floorspeed = Vector3.ZERO return 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: is_on_floor = true #modify simulated physics results func _integrate_forces(state) -> void: player_state = state velocity = state.get_linear_velocity() if should_move: nav.set_velocity(velocity) if nav.is_target_reached(): should_move = false # on input event func _input(event: InputEvent) -> void: if is_player: if event is InputEventMouseMotion: mouse_axis = event.relative camera_rotation() func walk(_delta:float) -> void: on_floor_test() # Input direction = Vector3() var aim: Basis = head.get_global_transform().basis direction += -move_axis.x * aim.z + move_axis.y * aim.x if !is_player and should_move: direction = nav.get_next_location() - global_transform.origin if nav.get_next_location().y - global_transform.origin.y > 0.05 and is_on_floor: apply_central_impulse(Vector3.UP*jump_height) direction.y = 0 direction = direction.normalized() # Jump if is_on_floor and is_player: if Input.is_action_just_pressed("move_jump"): apply_central_impulse(Vector3.UP*jump_height) #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: 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 _airspeed_cap - projVel > 0: add_central_force (mass*Vector3(direction.x*_temp_accel, 0, direction.z*_temp_accel)) is_on_floor = false #reset whether is on floor in between frames remotesync func damage(dmg_amt, type, shooter, extra = ""): health -= dmg_amt if health <= 0 and is_network_master(): if get_network_master() == 1: world._call_on_server("_character_death", {"killer" : shooter, "victim_mp_id" : get_network_master(), "victim" : name, "extra" : extra}) else: world.rpc_id(1, "_call_on_server", "_character_death", {"killer" : shooter, "victim_mp_id" : get_network_master(), "victim" : name, "extra" : extra}) remotesync func remove_dead(): deselect_character() queue_free() func camera_rotation() -> void: if Input.get_mouse_mode() != Input.MOUSE_MODE_CAPTURED: return if mouse_axis.length() > 0: var horizontal: float = -mouse_axis.x * (mouse_sensitivity / 100) var vertical: float = -mouse_axis.y * (mouse_sensitivity / 100) mouse_axis = Vector2() head.rotate_y(deg2rad(horizontal)) cam.rotate_x(deg2rad(vertical)) # Clamp mouse rotation var temp_rot: Vector3 = cam.rotation_degrees temp_rot.x = clamp(temp_rot.x, -90, 90) cam.rotation_degrees = temp_rot