Menu
CoddyTech

Ao Redor das Paredes

Lição 10 de 20 do curso Jogo de Roblox: Fuja da Escuridão da Coddy.

Fique em uma sala ao lado da porta, e o monstro vai bater na parede: MoveTo segue em linha reta. Duas mudanças fazem dele um caçador.

Primeiro, ele só caça dentro do alcance de Settings.MonsterSight. Segundo, quando há uma parede no caminho, ele segue uma rota. workspace:Raycast lança um raio dele até você: se nada for atingido (ou se você for atingido), o caminho está livre. Caso contrário, PathfindingService encontra um caminho ao redor das paredes e pelas portas, e o monstro anda até o próximo ponto da rota, tentando novamente um quarto de segundo depois:

path:ComputeAsync(root.Position, goal)
local points = path:GetWaypoints()
if path.Status == Enum.PathStatus.Success and points[2] then
	shadow.Humanoid:MoveTo(points[2].Position)
end
challenge icon

Desafio

Médio
  1. Obtenha PathfindingService e atribua um caminho a cada monstro: local path = PathfindingService:CreatePath() em runMonster.
  2. Defina a distância inicial de melhor resultado de nearestCharacter como Settings.MonsterSight.
  3. Escreva walkToward(shadow, goal, path): faça um raycast (excluindo o monstro); com o caminho livre, ande em linha reta; com uma parede no caminho, ande até o próximo ponto do caminho.
  4. Persiga usando walkToward; quando não houver ninguém ao alcance, fique parado.

Pressione Play e depois Check.

Experimente você mesmo

local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local Lighting = game:GetService("Lighting")
local TweenService = game:GetService("TweenService")
local Settings = require(game.ReplicatedStorage.Settings)

local rooms = workspace.Rooms
local lastRoom = rooms.Lobby -- a sala mais recente
local count = 0 -- salas criadas até agora
local monster = nil

-- A noite cai: sem sol, um pouco de luz por toda parte e neblina
Lighting.ClockTime = Settings.ClockTime
Lighting.Ambient = Settings.Ambient
Lighting.OutdoorAmbient = Settings.Ambient
Lighting.FogColor = Color3.new(0, 0, 0)
Lighting.FogEnd = Settings.FogEnd
print("Lights out")

-- Uma ferramenta que um jogador carrega: na mão ou no Backpack
local function findTool(player, name)
	return (player.Character and player.Character:FindFirstChild(name)) or player.Backpack:FindFirstChild(name)
end

-- Abra uma porta girando-a pela dobradiça
local function openDoor(door)
	door:SetAttribute("Open", true)
	door.Panel.Prompt.Enabled = false
	local hinge, panel = door.Hinge, door.Panel
	local goal = hinge.CFrame * CFrame.Angles(0, math.rad(90), 0) * hinge.CFrame:ToObjectSpace(panel.CFrame)
	TweenService:Create(panel, TweenInfo.new(0.6), { CFrame = goal }):Play()
end

-- O jogador vivo mais próximo e a que distância ele está
local function nearestCharacter(position)
	local best, bestDistance = nil, math.huge
	for _, player in Players:GetPlayers() do
		local character = player.Character
		local root = character and character:FindFirstChild("HumanoidRootPart")
		if root and character.Humanoid.Health > 0 then
			local distance = (root.Position - position).Magnitude
			if distance < bestDistance then
				best, bestDistance = character, distance
			end
		end
	end
	return best, bestDistance
end

-- A mente do monstro: a cada quarto de segundo, persegue alguém
local function runMonster(shadow)
	local humanoid = shadow.Humanoid
	local root = shadow.HumanoidRootPart
	while shadow.Parent do
		local character = nearestCharacter(root.Position)
		if character then
			humanoid:MoveTo(character.HumanoidRootPart.Position)
		end
		task.wait(0.25)
	end
end

-- O monstro aparece atrás de você: na entrada da sala duas posições antes da mais recente
local function spawnMonster()
	local behind = nil
	for _, room in rooms:GetChildren() do
		if room:GetAttribute("Number") == count - 2 then
			behind = room
		end
	end
	if not behind then
		return
	end
	monster = ServerStorage.Shadow:Clone()
	monster:PivotTo(behind.Entrance.CFrame + Vector3.new(0, 3.1, 0))
	monster.Humanoid.WalkSpeed = Settings.MonsterSpeed
	monster.Parent = workspace
	task.spawn(runMonster, monster)
end

local addRoom -- definida abaixo: uma porta adiciona uma sala, e uma sala tem uma porta

-- O que uma porta faz quando um jogador a abre
local function setupDoor(door)
	door.Panel.Prompt.Triggered:Connect(function(player)
		if door:GetAttribute("Open") then
			return
		end
		if door:GetAttribute("Locked") then
			local key = findTool(player, "Key")
			if not key then
				return
			end
			key:Destroy()
			door:SetAttribute("Locked", nil)
		end
		if door.Parent == lastRoom then
			addRoom()
		end
		openDoor(door)
	end)
end
setupDoor(workspace.Rooms.Lobby.Door)

-- Ao entrar em uma sala: ela se torna a Room do jogador e seu ponto de renascimento
local function setupEntry(room)
	room.Entry.Touched:Connect(function(hit)
		local player = Players:GetPlayerFromCharacter(hit.Parent)
		if player then
			local number = room:GetAttribute("Number")
			player.leaderstats.Room.Value = number
			player.RespawnLocation = room.Checkpoint
		end
	end)
end
setupEntry(workspace.Rooms.Lobby)

-- Uma nova sala na saída da mais recente
function addRoom()
	count += 1
	local name = Settings.Order[(count - 1) % #Settings.Order + 1]
	if count >= Settings.RoomsToEscape then
		name = "Exit"
	end
	local room = ServerStorage.Rooms[name]:Clone()
	room:PivotTo(lastRoom.Exit.CFrame)
	room:SetAttribute("Number", count)
	room.Sign.SurfaceGui.Number.Text = "Room " .. count
	room.Parent = rooms
	lastRoom = room
	setupDoor(room.Door)
	setupEntry(room)
	-- uma sala trancada guarda sua chave dentro dela
	local keySpot = room:FindFirstChild("KeySpot")
	if keySpot then
		local key = ServerStorage.Key:Clone()
		key.Handle.CFrame = keySpot.CFrame
		key.Parent = room
		key.Handle.Prompt.Triggered:Connect(function(player)
			key.Handle.Prompt.Enabled = false
			key.Parent = player.Backpack
		end)
	end
	-- mantém a sala mais recente e KeepRooms salas anteriores
	for _, old in rooms:GetChildren() do
		if old:GetAttribute("Number") < count - Settings.KeepRooms then
			old:Destroy()
		end
	end
	if count == Settings.MonsterFrom then
		spawnMonster()
	end
	return room
end

-- Para cada jogador: Room no placar e uma lanterna a cada vida
Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local room = Instance.new("IntValue")
	room.Name = "Room"
	room.Parent = leaderstats

	player.CharacterAdded:Connect(function()
		local flashlight = ServerStorage.Flashlight:Clone()
		flashlight.Parent = player.Backpack
		local beam = flashlight.Handle.Beam
		flashlight.Activated:Connect(function()
			beam.Enabled = not beam.Enabled
		end)
	end)
end)
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Jogo de Roblox: Fuja da Escuridão