How to give wedges to the edges of my map generation?

Hello, So at the moment I have been working on a block style map generation script that works.
But what I want it to do is for each block check if there is air in front of it and check if there is a block under where the air is and if so make a wedge there to give the edges a well edge.

This is what I mean if you don’t understand.

I have tried using raycasting but if it caused a lot of lag on joining and I couldn’t get it to work.

Here is my script so far.

--Objects//

local GenerationFolder = game:GetService("ReplicatedStorage"):FindFirstChild("GenerationParts")

local GeneratedMapFolder = workspace:FindFirstChild("GeneratedMap")

--Values//

local Seed = math.random(-100, 100)

local MapSize = 3 * 100

local MapHeight = 100

--Tables//

local PointsTable = {

}

--Functions//

function CreatePart(X, Y, Alpha)

local Part = GenerationFolder:FindFirstChild("Block"):Clone()

local newY = math.floor(Alpha / (3/MapHeight) + 0.5) * (3/MapHeight) * MapHeight

Part.Position = Vector3.new(X, newY, Y)

Part.Parent = GeneratedMapFolder

--Color Edits

Part.Color = Color3.fromRGB(91, 154, 76)

end

--Create Generation

for Y = 1, MapSize, 3 do

for X = 1, MapSize, 3 do

local Noise = math.noise((X + Seed) / MapSize, (Y + Seed) / MapSize, 0)

CreatePart(X, Y, Noise)

end

end

Any help is welcome :slight_smile:

Raycasting is the way to go. Raycast out all 4 directions and if one of the Raycasts doesn’t hit anything, raycast down from that position. If the second raycast hits a block, then place a wedge there.

The Raycasts don’t have to be big, just big enough to hit the block next to it.
Let’s say your blocks are 10x10x10 studs big, then you could make the ray 5.5 or 6 studs long starting from the middle of the block, or start it from the side of the block and make it only 1 stud long. That would definitely be enough and would cause slightly less lag.

As for the lag, you can’t really do much about it. Complex world generations like this will always cause lag because they need a lot of math and calculations to be playable. You should create a Loading Screen similar to Minecraft, and start the map generation after that UI is shown to the player to make sure they don’t notice anything from the lag or the generation itself.

You can also slow the generation down by only placing blocks that are visible or by adding a cooldown to the loop. But these would make the generation take longer which also isn’t a great factor. So do things how you find the best.

Hope this helps!

The marching cubes algorithm may be of interest to you. Bit of a complex subject, but it will give you that edge style you’re looking for. Also, this video may be of help.

Unfortunately ROBLOX isn’t well-suited to these type of projects simply because ROBLOX has very little support for real-time mesh generation.

1 Like

Could you possibly show me how to raycast then because when I tried it I couldn’t get it to work and only make it raycast in one direction.

I can’t test the code right now so I can’t test if it works or not but I would do something like this:

local block = -- the block
local sides = {
	block.CFrame.LookVector,
	block.CFrame.RightVector,
	block.CFrame.LookVector * -1,
	block.CFrame.RightVector * -1
} -- I used a table for the sides because it will make later uses of the sides less complicated

for i = 1, 4, 1 do -- looping through the 4 sides of the block
	local ray1 = workspace:Raycast(block.Position + sides[i]*4, sides[i]*2)
	-- Some explaining:
	-- Right now I will assume that a block is exactly 10*10*10 studs big, but correct some numbers based on the real sizes
	-- First, I move the beginning of the ray 4 studs to the direction in which the ray should go. This will allow me to make the ray shorter and thus increase performance (slightly) 
	-- The value you move with can be anything that is close to but smaller than half the size of the blocks. The point is to get the beginning of the ray as close to the side of the block as possible
	-- Second, I cast a ray that just goes out of the block enough to detect if there's a block next to it (i used 2 studs)

	if not(ray1) then -- only continue if the ray didn't hit anything
		local ray2 = workspace:Raycast(block.Position + sides[i]*6, Vector3.new(0, -6, 0))
		-- Cast a ray from the end of the first ray (4+2 = 6) and go straight down (I used 6 studs for the same reason as before)
		if ray2 then -- check if there is a block under where the wedge would be
			-- Place the wedge next to the block
		end
	end
end

Please try understanding it and if you have any questions or if something isn’t clear, feel free to ask.
Hope it helps!

That worked thanks and for some reason it didn’t make so much lag like mine did lol.
But now I’m struggling with how to set the rotation on the wedge as at the moment it only is facing one direction.

Here is the new function I added with your help.

--Create Edges
function CreateEdge(Position, Rotation)
	local EdgePart = GenerationFolder:FindFirstChild("EdgeBlock"):Clone()
	EdgePart.CFrame = CFrame.new(Position) * CFrame.Angles(Rotation)
	EdgePart.Parent = GeneratedMapFolder
	EdgePart.Color = Color3.fromRGB(91, 154, 76)
end

for _, Part in pairs(GeneratedMapFolder:GetChildren()) do
	
	local PointsTable = {
		Part.CFrame.LookVector,
		Part.CFrame.RightVector,
		Part.CFrame.LookVector * -1,
		Part.CFrame.RightVector * -1
	}
	
	for i = 1, 4, 1 do
		local ray1 = workspace:Raycast(Part.Position + PointsTable[i]*2, PointsTable[i]*1)
		if not(ray1) then
			local ray2 = workspace:Raycast(Part.Position + PointsTable[i]*3, Vector3.new(0, -3, 0))
			if ray2 then
				CreateEdge(Part.Position + PointsTable[i]*3)
			end
		end
	end
end

In the create wedge function it requires a rotation but I can’t seem to figure out how to give it the right rotation.

1 Like

Make the wedge look at whatever block it came from, and if it faces the wrong way give it a little extra rotation. CFrame.new(Position, LookAt)

I want it to face in the direction the ray hit so it makes a slope effect.

BBB
BAB
BBB

If b is the wedge and it came from a, point the flat side of b towards a

Instead of passing the rotation, pass the position of the part that “created” the wedge, and then you can use the method @oddcraft18 posted.

function CreateEdge(Position, MainPartPosition)
	local EdgePart = GenerationFolder:FindFirstChild("EdgeBlock"):Clone()
	EdgePart.CFrame = CFrame.new(Position, MainPartPosition)
end

This will make the wedge’s front face the part that created it. But, since the front of a wedge part is the side where it slopes, you have to turn it around, meaning to rotate it 180 degrees (= 1 pi).
So your final function would look like this:

function CreateEdge(Position, MainPartPosition)
	local EdgePart = GenerationFolder:FindFirstChild("EdgeBlock"):Clone()
	EdgePart.CFrame = CFrame.new(Position, MainPartPosition) * CFrame.Angles(0, 1, 0)
	-- add the rest
end

And make sure you pass the part position instead of a Rotation value as a second argument in the loop.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.