First time using full OOP part creation

Hi, I’m making a system for creating physics objects using OOP methods for easy client replication, and was wondering if anyone could give me their thoughts on what I have so far, or any tips on improving it in some way.

The idea behind it is that I have a handful of templates to choose from when I want to create a specific part.

I just went with one template to start:

--[[Templates]]
return {

    BlueBall = {
        Name = 'BlueBall';
        Properties = {Shape = Enum.PartType.Ball, Size = Vector3.new(3,3,3), Color = Color3.fromRGB(0,0,255)}
    };

}

If the template named doesn’t exist, or certain properties/attributes aren’t held in the template, then it defaults to a standard value defined by a metatable.

If even a string isn’t provided to give it a name, then the cube is just named “RedCube”
– planning to concatenate it with the number of identical objects to make them easier to find.

Here’s the part creation module:

--[[CreatePart]]

local temp = require(script:WaitForChild('Templates'))

local Object = {}
Object.__index = Object

function Object.NewTemplate(objInf, name)
    local newObj = setmetatable(temp[objInf] or {}, Object)
    newObj.ClassName = newObj.ClassName or 'Part'
    newObj.Parent = newObj.Parent or workspace
    newObj.Name = name or newObj.Name or objInf or 'RedCube'

    newObj.Properties = newObj.Properties or {
        Size = Vector3.new(2,2,2);
        Color = Color3.fromRGB(255,0,0);
        Material = Enum.Material.SmoothPlastic;
    }

    newObj.Surfaces = newObj.Surfaces or {
        TopSurface = Enum.SurfaceType.Smooth;
        BottomSurface = Enum.SurfaceType.Smooth;
    }

    newObj.Attributes = newObj.Attributes or {
        CustomAtt = true;
    }

    newObj.Tags = newObj.Tags or {
        'CustomTag';
    }

    return newObj
end

function Object:Create()
    local createdPart = Instance.new(self.ClassName, self.Parent)
    createdPart.Name = self.Name

    for prop,val in pairs(self.Properties) do
        createdPart[prop] = val
    end

    for face,app in pairs(self.Surfaces) do
        createdPart[face] = app
    end

    for att,val in pairs(self.Attributes) do
        createdPart:SetAttribute(att, val)
    end

    for i,tag in ipairs(self.Tags) do
        game:GetService('CollectionService'):AddTag(createdPart, tag)
    end

    return createdPart
end

return Object

Calling the required CreatePart module immediately creates a part, setting the first provided string value – if one is given – as the template.

  • No template results in the part’s name being set to the provided string
  • No string value still results in creating a default part, but with the default name.

A second optional string will be used to give the newly-created part a different name from the template.

Here’s how to create parts when putting it into practice with a script:

--[[PartManager]]
local modulesFolder = "Moduĺes Folder"
local CreatePartMod = require(modulesFolder.CreatePart)

function CreatePart(temp, name)
	return CreatePartMod.NewTemplate(temp, name):Create()
end
local redCube = CreatePart() -- creates a default part with the default 'RedCube' name.
redCube.Position = Vector3.new(-20,1,-10)

local blueBall = CreatePart('BlueBall') -- creates a part using the BlueBall template from the module.
blueBall.Position = redCube.Position + Vector3.new(5,0,0)

local otherCube = CreatePart('OtherCube') -- creates a default part with the name "OtherCube"
otherCube.Position = redCube.Position + Vector3.new(5,0,5)

local otherBall = CreatePart('BlueBall', 'OtherBall') -- creates a blue ball with the name "OtherBall"
otherBall.Position = redCube.Position + Vector3.new(0,0,5)

Essentially, CreatePart() is the part itself, and when set to a local variable, you can set its color, CFrame, change its name, apply tweens and add attachments to it, etc.

I figured this could help save a lot of space on the server by using templates like this to create instances, rather than keeping actual objects somewhere like ReplicatedStorage to be cloned or re-parented by the client.

Edit(s): I fixed a few mistakes because I literally wrote these scripts up on my phone lmao

3 Likes

[[Update]]

I figured out how to implement a call function into the CreatePart module so that it can be called without needing to add a return function in the manager script.

setmetatable(Object, {
	__call = function(self, temp, newName)
		return self.NewTemplate(temp, newName):Create()
	end,
})

