Stud Friend
Key RequiredUniversal

Stud Friend

Universal ScriptYeznor_ScriptsYeznor_Scripts 84 views 738 executesUpdated Jul 13, 2026
Unrated
00
Lua Script•1714 lines (16175 chars)
-- stud friend! 
-- Social Living Shapes

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

local player = Players.LocalPlayer


local folder = workspace:FindFirstChild("CuboidObjects")

if not folder then
	folder = Instance.new("Folder")
	folder.Name = "CuboidObjects"
	folder.Parent = workspace
end



local cuboids = {}

local selected = nil


local size = 4

local currentColor =
Color3.fromRGB(255,255,255)



local FACE_DISTANCE = 100





------------------------------------------------
-- PHRASES
------------------------------------------------

local phrases = {

   "😀",
   "😃",
   "😄",
   "😁",
   "😆",
   "😅",
   "🤣",
   "😂",
   "🙂",
   "🙃",
   "🫠",
   "😉",
   "😊",
   "😇",
   "🥰",
   "😍",
   "🤩",
   "😘",
   "😗",
   "😚",
   "😙",
   "😋",
   "😛",
   "😜",
   "🤪",
   "😝",
   "🤑",
   "🤗",
   "🤭",
   "🫢",
   "🫣",
   "🤫",
   "🤔",
   "🫡",
   "🤐",
   "🤨",
   "😐",
   "😑",
   "😶",
   "🫥",
   "😶‍🌫️",
   "😏",
   "😒",
   "🙄",
   "😬",
   "😮‍💨",
   "🤥",
   "😌",
   "😔",
   "😪",
   "🤤",
   "😴",
   "😷",
   "🤒",
   "🤕",
   "🤢",
   "🤮",
   "🤧",
   "🥵",
   "🥶",
   "🥴",
   "😵",
   "😵‍💫",
   "🤯",
   "🤠",
   "🥳",
   "🥸",
   "😎",
   "🤓",
   "🧐",
   "😕",
   "🫤",
   "😟",
   "🙁",
   "☹️",
   "😮",
   "😯",
   "😲",
   "😳",
   "🥺",
   "🥹",
   "😦",
   "😧",
   "😨",
   "😰",
   "😥",
   "😢",
   "😭",
   "😱",
   "😖",
   "😣",
   "😞",
   "😓",
   "😩",
   "😫",
   "🥱",
   "😤",
   "😡",
   "😠",
   "🤬",
   "😈",
   "👿",
   "💀",
   "☠️",
   "👻",
   "👽",
   "🤖",
   "💩",
   "🤡",
   "👹",
   "👺",
   "👶"
  

}





------------------------------------------------
-- GUI
------------------------------------------------

local gui = Instance.new("ScreenGui")

gui.Name = "CuboidUI"

gui.ResetOnSpawn = false

gui.Parent = player.PlayerGui





local function makeButton(text,x,y,func)


	local b = Instance.new("TextButton")


	b.Size =
	UDim2.new(
		0,
		60,
		0,
		20
	)


	b.Position =
	UDim2.new(
		0,
		x,
		0,
		y
	)



	b.Text = text

	b.TextScaled = true


	b.Parent = gui



	b.MouseButton1Click:Connect(func)



	return b

end





------------------------------------------------
-- FACE SYSTEM
------------------------------------------------

local function setFace(part,text)


	local old =
	part:FindFirstChild("Face")


	if old then

		old:Destroy()

	end



	local face =
	Instance.new("BillboardGui")


	face.Name =
	"Face"


	face.Size =
	UDim2.new(
		0,
		70,
		0,
		70
	)


	face.AlwaysOnTop = true


	face.Parent = part





	local label =
	Instance.new("TextLabel")



	label.Size =
	UDim2.fromScale(
		1,
		1
	)



	label.BackgroundTransparency = 1


	label.Text =
	text


	label.TextScaled = true


	label.Parent = face



end






------------------------------------------------
-- SPEECH
------------------------------------------------

local function speak(part)


	local old =
	part:FindFirstChild("Speech")


	if old then

		old:Destroy()

	end



	local bubble =
	Instance.new("BillboardGui")


	bubble.Name =
	"Speech"


	bubble.Size =
	UDim2.new(
		0,
		130,
		0,
		35
	)



	bubble.StudsOffset =
	Vector3.new(
		0,
		3,
		0
	)



	bubble.AlwaysOnTop = true


	bubble.Parent = part





	local text =
	Instance.new("TextLabel")



	text.Size =
	UDim2.fromScale(
		1,
		1
	)



	text.BackgroundTransparency = 1


	text.TextScaled = true


	text.Text =
	phrases[
		math.random(
			1,
			#phrases
		)
	]



	text.Parent = bubble




	task.delay(
		3,
		function()

			if bubble then

				bubble:Destroy()

			end

		end
	)

