mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-04 20:57:49 +00:00
459 lines
13 KiB
Lua
459 lines
13 KiB
Lua
-----------------
|
|
--DEFAULT VALUES-
|
|
-----------------
|
|
loaded = false
|
|
on = false
|
|
mousedown = false
|
|
r = 0
|
|
s = 1
|
|
|
|
|
|
|
|
---------------
|
|
--PLUGIN SETUP-
|
|
---------------
|
|
self = PluginManager():CreatePlugin()
|
|
self.Deactivation:connect(function()
|
|
Off()
|
|
end)
|
|
|
|
toolbar = self:CreateToolbar("Terrain")
|
|
toolbarbutton = toolbar:CreateButton("", "Elevation Adjuster", "elevation.png")
|
|
toolbarbutton.Click:connect(function()
|
|
if on then
|
|
Off()
|
|
elseif loaded then
|
|
On()
|
|
end
|
|
end)
|
|
|
|
mouse = self:GetMouse()
|
|
mouse.Button1Down:connect(function()
|
|
onClicked(mouse)
|
|
end)
|
|
mouse.Button1Up:connect(function() mousedown = false end)
|
|
|
|
|
|
|
|
-----------------------
|
|
--FUNCTION DEFINITIONS-
|
|
-----------------------
|
|
|
|
--find height at coordinate x, z
|
|
function findHeight(x, z)
|
|
c = game.Workspace.Terrain
|
|
h = 0
|
|
material, wedge, rotation = c:GetCell(x, h + 1, z)
|
|
while material.Value > 0 do
|
|
h = h + 1
|
|
material, wedge, rotation = c:GetCell(x, h + 1, z)
|
|
end
|
|
return h
|
|
end
|
|
|
|
|
|
--makes a shell around block at coordinate x, z using heightmap
|
|
function makeShell(x, z, heightmap, shellheightmap)
|
|
local c = game.Workspace.Terrain
|
|
local originalheight = heightmap[x][z]
|
|
for i = x - 1, x + 1 do
|
|
for k = z - 1, z + 1 do
|
|
if shellheightmap[i][k] < originalheight then
|
|
for h = originalheight, shellheightmap[i][k] - 2, -1 do
|
|
if h > 0 then
|
|
c:SetCell(i, h, k, 1, 0, 0)
|
|
end
|
|
end
|
|
shellheightmap[i][k] = originalheight
|
|
end
|
|
end
|
|
end
|
|
return shellheightmap
|
|
end
|
|
|
|
|
|
--makes a wedge at location x, y, z using info from heightmap instead of GetCell
|
|
--sets cell x, y, z to default material if parameter is provided, if not sets cell x, y, z to be whatever material it previously was
|
|
--returns true if made a wedge, false if the cell remains a block
|
|
function MakeWedge(x, y, z, heightmap, defaultmaterial)
|
|
local c = game.Workspace.Terrain
|
|
--gather info about all the cells around x, y, z
|
|
local surroundings = {} --surroundings is a 3 x 3 x 3 array of the cells adjacent to x, y, z (1 if a cell is there, 0 if not)
|
|
for i = x - 1, x + 1 do
|
|
surroundings[i] = {}
|
|
for j = y - 1, y + 1 do
|
|
surroundings[i][j] = {}
|
|
for k = z - 1, z + 1 do
|
|
heightmapi = heightmap[i]
|
|
height = nil
|
|
if heightmapi then
|
|
height = heightmapi[k]
|
|
end
|
|
if height and height >= j then
|
|
surroundings[i][j][k] = 1
|
|
else
|
|
surroundings[i][j][k] = 0
|
|
end
|
|
end
|
|
end
|
|
end
|
|
--make some useful arrays and counters
|
|
local sides = {} --sides is an array of the material of the 4 adjacent sides
|
|
sides[0] = surroundings[x - 1][y][z]
|
|
sides[1] = surroundings[x][y][z + 1]
|
|
sides[2] = surroundings[x + 1][y][z]
|
|
sides[3] = surroundings[x][y][z - 1]
|
|
local adjacentSides = 0
|
|
for n = 0, 3 do
|
|
if sides[n] > 0 then
|
|
adjacentSides = adjacentSides + 1
|
|
end
|
|
end
|
|
local sidesAbove = {} --sides is an array of the material of the 4 adjacent sides 1 height above
|
|
sidesAbove[0] = surroundings[x - 1][y + 1][z]
|
|
sidesAbove[1] = surroundings[x][y + 1][z + 1]
|
|
sidesAbove[2] = surroundings[x + 1][y + 1][z]
|
|
sidesAbove[3] = surroundings[x][y + 1][z - 1]
|
|
local adjacentSidesAbove = 0
|
|
for n = 0, 3 do
|
|
if sidesAbove[n] > 0 then
|
|
adjacentSidesAbove = adjacentSidesAbove + 1
|
|
end
|
|
end
|
|
local corners = {} --corners is an array of the material of the 4 adjacent corners
|
|
corners[0] = surroundings[x - 1][y][z - 1]
|
|
corners[1] = surroundings[x - 1][y][z + 1]
|
|
corners[2] = surroundings[x + 1][y][z + 1]
|
|
corners[3] = surroundings[x + 1][y][z - 1]
|
|
local adjacentCorners = 0
|
|
for n = 0, 3 do
|
|
if corners[n] > 0 then
|
|
adjacentCorners = adjacentCorners + 1
|
|
end
|
|
end
|
|
local cornersAbove = {} --corners is an array of the material of the 4 adjacent corners 1 height above
|
|
cornersAbove[0] = surroundings[x - 1][y + 1][z - 1]
|
|
cornersAbove[1] = surroundings[x - 1][y + 1][z + 1]
|
|
cornersAbove[2] = surroundings[x + 1][y + 1][z + 1]
|
|
cornersAbove[3] = surroundings[x + 1][y + 1][z - 1]
|
|
local adjacentCornersAbove = 0
|
|
for n = 0, 3 do
|
|
if cornersAbove[n] > 0 then
|
|
adjacentCornersAbove = adjacentCornersAbove + 1
|
|
end
|
|
end
|
|
--determine what type of wedge to make
|
|
local material = nil
|
|
local wedge = nil
|
|
local rotation = nil
|
|
if defaultmaterial then
|
|
material = defaultmaterial
|
|
else
|
|
material, wedge, rotation = c:GetCell(x, y, z) --start with the existing material, wedge, and rotation
|
|
end
|
|
wedge = 0 --default wedge is a block
|
|
rotation = 0 --default rotation is 0
|
|
--type 1: 45 degree ramp //must not have a block on top and must have a block under, and be surrounded by 1 side; or 3 sides and the 2 corners between them
|
|
if surroundings[x][y + 1][z] == 0 and surroundings[x][y - 1][z] > 0 then
|
|
if adjacentSides == 1 then
|
|
for n = 0, 3 do
|
|
if sides[n] > 0 then
|
|
wedge = 1
|
|
rotation = (n + 1) % 4
|
|
c:SetCell(x, y, z, material, wedge, rotation)
|
|
return true
|
|
end
|
|
end
|
|
elseif adjacentSides == 3 then
|
|
for n = 0, 3 do
|
|
if sides[n] > 0 and corners[(n + 1) % 4] > 0 and sides[(n + 1) % 4] > 0 and corners[(n + 2) % 4] > 0 and sides[(n + 2) % 4] > 0 then
|
|
wedge = 1
|
|
rotation = (n + 2) % 4
|
|
c:SetCell(x, y, z, material, wedge, rotation)
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
--type 2: 45 degree corner //must not have a block on top and must have a block under, and be surrounded by 2 sides and the 1 corner between them; or 3 sides and 1 corner between 2 of them (facing towards that corner)
|
|
if surroundings[x][y + 1][z] == 0 and surroundings[x][y - 1][z] > 0 then
|
|
for n = 0, 3 do
|
|
if sides[n] > 0 and corners[(n + 1) % 4] > 0 and sides[(n + 1) % 4] > 0 and (adjacentSides == 2 or (adjacentSides == 3 and (corners[(n + 3) % 4] > 0 or (sides[(n + 2) % 4] > 0 and corners[(n + 2) % 4] > 0) or (sides[(n + 3) % 4] > 0 and corners[n] > 0)))) then
|
|
wedge = 2
|
|
rotation = (n + 2) % 4
|
|
c:SetCell(x, y, z, material, wedge, rotation)
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
--type 3: 45 degree inverse corner //surrounded by three sides or 4 sides and 3 corners, with nothing above or else a block on top surrounded on 2 sides and the corner between them
|
|
if adjacentSides == 3 and surroundings[x][y + 1][z] > 0 then
|
|
if adjacentCorners > 1 then
|
|
for n = 0, 3 do
|
|
if (corners[n] == 0 or cornersAbove[n] == 0) and (sides[(n - 1) % 4] == 0 or sides[n] == 0) and (sidesAbove[n] == 0 and sidesAbove[(n + 1) % 4] > 0 and sidesAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 3) % 4] == 0) then
|
|
wedge = 3
|
|
rotation = (n + 3) % 4
|
|
c:SetCell(x, y, z, material, wedge, rotation)
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
elseif adjacentSides == 4 and adjacentCorners == 3 then
|
|
for n = 0, 3 do
|
|
if corners[n] == 0 and (surroundings[x][y + 1][z] == 0 or (sidesAbove[n] == 0 and sidesAbove[(n + 1) % 4] > 0 and cornersAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 3) % 4] == 0)) then
|
|
wedge = 3
|
|
rotation = (n + 3) % 4
|
|
c:SetCell(x, y, z, material, wedge, rotation)
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
--type 4: half a cube, as if it were cut diagonally from front to back //surrounded by 2 sides
|
|
if adjacentSides == 2 and adjacentCorners < 4 then
|
|
for n = 0, 3 do
|
|
if sides[n] == 0 and sides[(n + 1) % 4] == 0 and (surroundings[x][y + 1][z] == 0 or (sidesAbove[n] == 0 and sidesAbove[(n + 1) % 4] == 0 and sidesAbove[(n + 2) % 4] > 0 and sidesAbove[(n + 3) % 4] > 0)) then
|
|
wedge = 4
|
|
rotation = n
|
|
c:SetCell(x, y, z, material, wedge, rotation)
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
c:SetCell(x, y, z, material, wedge, rotation)
|
|
return false
|
|
end
|
|
|
|
|
|
--elevates terrain at point (x, y, z) in cluster c
|
|
--within radius r1 from x, z the elevation should become y + d
|
|
--from radius r1 to r2 the elevation should be a gradient
|
|
function elevate(x, y, z, r1, r2, d, range)
|
|
local c = game.Workspace.Terrain
|
|
|
|
for i = x - (range + 2), x + (range + 2) do
|
|
if oldheightmap[i] == nil then
|
|
oldheightmap[i] = {}
|
|
end
|
|
for k = z - (range + 2), z + (range + 2) do
|
|
if oldheightmap[i][k] == nil then
|
|
oldheightmap[i][k] = findHeight(i, k)
|
|
end
|
|
|
|
|
|
--figure out the height to make coordinate (i, k)
|
|
local distance = dist(i, k, x, z)
|
|
if distance < r1 then
|
|
height = y + d
|
|
elseif distance < r2 then
|
|
height = math.floor((y + d) * (1 - (distance - r1)/(r2 - r1)) + oldheightmap[i][k] * (distance - r1)/(r2 - r1))
|
|
else
|
|
height = oldheightmap[i][k]
|
|
end
|
|
if height == 0 then
|
|
height = -1
|
|
end
|
|
|
|
--heightmap[i][k] should be the current height of coordinate (i, k)
|
|
if heightmap[i] == nil then
|
|
heightmap[i] = {}
|
|
end
|
|
if heightmap[i][k] == nil then
|
|
heightmap[i][k] = oldheightmap[i][k]
|
|
end
|
|
|
|
--the height is either greater than or less than the current height
|
|
if height > heightmap[i][k] then
|
|
for h = heightmap[i][k] - 2, height do
|
|
c:SetCell(i, h, k, 1, 0, 0)
|
|
end
|
|
heightmap[i][k] = height
|
|
elseif height < heightmap[i][k] then
|
|
for h = heightmap[i][k], height + 1, -1 do
|
|
c:SetCell(i, h, k, 0, 0, 0)
|
|
end
|
|
heightmap[i][k] = height
|
|
end
|
|
end
|
|
end
|
|
|
|
--copy heightmap into shellheightmap
|
|
shellheightmap = {}
|
|
for i = x - (range + 2), x + (range + 2) do
|
|
if shellheightmap[i] == nil then
|
|
shellheightmap[i] = {}
|
|
end
|
|
for k = z - (range + 2), z + (range + 2) do
|
|
shellheightmap[i][k] = heightmap[i][k]
|
|
end
|
|
end
|
|
--shell everything
|
|
for i = x - range , x + range do
|
|
for k = z - range, z + range do
|
|
if shellheightmap[i][k] ~= oldheightmap[i][k] then
|
|
shellheightmap = makeShell(i, k, heightmap, shellheightmap)
|
|
end
|
|
end
|
|
end
|
|
|
|
for i = x - (range + 2), x + (range + 2) do
|
|
for k = z - (range + 2), z + (range + 2) do
|
|
heightmap[i][k] = shellheightmap[i][k]
|
|
end
|
|
end
|
|
|
|
for i = x - (range + 1), x + (range + 1) do
|
|
for k = z - (range + 1), z + (range + 1) do
|
|
local height = heightmap[i][k]
|
|
if height == nil then
|
|
height = -1
|
|
end
|
|
for h = height, 1, -1 do
|
|
if not MakeWedge(i, h, k, heightmap, 1) then
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
function dist(x1, y1, x2, y2)
|
|
return math.sqrt(math.pow(x2-x1, 2) + math.pow(y2-y1, 2))
|
|
end
|
|
|
|
function dist3d(x1, y1, z1, x2, y2, z2)
|
|
return math.sqrt(math.pow(dist(x1, z1, x2, z2), 2) + math.pow(math.abs(y2-y1)*100/d, 2))
|
|
end
|
|
|
|
function onClicked(mouse)
|
|
if on then
|
|
|
|
local c = game.Workspace.Terrain
|
|
oldheightmap = {}
|
|
heightmap = {}
|
|
local cellPos = c:WorldToCellPreferSolid(Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
|
|
local x = cellPos.X
|
|
local y = cellPos.Y
|
|
local z = cellPos.Z
|
|
|
|
mousedown = true
|
|
local originalY = mouse.Y
|
|
local prevY = originalY
|
|
local d = 0
|
|
local range = 0
|
|
while mousedown == true do
|
|
|
|
if math.abs(mouse.Y - prevY) >= 5 then
|
|
prevY = mouse.Y
|
|
r2 = r + math.floor(50 * 1/s * math.abs(originalY - prevY)/mouse.ViewSizeY)
|
|
if r2 > range then
|
|
range = r2
|
|
end
|
|
d = math.floor(50 * (originalY - prevY)/mouse.ViewSizeY)
|
|
elevate(x, y, z, r, r2, d, range)
|
|
end
|
|
wait(0)
|
|
end
|
|
print("Elevated at: "..x..", "..y..", "..z)
|
|
end
|
|
end
|
|
|
|
function On()
|
|
self:Activate(true)
|
|
toolbarbutton:SetActive(true)
|
|
frame.Visible = true
|
|
for w = 0, 0.3, 0.06 do
|
|
frame.Size = UDim2.new(w, 0, w/2, 0)
|
|
wait(0.0000001)
|
|
end
|
|
radl.Text = "Radius: "..r
|
|
sfl.Text = "Slope: "..s
|
|
on = true
|
|
end
|
|
|
|
function Off()
|
|
toolbarbutton:SetActive(false)
|
|
radl.Text = ""
|
|
sfl.Text = ""
|
|
for w = 0.3, 0, -0.06 do
|
|
frame.Size = UDim2.new(w, 0, w/2, 0)
|
|
wait(0.0000001)
|
|
end
|
|
frame.Visible = false
|
|
on = false
|
|
end
|
|
|
|
|
|
|
|
|
|
------
|
|
--GUI-
|
|
------
|
|
|
|
--load library for with sliders
|
|
local RbxGui = LoadLibrary("RbxGui")
|
|
|
|
--screengui
|
|
g = Instance.new("ScreenGui", game:GetService("CoreGui"))
|
|
|
|
--frame
|
|
frame = Instance.new("Frame", g)
|
|
frame.Position = UDim2.new(0.35, 0, 0.8, 0)
|
|
frame.Size = UDim2.new(0.3, 0, 0.15, 0)
|
|
frame.BackgroundTransparency = 0.5
|
|
frame.Visible = false
|
|
|
|
--current radius display label
|
|
radl = Instance.new("TextLabel", frame)
|
|
radl.Position = UDim2.new(0.05, 0, 0.1, 0)
|
|
radl.Size = UDim2.new(0.2, 0, 0.35, 0)
|
|
radl.Text = ""
|
|
radl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
|
radl.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
|
radl.Font = Enum.Font.ArialBold
|
|
radl.FontSize = Enum.FontSize.Size14
|
|
radl.BorderColor3 = Color3.new(0, 0, 0)
|
|
radl.BackgroundTransparency = 1
|
|
|
|
--radius slider
|
|
radSliderGui, radSliderPosition = RbxGui.CreateSlider(11, 0, UDim2.new(0.3, 0, 0.26, 0))
|
|
radSliderGui.Parent = frame
|
|
radBar = radSliderGui:FindFirstChild("Bar")
|
|
radBar.Size = UDim2.new(0.65, 0, 0, 5)
|
|
radSliderPosition.Value = r + 1
|
|
radSliderPosition.Changed:connect(function()
|
|
r = radSliderPosition.Value - 1
|
|
radl.Text = "Radius: "..r
|
|
end)
|
|
|
|
--current slope factor display label
|
|
sfl = Instance.new("TextLabel", frame)
|
|
sfl.Position = UDim2.new(0.05, 0, 0.55, 0)
|
|
sfl.Size = UDim2.new(0.2, 0, 0.35, 0)
|
|
sfl.Text = ""
|
|
sfl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
|
|
sfl.TextColor3 = Color3.new(0.95, 0.95, 0.95)
|
|
sfl.Font = Enum.Font.ArialBold
|
|
sfl.FontSize = Enum.FontSize.Size14
|
|
sfl.BorderColor3 = Color3.new(0, 0, 0)
|
|
sfl.BackgroundTransparency = 1
|
|
|
|
--slope factor slider
|
|
sfSliderGui, sfSliderPosition = RbxGui.CreateSlider(16, 0, UDim2.new(0.3, 0, 0.71, 0))
|
|
sfSliderGui.Parent = frame
|
|
sfBar = sfSliderGui:FindFirstChild("Bar")
|
|
sfBar.Size = UDim2.new(0.65, 0, 0, 5)
|
|
sfSliderPosition.Value = s * 10 - 0.4
|
|
sfSliderPosition.Changed:connect(function()
|
|
s = sfSliderPosition.Value / 10 + 0.4
|
|
sfl.Text = "Slope: "..s
|
|
end)
|
|
|
|
|
|
|
|
|
|
--------------------------
|
|
--SUCCESSFUL LOAD MESSAGE-
|
|
--------------------------
|
|
loaded = true
|
|
print("Elevation Plugin Loaded") |