How can I use OOP for this Highlight script?

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!
    I want to achieve an effect where the outline highlights the player with OOP.
  2. What is the issue? Include screenshots / videos if possible!
    But I’m not sure how I would get the properties onto a highlight instance?
  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I need some clarification. Help is appreciated.

Script

local OutlineModule = require(script.OutlineModule)

local CharacterOutline = Instance.new("Highlight")


game.Players.PlayerAdded:Connect(function(Player)
	Player.CharacterAdded:Connect(function(Character)
		
	end)
end)

Module

local mod = {}



function mod:AssignProperties(name, fillcolor, filltransparency, depthmode, outlinetransparency, outlinecolor)
	local self = {}
	
	self.Name = name
	self.FillColor = fillcolor
	self.FillTransparency = filltransparency
	self.DepthMode = depthmode
	self.OutlineTransparency = outlinetransparency
	self.OutlineColor = outlinecolor
	
	return self
end



return mod

(the Highlight Instance isn’t already existing, it’s created with Instance.New())

1 Like

I don’t really see why you would need to use mock-OOP for this, it’s wrapping a already existing class but there’s just not enough to make it worthwhile. You’re basically adding nothing to the original which makes it kind of useless.

But, if you really want to, you can do something like this:

local HighlightMod = {}
HighlightMod.__index = HighlightMod

function HighlightMod.new(parent: BasePart|Model, data: {[string]: any}): {[string]: any}
    --ignore if missing arguments
    if not parent or not data then
        error("Missing parameters to 'HighlightMod.new'. Please check your parameters passed.", 2)
    end

    --create mock-object
    local self = setmetatable({}, HighlightMod)
    self.Highlight = Instance.new("Highlight")

    --data contains the properties for the highlight
    for prop: string, value: any in next, data, nil do
        if typeof(value) ~= typeof(self.Highlight[prop]) and typeof(self.Highlight[prop]) ~= "nil" then
            error("Custom error telling the user one of the properties is incorrect", 2)
        end

        self.Highlight[prop] = value --assign the property
        self[prop] = value --also assign it in our class table
    end

    self.Highlight.Parent = parent --assign parent
    return self --return the highlight
end

--[[
example method with our table of properties and the highlight
this is just a quick example for listing these properties,
if you want an easier way where you could just use
a print statement you can modify the
__tostring metamethod
]]
function HighlightMod:ListProps()
    for prop: string, val: any in next, self, nil do
        if prop == "Highlight" then continue end
        print("{")
        print(`    [{prop}]: {val}`)
        print("}")
    end
end

return HighlightMod

Example usage:

local HighlightMod = require(--[[path to the module]])

local ModdedHighlight = HighlightMod.new(workspace:FindFirstChildOfClass("Part"), {
    ["FillColor"] = Color3.fromRGB(85, 170, 0)
})

ModdedHighlight:ListProps()

There’s going to be multiple outlines in the game, not just one.

If you’re using Luau’s newest typesolver, you can do something like this:

type Property = keyof<Highlight> --// returns a union of all highlight properties
type Data = { [Property]: any };

To make the interface more accessible.

Keep in mind that it also returns the property keys of the instance type aswell. (because it inherits from instance)

What I meant when I said it’s not really worth it is to do with how little extra you are adding. While class-wrapping with mock-OOP can be really useful, for example in notification systems, it seems more hassle to create a OOP system for it, not to mention it’ll be worse on memory. It seems better to just use separate highlight instances and store them in a table {Player: Highlight}. Up to you, I just thought it seemed like more work.


Thank you for expanding on the type annotation, I only used a basic one for a quick example of the OOP system.

2 Likes

Adding on, it’s unnecessary to OOP-ify everything (I hope that’s a term.)
If not you’re expanding over the Highlight instance (by adding new properties/methods for custom behavior), it’s technically useless to make an OOP system for that.

I did already say that, but thanks anyway! :slight_smile:

I have no idea what this means in the slightest. But thank you for telling me about it.

Basically provides autocomplete for the highlight properties:
image

1 Like

I kind of understand now. Thank you. So type is like a keyword?

Yes, type is a keyword.
It can be used to create custom types (like you saw). You can go through luau programming without even touching the concept of custom types.

1 Like

Why did no one tell me about this earlier? I’m not gonna use that, but thanks for the info I just learned.

It’s especially helpful for type documenting your own classes, I mainly use it for autocomplete.

1 Like

What are even classes? For clarification. And what is autocomplete?

Ok so this is what I did instead:

local CharacterOutline = Instance.new("Highlight")

-- assigning properties.

CharacterOutline.Name = "CharacterOutline"
CharacterOutline.FillColor = Color3.fromRGB(255, 255, 255)
CharacterOutline.FillTransparency = 1
CharacterOutline.DepthMode = Enum.HighlightDepthMode.Occluded
CharacterOutline.OutlineTransparency = 0.5
CharacterOutline.OutlineColor = Color3.fromRGB(0, 0, 0)


game.Players.PlayerAdded:Connect(function(Player)
	Player.CharacterAdded:Connect(function(Character)
		CharacterOutline.Parent = Character
		CharacterOutline.Adornee = Character
	end)
end)

Autocomplete is the words that shop up in studio as you type. So, if you ryped prin it would suggest print. You can press enter to use an autocomplete to finish your word.


Classes is basically you were trying to do in the first place. OOP stands for Object-Oriented Programming, and in this paradigm there are 2 things: a class and objects. Objects inherit from classes, so basically you define everything in the class. You can create objects using class constructors.

In some languages, it might look like this:

//JavaScript example
const Object = new Class(params)

But, Luau doesn’t support the OOP paradigm, which is also why i called it mock-OOP. We can create the same effect using metatables, which are just tables that control how other tables behave. The __index metamethod means we can redirect an object to the class when we call a function.

The class constructor in Luau typically uses .new as the name. It’s a function that sets up the structure for the table/object (see reply #2 to this topic).
We can create types for this and add them to our code:

export type Object = rawkeyof<Class> & {
    --extra properties
}

--note this doesn't type solve correctly, which means
--the properties don't match up to what is type annotated. This would be for autocomplete.

--You can manually set types like this:
export type Object = {
    ["example"]: string -- key "example" is associated with a string
}

--now we can annotate them on to our constructor to automatically give objects the type
function Class.new(): Object --this means the function returns something of the given type
end 
1 Like