Spawn Model on part surface

I have a ability where you spawn a trap, but if you spawn it on rotated terrain it will not orientate itself to onto the surface but go through it. How would I lay the trap on the surface of the part. (I made a line to show the orientation its meant to be in when it’s spawned on a rotated surface.)

This is my current code:

game.ReplicatedStorage.Abilites.Trap.OnServerEvent:Connect(function(player)
  local DIST_FROM_PLAYER = 0
  local char = player.Character or player.CharacterAdded:Wait()
  local BearTrap = game.ServerStorage.BearTrap:Clone()
  BearTrap.Open.Color = player.TeamColor.Color
  BearTrap.Parent = workspace
  BearTrap:SetPrimaryPartCFrame(CFrame.new(char.PrimaryPart.CFrame.Position+ 
  (DIST_FROM_PLAYER*char.PrimaryPart.CFrame.LookVector)))
  BearTrap.HitBox.Setup:Play()
  wait(30)
  BearTrap:Destroy()
end)
1 Like
local part = workspace.Part
local cframe = ( part.CFrame * CFrame.new(0, part.Size.Y/2, 0) ).Position game.Workspace.Part2.Position = cframe game.Workspace.Part2.Orientation = part.Orientation

Like that. And it automatically finds the surface.

You’d need to send a raycast out to the position where you want the part to be placed.

If the raycast hits an instance, you need to rotate the trap to the normal of that raycast; Otherwise, you need to just set the position of the trap to wherever you want it to be placed.

Because I don’t think anyone wants to spend an hour reading the documentation for raycasts, here is a module I wrote for a rewrite of Steep Steps that can explain what I mean.

You’re going to need to edit this code most likely, but I figure you can do that.

local Logic = {
	PLACE_DISTANCE = 5, -- REPLACE THIS WITH HOW FAR AWAY YOU WANT THE TRAP TO BE PLACED
}

local Params = RaycastParams.new()
Params.FilterType = Enum.RaycastFilterType.Include
Params.FilterDescendantsInstances = {workspace.Map, workspace.playerPlaced} -- REPLACE THIS WITH THE LIST OF INSTANCES YOU WANT TO FILTER, READ THE DOCS FOR MORE INFORMATION


function Logic:SetLadderPlacement(Ladder, Pivot) -- Usage: Logic:SetLadderPlacement(TrapModel, OriginCFrame)
	local Unit = Pivot.LookVector * Logic.PLACE_DISTANCE
	local Raycast = workspace:Raycast(Pivot.Position, Unit, Params)
	
	local Position = Raycast and Raycast.Position
	local Normal = Raycast and Raycast.Normal
	
	local LadderPosition = (Raycast and CFrame.new(Position, Position + Normal)) or Pivot * CFrame.new(0, 0, -Logic.PLACE_DISTANCE)

	Ladder:SetPrimaryPartCFrame(LadderPosition * CFrame.new(0, 1.25, -0.5) --[[ This is an offset because it casts directly from the center of the object, you could either make this module better or just change this offset to prevent the trap from floating ]])
end

return Logic

2 Likes

Why would you want to overcomplicate it so much?

Doesn’t this only rotate it to parts2 orientation and not all parts automatically?

no its the part of your choice. It automatically sets the position of Part2 to the surface of Part. And rotates it to.

Yeah but thats the thing, I want it to be for all parts not just 1 part

Okay then just make the part variable dynamic. This has nothing to do with the topic. The topic is how to position something on the surface of the part not how to do it for multiple parts. I gave you the base code that you will need for this.

you can use BasePart:GetClosestPointOnSurface() method, or you can parent an Attachment to your blocks which will contain traps, and use its Axis and SecondaryAxis properties to determine orientation