What I am trying to achieve is a car that can follow the Vector3 path that PathFindingService made. I would like to able to move the car similarly like Humanoid by doing Instance:MoveTo(<Vector3>).
I had tried BodyPosition however it doesn’t drive the car, it just moves it, and it feels very unrealistic.
I also tried doing some inefficient guessing but it didn’t work well.
You can lerp the cars CFrame, you can find lerping online pretty easy.
Its more or less just doing:
function Lerp(StartCF,EndCF,Multiplier)
return (EndCF - StartCF) * Multiplier
end
function MoveCar(CF)
local Progress = 1000
While Progress > 1000 do
Car:SetPrimaryPartCFrame(Lerp(Car.PrimaryPart.Cframe,CF, (Progress / 1000)))
wait(0.003)
end
end
(Only a rough draft do not copy and paste)
Topic is very much possible depending on how you simplify it and want to make it as realistic or unrealistic as you want.
Firstly in order to achieve the task you will need a movement controller to make the car move and rotate the way you want to.
You can actually use a humanoid behave like a car by accelerating by using the:move() every renderstep.
Plus this will make the car able to deal with obstacles like a slope or moving in a curve easier rather than using a physics based solution as well humanoids can basically ignore physics for the most part and focus on following the path we want the box to go to.
yeah I mean they can climb 89 degree slopes lol. But yeah a physics solution is still possible as long as you are able to make the car move in a direction and path you want.
If this method is too unrealistic then you can do other stuff like adding raycasting to make the car slow down on slopes and such.
However if the car were to directly move straight towards the goal position as you mentioned it wouldn’t be very realistic. Consequently, the solution will be the calculate a spline curve given the set of points and have your car move along this curve. I believe this is what other games do according to my research especially within the RTS genre where the player needs to control an tank AI unit as such. There are tutorials on this on youtube so maybe check it out and see what methods they use to move the car and accelerate and brake accordingly to the path set.
@dthecoolest What about creating two rays. One ray is straight, and second ray is angled to the point it should follow. Then I could take the angle and tell the car to either go left or go right depending on the angle. Is this a good idea?
@minimic2002 That can be very useful thanks. However the car still won’t rotate its wheels, however its more realistic than BodyPosition by itself.
@iSyriux Haha. I know. However I am trying to accomplish my goal, no matter what it takes. I want to be able to that. I am still trying to do it with RayCast .
I was thinking something along the lines of this vehicle AI tutorial that is used within an RTS game within unreal engine 4.
The timestamp in the video below is the part where he deals with the steering for the car and yeah your idea with finding the amount of steer with the angle is a similar idea in order to find the steer float of the vehicle to move the vehicle to the point.
The good thing is that the coding in unreal engine 4 in this case is done visually in block coding and so it’s simpler to understand the pure logic behind the code.
An additional thing to consider is what happens if the target point is behind the car. If so then the direction of steering will also need to be different which the video talks about.
Yeah, basically it’s all if statements telling the car when to steer left and right or move forwards/backward in relationship with the target point in order to reach the goal.
Perhaps this resource will come in helpful to construct the behavior of the car in order to reach the target point since we are dealing with ai here as if we were driving the car ourselves.
I believe the red line is the chassis look vector so it should just be like this. Remember to draw out the diagram on paper or in your head about the vector maths you are doing. The above line will only get you a point within the world of where the chassis is facing and not the direction.
My math skills are at nil level. So yeah. Should I use BasePart.Orientation instead? I may sound dumb, because I am not exactly sure what are you talking about.
Do I am missing something here?
local module = {}
function module:ComputeMoveAsync(VehicleSeat, Target)
local PathfindingService = game:GetService("PathfindingService")
local function toVector32(vect) return Vector3.new(vect.X, 0, vect.Z) end
local function getDistance(a, b) return (a - b).Magnitude end
local function castRay(Start, End)
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {}
raycastParams.FilterType = Enum.RaycastFilterType.Whitelist
local distance = getDistance(Start, End)
local raycastResult = workspace:Raycast(Start, (End - Start).Unit * distance, raycastParams)
local raypart = Instance.new("Part")
raypart.Name = "^"
raypart.Anchored = true
raypart.CanCollide = false
raypart.Size = Vector3.new(0.2, 0.2, distance)
raypart.CFrame = CFrame.new(End, Start) * CFrame.new(0, 0, -distance / 2)
raypart.Parent = workspace
return raypart
end
local Path = PathfindingService:CreatePath()
Path:ComputeAsync(toVector32(VehicleSeat.Position), toVector32(Target.Position))
if Path.Status == Enum.PathStatus.NoPath then return end
local Waypoints = Path:GetWaypoints()
for _, waypoint in pairs(Waypoints) do
local part = Instance.new("Part")
part.Shape = "Ball"
part.Material = "Neon"
part.Size = Vector3.new(0.6, 0.6, 0.6)
part.Position = waypoint.Position
part.Anchored = true
part.CanCollide = false
part.Name = "^"
part.Parent = game.Workspace
end
local from = Waypoints[1]
local to = Waypoints[2]
local angledRay = castRay(toVector32(from.Position),toVector32(to.Position))
angledRay.BrickColor = BrickColor.Green()
local straightRay = castRay(toVector32(from.Position), toVector32(VehicleSeat.CFrame.LookVector * 5))
straightRay.BrickColor = BrickColor.Red()
end
return module
Nope, don’t do base part orientation that’s even more confusing as you are doing with a weird version of Euler angles known as the Tait-Bryan angles which describe yaw, pitch, roll relative to the worlds x,y,z-axis. This means the angles are relative to the worlds axis like:
--orientation is (0,0,0)
--base part will have these vectors
local up = Vector3.new(0,1,0)
local right = Vector3.new(1,0,0)
local front = Vector3.new(0,0,-1)
Don’t deal with Euler angles unless you are really math fancy.
I am not with masters degree so yes I won’t deal with them. I wish I could
Someone already told me but it didn’t work for some reason.
local from = Waypoints[1]
local to = Waypoints[2]
local d = getDistance(from.Position, to.Position)
local angledRay = castRay(toVector32(from.Position),toVector32(to.Position))
angledRay.BrickColor = BrickColor.Green()
local straightRay = castRay(toVector32(from.Position), toVector32(Vector3.new(0, 1 * d, 0)))
straightRay.BrickColor = BrickColor.Red()
Do I just do everything upside down , it’s not even close to being straight.
or is it because of my toVector32() function, as it removes Y-axis. But I don’t think so.
I have no idea what you are trying to do with way point 1 and way point 2. Shouldn’t it be between waypoint 1 and the position of the car? basically the waypoint you want to move towards and where the car currently is.
Anyways this should create a straightray on waypoint 1 pointing towards the direction the car is facing if that is what you were trying to find.
local endPoint = toVector32(from.Position + (Chassis.CFrame.LookVector * d))
local straightRay = castRay(toVector32(from.Position), endPoint)
straightRay.BrickColor = BrickColor.Red()
local from = Waypoints[1]
local to = Waypoints[2]
local d = getDistance(from.Position, to.Position)
local angledRay = castRay(toVector32(from.Position), toVector32(to.Position))
angledRay.BrickColor = BrickColor.Green()
local straightRay = castRay(toVector32(from.Position), toVector32(from.Position + (VehicleSeat.CFrame.LookVector * d)))
straightRay.BrickColor = BrickColor.Red()
print(getAngle(straightRay.Position, angledRay.Position))
Since angle is 3.0752872726417 (in degrees) for other points (not the one above). How we can tell where to go, like left or right? So if it’s > 0 then left, if it’s < 0 then right?
To give it directionality we can use a cool property of the dot product which I use for my conical constraint in my inverse kinematics module shameless self-advertising sorry.
If we are given vectors a and b and we do a dot product between them we can find out directionality between these two vectors as seen in the diagram below for when the angle is 150° the dot product will become negative
Consequently, yeah we can do a bool check to find compare the direction between two vectors like so below.
local dotProduct = a:Dot(b)/(a.Magnitude * b.Magnitude)
local isOppositeDirection = false
--Detects the direction of the projection and adjust bool accordingly
if dotProduct < 0 then
isOppositeDirection = true
end
--if a and b same direction we will get 1 as we divide by the absolute value of itself
--if opposite we will get -1
--whoops also check for the zero condition so we don't divide
--by zero.
if dotProduct ~= 0 then
local steerFloat = dotProduct / math.abs(dotProduct)
end
In the car example diagram I drew you can do a dot product with the car’s .RightVector and the green vector which I drew going from the position of the car towards the target waypoint.
It keeps going in opposite direction. Unlike what I made so far:
local angle = getAngle(straightRay.Position, angledRay.Position)
if angle > 0 then
print("left")
setSteer(-1)
elseif angle < 0 then
print("right")
setSteer(1)
end
also, how can I check if the car is on the correct angle? so it doesn’t keep steering even tho its already going in correct direction
I don’t want my car to be anchored. I want it to go to the position that I had set, and I want car’s steer to move along, to make it seem like the car is actually driving.