end





------------------------------------------------
-- DISTANCE FACE HIDING
------------------------------------------------

local function updateFaceDistance()


	if not player.Character then
		return
	end


	local root =
	player.Character:FindFirstChild(
		"HumanoidRootPart"
	)


	if not root then
		return
	end



	for _,c in pairs(cuboids) do


		local face =
		c.Object:FindFirstChild(
			"Face"
		)


		local speech =
		c.Object:FindFirstChild(
			"Speech"
		)



		local distance =
		(
		root.Position -
		c.Object.Position
		).Magnitude



		if face then

			face.Enabled =
			distance <= FACE_DISTANCE

		end



		if speech then

			speech.Enabled =
			distance <= FACE_DISTANCE

		end


	end

end

------------------------------------------------
-- COLORS
------------------------------------------------

local colors = {

	{"Red",Color3.fromRGB(255,0,0)},
	{"Orange",Color3.fromRGB(255,120,0)},
	{"Yellow",Color3.fromRGB(255,255,0)},
	{"Lime",Color3.fromRGB(100,255,0)},
	{"Green",Color3.fromRGB(0,255,80)},
	{"Cyan",Color3.fromRGB(0,255,255)},
	{"Blue",Color3.fromRGB(0,100,255)},
	{"Purple",Color3.fromRGB(150,0,255)},
	{"Pink",Color3.fromRGB(255,0,170)},
	{"White",Color3.fromRGB(255,255,255)},
	{"Gray",Color3.fromRGB(120,120,120)},
	{"Black",Color3.fromRGB(0,0,0)}

}



for i,c in ipairs(colors) do


	makeButton(
		c[1],
		(i-1)%4*65,
		150+
		math.floor((i-1)/4)*25,

		function()

			currentColor =
			c[2]

		end
	)

end






------------------------------------------------
-- SPAWN CUBOID
------------------------------------------------

local function spawnCuboid(shape)


	local part =
	Instance.new("Part")



	part.Name =
	shape.." Cuboid"



	part.Size =
	Vector3.new(
		size,
		size,
		size
	)




	if shape == "Sphere" then

		part.Shape =
		Enum.PartType.Ball


	elseif shape == "Cylinder" then

		part.Shape =
		Enum.PartType.Cylinder


	elseif shape == "Wedge" then

		part.Shape =
		Enum.PartType.Wedge

	end




	part.Color =
	currentColor



	part.Position =
	player.Character.HumanoidRootPart.Position
	+
	Vector3.new(
		math.random(-10,10),
		5,
		math.random(-10,10)
	)



	part.Parent =
	folder




	local data = {

		Object = part,


		Type = shape,


		Mode = "Stare",


		IdleTime = 0,


		Sleeping = false,


		NormalFace = ":P",


		MoveTimer = 0,


		Direction = Vector3.zero,


		SpeechTimer =
		math.random(5,12),


		Bonk = false,


		SocialTimer = 0,

     LastBlock = 0,

     LastSpawn = 0,

     SpawnPoints = {},

     HomePosition = part.Position
	}




	table.insert(
		cuboids,
		data
	)




	-- alive instantly

	setFace(
		part,
		":P"
	)






	------------------------------------------------
	-- SELECTION
	------------------------------------------------

	local click =
	Instance.new("ClickDetector")



	click.MaxActivationDistance =
	60



	click.Parent =
	part




	click.MouseClick:Connect(function()


		selected =
		data



		print(
		shape.." selected"
		)



	end)







	------------------------------------------------
	-- BONK
	------------------------------------------------

	part.Touched:Connect(function(hit)



		if data.Bonk then
			return
		end



		if hit:IsDescendantOf(folder) then
			return
		end



		data.Bonk = true



		setFace(
			part,
			"o_O"
		)




		task.delay(
			1,
			function()


				data.Bonk = false



				if data.Mode=="Stare" then

					setFace(part,":P")


				elseif data.Mode=="Wonder" then

					setFace(part,":)")


				elseif data.Mode=="Attack" then

					setFace(part,">:(")


				elseif data.Mode=="Follow" then

					setFace(part,":D")


				elseif data.Mode=="Social" then

					setFace(part,":D")

				end



			end
		)



	end)



end

----------------------------------
-- FUNCTIONS
----------------------------------

local function buildBlock(c)

	if tick() - (c.LastPlank or 0) < 0.3 then
		return
	end

	c.LastPlank = tick()

	local block = Instance.new("Part")
	block.Name = "StudBlock"
	block.Anchored = true
	block.Size = Vector3.new(4,4,4)
	block.Material = Enum.Material.Plastic
	block.Color = c.Object.Color

	block.Position =
		Vector3.new(
			math.floor(c.Object.Position.X/4 + 0.5) * 4,
			math.floor((c.Object.Position.Y-4)/4 + 0.5) * 4,
			math.floor(c.Object.Position.Z/4 + 0.5) * 4
		)

	block.Parent = folder

