Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

How to use class inheritance?

edited January 2017 in Questions Posts: 121

I don't understand classes. Looked at the animal, dog example... umm i guess im a bit dumb

I want to make a building superclass and a bunch of subclasses like farm, house, barracks, wall and town center. Heres one of my attempts to make a barracks class, but im not knowing how to design the code so that it works or call the building class methods from the barracks class

Building = class()

function Building:makeFoundation(x,y,size,player)

end

function Building:addHP(add1,add2) 
    -- Call this method whenever an event should change the hit points of a building
    if add2 then
        local m = get_percent(hp1,hp2)
        self.hp1 = self.hp1 + hp2 * m/100
        self.hp2 = self.hp2 + add2
    end
    if add1 then
        self.hp = self.hp + hp1
    end
end

function Building:addArmor(a1, a2) --armor types MELEE
    if a1 then
        self.armor1 = self.armor1 + a1
    end
    if a2 then
        self.armor2 = self.armor2 + a2
    end
end

function Building:select()
    -- select building
end

Barracks = class(Building)

local __size = 3.0
local __cost1 = 125
local __buildTime = 30

function Barracks:init(x,y,hp,player)
    if hp == 1 then
        self:makeFoundation(x,y,__size,player)
    else
    end
    self.hp1 = hp   --active hit points
    self.hp2 = hp   --max Hit Points
    self.player = player
    self.armor1 = 5
    self.armor2 = 10
    self.attack = nil
    self.range = nil
    self.queue = {}
end

function Barracks:addUnitToQueue()

end


Comments

  • SimeonSimeon Admin Mod
    edited January 2017 Posts: 4,957

    I would recommend composition over inheritance. That is, instead of making your classes inherit, have them hold objects which perform the necessary computation and hold the data they need.

    For example, have class Damageable which holds the hit points and logic to accumulate them, then class Structure which holds the foundation/building base logic, then a further class UnitQueue which handles your unit storage (I'm guessing on your design here based on your sample code above).

    Barracks = class()
    
    local __size = 3.0
    local __cost1 = 125
    local __buildTime = 30
    local __capacity = 30
    
    function Barracks:init(x, y, hp, player)
        self.position = vec2(x,y)
        self.structure = Structure(player, __buildTime, __cost1, __size)
        self.health = Damageable(hp)
        self.queue = UnitQueue({}, __capacity)
    end
    

    The reason I like this better than inheritance is that it prevents your base classes from becoming bloated with functionality that is too specific purely because that functionality needs to be used across more than one class.

    Instead, the value of Barracks class comes from its specific configuration of reusable components, and any functionality highly specific to Barracks only.

    There's more here https://en.wikipedia.org/wiki/Composition_over_inheritance

    That said, if you want to go with inheritance, you can do what you're asking like this:

    Building base class

    Building = class()
    
    function Building:init(hp)
        self.hp = hp
    end
    
    function Building:showHP()
        print("HP = ", self.hp)
    end
    

    Barracks class

    Barracks = class(Building)
    
    function Barracks:init(hp, otherData)
        -- Initialise base class
        -- this is important
        Building.init(hp)
    
        self.otherData = otherData
    end
    

    Using it

    local barracks = Barracks(100, "Test")
    
    barracks:showHP()
    
    print(barracks.hp)
    print(barracks.otherData)
    
  • dave1707dave1707 Mod
    Posts: 7,602

    @xThomas You're not dumb. It takes time and experience to understand classes and inheritance. I know what inheritance is and what it's supposed to do. I've never had the need to use it, so I can't answer your questions without knowing specifics. And then I would have to write examples myself to figure out how to make it work.

  • Posts: 121

    @Simeon good ideas, I still have a lot to learn but I will try what you make

  • edited January 2017 Posts: 121

    Related problem. I have a mesh called self.Grass02mesh in the Chunk class and I have a subclass called Tile, which takes multiple values to create a textured grass rect (addRect, setRectTex), which i then want to insert back into the aforementioned self.Grass02mesh.

    Here's my code, what I ave so far, its a bit ugly as I only started it yesterday without any real plan edit: Tile:draw() is anacharistic but I left it in there by accident, son't want to edit code tha I already posted here, are there rules about that?


    --# Main -- 01292017.2 -- 0.1.0.3 (PRE ALPHA) textures = { Grass02 = readImage("Documents:Grass 02"), Bamboo01 = readImage("Documents:Bamboo 01") } Tile = class(Chunk) tileId = 0 function Tile:init(x,y,t,i, ii) --Tiles are created in chunks of 8x8 self.i = i self.ii = ii self.x = x self.y = y self.tex = t local m = mesh() if self.tex == texture.Grass02 then -- Insert local mesh into parent chunk Grass02mesh -- Inside Chunk:init() is self.Grass02mesh, but how to edit it from the Tile class? elseif self.tex == texture.Bamboo01 then --Insert a BambooTree01 object into the parent Chunk objects table and -- leaves terrain into the parent chunks leaves mesh end m:addRect(x,y,64,64) local u = 1/16 * self.i - 1/16 local v = 1/16 * self.ii - 1/16 local w,h = 1/8,1/8 m:setRectTex(1, u, v, w, h) end function Tile:draw() self.mesh:draw() end Chunk = class() NumberOfChunks= 0 function Chunk:init(t) -- These meshes are needed to draw everything in a given chunk of the map self.Grass02mesh = mesh() self.Leavesmesh = mesh() self.Objectsmesh = mesh() self.Units = mesh() self.Buildings = mesh() self.idChunk = NumberOfChunks + 1 local n, nn = self.idChunk*16-15, self.idChunk*16 for i = n,nn do for ii = n,nn do local x = i*32 local y = ii*32 table.insert(gamemap,Tile(x,y,terrain.Grass02,i,ii)) end end NumberOfChunks = NumberOfChunks + 1 end function Chunk:draw() self.Grass02mesh:draw() self.LeavesMesh:draw() --later add objects, units and buildings end function setup() Chunk:init(terrain.Grass02) end function draw() Chunk:draw() end
  • dave1707dave1707 Mod
    Posts: 7,602

    @xThomas At the top right of each discussion is a gear icon. If you tap that you have the option to edit your post. You can do whatever you want with your own post.

  • Posts: 121
    @dave1707: good to know but I was trying to ask this. How can I add stuff to things inside a class? Below you see ChunkMesh and in tile, I want to add a rectangle to ChunkMesh. Does that make sense?

    ~~~
    Chunk = class()

    function Chunk:init()
    self.ChunkMesh = mesh()
    end

    Tile = class(Chunk)

    function Tile:init()
    Chunk.ChunkMesh:addRect(x,y,w,h)
    end
    ~~~
  • SimeonSimeon Admin Mod
    Posts: 4,957

    @xThomas you need to call your Chunk:init function from your Tile:init like so:

    function Tile:init(x,y,t,i, ii)
        -- Call super class initializer
        Chunk.init(self, t)
    
        --Tiles are created in chunks of 8x8
        -- ... your existing code
    end
    

    (See my Barracks / Building example above. It does this too.)

    Then you can access Grass02mesh in Tile just by writing self.Grass02mesh

Sign In or Register to comment.