Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
COMMUNITY QUESTION

Applying images to a surface, rotation and different surfaces?

Visual example, youtube

Brief: We click on an object's front surface, and it applies a ImageLabel centered around the mouse. The size is constant on all different sizes.

Problem 2: I can't apply this to all surfaces, I've already got the Surface's Normal being returned, but from there on, I don't know how to apply this information.

Here is me code:

local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local Texture = "http://www.roblox.com/asset/?id=82021756"
local Sizer = 20


function Positioning(part,hitpos)
	local PixelRef = part.CFrame:toObjectSpace(CFrame.new(hitpos))--*CFrame.new(-part.Size.X/2,-part.Size.Y/2,0)
	local XRef = -PixelRef.p.X-- -math.ceil(PixelRef.X) If we want this to be applied on a stud=pixel scale (Messes up positions)
	local YRef = -PixelRef.p.Y-- -math.ceil(PixelRef.Y)
	return XRef,YRef
end

function click()
	local target = mouse.Target
	if target then
        local mRay = mouse.UnitRay
        local ray = Ray.new( mRay.Origin, mRay.Direction * 100 )
        local part, pos, normal = game.Workspace:FindPartOnRay( ray, player.Character )
		if part then
			print(part.Name,pos,normal)
			local surface
			local frame
			if part:findFirstChild("SurfaceGui") then
				surface = part:findFirstChild("SurfaceGui")
				frame = surface.Framey
			else
				print("Found none")
				surface = Instance.new( "SurfaceGui", part)
				surface.CanvasSize = Vector2.new(part.Size.X*10,part.Size.Y*10)
				frame = Instance.new("Frame", surface)
				frame.Name = "Framey"
				frame.Size = UDim2.new(1,0,1,0)
				frame.ClipsDescendants = true
				frame.BackgroundTransparency =1 
			end
			local Tex = Instance.new("ImageLabel",frame)
			Tex.Image = Texture
			Tex.Size = UDim2.new(0,Sizer,0,Sizer)
			Tex.BackgroundTransparency = 1
			local X,Y = Positioning(part,pos)
			print(X,Y)
			Tex.Position = UDim2.new(.5+(X/(part.Size.X)),-Sizer/2,.5+(Y/(part.Size.Y)),-Sizer/2)
		end
	end
end

mouse.Button1Down:connect(click)

I've figured out where I was going wrong with the application, but I don't understand how I need to edit this to apply to other surfaces.

1 answer

Kept running into problems, but this one works, all Parts (Including wedges and corners, however it will only work on the FLAT parts of this surface, it does not produce a Face value for the slopes)

Hopefully I'll be able to add more things to this, such as removing overlapping pictures and converting them into one big image, similairly, this would be cool for growing puddles. This would look really cool for explosions

I'm also fairly interested in getting these to wrap around corners, or be spread over multiple moving bricks (pretty sure there was a Snack Break problem about this).

In the meantime however, feel free to use the code. First applications I can think of are bullet holes and splats, but I'm sure someone can think of some more interesting applications. Here ya go!

local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local Texture = "http://www.roblox.com/asset/?id=82021756"--<Your image or whatever
local PicSize = 20 --How many "pixels" the image is (Always square shape)
local CanSize = 10 --10 pixels offset, unless replacing the Picture for something made of frames, not necessary to change


function Positioning(part,hitpos)
	local PixelRef
	return -PixelRef.p
end

function ReturnNormal(PartCF,RayNorm)
	if PartCF.lookVector - RayNorm == Vector3.new(0,0,0) then
		return "Front",5
	elseif PartCF.lookVector + RayNorm == Vector3.new(0,0,0) then
		return "Back",2
	else
		local x, y, z, R00, R01, R02, R10, R11, R12, R20, R21, R22 = PartCF:components()
		if Vector3.new(R01,R11,R21) == RayNorm then
			return"Top", 1
		elseif Vector3.new(-R01,-R11,-R21) == RayNorm then
			return "Bottom",4
		elseif Vector3.new(-R00,-R10,-R20) == RayNorm then
			return "Left",3
		elseif Vector3.new(R00,R10,R20) == RayNorm then
			return "Right",0
		end
	end
end

function click()
	local target = mouse.Target
	if target then
        local mRay = mouse.UnitRay
        local ray = Ray.new( mRay.Origin, mRay.Direction * 100 )
        local part, pos, normal = game.Workspace:FindPartOnRay( ray, player.Character )
		if part then
			local SizeWidth = part.Size.X
			local SizeHeight = part.Size.Y
			local Face,Val = ReturnNormal(part.CFrame,normal)
			print(Face,Val)
			if Face == nil then
				return
			end
			if Face == "Top" or Face == "Bottom" then
				SizeWidth = part.Size.Z
				SizeHeight = part.Size.X
			elseif Face == "Right" or Face == "Left" then
				SizeWidth = part.Size.Z
				SizeHeight = part.Size.Y
			end
			local surface
			local frame
				for _,i in pairs(part:GetChildren()) do
					if i:IsA("SurfaceGui") then
						if i.Face == Val then
							surface = part:findFirstChild("SurfaceGui")
							frame = surface.Framey
						end
					end
				end
			if surface == nil then
				surface = Instance.new("SurfaceGui", part)
				surface.CanvasSize = Vector2.new(SizeWidth*CanSize,SizeHeight*CanSize)
				surface.Face = Val
				frame = Instance.new("Frame", surface)
				frame.Name = "Framey"
				frame.Size = UDim2.new(1,0,1,0)
				frame.ClipsDescendants = true
				frame.BackgroundTransparency =1 
			end
			local Tex = Instance.new("ImageLabel",frame)
			Tex.Image = Texture
			Tex.Size = UDim2.new(0,PicSize,0,PicSize)
			Tex.BackgroundTransparency = 1
			local Size = -(part.CFrame:toObjectSpace(CFrame.new(pos))).p
			if Face == "Front" then
				Tex.Position = UDim2.new(.5+(Size.X/(SizeWidth)),-PicSize/2,.5+(Size.Y/(SizeHeight)),-PicSize/2)
			elseif Face == "Back" then
				Tex.Position = UDim2.new(.5+(-Size.X/(SizeWidth)),-PicSize/2,.5+(Size.Y/(SizeHeight)),-PicSize/2)
			elseif Face == "Right" then
				Tex.Position = UDim2.new(.5+(Size.Z/(SizeWidth)),-PicSize/2,.5+(Size.Y/(SizeHeight)),-PicSize/2)
			elseif Face == "Left" then
				Tex.Position = UDim2.new(.5+(-Size.Z/(SizeWidth)),-PicSize/2,.5+(Size.Y/(SizeHeight)),-PicSize/2)
			elseif Face == "Top" then
				Tex.Position = UDim2.new(.5+(Size.Z/(SizeWidth)),-PicSize/2,.5+(-Size.X/(SizeHeight)),-PicSize/2)
			elseif Face == "Bottom" then
				Tex.Position = UDim2.new(.5+(Size.Z/(SizeWidth)),-PicSize/2,.5+(Size.X/(SizeHeight)),-PicSize/2)
			end
		end
	end
end

mouse.Button1Down:connect(click)

This discussion is preserved as it was. New answers, comments, and votes are closed.