I have two problems:
- Maze genertation; I am making a maze generator, and everything works, including the exit however across from the exit there is a problem with the wall genertation. Below I have a picture showcasing the problem and the maze generation script. Please note that this happens only sometimes and is hard to fix, any help is appreciated.
Here is the script:
-- Variables
local MazeGeneration = {}
local debounce = false
-- Settings
local maze = {}
local pathWd = 10
local wallHt = 15
local wallHtPos = wallHt / 2
local wallThick = 2
local wallLen = pathWd + 2 * wallThick
local wallOffset = pathWd / 2 + wallThick / 2
local floorHt = 1
local floorHtPos = floorHt / 2
local floorTileDist = pathWd + wallThick
local stack = {}
table.insert(stack, { zVal = 0, xVal = 0 })
local cols = 10 -- Number of columns
local rows = 10 -- Number of rows
local rnd = Random.new()
-- Unload maze
function MazeGeneration.UnLoad()
for _, part in pairs(game.Workspace.Maze:GetChildren()) do
part:Destroy()
end
for _, part in pairs(game.Workspace.Waypoints:GetChildren()) do
part:Destroy()
end
game.Workspace:FindFirstChild("Enemy"):Destroy()
maze = {}
stack = {}
table.insert(stack, { zVal = 0, xVal = 0 })
end
-- Creates a part
local function CreatePart(x, y, z, px, py, pz)
local part = Instance.new("Part", game.Workspace.Maze)
part.Anchored = true
part.Size = Vector3.new(x, y, z)
part.Position = Vector3.new(px, py, pz)
part.TopSurface = Enum.SurfaceType.Smooth
part.Material = Enum.Material.Concrete
part.BrickColor = BrickColor.new("Dark stone grey")
return part
end
-- Creates a waypoint
local function CreateWaypoint(px, py, pz)
local part = Instance.new("Part", game.Workspace.Waypoints)
part.Anchored = true
part.Size = Vector3.new(1, 1, 1)
part.Position = Vector3.new(px, py + 1, pz)
part.Transparency = 1
part.CanCollide = false
part.CanTouch = false
end
-- Creates the floor
local function CreateFloor()
for z = 0, rows - 1 do
maze[z] = {}
for x = 0, cols - 1 do
local posX = x * floorTileDist
local posZ = z * floorTileDist
local part = CreatePart(pathWd, floorHt, pathWd, posX, floorHtPos, posZ)
local waypoint = CreateWaypoint(posX, floorHtPos, posZ)
maze[z][x] = { tile = part }
end
end
end
-- Creates the walls
local function CreateWalls()
local exitPosX = (cols - 1) * floorTileDist + wallOffset
local exitPosZ = (rows - 1) * floorTileDist
for z = 0, rows - 1 do
for x = 0, cols - 1 do
-- East Walls
local posX = x * floorTileDist + wallOffset
local posZ = z * floorTileDist
if posX or posZ then
local part = CreatePart(wallThick, wallHt, wallLen, posX, wallHtPos, posZ)
maze[z][x].eastWall = part
if posX == exitPosX and posZ == exitPosZ then
part.Color = Color3.fromRGB(0, 255, 0)
part.Material = Enum.Material.Neon
part.Name = "Exit"
end
if maze[z][x + 1] then
maze[z][x + 1].westWall = part
end
end
-- South Walls
posX = x * floorTileDist
posZ = z * floorTileDist + wallOffset
if posX or posZ then
local part = CreatePart(wallLen, wallHt, wallThick, posX, wallHtPos, posZ)
maze[z][x].southWall = part
if maze[z + 1] then
maze[z + 1][x].northWall = part
end
end
end
end
-- Create edge walls except at the exit position
-- West edge walls
for z = 0, rows - 1 do
local posX = -wallOffset
local posZ = z * floorTileDist
if posZ ~= exitPosZ then
CreatePart(wallThick, wallHt, wallLen, posX, wallHtPos, posZ)
end
end
-- North edge walls
for x = 0, cols - 1 do
local posX = x * floorTileDist
local posZ = -wallOffset
if posX ~= exitPosX then
CreatePart(wallLen, wallHt, wallThick, posX, wallHtPos, posZ)
end
end
-- Create the exit part separately
--[[local exitPart = CreatePart(wallThick, wallHt, wallLen, exitPosX, wallHtPos, exitPosZ - wallOffset)
exitPart.Color = Color3.fromRGB(0, 255, 0)
exitPart.Material = Enum.Material.Neon
exitPart.Name = "Exit"--]]
-- Add a wall across from the exit part if there is no wall
if maze[(rows - 1)][(cols - 1)] then
local exitWallX = exitPosX + -(rows * (pathWd + wallThick))
local exitWallZ = exitPosZ -- Adjust to place wall across from the exit
-- Check if the part at the position already exists
local existingWall = game.Workspace.Maze:FindFirstChildWhichIsA("Part") and game.Workspace.Maze:FindFirstChildWhichIsA("Part").Position == Vector3.new(exitWallX, wallHtPos, exitWallZ)
if not existingWall then
local wallAcrossExit = CreatePart(wallThick, wallHt, wallLen, exitWallX, wallHtPos, exitWallZ)
wallAcrossExit.BrickColor = BrickColor.new("Dark stone grey")
wallAcrossExit.Material = Enum.Material.Concrete
end
end
end
-- Remove wall
local function RemoveWall(wall)
local s = wall.Size
local p = wall.Position
wall.Size = Vector3.new(s.X, floorHt, s.Z)
wall.Position = Vector3.new(p.X, floorHtPos, p.Z)
end
-- Redraw the maze
local function Redraw()
for z = 0, rows - 1 do
for x = 0, cols - 1 do
local cell = maze[z][x]
if cell.visited then
if cell.northPath then
RemoveWall(cell.northWall)
end
if cell.eastPath then
RemoveWall(cell.eastWall)
end
if cell.southPath then
RemoveWall(cell.southWall)
end
if cell.westPath then
RemoveWall(cell.westWall)
end
end
end
end
end
-- Fun math checks
local function GetUnvisitedNeighbours(z, x)
local neighbours = {}
-- North
if maze[z - 1] and not maze[z - 1][x].visited then
table.insert(neighbours, 0)
end
-- East
if maze[z][x + 1] and not maze[z][x + 1].visited then
table.insert(neighbours, 1)
end
-- South
if maze[z + 1] and not maze[z + 1][x].visited then
table.insert(neighbours, 2)
end
-- West
if maze[z][x - 1] and not maze[z][x - 1].visited then
table.insert(neighbours, 3)
end
return neighbours
end
-- Searching algorithm
local function SearchPath()
if stack == nil or #stack == 0 then
return false
end
local stackCell = stack[#stack]
local x = stackCell.xVal
local z = stackCell.zVal
task.wait()
local neighbours = GetUnvisitedNeighbours(z, x)
if #neighbours > 0 then
local idx = rnd:NextInteger(1, #neighbours)
local nextCellDir = neighbours[idx]
if nextCellDir == 0 then -- North
maze[z][x].northPath = true
maze[z - 1][x].southPath = true
maze[z - 1][x].visited = true
table.insert(stack, { zVal = z - 1, xVal = x })
elseif nextCellDir == 1 then -- East
maze[z][x].eastPath = true
maze[z][x + 1].westPath = true
maze[z][x + 1].visited = true
table.insert(stack, { zVal = z, xVal = x + 1 })
elseif nextCellDir == 2 then -- South
maze[z][x].southPath = true
maze[z + 1][x].northPath = true
maze[z + 1][x].visited = true
table.insert(stack, { zVal = z + 1, xVal = x })
elseif nextCellDir == 3 then -- West
maze[z][x].westPath = true
maze[z][x - 1].eastPath = true
maze[z][x - 1].visited = true
table.insert(stack, { zVal = z, xVal = x - 1 })
end
else
table.remove(stack, #stack)
end
return true
end
-- Generate Maze
function MazeGeneration.Generate(difficulty)
if difficulty == 0 then
cols = rnd:NextInteger(5, 6)
rows = rnd:NextInteger(5, 6)
elseif difficulty == 1 then
cols = rnd:NextInteger(8, 10)
rows = rnd:NextInteger(8, 10)
elseif difficulty == 2 then
cols = rnd:NextInteger(15, 20)
rows = rnd:NextInteger(15, 20)
elseif difficulty == 3 then
cols = rnd:NextInteger(25, 30)
rows = rnd:NextInteger(25, 30)
end
CreateFloor()
CreateWalls()
maze[0][0].visited = true
while SearchPath() do
Redraw()
task.wait() -- remove for game; add if maze size is over 40x40
end
task.wait(5)
-- Clone enemy and ensure visibility
local enemy = script.Enemy:Clone()
enemy.Parent = game.Workspace
-- Ensure enemy parts are visible
task.wait(5)
for _, bodyPart in ipairs(enemy:GetDescendants()) do
if bodyPart:IsA("BasePart") and bodyPart.Name ~= "HumanoidRootPart" then
bodyPart.Transparency = 0
end
end
end
return MazeGeneration
- N.P.C., everything works but when the enemy (aka N.P.C.) found the player and should go to attack the player it just stands there, until the player leaves again. Here is the handler of the N.P.C.
-- Services
local Players = game:GetService("Players")
local PathfindingService = game:GetService("PathfindingService")
-- Constants
local ATTACK_DISTANCE = 5.5
local WAIT_TIME_BEFORE_PATROL = 7
local WAYPOINT_CHECK_INTERVAL = 0.1
-- Variables
local player = Players.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local enemy = nil
local waypointsFolder = game.Workspace:FindFirstChild("Waypoints")
repeat
task.wait(0.1)
until game.Workspace:FindFirstChild("Enemy")
enemy = game.Workspace:FindFirstChild("Enemy")
-- Animations and Sounds
local walkAnim = enemy:WaitForChild("Humanoid"):LoadAnimation(script.WalkAnim)
local attackAnim = enemy.Humanoid:LoadAnimation(script.AttackAnim)
local walkSound = script.WalkSound
local attackSound = script.AttackSound
-- Pathfinding parameters
local pathParams = {
AgentHeight = 5,
AgentRadius = 3,
AgentCanJump = false
}
-- Wait until enemy and waypoints are loaded
repeat
task.wait(WAYPOINT_CHECK_INTERVAL)
enemy = game.Workspace:FindFirstChild("Enemy")
until enemy and waypointsFolder and #waypointsFolder:GetChildren() > 0
-- Functions
local function CheckForCharacter(char)
local rayOrigin = enemy:FindFirstChild("HumanoidRootPart").Position
local rayDirection = (char.HumanoidRootPart.Position - rayOrigin).Unit * 40
local raycastResult = workspace:Raycast(rayOrigin, rayDirection, RaycastParams.new())
if raycastResult then
local raycastInstance = raycastResult.Instance
if raycastInstance:IsDescendantOf(char) then
return true
end
else
return false
end
end
local function FindNearestPlayers()
local players = Players:GetPlayers()
local nearestPlayer = nil
local maxDistance = 40
for _, player in pairs(players) do
if player.Character ~= nil then
local targetCharacter = player.Character
local distance = (enemy.HumanoidRootPart.Position - targetCharacter.HumanoidRootPart.Position).Magnitude
if distance < maxDistance and CheckForCharacter(targetCharacter) then
nearestPlayer = targetCharacter
maxDistance = distance
end
end
end
return nearestPlayer
end
local function CalculatePath(destination)
local path = PathfindingService:CreatePath(pathParams)
path:ComputeAsync(enemy.HumanoidRootPart.Position, destination)
return path
end
local function Attack(char)
local distance = (enemy.HumanoidRootPart.Position - char.HumanoidRootPart.Position).Magnitude
if distance > ATTACK_DISTANCE then
local path = CalculatePath(char.HumanoidRootPart.Position)
if path.Status == Enum.PathStatus.Success then
if not walkSound.Playing then
walkAnim:Play()
walkSound:Play()
end
end
else
walkSound:Stop()
walkAnim:Stop()
attackAnim:Play()
attackSound:Play()
task.wait(0.7)
char.Humanoid.Health = 0
end
end
local function WalkToDesination(destination)
local path = CalculatePath(destination)
if path.Status == Enum.PathStatus.Success then
if not walkSound.Playing then
walkAnim:Play()
walkSound:Play()
end
for _, waypoint in pairs(path:GetWaypoints()) do
local nearestPlayer = FindNearestPlayers()
if nearestPlayer then
Attack(nearestPlayer)
break
else
enemy.Humanoid:MoveTo(waypoint.Position)
enemy.Humanoid.MoveToFinished:Wait()
end
end
else
enemy.Humanoid:MoveTo(destination - (enemy.HumanoidRootPart.CFrame.LookVector * 10))
end
end
local function Patrol()
local waypoints = workspace.Waypoints:GetChildren()
if #waypoints > 0 then
local randomNumber = math.random(1, #waypoints)
WalkToDesination(waypoints[randomNumber].Position)
end
end
-- Start patrol after initial wait
task.wait(WAIT_TIME_BEFORE_PATROL)
Patrol()
-- Check for enemy and waypoints continuously
while true do
repeat
task.wait(WAYPOINT_CHECK_INTERVAL)
enemy = game.Workspace:FindFirstChild("Enemy")
until enemy
repeat
task.wait(WAYPOINT_CHECK_INTERVAL)
until #waypointsFolder:GetChildren() > 0
task.wait(WAIT_TIME_BEFORE_PATROL) -- Wait before starting patrol again
while true do
Patrol()
task.wait(0.1)
end
end
Any help makes my day 2Mx better