Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --// Made by remi
- -- Control Module which handles the control of the vehicle.
- local playerService = game:GetService("Players")
- local userInputService = game:GetService("UserInputService")
- local contextActionService = game:GetService("ContextActionService")
- local runService = game:GetService("RunService")
- local player = playerService.LocalPlayer
- local speed_meter = script.CarControlGUI
- local interface = speed_meter.SpeedOMeter
- local display = interface.SpeedDisplay
- local needle = interface.Needle
- local reverse_indicator = interface.ReverseIndicator
- local reverse_light = reverse_indicator.Light
- local hover_indicator = interface.HoverMode
- local hover_light = hover_indicator.Light
- local function reset_gui()
- display.Text = "0"
- needle.Rotation = 0
- reverse_light.BackgroundColor3 = Color3.fromRGB(65, 0, 1)
- hover_light.BackgroundColor3 = Color3.fromRGB(65, 0, 1)
- end
- local camera = workspace.CurrentCamera
- local camera_height = 5
- local camera_distance = 22
- local looking_back = false
- local camera_sensitivity = 0.2
- local camera_fov = 70
- local camera_x_goal = 0
- local camera_y_goal = 0
- local camera_x = 0
- local camera_y = 0
- local mouse_idle_count = 0.7
- local mouse_idle_time = 0
- local steer_angle = 30
- local steer = 0
- local throttle = 0
- local altitude_gain = 0
- local altitude = 0
- local VECTOR3_ZERO = Vector3.new()
- local VECTOR2_ZERO = Vector2.new()
- local CFRAME_ZERO = CFrame.new()
- local HORIZONTAL = Vector3.new(1, 0, 1)
- local flipping = false
- local function raycast_parameters(...)
- local params = RaycastParams.new()
- params.FilterType = Enum.RaycastFilterType.Blacklist
- params.FilterDescendantsInstances = {...}
- return params
- end
- local function is_upsidedown(car, chasis)
- if flipping then return flipping end
- local up_vector = chasis.CFrame.UpVector
- local right_vector = chasis.CFrame.RightVector
- local position = chasis.Position
- local difference = (position + up_vector).Y - position.Y
- local upside_down = difference <= 0.5
- local parameters = raycast_parameters(car, player.Character)
- local up_cast = up_vector * (chasis.Size.Y/1.7)
- local right_cast = right_vector * (chasis.Size.X/1.7)
- local left_cast = right_vector * (-chasis.Size.X/1.7)
- local up_result = workspace:Raycast(position, up_cast, parameters)
- local right_result = workspace:Raycast(position, right_cast, parameters)
- local left_result = workspace:Raycast(position, left_cast, parameters)
- return upside_down and (up_result or right_result or left_result)
- end
- local function processGroundSteer(steer_constraints, steer)
- for _, constraint in ipairs(steer_constraints) do
- local orientation = constraint.Attachment0.Orientation
- constraint.Attachment0.Orientation = Vector3.new(orientation.X, steer ,orientation.Z)
- end
- end
- local function processGroundThrottle(origin, constraints0, constraints1, speed)
- for _, constraint in ipairs(constraints0) do
- local relative_pos = origin:PointToObjectSpace(constraint.Attachment0.WorldPosition)
- constraint.AngularVelocity = relative_pos.X > 0 and speed or -speed
- end
- for _, constraint in ipairs(constraints1) do
- local relative_pos = origin:PointToObjectSpace(constraint.Attachment0.WorldPosition)
- constraint.AngularVelocity = relative_pos.X > 0 and speed or -speed
- end
- end
- local function calculateFriction(velocity, wheels, chasis)
- local origin = chasis.CFrame
- for _, wheel in ipairs(wheels) do
- local relative_pos = origin:PointToObjectSpace(wheel.Position)
- if relative_pos.Z > 0 then continue end
- local friction = velocity <= 80 and 2 or 1.98
- if wheel.CustomPhysicalProperties.Friction == 1.9 then continue end
- local default = wheel.CustomPhysicalProperties
- wheel.CustomPhysicalProperties = PhysicalProperties.new(
- default.Density,
- default.Elasticity,
- default.ElasticityWeight,
- friction,
- default.FrictionWeight
- )
- end
- end
- local function calculateFlyForce(chasis, seat, steer, speed, altitude, dt)
- local vertical_force = Vector3.new(0, altitude, 0)
- local front_speed = -chasis.CFrame.LookVector * speed * 1.7
- local angular_velocity = Vector3.new(0, math.clamp(steer * 0.5, -25, 25), 0)
- return vertical_force + front_speed, angular_velocity
- end
- local function turnWheels(wheels)
- for index, wheel in ipairs(wheels) do
- local zero = wheel.Motor6D.Part0.CFrame:Inverse()
- local goal = CFrame.new(wheel.Position, wheel.Position-Vector3.new(0, 1, 0)) * CFrame.Angles(0, math.rad(90), 0)
- wheel.Motor6D.C0 = zero * goal
- end
- end
- local function resetWheels(wheels)
- for index, wheel in ipairs(wheels) do
- wheel.Motor6D.C0 = CFRAME_ZERO
- end
- end
- local function reset(steer, power)
- for _, constraint in ipairs(steer) do
- constraint.AngularVelocity = 0
- local orientation = constraint.Attachment0.Orientation
- constraint.Attachment0.Orientation = Vector3.new(orientation.X, 0 ,orientation.Z)
- end
- for _, constraint in ipairs(power) do
- constraint.AngularVelocity = 0
- end
- end
- local control = {}
- control.inputs = {
- GainAltitude = Enum.KeyCode.E;
- LoseAltitude = Enum.KeyCode.Q;
- Turnback = Enum.UserInputType.MouseButton3;
- ChangeMode = Enum.KeyCode.H;
- }
- local modes = {
- "ground";
- "hover";
- }
- local current_mode = 1
- function control.Init(car, speed, turn_speed, torque, acceleration, vertical_speed, vertical_acceleration)
- if control.car then return error("Player is already controlling a vehicle.") end
- local aesthetics = car.Aesthetics
- local constraints = car.Body.Constraints
- local physics = car.Physics
- control.car = car
- control.body = car.Body
- control.seat = car.Seat
- control.chasis = aesthetics.Chasis
- control.wheels = physics.Wheels:GetChildren()
- control.speed = speed
- control.turn_speed = turn_speed
- control.torque = torque
- control.acceleration = acceleration
- control.vertical_speed = vertical_speed
- control.vertical_acceleration = vertical_acceleration
- control.fly_force = car.Body.FlyForce
- control.control_force = car.Body.ControlForce
- control.gyro = car.Body.Gyro
- control.fly_rotation = car.Body.FlyRotation
- control.power = constraints.Powered:GetChildren()
- control.steer = constraints.Steering:GetChildren()
- control.state = "ground"
- camera.CameraType = Enum.CameraType.Scriptable
- userInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
- userInputService.MouseIconEnabled = false
- for input_name, keybind in pairs(control.inputs) do
- contextActionService:BindAction(input_name, control.ProcessInput, false, keybind)
- end
- speed_meter.Parent = player.PlayerGui
- runService:BindToRenderStep("ControlUpdate", Enum.RenderPriority.Last.Value, control.Update)
- end
- function control.Stop()
- runService:UnbindFromRenderStep("ControlUpdate")
- flipping = false
- steer = 0
- throttle = 0
- altitude = 0
- altitude_gain = 0
- camera_x = 0
- camera_y = 0
- camera_distance = 22
- for input_name, keybind in pairs(control.inputs) do
- contextActionService:UnbindAction(input_name)
- end
- reset_gui()
- reset(control.steer, control.power)
- current_mode = 1
- control.state = "ground"
- control.body.Chasis.C0 = CFRAME_ZERO
- resetWheels(control.wheels)
- control.fly_force.Force = VECTOR3_ZERO
- control.control_force.Velocity = VECTOR3_ZERO
- control.fly_rotation.AngularVelocity = VECTOR3_ZERO
- speed_meter.Parent = script
- camera.CameraType = Enum.CameraType.Custom
- userInputService.MouseBehavior = Enum.MouseBehavior.Default
- userInputService.MouseIconEnabled = true
- for k, v in pairs(control) do
- if k == "inputs" or k == "state" then continue end
- if type(v) == "function" then continue end
- control[k] = nil
- end
- end
- function control.ProcessInput(input_name, state, input)
- if input_name == "Turnback" then
- camera_distance = -camera_distance
- looking_back = not looking_back
- elseif input_name == "ChangeMode" and state == Enum.UserInputState.Begin then
- current_mode += 1
- if current_mode > #modes then current_mode = 1 end
- local state = modes[current_mode]
- control.state = state
- if state == "ground" then
- resetWheels(control.wheels)
- control.body.Chasis.C0 = CFRAME_ZERO
- hover_light.BackgroundColor3 = Color3.fromRGB(65, 0, 1)
- elseif state == "hover" then
- hover_light.BackgroundColor3 = Color3.fromRGB(255, 76, 76)
- end
- elseif input_name == "GainAltitude" then
- if state == Enum.UserInputState.Begin then
- altitude_gain = 1
- else
- altitude_gain = 0
- end
- elseif input_name == "LoseAltitude" then
- if state == Enum.UserInputState.Begin then
- altitude_gain = -1
- else
- altitude_gain = 0
- end
- end
- end
- function control.Update(dt)
- local mouseDelta = userInputService:GetMouseDelta()
- local chasis = control.chasis
- local velocity = (chasis.Velocity * HORIZONTAL).Magnitude
- local fly_force = control.fly_force
- local control_force = control.control_force
- local fly_rotation = control.fly_rotation
- local steer_goal = -control.seat.SteerFloat * steer_angle
- steer += (steer_goal - steer) * math.min(dt * control.turn_speed, 1)
- steer = math.abs(steer) < 0.1 and 0 or steer
- local throttle_goal = control.seat.ThrottleFloat
- throttle += (throttle_goal - throttle) * math.min(dt * control.acceleration, 1)
- local speed = throttle * control.speed
- speed = math.abs(speed) < 0.1 and 0 or speed
- local altitude_goal = altitude_gain * control.vertical_speed
- altitude += (altitude_goal - altitude) * math.min(dt * control.vertical_acceleration, 1)
- altitude = math.abs(altitude) < 0.1 and 0 or altitude
- local fov_goal = velocity > 70 and velocity or 70
- camera_fov += (fov_goal - camera_fov) * dt
- camera.FieldOfView = math.clamp(camera_fov, 70, 100)
- if control.state == "ground" then
- control.control_force.MaxForce = VECTOR3_ZERO
- control.gyro.MaxTorque = VECTOR3_ZERO
- calculateFriction(chasis.Velocity.Magnitude, control.wheels, chasis)
- processGroundSteer(control.steer, steer)
- processGroundThrottle(chasis.CFrame, control.steer, control.power, speed)
- if is_upsidedown(control.car, chasis) and not flipping and velocity < 10 then
- flipping = true
- elseif fly_force ~= VECTOR3_ZERO and not flipping then
- fly_rotation.AngularVelocity = VECTOR3_ZERO
- fly_force.Force = VECTOR3_ZERO
- elseif flipping then
- fly_rotation.AngularVelocity = Vector3.new(0, 0, 1) * -math.clamp(steer, -15, 15)
- fly_force.Force = steer == 0 and VECTOR3_ZERO or Vector3.new(0, 0.8, 0) * chasis.AssemblyMass * workspace.Gravity
- local position = chasis.Position
- local up_vector = chasis.CFrame.UpVector
- local parameters = raycast_parameters(control.car, player.Character)
- local larger_side = chasis.Size.X > chasis.Size.Y and chasis.Size.X or chasis.Size.Y
- local in_ground = workspace:Raycast(position, Vector3.new(0, -1.2, 0) * larger_side, parameters)
- if in_ground then
- local touching_ground = true
- for _, wheel in ipairs(control.wheels) do
- local origin = wheel.Position
- local direction = -up_vector * wheel.Size.Y
- local result = workspace:Raycast(origin, direction, parameters)
- if not result then touching_ground = false break end
- end
- local difference = (position + up_vector).Y - position.Y
- local standing = difference > 0.5
- if touching_ground and standing then
- flipping = false
- end
- else
- flipping = false
- end
- end
- elseif control.state == "hover" then
- control.control_force.MaxForce = Vector3.new(1, 1, 1) * 40000
- control.gyro.MaxTorque = Vector3.new(1, 0, 1) * 400000
- control.gyro.CFrame = CFrame.fromOrientation(0, 0, 0)
- turnWheels(control.wheels)
- local movement_force, angular_velocity = calculateFlyForce(chasis, control.seat, steer, speed, altitude, dt)
- if velocity > 2 then
- local angle = chasis.CFrame.RightVector:Dot(chasis.Velocity.Unit) * -4
- control.body.Chasis.C0 = CFrame.Angles(0, 0, math.rad(angle))
- else
- control.body.Chasis.C0 = CFRAME_ZERO
- end
- fly_force.Force = Vector3.new(0, 1, 0) * chasis.AssemblyMass * workspace.Gravity
- fly_rotation.AngularVelocity = angular_velocity
- control_force.Velocity = movement_force
- end
- if math.floor(chasis.CFrame:VectorToObjectSpace(chasis.Velocity).Z) < -10 and throttle < 0 then
- if looking_back == false then
- camera_distance = -camera_distance
- looking_back = true
- end
- else
- if camera_distance < 0 and not userInputService:IsMouseButtonPressed(Enum.UserInputType.MouseButton3) then
- camera_distance = -camera_distance
- looking_back = false
- end
- end
- local rotation_goal = (math.abs(speed) / control.speed) * 180
- needle.Rotation += (rotation_goal - needle.Rotation) * dt
- display.Text = math.floor(velocity)
- reverse_light.BackgroundColor3 = speed >= 0 and Color3.fromRGB(65, 0, 1) or Color3.fromRGB(255, 76, 76)
- camera_x_goal = math.clamp(camera_x_goal-mouseDelta.X*camera_sensitivity, -130, 130)
- camera_y_goal = math.clamp(camera_y_goal+mouseDelta.Y*camera_sensitivity, -18, 45)
- camera_x_goal = math.abs(camera_x_goal) < 0.05 and 0 or camera_x_goal
- camera_y_goal = math.abs(camera_y_goal) < 0.05 and 0 or camera_y_goal
- if mouseDelta == VECTOR2_ZERO and not (camera_x_goal == 0 and camera_y_goal == 0) then
- mouse_idle_time += dt
- else
- mouse_idle_time = 0
- end
- if mouse_idle_time >= mouse_idle_count then
- camera_x_goal -= camera_x_goal * camera_sensitivity
- camera_y_goal -= camera_y_goal * camera_sensitivity
- end
- camera_x += (camera_x_goal - camera_x)
- camera_y += (camera_y_goal - camera_y)
- camera_x = math.abs(camera_x) <= 0.05 and 0 or camera_x
- camera_y = math.abs(camera_y) <= 0.05 and 0 or camera_y
- local offset = CFrame.lookAt(Vector3.new(0, camera_height, -camera_distance), (chasis.CFrame.LookVector * Vector3.new(1, 0, 1)) + Vector3.new(0, camera_height, 0))
- camera.CFrame = chasis.CFrame * CFrame.fromEulerAnglesYXZ(math.rad(camera_y), math.rad(camera_x), 0) * offset
- end
- return control
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement