extends Node class_name Player const MAX_SPEED:float = 0.2 const START_OFFSET = [1.70223, 1.20223, 0.702227, 0.202227 ] const LANE_OFFSET = [-0.085, 0.085, -0.255, 0.255 ] export var player_color:Color var player_name:String var thrust:int = 0 var current_speed:float = 0.0 export var speed_factor:float = 0.001 export var brake_factor:float = 2.0 export var friction_brake_factor:float = 0.8 onready var race_car = get_node("Path/PathFollow/raceCar") onready var timer:Timer = get_node("ResetTimer") onready var path:Path = get_node("Path") onready var follow:PathFollow = get_node("Path/PathFollow") onready var route:Route var lane:int var start_init:bool = true var has_next:bool = false var is_resetable:bool = false var buffered_curve:Curve3D var buffered_translate:Vector3 = Vector3(0,0,0) var buffered_rotation:Vector3 = Vector3(0,0,0) var last_rotation:Vector3 = Vector3(0,0,0) var torque_penalty:Vector3 var force_penalty:Vector3 var path_penalty:float var is_out:bool = false var position:Vector2 puppet var slave_position:Vector2 func _ready(): route = gamestate.game.route race_car.road_ray.set_collision_mask_bit(get_index(),1) path.curve = path.curve.duplicate() path.curve.set_bake_interval(0.05) func _physics_process(delta): if is_network_master(): if not is_out: var max_speed = MAX_SPEED if get_road() != null: var road = get_road() if is_in_group("first"): max_speed *= road.get_first_speed_factor() elif road.get_creator() == get_index(): max_speed *= road.get_creator_speed_factor() else: max_speed *= road.get_chasers_speed_factor() if thrust == 1: current_speed += speed_factor elif thrust == -1: current_speed -= speed_factor * brake_factor else: current_speed -= speed_factor * friction_brake_factor if current_speed >= max_speed: current_speed = max_speed elif current_speed < 0: current_speed = 0 follow.set_offset(follow.get_offset() + current_speed) if follow.get_offset() < 0: follow.set_offset(0) if has_next && (path.curve.get_point_count() == 0 || follow.get_unit_offset() >= 1.0): has_next = false if path.curve.get_point_count() > 0: path.curve.clear_points() path.curve.set_bake_interval(0.05) for i in range(buffered_curve.get_point_count()): var _pos = buffered_curve.get_point_position(i) var _in = buffered_curve.get_point_in(i) var _out = buffered_curve.get_point_out(i) if buffered_rotation.length() != 0: _pos = _pos.rotated(buffered_rotation.normalized(), buffered_rotation.length()) _in = _in.rotated(buffered_rotation.normalized(), buffered_rotation.length()) _out = _out.rotated(buffered_rotation.normalized(), buffered_rotation.length()) path.curve.add_point(buffered_translate + _pos, _in, _out) path.curve.set_point_tilt(i, buffered_curve.get_point_tilt(i)) if not start_init: follow.set_offset(0.001) else: follow.set_offset(START_OFFSET[lane]) start_init = false if get_road() != null: var road = get_road() var penalty_index = road.penalty_index(follow.get_offset(), current_speed) if penalty_index >= 0: torque_penalty = road.get_torque_penalty(penalty_index) force_penalty = road.get_force_penalty(penalty_index) path_penalty = road.get_path_penalty(penalty_index) rpc("set_out") check_position() else: var road = get_road() race_car.get_node("ray").set_enabled(false) if force_penalty.length() != 0: race_car.move_and_slide(force_penalty * current_speed + Vector3(0,-0.5,0)) if torque_penalty.length() != 0: race_car.rotate_object_local(torque_penalty.normalized(), torque_penalty.length() * current_speed) if path_penalty > 0 && follow.get_offset() > 0.0: follow.set_offset(follow.get_offset() - 0.01) path_penalty -= 0.01 current_speed -= 0.0002 if current_speed < 0: current_speed = 0 else: position = slave_position func get_road(): return race_car.road func _on_raceCar_road_entered(road): var prev_road = route.get_road(road.get_index()-1) if prev_road != null: prev_road.body.set_collision_layer_bit(get_index(),0) buffered_curve = road.get_lane_curve(lane) buffered_rotation = last_rotation if path.curve.get_point_count() > 0: buffered_translate = util.curve_get_last_point(path.curve) if road.get_end_rotation().length() != 0: last_rotation += road.get_end_rotation() has_next = true func get_player_name(): return player_name func set_player_name(new_name): player_name = new_name func get_player_color(): return player_color func set_player_color(new_color): player_color = new_color var material = SpatialMaterial.new() material.set_albedo(player_color) race_car.get_node("body").set_surface_material(1,material) func is_out(): return is_out remotesync func set_out(): is_out = true is_resetable = false timer.start() remotesync func set_in(): is_out = false is_resetable = false remotesync func set_first(is_first:bool): if get_tree().get_rpc_sender_id() == 0 || get_tree().get_rpc_sender_id() == get_network_master(): if is_first: add_to_group("first") else: remove_from_group("first") master func check_position(): position = Vector2(race_car.road_index, follow.get_offset()) rset("slave_position", position) master func set_thrust(new_thrust:int): var sender_id = get_tree().get_rpc_sender_id() if is_network_master() || gamestate.game.get_player_by_network_id(sender_id) == self && [-1,0,1].has(new_thrust): thrust = new_thrust master func reset(): var sender_id = get_tree().get_rpc_sender_id() if (is_network_master() || gamestate.game.get_player_by_network_id(sender_id) == self) && is_resetable: has_next = false current_speed = 0 var road = race_car.road road.body.set_collision_layer_bit(get_index(),1) var reset_index = road.reset_index for i in range(reset_index): road = route.get_road(road.get_index() - 1) road.body.set_collision_layer_bit(get_index(),1) path.curve.clear_points() force_penalty = Vector3(0,0,0) torque_penalty = Vector3(0,0,0) buffered_translate = road.get_translation() last_rotation = road.get_rotation() race_car.road_index = road.get_index() race_car.road = null race_car.collider = null race_car.transform = Transform() race_car.get_node("ray").set_enabled(true) follow.set_transform(road.get_transform()) rpc("set_in") func set_start(new_lane:int): lane = new_lane follow.set_h_offset(LANE_OFFSET[lane]) func _on_ResetTimer_timeout(): is_resetable = true