end


local function buildSpawn(c)

	c.SpawnPoints=c.SpawnPoints or {}

	if tick()-(c.LastSpawn or 0)<60 then
		return
	end

	c.LastSpawn=tick()

	local spawn=Instance.new("SpawnLocation")

	spawn.Anchored=true
	spawn.Size=Vector3.new(6,1,6)

	spawn.Position=
	c.Object.Position-
	Vector3.new(0,2.5,0)

	spawn.Neutral=true
	spawn.Color=c.Object.Color

	spawn.Parent=folder

	table.insert(
		c.SpawnPoints,
		spawn
	)

end


local function checkVoid(c)

	if c.Object.Position.Y>-100 then
		return
	end

	local closest
	local dist=math.huge

	for _,spawn in ipairs(c.SpawnPoints or {}) do

		if spawn.Parent then

			local d=
			(c.Object.Position-
			spawn.Position).Magnitude

			if d<dist then

				dist=d
				closest=spawn

			end

		end

	end

	if closest then

		c.Object.Position=
		closest.Position+
		Vector3.new(0,4,0)

	end

end


local function checkGap(c)

	local params=RaycastParams.new()

	params.FilterType=
	Enum.RaycastFilterType.Exclude

	params.FilterDescendantsInstances={
		folder,
		c.Object
	}

	local ray=
	workspace:Raycast(

		c.Object.Position,

		Vector3.new(0,-6,0),

		params

	)

	if not ray then

		buildBlock(c)

	end

end


local function randomSpawn(c)

	if math.random(1,800)==1 then

		buildSpawn(c)

	end

end


------------------------------------------------
-- FIND PLAYER
------------------------------------------------

local function getClosestPlayer(pos)

	local closest
	local distance = math.huge


	for _,p in pairs(Players:GetPlayers()) do


		if p.Character
		and p.Character:FindFirstChild("HumanoidRootPart") then


			local d =
			(
			p.Character.HumanoidRootPart.Position
			-pos
			).Magnitude



			if d < distance then

				distance = d
				closest = p

			end

		end

	end


	return closest

end






------------------------------------------------
-- FIND NEARBY CUBOID
------------------------------------------------

local function findNearbyCuboid(c)


	local closest
	local distance = 30



	for _,other in pairs(cuboids) do


		if other ~= c then



			local d =
			(
			other.Object.Position
			-c.Object.Position
			).Magnitude



			if d < distance then

				distance = d
				closest = other

			end


		end


	end



	return closest

end






------------------------------------------------
-- AI LOOP
------------------------------------------------

