How could I make a soldier system, like in evades? (Rebels AI?)

  1. What do you want to achieve? Keep it simple and clear!

I want to make an AI system like the evade rebels.

  1. What’s the problem? Include screenshots/videos if possible!

The problem is that I don’t know how to do it, I know how to program it, currently the most similar script (from the toolbox) is this one:

  1. What solutions have you tried so far? Did you search for solutions on Developer Hub?

No.

local npc = script.Parent

------Respawn------
local clone = npc:Clone()

------Fix network issues------
while npc.HumanoidRootPart:GetNetworkOwnershipAuto() do
	npc.HumanoidRootPart:SetNetworkOwner()
	wait()
end



------Body Variables------
local Humanoid = npc.Humanoid
local myTorso = npc.Torso
local myHead = npc.Head
local myFace = myHead.face
local neck = myTorso.Neck
local headWeld = myTorso["Head Weld"]
local rArm = npc["Right Arm"]
local lArm = npc["Left Arm"]
local lShoulder = myTorso["Left Shoulder"]
local rShoulder = myTorso["Right Shoulder"]
local lArmWeld = myTorso["Left Arm Weld"]
local rArmWeld = myTorso["Right Arm Weld"]
local gyro = npc.HumanoidRootPart.BodyGyro





------M4 Variables------
local m4 = npc.M4
local m4Weld = m4["M4 Weld"]
local barrel = npc.Barrel
local aimer = npc.Aimer
local aimerWeld = aimer["Aimer Weld"]
local fullMag = 30
local mag = fullMag
local flash = barrel.Attachment.Flash



------Sounds------
local equipSound = m4.Equip
local fireSound = m4.Fire
local reloadSound = m4.Reload

local hurtSound = myHead.Hurt


--Animation
local reloadAnimation = Humanoid:LoadAnimation(npc.Animations.Reload)
reloadAnimation.Priority = Enum.AnimationPriority.Action

------Status------
local reloading = false
local weaponAimed = false
local weaponCool = true
local m4Equipped = false
local knifeEquipped = false
local grenadeCool = true
local currentTarget = nil
local status = "Idle"
local faces = {Idle = "http://www.roblox.com/asset/?id=23219775", 
	Attacking = "http://www.roblox.com/asset/?id=286688505", 
	Hunting = "http://www.roblox.com/asset/?id=209715003 ", 
	Hurt = "http://www.roblox.com/asset/?id=258192246",
	Dead = "http://www.roblox.com/asset/?id=15426038"}
local gunPointedAt = nil

------Target/Ally Tracking------
local allies = {"Rescripted_Developer"}
local potentialTargets = {}
local activeAllies = {}
local team = npc.Settings.Team.Value
local attackPlayers = npc.Settings.AttackPlayers.Value

function dofunction(func,...)
	local co = coroutine.wrap(func)
	co(...)
end

function checkDist(part1,part2)
	return (part1.Position - part2.Position).Magnitude
end

function checkSight(target)
	local ray = Ray.new(barrel.Position, (target.Position - barrel.Position).Unit * 75)
	local part,position = workspace:FindPartOnRayWithIgnoreList(ray, {script.Parent})
	local ray2 = Ray.new(myTorso.Position, (target.Position - myTorso.Position).Unit * 75)
	local part2,position2 = workspace:FindPartOnRayWithIgnoreList(ray2, {script.Parent})
	if part and part2 then
		if part:IsDescendantOf(target.Parent) and part2:IsDescendantOf(target.Parent) then
			return true
		end
	end
	return false
end

function checkSight2(target)
	local ray = Ray.new(myHead.Position, (target.Position - myHead.Position).Unit * 75)
	local part,position = workspace:FindPartOnRayWithIgnoreList(ray, {script.Parent})
	local ray2 = Ray.new(myTorso.Position, (target.Position - myTorso.Position).Unit * 75)
	local part2,position2 = workspace:FindPartOnRayWithIgnoreList(ray2, {script.Parent})
	if part and part2 then
		if part:IsDescendantOf(target.Parent) and part2:IsDescendantOf(target.Parent) then
			return true
		end
	end
	return false
end


function updateFace()
	if myFace.Texture ~= faces.Dead and myFace.Texture ~= faces.Hurt then
		myFace.Texture = faces[status]
	end
end

function findTarget()
	local dist = npc.Settings.DetectionRange.Value
	local target = nil
	potentialTargets = {}
	local seeTargets = {}
	for _,v in ipairs(workspace:GetChildren()) do

		local human = v:FindFirstChild("Humanoid")
		local torso = v:FindFirstChild("HumanoidRootPart") or v:FindFirstChild("Torso")

		local closestdistance = math.huge
		local closestcharacter = nil


		if human and torso and v ~= npc then
			--Check and see if they are on our team, if they are break the loop.
			local targetTeam
			local teammate = false
			if v:FindFirstChild("Team") then
				targetTeam = v.Team.Value
			elseif v:FindFirstChild("Settings") and v.Settings:FindFirstChild("Team") then
				targetTeam = v.Settings.Team.Value			
			end
			if (targetTeam and targetTeam == team) or (not attackPlayers and game.Players:GetPlayerFromCharacter(v)) then
				teammate = true --es mi equipo
			end

			if (myTorso.Position - torso.Position).magnitude < dist and human.Health > 0 then
				if (myTorso.Position - torso.Position).magnitude < closestdistance and human.Health > 0 then
					for i,x in ipairs(allies) do
						if x == v.Name or teammate then
							table.insert(activeAllies,torso)
							break
						elseif i == #allies then
							table.insert(potentialTargets,torso)
						end
					end
				end
			end
		end
	end
	if #potentialTargets > 0 then
		for i,v in ipairs(potentialTargets) do
			if checkSight(v) then
				table.insert(seeTargets,v)
			end
		end
		if #seeTargets > 0 then
			for i,v in ipairs(seeTargets) do
				if (myTorso.Position - v.Position).magnitude < dist then
					target = v.Head
					dist = (myTorso.Position - v.Position).magnitude
				end
			end
		else
			for i,v in ipairs(potentialTargets) do
				if (myTorso.Position - v.Position).magnitude < dist then
					target = v.Head
					dist = (myTorso.Position - v.Position).magnitude
				end
			end
		end
	end
	currentTarget = target 
end

function pathToLocation(target)
	local path = game:GetService("PathfindingService"):CreatePath()
	path:ComputeAsync(myTorso.Position, target.Position)
	local waypoints = path:GetWaypoints()

	for _,waypoint in ipairs(waypoints) do
		if waypoint.Action == Enum.PathWaypointAction.Jump then
			Humanoid.Jump = true
		end
		Humanoid:MoveTo(waypoint.Position)
		dofunction(function()
			wait(0.5)
			if Humanoid.WalkToPoint.Y > myTorso.Position.Y then
				Humanoid.Jump = true
			end
		end)
		local moveSuccess = Humanoid.MoveToFinished:Wait()
		if not moveSuccess or not target.Parent or (checkDist(myTorso,target) < 30 and checkSight(target)) or currentTarget ~= target then
			break
		end
		if checkDist(target,waypoints[#waypoints]) > 30 then
			pathToLocation(target)
		end
	end
end

function walkRandom()
	local randX = math.random(-100,100)
	local randZ = math.random(-100,100)
	local goal = myTorso.Position + Vector3.new(randX, 0, randZ)
	local path = game:GetService("PathfindingService"):CreatePath()
	path:ComputeAsync(myTorso.Position, goal)
	local waypoints = path:GetWaypoints()

	if path.Status == Enum.PathStatus.Success then
		for i,waypoint in ipairs(waypoints) do
			if waypoint.Action == Enum.PathWaypointAction.Jump then
				Humanoid.Jump = true
			end
			Humanoid:MoveTo(waypoint.Position)
			dofunction(function()
				wait(0.5)
				if Humanoid.WalkToPoint.Y > myTorso.Position.Y then
					Humanoid.Jump = true
				end
			end)
			local moveSuccess = Humanoid.MoveToFinished:Wait()
			if not moveSuccess or currentTarget then
				break
			end
		end
	else
		wait(2)
	end
end

function drawM4()
	if m4Equipped == false then
		m4Equipped = true
		equipSound:Play()

		--Right Arm Setup
		rShoulder.Part1 = nil
		rArm.CFrame = aimer.CFrame * CFrame.new(1.25,0.05,-0.65) * CFrame.Angles(math.rad(80),math.rad(0),math.rad(-10))
		rArmWeld.Part1 = rArm

		--Left Arm Setup 
		lShoulder.Part1 = nil
		lArm.CFrame = aimer.CFrame * CFrame.new(-0.35,0.05,-1.48) * CFrame.Angles(math.rad(84),math.rad(-3),math.rad(28))
		lArmWeld.Part1 = lArm

		--M4 Setup
		m4Weld.Part0 = nil
		m4.CFrame = aimer.CFrame * CFrame.new(0.65,0.37,-2.22) * CFrame.Angles(math.rad(-90),math.rad(0),math.rad(0))
		m4Weld.Part0 = aimer
	end
end

function yieldM4()
	Humanoid.AutoRotate = true 
	gyro.MaxTorque = Vector3.new(0,0,0)
	if weaponAimed == true then
		weaponAimed = false
		resetHead()
	end
	if m4Equipped == true then
		m4Equipped = false
		equipSound:Play()

		--Right Arm setup
		rArmWeld.Part1 = nil
		rShoulder.Part1 = rArm

		--Left Arm Setup
		lArmWeld.Part1 = nil
		lShoulder.Part1 = lArm

		--M4 Setup
		m4Weld.Part0 = nil
		m4.CFrame = myTorso.CFrame * CFrame.new(0,0,0.6) * CFrame.Angles(math.rad(-90),math.rad(-60),math.rad(90))
		m4Weld.Part0 = myTorso
	end
end


function aim(target)
	if weaponAimed == false then
		game:GetService("TweenService"):Create(neck,TweenInfo.new(0.5),{C0 = neck.C0 * CFrame.Angles(0,math.rad(-15),0)}):Play()
	end

	Humanoid.AutoRotate = false

	weaponAimed = true

	gyro.CFrame = CFrame.new(myTorso.Position,target.Position)
	gyro.MaxTorque = Vector3.new(0,math.huge,0)
	if not reloading then

		local aimCFrame = CFrame.new(aimer.Position,target.Position)
		aimCFrame = aimCFrame - aimCFrame.Position
		local negateCFrame = myTorso.CFrame - myTorso.Position
		local newC0 = CFrame.new(0,0.5,0) * negateCFrame:Inverse() * aimCFrame
		local x,y,z = newC0:ToEulerAnglesXYZ()
		x = math.clamp(x,-0.8,0.8) --So his aiming isn't crazy backwards
		newC0 = CFrame.new(0,0.5,0) * CFrame.fromEulerAnglesXYZ(x,0,0)
		local lookDiff = (newC0.LookVector - aimerWeld.C0.LookVector).Magnitude 
		game:GetService("TweenService"):Create(aimerWeld,TweenInfo.new(lookDiff * 0),{C0 = newC0}):Play()
	

		local newC0 = CFrame.new(0,1,0) * CFrame.Angles(-1.5 + math.rad(aimer.Orientation.X),math.rad(15),math.rad(180)) ---1.5 - 
		game:GetService("TweenService"):Create(neck,TweenInfo.new(lookDiff * 0),{C0 = newC0}):Play()
		npc.HumanoidRootPart.CFrame = CFrame.new(npc.HumanoidRootPart.Position,Vector3.new(target.Position.x,npc.HumanoidRootPart.Position.y,npc.Position.z))
		wait(lookDiff*0)
	end
end


function resetHead()
	game:GetService("TweenService"):Create(neck,TweenInfo.new(0.5),{C0 = CFrame.new(0,1,0) * CFrame.Angles(math.rad(-90),0,math.rad(180))}):Play()
end

function shoot(target)
	if weaponCool == true and reloading == false then
		weaponCool = false

		local shot
		if checkDist(target,myTorso) > 60 then
			shot = 1
		else
			shot = 10
		end
		for i = 1, shot do
			wait(0.1)
			mag = mag - 1 

			flash:Emit(1)
			local flash2 = Instance.new("PointLight")
			game:GetService("Debris"):AddItem(flash2,0.03)

			local bullet = Instance.new("Part")
			bullet.Name = "bullet"
			bullet.Size = Vector3.new(0.5,0.1,0.3) --evade
			bullet.BrickColor = BrickColor.new("Gold")
			bullet.Material = Enum.Material.Neon
			bullet.CFrame = barrel.CFrame
			--bullet.CFrame = CFrame.new(barrel.CFrame.Position) * CFrame.Angles(barrel.CFrame:toEulerAnglesXYZ().x, barrel.CFrame:toEulerAnglesXYZ().y, 0)
			
			local barrelCFrame = barrel.CFrame
			local newCFrame = CFrame.Angles(math.rad(0),0,math.rad(0))

			-- Asigna el nuevo CFrame al objeto bullet
			bullet.CFrame = bullet.CFrame:ToWorldSpace(newCFrame)

			bullet.CanCollide = false
			bullet.Touched:Connect(function(obj)
				if not obj:IsDescendantOf(npc) then 
					local human = obj.Parent:FindFirstChild("Humanoid")
					if human then
						if obj.Name == "Head" then
							human:TakeDamage(80)
						else
							human:TakeDamage(math.random(20,30))
						end
						if human.Health <= 0 then
							if human.RootPart == currentTarget then
								--Update target as soon as we kill the current one
								findTarget()
							end
						end
					end
					bullet:Destroy()
				end
			end)
			bullet.Parent = workspace
			fireSound:Play()

			local spread = Vector3.new(math.random(-shot,shot)/100,math.random(-shot,shot)/100)
			--local spread = Vector3.new(math.random(-shot,shot)/300,math.random(-shot,shot)/100*1.5,math.random(-shot,shot)/300)
			--local spread = Vector3.new(0,math.random(-shot,shot)/100*2.5,0)
			local bv = Instance.new("BodyVelocity",bullet)
			bv.MaxForce = Vector3.new(math.huge,math.huge,math.huge)
			bv.Velocity = (aimer.CFrame.LookVector + spread) * 300

			local s = Instance.new("Sound",bullet)
			s.Volume = 0.7
			s.PlaybackSpeed = 7
			s.Looped = true
			s.SoundId = "rbxasset://sounds/Rocket whoosh 01.wav"
			s:Play()

			local a1 = Instance.new("Attachment",bullet)
			a1.Position = Vector3.new(0,0.05,0)
			local a2 = Instance.new("Attachment",bullet)
			a2.Position = Vector3.new(0,-0.05,0)

			local t = Instance.new("Trail",bullet)
			t.Attachment0 = a1
			t.Attachment1 = a2
			t.Color = ColorSequence.new(bullet.Color)
			t.WidthScale = NumberSequence.new(0.1,0.01)
			t.Lifetime = 0.3

			--TODO ADD KICK

			game:GetService("Debris"):AddItem(bullet, 5)
		end

		if mag <= 0 then
			reload()
		end

		dofunction(function()
			wait(1)
			weaponCool = true
		end)
	end
end

function reload()
	if weaponAimed == true then
		resetHead()
		weaponAimed = false
	end
	reloadSound:Play()
	reloading = true

	yieldM4()
	m4Weld.Part0 = nil
	m4.CFrame = lArm.CFrame * CFrame.new(0.6,-1.3,0.2) * CFrame.Angles(math.rad(180),0,0)
	m4Weld.Part0 = lArm

	reloadAnimation:Play()
	reloadAnimation:AdjustSpeed(3)
	reloadAnimation.Stopped:Wait()
	reloading = false 
	mag = fullMag
	drawM4()
end


function yieldWeapons()
	yieldM4()
	if weaponAimed == true then
		weaponAimed = false 
		resetHead()
	end
end

function checkCluster(target)
	--Check for nearby allies
	for i,v in ipairs(activeAllies) do
		if checkDist(target,v) < 30 then
			return false
		end
	end
	--Check if enemies are paired close together
	for i,v in ipairs(potentialTargets) do
		if v ~= target then
			if checkDist(target,v) < 15 then
				return true
			end
		end
	end
	return false
end


function movementLoop()
	while Humanoid.Health>0 do
		if currentTarget then
			if checkDist(currentTarget,myTorso) > 30 or not checkSight(currentTarget) then
				pathToLocation(currentTarget)
			elseif checkDist(currentTarget,myTorso) > 8 then
				if math.random(0,1) == 1 then
					Humanoid:Move(myTorso.CFrame.RightVector)
				else
					Humanoid:Move(-myTorso.CFrame.RightVector)
				end
				wait(.5) --.5)
			end
		else
			local randomAction = math.random(4)
			if randomAction == 3 then
				walkRandom()
			elseif randomAction == 2 then
				--print("Look randomly")
			end
			wait(3)
		end
		wait(0.1)
	end
end

function searchTargetLoop()
	while Humanoid.Health>0 do
		findTarget() 
		wait(3)
	end
end

function aimingLoop()
	while Humanoid.Health>0 do
		if currentTarget then
			if checkSight(currentTarget) then
				aim(currentTarget)
				gunPointedAt = currentTarget
			else
				task.wait()
			end
		else
			task.wait()
		end
		task.wait()
	end
end

function attackLoop()
	while Humanoid.Health>0 do
		if currentTarget then
			status = "Hunting"
			updateFace()
			if checkSight(currentTarget) then
				status = "Attacking"
				updateFace()
				local distance = checkDist(myTorso,currentTarget)
				if distance > 15 then
					if checkCluster(currentTarget) == true and distance < 100 and distance > 30 and grenadeCool then
					else
						drawM4()
						repeat 
							wait()
						until gunPointedAt == currentTarget
						shoot(currentTarget)
					end
				else
					for i,v in pairs(currentTarget.Parent:GetChildren()) do
						if v:IsA("BasePart") and checkDist(v,myTorso) < 100 then
						end
					end
				end
			else
				if weaponAimed == true then
					weaponAimed = false
					Humanoid.AutoRotate = true
					gyro.MaxTorque = Vector3.new(0,0,0)
					resetHead()
					local newC0 = CFrame.new(0,0.5,0) * CFrame.Angles(-0.5,0,0)
					local lookDiff = (newC0.LookVector - aimerWeld.C0.LookVector).Magnitude 
					game:GetService("TweenService"):Create(aimerWeld,TweenInfo.new(lookDiff * 0.2),{C0 = newC0}):Play()
				end
			end
		else
			status = "Idle"
			updateFace()
			yieldWeapons()
			wait(2)
		end
		wait(0.1)
	end
end

function Died()
	yieldM4()
	status = "Dead"
	myFace.Texture = faces.Dead
	for i,v in ipairs(npc:GetDescendants()) do
		if v:IsA("BallSocketConstraint") then
			v.Enabled = true
		elseif v:IsA("BasePart") and v.Name ~= "HumanoidRootPart" and v ~= aimer then
			v.CanCollide = false
		elseif v:IsA("Motor6D") then
			v:Destroy()
		end
	end
	if npc.Settings.Respawn.Value then
		wait(npc.Settings.RespawnDelay.Value)
		clone.Parent = npc.Parent
	end
	for i,v in ipairs(npc:GetDescendants()) do
		if v:IsA("BasePart") or v:IsA("Decal") then
			game:GetService("TweenService"):Create(v,TweenInfo.new(0.2),{Transparency = 0}):Play()
		end
	end
	wait(5)
	--npc:Destroy()
end

Humanoid.Died:Connect(Died)

local oldHealth = Humanoid.Health
local soundSpeeds = {0.9,0.95,1,1.05,1.1}
Humanoid.HealthChanged:Connect(function(health)
	if health < oldHealth and hurtSound.IsPlaying == false then
		hurtSound.PlaybackSpeed = soundSpeeds[math.random(#soundSpeeds)]
		hurtSound:Play()
		dofunction(function()
			myFace.Texture = faces.Hurt
			wait(1)
			if myFace.Texture == faces.Hurt then
				myFace.Texture = faces[status]
			end
		end)
	end
	oldHealth = health
end)

dofunction(searchTargetLoop)
dofunction(attackLoop)
dofunction(movementLoop)
dofunction(aimingLoop)
1 Like