Jump to content
  • entries
    10
  • comments
    21
  • views
    6,164

Leadwerks 5 - OOP refactor of FPS Template


OOP (Object-Oriented Programming) in short:

  • Encapsulation – bundling data and methods that operate on it into objects, controlling access.

  • Abstraction – hiding implementation details, showing only the necessary interface.

  • Inheritance – creating new classes based on existing ones, reusing and extending functionality.

  • Polymorphism – the ability of different classes to be treated through a common interface, with behavior depending on the actual type.

  • Modularity - the property of a system that has been decomposed into internally cohesive but loosely coupled modules.

Thats what you currently do, i did improve for lua by my script and thats what Josh wants to destroy for no real reasons instead of doing what i did internally in the Engine.

About OOP.lua:

It starts before main.lua as script from "Source\Start" and add global functions that allow you to do Inheritance and Interfaces for tables, including components.

CreateClass("className", BaseClass) - it needed to make table support interfaces and add parent table if needed to use its variables and methods

component:AddInterface("interfaceName") - to add interface's variables and methods. Could be several of them per class.

To use in component you just need to do:

Monster = CreateClass("Monster")
Monster:AddInterface("Killable")

Interface scripts should be in Source\Interfaces folder

To make one do something like that inside script:

return CreateInterface("Killable", {
    health = 100,
    team = 0,
    Kill = function(self) end,
    IsDead = function(self) 
        return self.health <= 0 
    end,
    DamageEffect = function(self, amount, attacker) end,
    Damage = function(self, amount, attacker)
        if self:IsDead() then 
            return 
        end
        self.health = MoveTowards(self.health, 0, amount)
        self:DamageEffect()
        if self:IsDead() then 
            self:Kill() 
        end
    end
})

CreateInterface(name, members) - name of interface and vars with functions inside of {}

You can make function implementation inside of functions there and use self as self of component, including interface functions and variables

Or you can leave function body empty: "DamageEffect = function(self, amount, attacker) end"

You can check if entity interface in a very simple way:

GetComponentByInterface(entity, "Killable")

So for example checking and doing damage for entity in bullet component will looks like that:

local pickinfo = world:Pick(pos, nextpos, 0.0, true, Bullet.PickFilter, self.owner)
local killable = GetComponentByInterface(pickinfo.entity, "Killable")
if killable then
	killable:Damage(self.damage, entity)
end

No loops or removing component requires to make proper OOP code already.

For comparison it looked like that before in Josh code:

        if type(pickinfo.entity.health) == "number" then
            pickinfo.entity.health = pickinfo.entity.health - self.damage
            for n = 1, #pickinfo.entity.components do
                if type(pickinfo.entity.components[n].Damage) == "function" then
                    pickinfo.entity.components[n]:Damage(self.damage, entity)
                end
                if pickinfo.entity.health <= 0 and type(pickinfo.entity.components[n].Kill) == "function" then
                    pickinfo.entity.components[n]:Kill()
                end
            end
        end

And his way requiring copy pasting same functions and vars in every component that you want to make killable or usable for example.

And it will not looks much better after removing components anyway:

      if type(pickinfo.entity.health) == "number" then
            pickinfo.entity.health = pickinfo.entity.health - self.damage
                if type(pickinfo.entity.Damage) == "function" then
                    pickinfo.entity:Damage(self.damage, entity)
                end
                if pickinfo.entity.health <= 0 and type(pickinfo.entity.components[n].Kill) == "function" then
                    pickinfo.entity:Kill()
                end
        end

And even if Josh add Damage and health members in every entity (which is just silly), it will be same for anything else and in same time you will loose the most basic thing of modern engines as Component system without getting any real advantages.

Source code: https://github.com/Dreikblack/OOP-FPS-Template

OOP.zip

0 Comments


Recommended Comments

There are no comments to display.

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...