RunService.Heartbeat:Connect(function(dt)


	updateFaceDistance()



	for _,c in pairs(cuboids) do



		local part =
		c.Object



		local target =
		getClosestPlayer(
			part.Position
		)





		------------------------------------------------
		-- TALK TIMER
		------------------------------------------------

		c.SpeechTimer -= dt



		if c.SpeechTimer <= 0
		and c.Mode=="Social" then


			local other =
			findNearbyCuboid(c)



			if other then


				speak(part)



				part.CFrame =
				CFrame.lookAt(
					part.Position,
					other.Object.Position
				)


			end



			c.SpeechTimer =
			math.random(8,15)


		end







		------------------------------------------------
		-- STARE
		------------------------------------------------

		if c.Mode=="Stare" then



			part.AssemblyLinearVelocity =
			Vector3.zero



			c.IdleTime += dt




			if c.IdleTime >= 10 then



				c.Sleeping = true



				setFace(
					part,
					"-_-"
				)



			else


				setFace(
					part,
					":P"
				)


			end





			local other =
			findNearbyCuboid(c)



			if other
			and other.Mode=="Stare" then


				local d =
				(
				other.Object.Position
				-part.Position
				).Magnitude



				if d < 20 then


					part.CFrame =
					CFrame.lookAt(
						part.Position,
						other.Object.Position
					)



					if math.random(1,200)==1 then

						speak(part)

					end


				end


			end


		end





		------------------------------------------------
		-- WONDER
		------------------------------------------------

		if c.Mode=="Wonder" then


			c.IdleTime=0
			c.Sleeping=false



			setFace(
				part,
				":)"
			)




			c.MoveTimer -= dt



			if c.MoveTimer <= 0 then


				c.MoveTimer =
				math.random(2,5)



				c.Direction =
				Vector3.new(
					math.random(-10,10),
					0,
					math.random(-10,10)
				).Unit


			end




			part.AssemblyLinearVelocity =
			c.Direction*8




			if c.Type=="Cube"
			or c.Type=="Wedge" then


				part.CFrame =
				CFrame.lookAt(
					part.Position,
					part.Position+c.Direction
				)


			end

        checkGap(c)

        randomSpawn(c)

        checkVoid(c)

		end

		------------------------------------------------
		-- ATTACK
		------------------------------------------------

		if c.Mode=="Attack" then


			c.IdleTime = 0
			c.Sleeping = false


			setFace(
				part,
				">:("
			)



			if target then


				local direction =
				(
				target.Character.HumanoidRootPart.Position
				-part.Position
				).Unit



				part.AssemblyLinearVelocity =
				direction*18



				if c.Type=="Cube"
				or c.Type=="Wedge" then


					part.CFrame =
					CFrame.lookAt(
						part.Position,
						part.Position+direction
					)


				end



				if
				(part.Position -
				target.Character.HumanoidRootPart.Position)
				.Magnitude < 5 then


					target.Character.Humanoid:TakeDamage(5)


				end



			end


		end






		------------------------------------------------
		-- FOLLOW
		------------------------------------------------

		if c.Mode=="Follow" then


			c.IdleTime=0
			c.Sleeping=false


			setFace(
				part,
				":D"
			)



			if target then


				local direction =
				(
				target.Character.HumanoidRootPart.Position
				-part.Position
				).Unit



				part.AssemblyLinearVelocity =
				direction*10



				if c.Type=="Cube"
				or c.Type=="Wedge" then


					part.CFrame =
					CFrame.lookAt(
						part.Position,
						part.Position+direction
					)


				end


			end


		end






		------------------------------------------------
		-- SOCIAL MODE
		------------------------------------------------

		if c.Mode=="Social" then



			c.IdleTime=0
			c.Sleeping=false



			local other =
			findNearbyCuboid(c)



			if other then


				local distance =
				(
				other.Object.Position
				-part.Position
				).Magnitude




				if distance > 8 then


					local direction =
					(
					other.Object.Position
					-part.Position
					).Unit



					part.AssemblyLinearVelocity =
					direction*7



					setFace(
						part,
						":D"
					)


				else



					part.AssemblyLinearVelocity =
					Vector3.zero



					part.CFrame =
					CFrame.lookAt(
						part.Position,
						other.Object.Position
					)



					setFace(
						part,
						":D"
					)



					c.SpeechTimer -= dt



					if c.SpeechTimer <= 0 then


						speak(part)


						c.SpeechTimer =
						math.random(8,15)


					end



				end


			end



		end



	end


end)







------------------------------------------------
-- SPAWN BUTTONS
------------------------------------------------


makeButton(
"Cube",
10,
20,
function()

	spawnCuboid("Cube")

end)



makeButton(
"Sphere",
75,
20,
function()

	spawnCuboid("Sphere")

end)



makeButton(
"Cyl",
140,
20,
function()

	spawnCuboid("Cylinder")

end)



makeButton(
"Wedge",
205,
20,
function()

	spawnCuboid("Wedge")

end)







------------------------------------------------
-- SIZE BUTTONS
------------------------------------------------


makeButton(
"+",
270,
20,
function()

	size += 2

end)



makeButton(
"-",
335,
20,
function()

	size =
	math.max(
		2,
		size-2
	)

end)






------------------------------------------------
-- MODE BUTTONS
------------------------------------------------


makeButton(
"Stare",
10,
100,
function()


	if selected then

		selected.Mode="Stare"
		selected.IdleTime=0
		setFace(selected.Object,":P")

	end


end)



makeButton(
"Wonder",
75,
100,
function()


	if selected then

		selected.Mode="Wonder"
		selected.IdleTime=0
		setFace(selected.Object,":)")

	end


end)



makeButton(
"Attack",
140,
100,
function()


	if selected then

		selected.Mode="Attack"
		selected.IdleTime=0
		setFace(selected.Object,">:(")

	end


end)



makeButton(
"Follow",
205,
100,
function()


	if selected then

		selected.Mode="Follow"
		selected.IdleTime=0
		setFace(selected.Object,":D")

	end


end)



makeButton(
"Social",
270,
100,
function()


	if selected then

		selected.Mode="Social"
		selected.IdleTime=0
		setFace(selected.Object,":D")

	end


end)

Features & Information

This is my first script! It isn't supposed to be something great as all it is just a funny little test. This is Stud Friend! Spawn little shape dudes and play around with them! How to use: Choose your Stud Friend's color, and size, (using the + and -) then choose a shape and he spawns! To make him do stuff, click on one of the command buttons (wander, attack, stare, follow) and click on the Stud Friend to activate it! You can spawn as much Stud Friends as this script says you can (idrk the max) Have fun with your new friend!
#Friend#Buddy#NPC#Shapes

Community Comments (0)

No comments yet for this script.

More Scripts for Universal Scripts