
Key RequiredUniversal

-- 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)No comments yet for this script.



