Hello community
i am using the Placement System from zblox and i am having a hard time getting the floor feature correctly to work.
Currently i am using the Q and E keys to raise/lower the floors. This works perfectly fine. The only issue I have is when i raise my floor a space between my mouse and the object generates:
Here i am at the lowest floor and the object is perfectly positioned at my mouse:
(picture 1)
Now the more i raise the floor to build the more a space between these two generates:
(picture2)
In the following code snippet you can see that i customized a bit of the raiseFloor and lowerFloor functions from the original module. But this is only for the texture to go up with the model:
local function raiseFloor(actionName: string, inputState: Enum.UserInputState, inputObj: InputObject?)
if not (currentState ~= 4 and inputState == Enum.UserInputState.Begin) then return end
if not (enableFloors and not stackable) then return end
floorHeight += floor(abs(floorStep))
floorHeight = math.clamp(floorHeight, 0, maxHeight)
if preferSignals then changeFloors:Fire(true) end
local gridPart = plot.plotGridPart
if floorHeight < maxHeight then
gridPart.Position = Vector3.new(gridPart.Position.X, gridPart.Position.Y + floorStep, gridPart.Position.Z)
end
end
local function lowerFloor(actionName: string, inputState:Enum.UserInputState, inputObj: InputObject?)
if not (currentState ~= 4 and inputState == Enum.UserInputState.Begin) then return end
if not (enableFloors and not stackable) then return end
floorHeight -= floor(abs(floorStep))
floorHeight = math.clamp(floorHeight, 0, maxHeight)
if preferSignals then changeFloors:Fire(false) end
local plotBaseY = plot.Position.Y
local gridPart = plot.plotGridPart
if gridPart.Position.Y - floorStep >= plotBaseY then
gridPart.Position = Vector3.new(gridPart.Position.X, gridPart.Position.Y - floorStep, gridPart.Position.Z)
end
end
In the main function ‘activate’ where the player is then able to build we could see that the model gets correctly positioned to the mouse (picture 1).
function PlacementInfo:activate(ID: string, PlacedObjects: Instance, Plot: BasePart,
Stackable: boolean, SmartRotation: boolean, AutoPlace: boolean)
if currentState ~= 4 then TERMINATE_PLACEMENT() end
if GET_PLATFORM() == "Mobile" then mobileUI.Parent = player.PlayerGui end
-- Sets necessary variables for placement
character = player.Character or player.CharacterAdded:Wait()
plot = Plot
object = self.Prefabs:FindFirstChild(tostring(ID)):Clone()
placedObjects = PlacedObjects
primary = object.PrimaryPart
approveActivation()
if displayGridTexture then displayGrid() end
if includeSelectionBox then displaySelectionBox() end
if audibleFeedback then createAudioFeedback() end
-- Sets properties of the model (CanCollide, Transparency)
for i, inst in ipairs(object:GetDescendants()) do
if not inst:IsA("BasePart") then continue end
if transparentModel then inst.Transparency = inst.Transparency + transparencyDelta end
inst.CanCollide = false
inst.Anchored = true
end
if removeCollisionsIfIgnored then
for i, v: Instance in ipairs(self.IgnoredItems) do
if v:IsA("BasePart") then v.CanTouch = false end
end
end
object.PrimaryPart.Transparency = hitboxTransparency
stackable = Stackable
smartRot = SmartRotation
-- Allows stackable objects depending on stk variable given by the user
raycastParams.FilterDescendantsInstances = {placedObjects, character, unpack(self.IgnoredItems)}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
if Stackable then
raycastParams.FilterDescendantsInstances = {object, character, unpack(self.IgnoredItems)}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
end
-- Toggles buildmode placement (infinite placement) depending on if set true by the user
canActivate = false
if buildModePlacement then
canActivate = true
end
-- Gets the initial y pos and gives it to y
initialY = calculateYPos(Plot.Position.Y, Plot.Size.Y, object.PrimaryPart.Size.Y, 1)
y = initialY
removePlotDependencies = false
autoPlace = AutoPlace
local preSpeed = 1
set()
editHitboxColor()
roundInts()
bindInputs()
if interpolation then
preSpeed = clamp(abs(tonumber(1 - lerpSpeed)::number), 0, 0.9)
speed = preSpeed
if instantActivation then
setup = true
speed = 1
end
end
-- Parents the object to the location given
if not object then TERMINATE_PLACEMENT(); warn(messages["101"]) end
setCurrentState(1)
if instantActivation then translateObj() end
object.Parent = PlacedObjects
task.wait()
speed = preSpeed
if preferSignals then activated:Fire() end
setup = false
end
The only thing i could think of is that the objects gets positioned in the translateObj function where the calculateItemLocation is called to calculate its position but i am not exactly sure since it does not contain any mouse values. The translateObj function:
-- Sets the position of the object
local function translateObj(dt)
if not (currentState ~= 2 and currentState ~= 4) then return end
range = false
setCurrentState(1)
if getRange() > maxRange then
setCurrentState(5)
if preferSignals then outOfRange:Fire() end
range = true
end
checkHitbox()
editHitboxColor()
if removePlotDependencies then plot = findPlot() or plot end
if interpolation and not setup then
object:PivotTo(primary.CFrame:Lerp(calculateItemLocation(primary.CFrame.Position, false), speed*dt*targetFPS))
hitbox:PivotTo(calculateItemLocation(hitbox.CFrame.Position, true))
else
object:PivotTo(calculateItemLocation(primary.CFrame.Position, false))
hitbox:PivotTo(calculateItemLocation(hitbox.CFrame.Position, true))
end
end
The calculateItemLocation function:
-- Calculates the position of the object
local function calculateItemLocation(last, final: boolean): CFrame
local x: number, z: number
local sizeX: number, sizeZ: number = primary.Size.X*0.5, primary.Size.Z*0.5
local offsetX: number, offsetZ: number = sizeX, sizeZ
local finalC: CFrame
if not currentRot then sizeX = primary.Size.Z*0.5; sizeZ = primary.Size.X*0.5 end
if moveByGrid then
offsetX = sizeX - floor(sizeX/GRID_UNIT)*GRID_UNIT
offsetZ = sizeZ - floor(sizeZ/GRID_UNIT)*GRID_UNIT
end
local cam: Camera = workspace.CurrentCamera
local ray
local nilRay
local target
if isMobile then
local camPos: Vector3 = cam.CFrame.Position
ray = workspace:Raycast(camPos, cam.CFrame.LookVector*rangeOfRay, raycastParams)
nilRay = camPos + cam.CFrame.LookVector*(maxRange + plot.Size.X*0.5 + plot.Size.Z*0.5)
else
local unit: Ray = cam:ScreenPointToRay(mouse.X, mouse.Y, 1)
ray = workspace:Raycast(unit.Origin, unit.Direction*rangeOfRay, raycastParams)
nilRay = unit.Origin + unit.Direction*(maxRange + plot.Size.X*0.5 + plot.Size.Z*0.5)
end
if ray then
x, z = ray.Position.X - offsetX, ray.Position.Z - offsetZ
if stackable then target = ray.Instance; else target = plot end
else
x, z = nilRay.X - offsetX, nilRay.Z - offsetZ
target = plot
end
target = target
local pltCFrame: CFrame = plot.CFrame
local positionCFrame = cframe(x, 0, z)*cframe(offsetX, 0, offsetZ)
y = calculateYPos(plot.Position.Y, plot.Size.Y, primary.Size.Y, 1) + floorHeight
-- Changes y depending on mouse target
if stackable and target and (target:IsDescendantOf(placedObjects) or target == plot) then
if ray and ray.Normal then
local normal = cframe(ray.Normal):VectorToWorldSpace(Vector3.FromNormalId(Enum.NormalId.Top)):Dot(ray.Normal)
y = calculateYPos(target.Position.Y, target.Size.Y, primary.Size.Y, normal)
end
end
if moveByGrid then
-- Calculates the correct position
local rel: CFrame = pltCFrame:Inverse()*positionCFrame
local snappedRel: CFrame = snapCFrame(rel)*cframe(offsetX, 0, offsetZ)
if not removePlotDependencies then snappedRel = bounds(snappedRel, sizeX, sizeZ) end
finalC = pltCFrame*snappedRel
else
finalC = pltCFrame:Inverse()*positionCFrame
if not removePlotDependencies then finalC = bounds(finalC, sizeX, sizeZ) end
finalC = pltCFrame*finalC
end
-- Clamps y to a max height above the plot position
y = clamp(y, initialY, maxHeight + initialY)
-- For placement or no intepolation
if final or not interpolation then
return (finalC*cframe(0, y - plot.Position.Y, 0))*anglesXYZ(0, rotation*pi/180, 0)
end
return (finalC*cframe(0, y - plot.Position.Y, 0))*anglesXYZ(0, rotation*pi/180, 0)*calcAngle(last, finalC)
end
If you need further details to the scripts or have questions feel free to ask because i´ve tried to make the post small. Thank you very much!