I highly recommend ECS. However, on a side note you could achieve the something with OOP as long as you use components, one module script only does one thing with a single responsibility principle.
Here are some code examples to illustrate
Entity creation of player with pure data
local npcEntity = world:Entity()
npcEntity :Set(HumanoidComponent(Instance.new("Humanoid")))
npcEntity:Set(PoisonComponent(5))
--You can add infinite amounts of components hence modular
npcEntity:Set(StunComponent(10))
npcEntity:Set(SpeedBuffComponent({value = 5, duration = 30}))
local entityDictionary = {}
entityDictionary[npcModel] = npcEntity --keep track of model --> entity
--hit detection -->part-->model-->dictionary --> Entity object
--remember to delete after model is destroyed, ancestor is set to nil should be good enough
System detects and tracks components, ex: status effect every frame doing poison damage, one module script called PoisonSystem.lua, easily find and track this system in charge of only doing one thing
PoisonSystem module script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Components = require(script.Parent.Parent.Components)
local PoisonComponent = Components.PoisonComponent
local HealthComponent = Components.HealthComponent
local ECS = require(ReplicatedStorage.Shared.ECSFolder.ECS)
local World, System, Query, Component = ECS.World, ECS.System, ECS.Query, ECS.Component
--only thing that matters is if an entity is poisoned and has health
--transform is kinda equal to RunService heartbeat
local PoisonDamageSystem = System("transform", 1, Query.All(PoisonComponent, HealthComponent))
function PoisonDamageSystem:Update(Time)
for i, entity in self:Result():Iterator() do
local health = entity[HealthComponent].value
local poisonDamageRate = entity[PosionComponent].value
entity:Set(HealthComponent(health - poisonDamageRate*))
end
end
return PoisonDamageSystem
Another system is in charge of purely poison visual effects
Summary
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Components = require(script.Parent.Parent.Components)
local ECS = require(ReplicatedStorage.Shared.ECSFolder.ECS)
local World, System, Query, Component = ECS.World, ECS.System, ECS.Query, ECS.Component
local PoisonVisualEffects = System("transform", 1, Query.All(PoisonComponent, ModelComponent))
--When a new entity is created with a char model, and poisoned
function PoisonVisualEffects:OnEnter(Time, entity)
local model = entity[ModelComponent].value
--add particles to model
end
return PoisonVisualEffects
And you add drop on demand components.
npcEntity:Unset(PoisonComponent)