# How to Create a Black Hole

 This is an Advanced, Lua Script related tutorial.

## Introduction

A black hole destroys SonOfSevenLess's castle

This tutorial is designed for advanced scripters and scripters who can be described as medium-level. It will cover several concepts, such as area-of-effect, and will provide the finished code for a black hole at the end.

If you are unable to understand this tutorial, it is suggested that you learn from the Novice tutorials first. If you are merely here to get a black hole, you can find in Roblox Studio in Insert / Free Models / typing "Black Hole" / Clicking "Search" / double-clicking the black hole you want.

## Starting off

Before creating a black hole, it is prudent to clear an area and anchor anything in the area which you would like to keep. Beware, as black holes actually increase in power as they gain mass, so the area should probably be at least 128 units in radius. It is also a good idea to figure out EXACTLY what you want the black hole to do. In this case, I have laid out the desired effects and the concepts that I use.

### Desired Effects

The black hole will do the following:

• Suck up ANYTHING that can move within a reasonable radius.
• Destroy objects that get close enough.

### Concepts

• Anchored The black hole, to be efficient, should not attempt to suck up any brick that cannot move anyway. This also prevents the floor from being destroyed.
• Area of Effect This black hole will suck ANYTHING that comes within a reasonable distance into itself.
• Arrays Arrays are sets of variables.
• Children In order to find every brick, functions will need to find them first.
• Classes The black hole must only work on certain types of objects, namely "Parts".
• Iteration Functions will use loops to cycle through arrays.
• Mass Similar to weight, but without taking gravity into account.
• Recursion The function for finding objects will call itself.

## Variable Initialization

The black hole will need to keep track of a number of things. It will need an array to keep track of objects and a floating-point variable to keep track of its mass (power).

```local hole = script.Parent -- Optional. Added for optimization
local childList = {}
local massConstant = 5.8 -- Generally a good value (again, optional)
local mass = 32000 * massConstant```

## Area of Effect

Area of effect is one of the most important concepts when creating a black hole, or any script intended to affect a wide range of bricks. The basic idea is to find every brick in the map, add them to an array, and use the array later. A recursive function will work well, allowing both simplicity and elegance.

Create a function, in this case called checkObject, which accepts an object's handle as an input. I named this variable obj. This function will first get the array of children using

`local list = obj:GetChildren()`

If the child's className variable indicates that it is a Part (brick), then it is added to the array of bricks using

`table.insert(childList, 1, list[n])`

If it is a Model, Workspace, Tool, or Hat, then it is checked for bricks by calling

`local list = obj:GetChildren()`

(This sets list to an array containing every child) and using a for loop to call

`checkObject(list[n])`

on every child, and it is made to check for children that are added later by using

`list[n].ChildAdded:connect(checkObject)`

This works because the ChildAdded event calls function with an argument of the child that was added. This ends the checkObject function. To get all bricks included, the script calls

`checkObject(workspace)`

Put together, the above code makes this:

```-- Note: This should only be run once for each object
function checkObject(obj)
if (obj ~= hole) and (obj.className == "Part") then
if (obj.Anchored == false) then
table.insert(childList, 1, obj)
end
elseif (obj.className == "Model") or (obj.className == "Hat") or (obj.className == "Tool") or (obj == workspace) then
local child = obj:GetChildren()
for x = 1, #child do
checkObject(child[x])
end
end
end```

## Finished Code

When complete, the code will look something like this:

```local hole = script.Parent
local childList = {}

local massConstant = 5.8 -- Generally a good value

local mass = 32000 * massConstant

-- This is basically a function that finds all unanchored parts and adds them to childList.
-- Note: This should only be run once for each object
function checkObject(obj)
if (obj ~= hole) and (obj.className == "Part") then
if (obj.Anchored == false) then
table.insert(childList, 1, obj)
end
elseif (obj.className == "Model") or (obj.className == "Hat") or (obj.className == "Tool") or (obj == workspace) then
local child = obj:GetChildren()
for x = 1, #child do
checkObject(child[x])
end
end
end

checkObject(workspace)

local n = 0
while true do
if n < #childList then
n = n + 1
if n % 800 == 0 then
wait()
end
else
n = 1
wait()
end

local child = childList[n]
if (child ~= hole) and (child.className == "Part") and (child.Anchored == false) then
local relPos = hole.Position - child.Position
local motivator = child:FindFirstChild("BlackHole Influence")
if relPos.magnitude * 240 * massConstant < mass then
child:BreakJoints()
if (relPos.magnitude * 320 * massConstant < mass) and (child.Size.z + hole.Size.x >  relPos.magnitude * 2 - 4) then
mass = mass + child:GetMass()
child:Remove()
table.remove(childList, n)
n = n - 1 -- This is the reason I need a counter of my own design
else
child.CanCollide = false -- I Can assume that things won't escape the black hole.
if motivator == nil then
motivator = Instance.new("BodyPosition")
motivator.Parent = child
motivator.Name = "BlackHole Influence"
end
motivator.position = hole.Position
motivator.maxForce = Vector3.new(1, 1, 1) * mass * child:GetMass() / (relPos.magnitude * massConstant)
end
elseif motivator ~= nil then
motivator:Remove()
end
end
end```