Need help with machine learning

so, I recently learned that arc raiders uses ML to make their enemies work. I want to replicate that, I currently know the basics of machine learning and would like help on how I could do what Arc raiders did.

I need the enemies to:
Patrol areas/ search for players
engage in combat
know how to fly or walk (they will be a drone or spider-like creature)
overall be smart

any info or knowledge you could pass to me is heavily appreciated. also, I am using OpenML for my machine learning model, if you have any recommendations on other models I should use, then I am open (I am not using datapredict)

2 Likes

here is an example of what I am doing:

local OpenML = require(game.ServerScriptService.OpenML)

local States = {'NearGround',"ProperlyOrientated", "TooHigh", "Target"}
local Actions = {
	"Thrust",
	"Propeller_X", "Propeller_Z",
}

local ActivationFunction = OpenML.ActivationFunctions.TanH

local learningRate = .2

local Drone = script.Parent.Torso
local Eye = script.Parent.Eye.HitBox

local NewAI = setmetatable(OpenML.Resources.MLP.new({ #States, 10, 10, 10, #Actions }, function()
	return (math.random() * 2 - 1) * 1.5
end), { __index = OpenML.Algorithms.Propagator})

local DQL = OpenML.Algorithms.DQL.new()

DQL.OnForwardPropagation = function(state) return NewAI:ForwardPropagation(state, ActivationFunction) end
DQL.OnBackPropagation = function(activations, target) return NewAI:BackPropagation(activations, target, { ActivationFunction = ActivationFunction, LearningRate = learningRate }) end

function SimplifiyPrediction(Prediction)
	if typeof(Prediction[1]) == "number" then
		return Prediction
	end

	local NewPrediction = {}
	for I, Slot in ipairs(Prediction) do
		local Average = 0
		for _, Number in ipairs(Slot) do
			Average += Number
		end
		NewPrediction[I] = Average / #Slot
	end
	return NewPrediction
end

Eye.Touched:Connect(function()
	
end)

function NearGround()
	local Raycast = workspace:Raycast(script.Parent.Torso.Position, Vector3.new(0, -5, 0))
	
	if Raycast then
		return 1
	end
	return 0
end

local function clampPrediction(prediction)
	for i = 1, #prediction do
		prediction[i] = math.clamp(prediction[i], -1, 1)
	end
	return prediction
end

function GetTarget()
	local Eye = script.Parent.Eye.HitBox
	
	local HasTarget = 0
	
	for _, Part in Eye:GetTouchingParts() do
		if Part.Name == "TargetPart" then
			HasTarget = 1
		end
	end
	
	local Target = workspace.Target
	
	if HasTarget == 0 then
		Target = nil
	end
	
	return HasTarget, Target
end

local FrontLeft = script.Parent.FrontLeftPropeller
local BackLeft = script.Parent.BackLeftPropeller
local FrontRight = script.Parent.FrontRightPropeller
local BackRight = script.Parent.BackRightPropeller

local Propellers = {
	["FrontLeft"] = {
		FrontLeft.Attachment.AlignOrientation,
		FrontLeft.Attachment.AlignPosition,
	},
	["BackLeft"] = {
		BackLeft.Attachment.AlignOrientation,
		BackLeft.Attachment.AlignPosition,
	},
	["FrontRight"] = {
		FrontRight.Attachment.AlignOrientation,
		FrontRight.Attachment.AlignPosition,
	},
	["BackRight"] = {
		BackRight.Attachment.AlignOrientation,
		BackRight.Attachment.AlignPosition,
	},
}

local LastEnviroment = nil

task.wait(3)

local LastDronePosition = Drone.Position
while true do
	local NearGround = NearGround()
	local TooHigh = if script.Parent.Torso.Position.Y > 40 then 1 else 0
	local ProperlyOrientated = 1
	local TargetValue, Target = GetTarget()
	local enviroment = {NearGround, ProperlyOrientated, TooHigh, TargetValue}
	
	if LastEnviroment == nil then
		LastEnviroment = enviroment
	end

	local _, Prediction = NewAI:ForwardPropagation(enviroment, ActivationFunction)
	
	local StillFlyingValue = 137.5

	if Prediction[1] then
		local thrust = Prediction[1] * 5 -- small adjustment range
	
		Propellers.FrontLeft[2].VectorVelocity = Vector3.new(0, thrust, 0)
		Propellers.FrontRight[2].VectorVelocity = Vector3.new(0,  thrust, 0)
		Propellers.BackLeft[2].VectorVelocity = Vector3.new(0,  thrust, 0)
		Propellers.BackRight[2].VectorVelocity = Vector3.new(0,  thrust, 0)
	end
	
	if Prediction[2] and Prediction[3] then
		local X = math.clamp(Prediction[2], -1, 1) * 10
		local Z = math.clamp(Prediction[3], -1, 1) * 10
		
		Propellers.FrontLeft[1].CFrame = CFrame.Angles(math.rad(X), 0, math.rad(-Z))
		Propellers.FrontRight[1].CFrame = CFrame.Angles(math.rad(X), 0, math.rad(-Z))
		Propellers.BackLeft[1].CFrame = CFrame.Angles(math.rad(X), 0, math.rad(-Z))
		Propellers.BackRight[1].CFrame = CFrame.Angles(math.rad(X), 0, math.rad(-Z))
		
		local Y = Propellers.FrontLeft[2].VectorVelocity.Y
		Propellers.FrontLeft[2].VectorVelocity = Vector3.new(X, Y, Z)
		Propellers.FrontRight[2].VectorVelocity = Vector3.new(X,  Y, Z)
		Propellers.BackLeft[2].VectorVelocity = Vector3.new(X,  Y, Z)
		Propellers.BackRight[2].VectorVelocity = Vector3.new(X,  Y, Z)
	end
	
	local maxSafeHeight = 30
	local currentHeight = Drone.Position.Y

	local HeightReward = -math.max(0, (currentHeight - maxSafeHeight)) * 0.05
	
	if currentHeight > (maxSafeHeight + 10) then
		HeightReward = -1
	end
	
	local TargetReward = if TargetValue == 0 then -1 else 1
	
	if TargetReward == -1 then
		local HoldingStillAmount = 0
		
		if Prediction[1] < .1 and Prediction[1] > -.1 then
			HoldingStillAmount += 1
		end
		if Prediction[2] < .1 and Prediction[2] > -.1 then
			HoldingStillAmount += 1
		end
		
		if HoldingStillAmount == 2 then
			TargetReward = 0
		else
			TargetReward = 1
		end
	end
	
	if Target then
		local distanceToPlayer = (Drone.Position - Target.PrimaryPart.Position).Magnitude
		local maxDistance = 100

	-- Reward is highest when close, lowest when far
		TargetReward = 10 - math.clamp(distanceToPlayer / maxDistance, 0, 1) * 10

	-- Bonus for getting closer than last frame
		local lastDistance = (LastDronePosition - Target.PrimaryPart.Position).Magnitude
		if distanceToPlayer < lastDistance then
			TargetReward += 0.2
		end
	end

	LastDronePosition = Drone.Position

	DQL:Learn {
		State = enviroment,
		LastState = LastEnviroment,
		Action = 1,
		Reward = HeightReward
	}
	
	DQL:Learn {
		State = enviroment,
		LastState = LastEnviroment,
		Action = 2,
		Reward = TargetReward
	}
	
	DQL:Learn {
		State = enviroment,
		LastState = LastEnviroment,
		Action = 3,
		Reward = TargetReward
	}
	
	task.wait()
end

yes, I have been using some ai, purely just cause I barely know what I am doing

1 Like

I don’t think you really need machine learning for that. Simply have the main part “the root” do pathfinding, patrolling etc (just moving its position and having everything else welded to that) and then use an inverse kinematic algorithm for the leg animations.

1 Like

the reason why I want machine learning, is because they are EXTREMELY smart. they actively learn and adjust to what is going on around them. sure, I could do it without ML, but I would prefer to do it with ML.

1 Like

check out this video. Also, I don’t really know much about ML other than python classic models so this is all I got haha

I have seen it and got it working before, but that doesn’t change behavior.

what behaviors do you mean? list them out

just generally being smart.

here are some examples though:

  • they react and learn to search areas if they heard gun shots or if a fellow robot died there.

  • they will react to losing legs and adjust so they can walk again

  • they will understand that they can’t get inside of an area that is too small for them, so they will hide nearby and want for the player to come out

sure, this can be done with a script, but it won’t react and adjust as well.

I mainly have this issue:


it finds the player, continues to move, then gets punished for leaving the player, then wiggles out of the punish zone. how would I teach it to stay and stare at the player?

updated version of the script

local OpenML = require(game.ServerScriptService.OpenML)

local States = {'NearGround',"ProperlyOrientated", "TooHigh", "Target"}
local Actions = {
	"Thrust",
	"Propeller_X", "Propeller_Z",
}

local ActivationFunction = OpenML.ActivationFunctions.TanH

local learningRate = .2

local Drone = script.Parent.Torso
local Eye = script.Parent.Eye.HitBox

local NewAI = setmetatable(OpenML.Resources.MLP.new({ #States, 10, 10, 10, #Actions }, function()
	return (math.random() * 2 - 1) * 1.5
end), { __index = OpenML.Algorithms.Propagator})

local DQL = OpenML.Algorithms.DQL.new()

DQL.OnForwardPropagation = function(state) return NewAI:ForwardPropagation(state, ActivationFunction) end
DQL.OnBackPropagation = function(activations, target) return NewAI:BackPropagation(activations, target, { ActivationFunction = ActivationFunction, LearningRate = learningRate }) end

function SimplifiyPrediction(Prediction)
	if typeof(Prediction[1]) == "number" then
		return Prediction
	end

	local NewPrediction = {}
	for I, Slot in ipairs(Prediction) do
		local Average = 0
		for _, Number in ipairs(Slot) do
			Average += Number
		end
		NewPrediction[I] = Average / #Slot
	end
	return NewPrediction
end

Eye.Touched:Connect(function()
	
end)

function NearGround()
	local Raycast = workspace:Raycast(script.Parent.Torso.Position, Vector3.new(0, -5, 0))
	
	if Raycast then
		return 1
	end
	return 0
end

local function clampPrediction(prediction)
	for i = 1, #prediction do
		prediction[i] = math.clamp(prediction[i], -1, 1)
	end
	return prediction
end

function GetTarget()
	local Eye = script.Parent.Eye.HitBox
	
	local HasTarget = 0
	
	for _, Part in Eye:GetTouchingParts() do
		if Part.Name == "TargetPart" then
			HasTarget = 1
		end
	end
	
	local Target = workspace.Target
	
	if HasTarget == 0 then
		Target = nil
	end
	
	return HasTarget, Target
end

local FrontLeft = script.Parent.FrontLeftPropeller
local BackLeft = script.Parent.BackLeftPropeller
local FrontRight = script.Parent.FrontRightPropeller
local BackRight = script.Parent.BackRightPropeller

local Propellers = {
	["FrontLeft"] = {
		FrontLeft.Attachment.AlignOrientation,
		FrontLeft.Attachment.AlignPosition,
	},
	["BackLeft"] = {
		BackLeft.Attachment.AlignOrientation,
		BackLeft.Attachment.AlignPosition,
	},
	["FrontRight"] = {
		FrontRight.Attachment.AlignOrientation,
		FrontRight.Attachment.AlignPosition,
	},
	["BackRight"] = {
		BackRight.Attachment.AlignOrientation,
		BackRight.Attachment.AlignPosition,
	},
}

local LastEnviroment = nil
local LastUpdateTick = tick()
local LastTargetValue = 0

task.wait(3)

local LastDronePosition = Drone.Position
while true do
	local NearGround = NearGround()
	local TooHigh = if script.Parent.Torso.Position.Y > 40 then 1 else 0
	local ProperlyOrientated = 1
	local TargetValue, Target = GetTarget()
	local enviroment = {NearGround, ProperlyOrientated, TooHigh, TargetValue}
	
	if LastEnviroment == nil then
		LastEnviroment = enviroment
	end

	local _, Prediction = NewAI:ForwardPropagation(enviroment, ActivationFunction)
	
	local StillFlyingValue = 137.5

	if Prediction[1] then
		local thrust = Prediction[1] * 5 -- small adjustment range
	
		Propellers.FrontLeft[2].VectorVelocity = Vector3.new(0, thrust, 0)
		Propellers.FrontRight[2].VectorVelocity = Vector3.new(0,  thrust, 0)
		Propellers.BackLeft[2].VectorVelocity = Vector3.new(0,  thrust, 0)
		Propellers.BackRight[2].VectorVelocity = Vector3.new(0,  thrust, 0)
	end
	
	if Prediction[2] and Prediction[3] then
		local X = math.clamp(Prediction[2], -1, 1) * 10
		local Z = math.clamp(Prediction[3], -1, 1) * 10
		
		Propellers.FrontLeft[1].CFrame = CFrame.Angles(math.rad(X), 0, math.rad(-Z))
		Propellers.FrontRight[1].CFrame = CFrame.Angles(math.rad(X), 0, math.rad(-Z))
		Propellers.BackLeft[1].CFrame = CFrame.Angles(math.rad(X), 0, math.rad(-Z))
		Propellers.BackRight[1].CFrame = CFrame.Angles(math.rad(X), 0, math.rad(-Z))
		
		local Y = Propellers.FrontLeft[2].VectorVelocity.Y
		Propellers.FrontLeft[2].VectorVelocity = Vector3.new(X, Y, Z)
		Propellers.FrontRight[2].VectorVelocity = Vector3.new(X,  Y, Z)
		Propellers.BackLeft[2].VectorVelocity = Vector3.new(X,  Y, Z)
		Propellers.BackRight[2].VectorVelocity = Vector3.new(X,  Y, Z)
	end
	
	local maxSafeHeight = 30
	local currentHeight = Drone.Position.Y

	local HeightReward = -math.max(0, (currentHeight - maxSafeHeight)) * 0.05
	
	if currentHeight > (maxSafeHeight + 10) then
		HeightReward = -1
	end
	
	local TargetReward = if TargetValue == 0 then -1 else 1
	
	if TargetReward == -1 then
		local HoldingStillAmount = 0
		
		if Prediction[1] < .1 and Prediction[1] > -.1 then
			HoldingStillAmount += 1
		end
		if Prediction[2] < .1 and Prediction[2] > -.1 then
			HoldingStillAmount += 1
		end
		
		if HoldingStillAmount == 2 then
			TargetReward = -1
		else
			TargetReward = 0
		end
	end
	
	if Target then
		local distanceToPlayer = (Drone.Position - Target.PrimaryPart.Position).Magnitude
		local maxDistance = 100

		TargetReward = 5

		local lastDistance = (LastDronePosition - Target.PrimaryPart.Position).Magnitude
		if distanceToPlayer < lastDistance then
			TargetReward += 5
		end
	end
	if LastTargetValue == 1 and TargetValue == 0 and Drone.Position.Magnitude - LastDronePosition.Magnitude < 1 then
		TargetReward = -5
		TargetValue = 1

		DQL:Learn {
			State = enviroment,
			LastState = LastEnviroment,
			Action = 2,
			Reward = TargetReward
		}

		DQL:Learn {
			State = enviroment,
			LastState = LastEnviroment,
			Action = 3,
			Reward = TargetReward
		}
	end
	print(TargetReward)
	
	if (tick() - LastUpdateTick) > .5 then
		DQL:Learn {
			State = enviroment,
			LastState = LastEnviroment,
			Action = 1,
			Reward = HeightReward
		}
	
		DQL:Learn {
			State = enviroment,
			LastState = LastEnviroment,
			Action = 2,
			Reward = TargetReward
		}
	
		DQL:Learn {
			State = enviroment,
			LastState = LastEnviroment,
			Action = 3,
			Reward = TargetReward
		}
		
		LastUpdateTick = tick()
	end 
	
	LastTargetValue = TargetValue
	LastDronePosition = Drone.Position
	task.wait()
end

Just to clarify. ARC only uses ML for the animations of the robots. The decisions the robots make like detecting gunshots, dead robots, and areas that are too small are made with normal AI systems. You can use the procedural aniamtions tutorial like i gave you and then just add certain functions that change what the robot does. For instance, if someone shoots a gun, send a remote event to all the robots int he nearby area to start walking towards where that shot was fired. As for the not going into small spaces part, you can use basic path finding and set limits to where they will try to go. Idk if I explained that well so here also an AI response that may explain it better


The robots in those demos aren’t using machine learning to decide what to do — the ML is only controlling how they move (balance, stepping, reacting to hits, etc.). The actual behaviors like searching an area, taking cover, or deciding they can’t fit somewhere are done through normal AI systems like behavior trees or state machines. So the “brain” is scripted, and the ML just handles the animation/movement layer to make it look natural. In Roblox, you can get a similar effect using procedural animation techniques like IKControl, AlignConstraints, and Motor6D manipulation to adjust limbs dynamically instead of relying on fixed animation clips.

1 Like

so, you recommend I should just give the ML a pos and if it follows it gets a reward?

also, that is good to hear. this will be much easier.

No, you actually don’t need ML at all and I think it would be unoptimized if you did use ML for all the robots. What I’m saying is you script out a few states like Patrolling (just walk around for a bit), Spotting (go towards that area), Attacking (follow the player and shoot as long as they’re within distance). All this can be done with basic pathfinding, then just use procedural animations. If a bullet hits a drone you can add some velocity to the side that was hit so it tilts the drone, and use something like a AlignOrientation acting as a “stabilizer” to make the drone try to balance itself out again

but I want to use ML. They use ML to make their bots much smarter; they have the most impressive bots I have seen in a game while staying extremely optimized.

damn bro stop glazing and being attached to ML, you’ll probably burn yourself out trying to implement ML than just doing normal AI.

for the love of god they dont use ML for general AI. they use ML for ANIMATION.

2 Likes

another point is that this is just overcomplication. Code it in manually.

1 Like

As others have said, arc only use ml for live adjusting the way the machines move

Both

  • missing legs/rotors and adapting their movement to stay afloat
  • the way that the move visually

Everything else like the actual direction and intelligence is all clever programming.

ML is so sick for those 2 reasons tho

1 Like

Poor guy.

Only if a proper “machine learning engineer” like me could make your dream come true.

Currently, nobody uses OpenML since it is a hobbyist ML library, not a production-grade one.

Also, what you’re trying to do cannot be done with OpenML since it does not have algorithms capable of diagonal gaussian policy. You have to go to something like DataPredict for that.

professional devforum advertiser

2 Likes

no