Now the full part creation script looks like this:

local CreatePart = require(game:GetService('ReplicatedStorage').Modules.CreatePart)

local redCube = CreatePart() -- creates a default part with the default 'RedCube' name.
redCube.Position = Vector3.new(-20,1,-10)

local blueBall = CreatePart('BlueBall') -- creates a part using the BlueBall template from the module.
blueBall.Position = redCube.Position + Vector3.new(5,0,0)

local otherCube = CreatePart('OtherCube') -- creates a default part with the name "OtherCube"
otherCube.Position = CreateCube.Position + Vector3.new(5,0,5)

local otherBall = CreatePart('BlueBall', 'OtherBall') -- creates a blue ball with the name "OtherBall"
otherBall.Position = redCube.Position + Vector3.new(0,0,5)

And does indeed work.
image

1 Like

I’ve changed up a few things and contained it all within a metatable. It still runs the same way, only it changes each individual property, as I noticed it wasn’t changing the balls from Plastic to Smooth Plastic.

local temp = require(script:WaitForChild('Templates'))
local obj = setmetatable({
	ClassName = 'Part';
	Parent = workspace;
	Name = 'RedCube';
	Props = {
		Size = Vector3.new(2,2,2);
		Color =  Color3.fromRGB(255,0,0);
		Material = Enum.Material.SmoothPlastic;
		TopSurface = Enum.SurfaceType.Smooth;
		BottomSurface = Enum.SurfaceType.Smooth;
	};
	Atts = {CustomAtt = true};
	Tags = {'CustomTag'};
	New = function(self, label, name)
		local new = setmetatable(temp[label] or {}, self)
		new.ClassName = new.ClassName
		new.Parent = new.Parent
		new.Name = name or label or new.Name
		new.Props = {
			Shape = new.Props.Shape or self.Props.Shape;
			Size = new.Props.Size or self.Props.Size;
			Color = new.Props.Color or self.Props.Color;
			Material = new.Props.Material or self.Props.Material;
			TopSurface = new.Props.TopSurface or self.Props.TopSurface;
			BottomSurface = new.Props.BottomSurface or self.Props.BottomSurface;
		}
		new.Atts = new.Atts
		new.Tags = new.Tags
		return new
	end;
	Create = function(self)
		local inst = Instance.new(self.ClassName, self.Parent)
		inst.Name = self.Name
		for prop,val in pairs(self.Props) do
			inst[prop] = val
		end
		for att,val in pairs(self.Atts) do
			inst:SetAttribute(att, val)
		end
		for i,tag in ipairs(self.Tags) do
			game:GetService('CollectionService'):AddTag(inst, tag)
		end
		return inst
	end;
},
{
	__call = function(self, ...) return self:New(...):Create()end;
})
obj.__index = obj

return obj
1 Like

You might say this thread has been a little

self centered

local self = setmetatable({
	Props = {};
	New = function(self, label, name)
		local self = setmetatable(require(script.Templates)[label] or {}, self)
		self.ClassName = self.ClassName or 'Part'
		self.Parent = self.Parent or workspace
		self.Name = name or label or self.Name or 'RedCube'
		self.Props = {
			CanCollide = self.Props.CanCollide;
			Anchored = self.Props.Anchored;
			Shape = self.Props.Shape;
			Size = self.Props.Size or Vector3.new(2,2,2);
			Color = self.Props.Color or Color3.fromRGB(255,0,0);
			Material = self.Props.Material or Enum.Material.SmoothPlastic;
			TopSurface = self.Props.TopSurface or Enum.SurfaceType.Smooth;
			BottomSurface = self.Props.BottomSurface or Enum.SurfaceType.Smooth;
		}
		self.Atts = self.Atts
		self.Tags = self.Tags
		return self
	end;
	Create = function(self)
		local inst = Instance.new(self.ClassName, self.Parent)
		inst.Name = self.Name
		for prop,val in pairs(self.Props or {}) do
			inst[prop] = val
		end
		for att,val in pairs(self.Atts or {}) do
			inst:SetAttribute(att, val)
		end
		for i,tag in ipairs(self.Tags or {}) do
			game:GetService('CollectionService'):AddTag(inst, tag)
		end
		return inst
	end;
},
{__call = function(self, ...) return self:New(...):Create() end})
self.__index = self
return self
3 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.