I'm so proud cause I added AI drivers to my race game! [Free script giveaway!]

https://www.roblox.com/games/4519631442/Bloxy-Roads#!/game-instances

Hours of critical thinking and trial and error.

9 Likes

I played a round of it and I can say that’s really amazing.

Nice to see even AI’S could be racing with players.

Gives me some Mario Kart vibes playing this.

Keep up the great work.

1 Like

Mario kart with destruction physics

Here’s the script so far if you guys want to check it out. I’m giving it for free for those who might be struggling with AI cars or whatnot <3


local CurrentNode = nil

local NodeIndex = 0
local Nodes = {}

function GetNodes(Map)
	local FakeNodes = Map:FindFirstChild("AIPath"):GetChildren()
	
	-- you have the table. 
	-- you want to get the names of the table.
	-- convert the names to numbers
	-- find the one 
	local num  = 0
	repeat wait()
		num = num + 1
		for i,v in pairs(FakeNodes) do
			if tonumber(v.Name) == num and (not table.find(Nodes, v)) then
				table.insert(Nodes, v)
		--		print(num, v.Name)
		--		print(#Nodes, #FakeNodes)
			end
		end
		
	until #Nodes == #FakeNodes
	--print(#Nodes)
end


repeat wait() until script.Parent.Humanoid.SeatPart
local Car = script.Parent.Humanoid.SeatPart.Parent
--print("I'm driving this car "..Car.Name)

repeat wait() until game.ServerScriptService["Car Stiff"].Map.Value ~= nil

--print("wow")

-- add a coroutine while loop for constantly checking the surroundings for crash logic avoiding.
-- if the car is stuck and it cannot go left or right or to the front then it reverses towards the last node.
-- steering too.
local char = script.Parent
GetNodes(game.ServerScriptService["Car Stiff"].Map.Value)

local path = game.ServerScriptService["Car Stiff"].Map.Value:FindFirstChild("AIPath", true) 
--print(#Nodes)

--print("okay let's go!")
function Throttle(num)
	if Car.VehicleSeat.Throttle == num then return end
	Car.VehicleSeat.Throttle = num
end

function Steer(num)
	if Car.VehicleSeat.Steer == num then return end
	Car.VehicleSeat.Steer = num
end

if NodeIndex == 0 then
	NodeIndex = NodeIndex + 1
end
local evade = false

coroutine.wrap(function() -- avoidance logic
	while script.Parent.Humanoid.SeatPart do 
		wait(.5)





		local rayOrigin = Car.VehicleSeat.Position  + Car.VehicleSeat.CFrame.LookVector 
		local rayDirection = Car.VehicleSeat.CFrame.LookVector * 30

		-- Build a "RaycastParams" object and cast the ray
		local raycastParams = RaycastParams.new()
		raycastParams.FilterDescendantsInstances = {char.Head.Parent, Car }
		raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
		local raycastResult = workspace:Raycast(rayOrigin, rayDirection, raycastParams)

		if raycastResult and (raycastResult.Instance.Size.Magnitude < 40 and (raycastResult.Instance.Name ~= "Landscape" or raycastResult.Instance.Name ~= "Road"  )) then

			
			--print("There's an obstacle in front of me")
			local rrayOrigin = Car.VehicleSeat.Position  + Car.VehicleSeat.CFrame.LookVector 
			local rrayDirection = CFrame.fromAxisAngle(Vector3.new(0,1,0), math.rad(20)) * Car.VehicleSeat.CFrame.LookVector *30

			-- Build a "RaycastParams" object and cast the ray
			local rraycastParams = RaycastParams.new()
			rraycastParams.FilterDescendantsInstances = {char.Head.Parent, Car }
			rraycastParams.FilterType = Enum.RaycastFilterType.Blacklist
			local rraycastResult = workspace:Raycast(rayOrigin, rayDirection, raycastParams)

			if rraycastResult and (rraycastResult.Instance.Size.Magnitude < 40 and (rraycastResult.Instance.Name ~= "Landscape" or rraycastResult.Instance.Name ~= "Road"  )) then

				--	print("I can't turn to the right so i'll check the left")

			else
				evade = true
				Steer(-1)
				wait(1)
				evade = false
			end
			local lrayOrigin = Car.VehicleSeat.Position  + Car.VehicleSeat.CFrame.LookVector 
			local lrayDirection =  CFrame.fromAxisAngle(Vector3.new(0,1,0), math.rad(-20)) * Car.VehicleSeat.CFrame.LookVector * 30

			-- Build a "RaycastParams" object and cast the ray
			local lraycastParams = RaycastParams.new()
			lraycastParams.FilterDescendantsInstances = {char.Head.Parent, Car }
			lraycastParams.FilterType = Enum.RaycastFilterType.Blacklist
			local lraycastResult = workspace:Raycast(rayOrigin, rayDirection, raycastParams)

			if lraycastResult and (lraycastResult.Instance.Size.Magnitude < 40 and (lraycastResult.Instance.Name ~= "Landscape" or lraycastResult.Instance.Name ~= "Road"  )) then

				--	print("I can't turn to the left so i'll check to the right")
				evade = true
				Throttle(-1)
				Steer(0)
				wait(1.5)
				evade = false
			else
				evade = true
				Steer(1)
				wait(1)
				evade = false
			end
		end
	end
end)() 
CurrentNode = path:FindFirstChild("1")
local cframe = nil
local OffCourse = false

local OldNode = nil
coroutine.wrap(function()
	repeat wait() until cframe
	while true do 
		OldNode = CurrentNode
		wait(1)
		repeat wait(.5) until Car.VehicleSeat.Velocity.Magnitude < 10 or OffCourse == true
		local stuck = false
		for i = 1,30 do
			wait(.1)
			if i < 30 and Car.VehicleSeat.Velocity.Magnitude > 10 then
				stuck = false
				break
			end
			if i == 30 then
				stuck = true
			end
		end

		if (CurrentNode == OldNode and script.Parent.Head.Velocity.Magnitude < 5 and evade == false and stuck == true) or  OffCourse == true then
			evade = true
			Throttle(-1)
			Steer(0)
			wait(math.random(1,3))
			NodeIndex = NodeIndex
			local count = 0
			repeat 
				if Car.VehicleSeat.CFrame:ToObjectSpace(CurrentNode.CFrame).X > 0 then
					Steer(-1)
					--		print("I'm reversing to the left")

				elseif Car.VehicleSeat.CFrame:ToObjectSpace(CurrentNode.CFrame).X <= 0 then
					Steer(1)
					--	print("I'm reversing to the right")
				end
				wait()
				count = count + 1

				if Car.VehicleSeat.Velocity.Magnitude > 40 then
					Throttle(1)

				elseif Car.VehicleSeat.Velocity.Magnitude < 40 then
					Throttle(-1)
				end

				if count > 1300 and CurrentNode == OldNode then

					--	print("time to look for previous node")
					NodeIndex = NodeIndex - 1
					CurrentNode = FindNextNearestNode(NodeIndex)
					break
				end
			until Car.VehicleSeat.CFrame:ToObjectSpace(CurrentNode.CFrame).Z < 0
			--	print("ALRIGHT LET'S GO!!!!")
			OffCourse = false
			NodeIndex = NodeIndex + 1
			
			CurrentNode = FindNextNearestNode(NodeIndex)
			evade = false
			stuck = false
			--print("I suck at racing")
		end
	end
end)()




local checkifoffcourse = false

local topspeed = 180 + (6) * (Car.Level.Value ) - 1
local ImustDecideWhichPathToTake = false
local Followingstraightpath = true

local Factor = 10
local Exp = nil
for i,v in pairs(Car:GetDescendants()) do
	if v:IsA("HingeConstraint") and v.ActuatorType == Enum.ActuatorType.Servo and v.ServoMaxTorque > 10000  then
		Steer(1)

		Exp = v

		break
	end
end

--print(math.abs(Exp.TargetAngle).." is the target angle of this car")
local Coo = 0
repeat 
	
	Coo = Coo + 1
	wait(.1)
until Exp or Coo > math.random(10,40)
if Exp then
Factor = math.abs(Exp.TargetAngle)
elseif Exp == nil then
	Factor = 18
end
Steer(0)

local SpeedNecessary = 0

local truespeednec = 0
local Check = {}


function FindNextNearestNode(index)
	local Node = nil
	local NearestDist = 100000
	for i, d in pairs(Nodes) do

		if  (Car.VehicleSeat.Position - d.Position).Magnitude < NearestDist and tonumber(d.Name) == index  then

			Node = d
			NearestDist = (Car.VehicleSeat.Position - d.Position).Magnitude

		end
	end
	if Node == nil then
		Node = path:FindFirstChild("1")
		NodeIndex = 1
	end
	NearestDist = nil
	return Node
end
local PredictedPath = nil

local CarSpeed = nil

while script.Parent.Humanoid.Health > 0 and script.Parent.Humanoid.SeatPart and script.Parent:FindFirstChild("Head") do
	game:GetService("RunService").Heartbeat:Wait()

	print(Car.Name.. " is trying to reach "..CurrentNode.Name .." which is ".. (CurrentNode.Position - Car.VehicleSeat.Position).Magnitude .." studs away")
	if CurrentNode == nil then
		CurrentNode = path:FindFirstChild("1")
		
	end
	
	
	
	
	
	local Val = CurrentNode.CFrame + Vector3.new(math.random(-20,20),0,math.random(-20,20))
	Throttle(1)
	
	
	
	
	
	
	
	--	print(NodeIndex)

	
	
	
	
	
	
	
	
	
	SpeedNecessary = ((CurrentNode.Position - FindNextNearestNode(NodeIndex+1).Position ).Magnitude )/(( 20 / Factor))
	
	repeat wait(.025)-- game:GetService("RunService").Heartbeat:Wait()
		if evade == false then




			cframe = Car.VehicleSeat.CFrame:ToObjectSpace(Val) 
			--print(CurrentNode.Name.." is the target")
			--print(Car.VehicleSeat.AssemblyAngularVelocity.Magnitude)
			PredictedPath = (Car.VehicleSeat.CFrame + Car.VehicleSeat.Velocity):ToObjectSpace(Val)
			-- print(cframe.X.." car is steering "..Car.VehicleSeat.Steer)
			if cframe.X   + (Car.VehicleSeat.Velocity.X * 0.25) > (45 )  then
				coroutine.wrap(function()
					if Car.VehicleSeat.Steer == 1 then return end
					Steer(1)
				--	print("steer to the right now!")
					repeat game:GetService("RunService").Heartbeat:Wait() Steer(1) until Car.VehicleSeat.CFrame:ToObjectSpace(Val).X  + (Car.VehicleSeat.Velocity.X * 0.1) <30
					--	print("I'm aligned to the right")
					Steer(0)
				end)()

			elseif cframe.X + (Car.VehicleSeat.Velocity.X * 0.25) <  -(45 )   then
				--	print("Node is to left of player!")
				coroutine.wrap(function()
					if Car.VehicleSeat.Steer == -1 then return end
					Steer(-1)
				--	print("Steer to the left")
					repeat game:GetService("RunService").Heartbeat:Wait() Steer(-1) until Car.VehicleSeat.CFrame:ToObjectSpace(Val).X  + (Car.VehicleSeat.Velocity.X * 0.1) >-30
					--		print("I'm aligned to the left")
					Steer(0)
				end)()

			elseif cframe.X > -45 and cframe.X < 45 and Car.VehicleSeat.Brakes.Value == false then
				Steer(0)
				if Car.VehicleSeat.Throttle ~= 1 then
					Throttle(1)
				end
				
				
				
			end

	


		
			--	print(value.." is what we'll go for")

			if SpeedNecessary == 0 then
				SpeedNecessary = topspeed
			end
			CarSpeed = Car.VehicleSeat.Velocity.Magnitude
			--print(SpeedNecessary , CarSpeed .." reaching for "..value.." node")
			truespeednec = SpeedNecessary
			if SpeedNecessary > topspeed * 2 then
				SpeedNecessary = topspeed * 2
			end

			if OffCourse == false and (Car.VehicleSeat.CFrame):ToObjectSpace(FindNextNearestNode(NodeIndex).CFrame).Z > 0 and (Car.VehicleSeat.Velocity.Magnitude < 10) and checkifoffcourse == false and  (Car.VehicleSeat.CFrame):ToObjectSpace(FindNextNearestNode(NodeIndex + 1).CFrame).Z > 0 then
			--	print("Am I going off course?")
				checkifoffcourse = true
				Throttle(0)
				coroutine.wrap(function()
					wait(3) 
					if checkifoffcourse == true and (Car.VehicleSeat.CFrame):ToObjectSpace(FindNextNearestNode(NodeIndex).CFrame).Z > 0 and (Car.VehicleSeat.Velocity.Magnitude < 10) and (Car.VehicleSeat.CFrame):ToObjectSpace(FindNextNearestNode(NodeIndex + 1).CFrame).Z > 0  then
						OffCourse = true
						print("Looks like im going off course")
					end
					checkifoffcourse = false
				end)()
			end
			--	print("car is off course: "..tostring(OffCourse))
	--		print(Car.Name.." should go to speed: "..SpeedNecessary)

			if OffCourse == false then
				if CarSpeed < SpeedNecessary *1.75 then
					--print(CarSpeed.." is speed of "..Car.Name)
					Throttle(1)
					
					Car.VehicleSeat.Brakes.Value = false
				elseif CarSpeed > SpeedNecessary * 2 then
					Throttle(0)
					coroutine.wrap(function()
						if Car.VehicleSeat.Brakes.Value == false then

							Car.VehicleSeat.Brakes.Value = true
							repeat wait() until CarSpeed < SpeedNecessary	* 1.25
						end

					end)()
					Car.VehicleSeat.Boost.Value = false
				elseif CarSpeed < SpeedNecessary * 2 and CarSpeed > SpeedNecessary * 1.75  then
					Throttle(0)
					Car.VehicleSeat.Boost.Value = false
				end
				
				if (Car.VehicleSeat.Position - CurrentNode.Position).Magnitude > topspeed * 0.5  then 
					Car.VehicleSeat.Boost.Value = true
				elseif (Car.VehicleSeat.Position - CurrentNode.Position).Magnitude < topspeed * 0.5  then
					Car.VehicleSeat.Boost.Value = false
				end

			end
			
			
			
			
			if math.abs(Car.VehicleSeat.AssemblyAngularVelocity.Y) > 2.4 then
				
				--Car.VehicleSeat.Brakes.Value = true
				
				print("Steering too fast")
				repeat wait() Steer(0) until math.abs(Car.VehicleSeat.AssemblyAngularVelocity.Y) < 2
				--	Car.VehicleSeat.Brakes.Value = false
			end

		end	
		--	print(Car.Name.." tries reaching: ".. CurrentNode.Name,  math.abs(cframe.X),  math.abs(cframe.Z))
		--print((Val.Position - Car.VehicleSeat.Position).Magnitude)	


	until   Car.VehicleSeat.CFrame:ToObjectSpace(Val).Z > math.random(-20,5) and (Val.Position - Car.VehicleSeat.Position).Magnitude < 200

	NodeIndex = NodeIndex + 1

	
	-- if there aren't other of those same node values it means 

	
	CurrentNode = FindNextNearestNode(NodeIndex)
	print("I'm now moving to "..CurrentNode.Name.." yay")

	
	
	
	
	
	
	
	
	
	
	
	
	
end


7 Likes

i wish my math brain is yours :sob:

1 Like

Here… All you need to do when making AI is to define the environment.

Define where it is and where it should be.

Define what it has to do with what it already knows.

If it doesn’t know something, teach it. Lol but still it’s really hard you’d need to work in cooperation with others.

Honestly the brainstorming part is the hard part.