Howdy, Stranger!

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

Draggable objects and design patterns

I wrote a small Draggable class that takes care of moving an object when you touch it with the screen.

The way to use it is to inherit from Draggable, and do obj:SetDraggable(true). The implementation is broken down in different (virtual) class methods (Draggable:IsDraggable(), Draggable:IsInside(touch), Draggable:Move(touch)) so that any derived class can override the parts of the behaviour that they need to alter.

Now the issue with such an approach is that if I want to combine that with another type of behaviour (say, the ability for an object to react to double-taps), I am a bit stuck because AFAIK multiple inheritance doesn't work with the class() provided in Codea.

An alternative implementation for the Draggable behaviour is to have some kind of wrapper object around any object I want to drag, which redirects touch/draw to my object, and takes care of the dragging. Not super clear in that case though how to override the behaviour like above, and the wrapping will cause a lot of syntactic pain when creating objects, especially if there are several layers of wrapping.

So I guess what I am after is something along the lines of python decorators, which allow you to modify the behaviour of a class method without inheritance, and without the need to create a wrapper object. I saw that lua allows altering low-level behaviours (with metatable and stuff like that), so presumably there should be ways to do what I need, and hopefully someone else has already done it?

Comments

  • SimeonSimeon Admin Mod
    Posts: 5,718

    @joelhoro I would suggest approaching the design as a component driven, rather than inheritance based. I generally avoid inheritance in designs where possible now days. It leads to hard-to-reuse structures.

    That is, you create a draggable component and attach that to your object.

    Alternatively, you can always override the class system in Codea with your own (there are many Lua class implementations, some of which support multiple inheritance).

  • Posts: 25

    @Simeon, do you have an example of that (not necessarily for draggable, but any behaviour)?

    It seems that what you are suggesting is a variant to my wrapper idea. Presumably you mean sth like this

    Draggable = class()
    function Draggable:Init(parent)
        self.parent = parent
    end
    -- same implementation as I had before except everything redirects to parent, for instance
    function Draggable:Move(touch)
        self.parent.x = touch.x
        self.parent.y = touch.y
    end
    
    SomeDraggableObject = class()
    
    function SomeDraggableObject:Init()
        -- standard initialization
        --
        self.draggable = Draggable(self)
        self.IsInside = function() ... end   -- if I need to override it
    end
    
    -- the only drawback is that I need to explicitly call the touch method on the draggable in touch (unlike in inheritance, where it was automatically inherited), i.e. Not ideal but probably not such a big deal.
    
    function touched(touch)
        self.draggable:touched(touch)
    end
    

    That seems like a great approach, can't wait to try it!

  • SimeonSimeon Admin Mod
    edited April 2015 Posts: 5,718

    @joelhoro you could potentially have your base object class "know" about components (note I haven't put much thought into this, so it's just a high level example):

    --# Component
    Component = class()
    
    function Component:touched(touch) 
        -- do nothing
    end
    
    function Component:draw()
        -- do nothing
    end
    
    function Component:update(dt)
        -- do nothing
    end
    
    function Component:addedToObject(obj)
        -- do nothing
    end
    
    function Component:updateObject(obj)
        -- do nothing
    end
    
    
    --# Object
    Object = class()
    
    function Object:init()
        self.components = {}
    end
    
    function Object:addComponent(component)
        table.insert(self.components, component)
    
        component:addedToObject(self)
    end
    
    function Object:iterateComponents(funcName, ...)
        for _,v in pairs(self.components) do
            v[funcName](v, ...)
        end
    end
    
    -- Methods to remove / manage / etc
    
    function Object:touched(touch)
        self:iterateComponents("touched", touch)
    end
    
    function Object:update(dt)
        -- Update components
        self:iterateComponents("update", dt)
    
        -- Allow component updates to feed back into object
        self:iterateComponents("updateObject", self)
    end
    
    function Object:draw()
        self:iterateComponents("draw")
    end
    
    --# Draggable
    Draggable = class(Component)
    
    function Draggable:touched(touch)
        print("Draggable touched")
    end
    
    function Draggable:addedToObject(obj)
        -- Maybe we need to record the object's initial position?
    end
    
    function Draggable:updateObject(obj)
        -- Somehow move the object
    end
    
    -- etc
    

    I'm not keen on the v[funcName](v, ...) syntax, there's probably a better way.

    Then in use:

    function setup()
        obj = Object()
        obj:addComponent(Draggable())
    end
    
    function draw()
        background(100)
        obj:draw()
    end
    
    function touched(touch)
        obj:touched(touch)
    end
    

    Edit: you don't even really need Component as a base class — since it is just an interface or protocol definition and Lua doesn't do interfaces. You just need to be strict and ensure your components conform to a standard.

    Edit2: expanded this so components can feed-back into objects without containing explicit references to objects (I think cohesion between components and objects here would be bad).

  • Jmv38Jmv38 Mod
    Posts: 3,297

    @Simeon interesting. I am with you about components vs inheritance, for re-use easiness.
    If i understand your Edit2 point, the components cannot directly feedback to objects, the objects themselves decide when to update? I fear this would be inefficient cause you should go through all objects event if they havent changed. I am currently on the same questions and i consider different options:
    1/ the component has a self.boss field to the object.
    self.boss = object.
    2/ the component has a weak values table that links to object.
    self.weak.boss = object.
    3/ the object register to its component and listens to an 'update' event.The component triggers an 'update' event when necessary.

    object.component:on("update", self.update, self)
    

    Any thoughts?

  • SimeonSimeon Admin Mod
    Posts: 5,718

    @Jmv38 I would not consider efficiency at this stage, you can later add performance improvements as long as you adhere to the constraints defined by the system.

    We actually have no idea whether the code even needs performance improvements.

    If you can later violate a constraint of the system to improve performance, and guarantee there are no side effects, then you can make that performance improvement. But I would only do so once I knew exactly what was causing the poor performance (i.e., only optimise once you experience a performance issue, not before).

  • Jmv38Jmv38 Mod
    Posts: 3,297

    @simeon thanks for your reply!

    That is a good point. I'll try to use it and feedback.
    Btw, a small change maybe:

    function Object:iterateComponents(funcName, ...)
        for _,v in pairs(self.components) do
            if v[funcName] then v[funcName](v, ...) end
        end
    end
    

    This allows more robustness about components.

  • SimeonSimeon Admin Mod
    Posts: 5,718

    @Jmv38 I think that change depends on whether you want your system to enforce all components to support the entire API, or if you don't mind them supporting a subset.

    Generally I like to see runtime errors and assertion failures if something is not meeting the spec, because this prevents more subtle and hard-to-find logic errors from creeping in.

    (In this case the Component base class implements the full API (despite doing nothing) so it is certain that the functions will exist — but I don't think the base class is necessary except as information for the programmer, so your change works if we eliminate the Component class)

    We could even be more strict by adding an assertion with a clear error message when something goes wrong:

    function Object:iterateComponents(funcName, ...)
        for _,v in pairs(self.components) do
            assert(v[funcName], "Component must implement "..funcName)
            v[funcName](v, ...)
        end
    end
    
  • Jmv38Jmv38 Mod
    Posts: 3,297

    Thanks for making that clear. I must admit I have a tendency towards allowing lousiness in programming. It is easier in the short term, and probably wrong in the long run. I'll have to whip myself into that.

  • SimeonSimeon Admin Mod
    Posts: 5,718

    @Jmv38 I think it's fine, and Codea is designed to encourage looseness in coding. It depends if you're building a quick test/prototype or a library or a complex app.

  • Posts: 25

    @Simeon, yeah the idea of registering components is definitely good practice, I should do that. I am not sure I like this sort of half-inheritance model where a class does not really inherit from another, but still needs to implement some methods.

    Instead I opted for something that is syntactically light and hopefully easy to implement

    It"s something along the lines of

    Someobject = class()
    
    function Someobject:init()
        -- ...
        Draggable:Attach(self, {
            Move = function(touch) self.x=touch.x [[ etc... ]] end, -- optional
            IsInside = function(touch) [[ ... ]] end  -- optional
        } )
    
    end
    
    -- nothing more to add to SomeObject class to make it draggable
    
    
    and for the Attach fn I do something like that
    
    function Draggable:Attach(parent,callbacks)
        local draggable = Draggable() -- local but will be captured in the closure
        -- of the methods I will be creating
        draggable.parent = parent
        -- this attaches a class method on the parent at runtime
        -- so that I can do someObject:SetDraggable(true) even though
        parent.SetDraggable = function(s,v) return draggable:SetDraggable(v) end
        local isInsideFn = callbacks.IsInside
        parent.IsInside = function(s,touch) isInsideFn(touch) end
    
        -- wrap the original touched fn into the draggable touch fn
        local touched = parent.touched or function(touch) end
        parent.touched = function(s,touch) 
             touched(parent,touch)
             Draggable:touched(touch)
        end
    
    end
    
    

    This may of course look horrible, because I am adding new methods at runtime.
    However the benefit of this is that all I need to specify for the draggable to work is done at a single place. No need to alter the touch fn.

    This is similar to a python decorator pattern + some metaclass thing (I think), because I am adding new methods.

    Seemed to work for me and is reasonably combinable with other decorators I will add.

  • SimeonSimeon Admin Mod
    Posts: 5,718

    @joelhoro my example used full inheritance (components inherited Component, but it was suggested you could just have an informal interface, since it makes very little difference in Lua — the interpreter doesn't enforce anything).

    I'm not sure I like mutating the parent so directly — e.g., what if another component adds an IsInside function? What if you design components where it makes sense to have multiple instances attached? Also removing a component seems like it might not be straightforward.

    You might consider hiding your component functions under the key of the component itself:

    local draggable ...
    ...
    parent[draggable] = {}
    parent[draggable].IsInside = ...
    

    I do like the concept of having Move defined by the object-component pair. I had considered a similar system where you bind the object to an "API" defined by the component and then just pass the API to the component (basically what you have here but with a more formal method for declaring an API).

    But I guess it will depend on how homogenous your object types will be and whether you need that flexibility.

  • Jmv38Jmv38 Mod
    Posts: 3,297

    hi @Simeon. Could you show an example of

    I had considered a similar system where you bind the object to an "API" defined by the component and then just pass the API to the component (basically what you have here but with a more formal method for declaring an API).

    That would be very interesting.

  • Posts: 25

    @Simeon in fact I realized that the mutating is just a way of implementing a pedestrian selective multiple inheritance. So indeed it could clash with other components which would add additional methods.

    As you say it may depend on my object types. An alternative that could be more generic is to have the components less obstrusive, but that means that the user of the components would have to explicitly define some parts of the API themselves. For instance, instead of the touched method of the object automatically being set to delegate to that of the draggable, the developer will need to make an explicit redirection themselves.

    It's all a question of minimizing code writing (at the expense of having some undesired automation) or having to write more code and less issues surprises. I tend to prefer the former, but given the very limited debugging abilities in Codea I realize I am probably asking for trouble ;-)

  • edited April 2015 Posts: 25

    I liked this mixin pattern as well, as on [http://codea.io/talk/discussion/4511/using-events-to-communicate-between-instances-of-a-class](Using events to communicate)

  • edited April 2015 Posts: 2,020

    I've found this conversation really fascinating. I've only relatively recently got my head around class inheritance, and I now find it absolutely essential for cutting out code repetition and achieving consistency across, say, all of the physics bodies that are in play.

    What I don't quite understand is how the component based approach that @Simeon and others have suggested is better than class inheritance. I get that it allows multiple inheritance (or whatever the equivalent to "inheritance" is in a component system) which could be useful, but what I don't understand is the claim that using the component system makes your code more re-usable and portable. Isn't the code just as dependent on its components as it would be on its super-class(es)?

  • Jmv38Jmv38 Mod
    edited April 2015 Posts: 3,297

    @yojimbo2000 some elements of answer (from my non-professionnal-programmer experience):

    When you use inheritance, all parent class functions are there. So you use them. And you child class becomes completely intricated with the parent methods and properties. So when you want to reuse some method A into another object, the other object doesnt have all the methods or properties you need for A to work.

    When you design a sub part of your code as a component , you explicitely communicate methods and properties between the component and its owner. So you define (even implicitely) some kind of interface. This is boring and complex, so you will define the smallest interface possible to get your component do the job. So when you want to reuse it into another object, the intrication with initial owner is 1/ described, 2/ minimal. Makes reuse much easier.

    The key for reuse is code decoupling. The more your code blocs are decoupled, the easier the reuse. Inhertance is very bad (I think) in terms of decoupling, although it is good for factorizing code. Of course you cannot be 100% decoupled, because your parts work together. Then come design patterns and your coding experience to help you keep things as decoupled as possible...

  • Posts: 2,020

    I suppose with the Codea implementation of classes, you can end up with a long hierarchy of class inheritance (CargoBot is a fairly extreme example of this, where you have great-great-great-great-great-grandparents of certain classes), and I can see how that kind of very vertical structure makes re-usability difficult. So perhaps the "flat" (non-hierarchical) nature of a component based system makes code migration easier.

    It's probably one of those things where you have to have a go at implementing it in one of your own projects before you really get to understand the benefits. Somewhere down the line I think I'll give the components model suggested by @Simeon above a try.

    (As an aside, I've gone off the kind of "events manager" system that @joelhoro linked to above. I tried it in one large-scale project, but I felt that it made things unnecessarily complex)

  • SimeonSimeon Admin Mod
    Posts: 5,718

    @yojimbo2000 the explanation by @Jmv38 is exactly right.

    Inheritance isn't bad if the classes are intended to be very tightly coupled. A more general system is interfaces: that is, the ability to say "this class conforms to this API" without actually inheriting all the functionality. Then you can define your functions and methods to expect objects which adhere to a specific interface. Unfortunately, Lua is not a strongly typed language and so cannot really support this.

    For general code reuse, I find keeping functions (and methods) simple and focused is a good habit. Functions should do one thing, in a few lines of code, and expect input and produce output without side effects (that is, they shouldn't mutate global state).

  • edited April 2015 Posts: 25

    @yojimbo2000 about reusability and portability, the fact that your code is dependent on components (instead of subclasses) is not really hindering reusability.

    @Jmv38 made an excellent point about decoupling vs. factoring. Let me add my 2c worth.

    Being dependent on components is fine if the interface is clearly defined (it's the decoupling @Jmv38 mentionned). This is because then you (or the author of the components) can make alteration to the component's implementation without you having to change a single line of code. Alternatively you can use another component if it complies with the same interface.

    Of course you are never shielded from bugs in the implementation, whether you wrote them yourself or the author of the component. But at least if the interface is reasonably standard, you may hope that someone else wrote a component with a similar interface and replace it with that. Or maybe nobody did, however someone wrote a better implementation of the component's functionalities but without structuring it into a class. Then you can use the 'adapter' pattern and quickly write a component that complies with your desired interface and delegates to that better implementation.

    @Simeon makes an excellent point about input/output without side effects. This is the basis for functional programming, but turns into an excellent advice in procedural programming as well. Some benefits of that are

    • simpler functions have more chance of being re-used
    • no side effects (and also no external inputs, i.e. only function arguments, but no calls to global variables) mean that when a fn is given a set of inputs, the output should always be the same. This makes it much easier to test it, be it in an automated unit test system or just manually
    • no side effects mean that, if necessary, a function's output for a given set of inputs can be cached (i.e. memoized). This is so that any subsequent call to that function, with the same arguments, can be answered to straightaway, without having to recompute. This can have a meaningful impact on performance, as we are getting speed in exchange for more memory usage. An example of that could be retrieving a sprite from a spritemap.
  • Posts: 2,020

    OK, I think I'm beginning to get it. It's true that in class inheritance systems I've written, I do find myself writing little notes in the comments, "class X overrides function A, but classes Y and Z inherit it", etc. I guess inheritance allows you to be more lazy, which can come back to haunt you.

    I found these two articles quite useful for comparing component systems to inheritance. Although their examples are in C++ and C# respectively (the second one describes Unity's component system), their discussion of the principles was very helpful for me in understanding the issues raised in this thread.

    http://en.m.wikipedia.org/wiki/Composition_over_inheritance

    http://www.udellgames.com/posts/entity-component-systems/

  • Posts: 2,020

    Quick review of Game Programming Patterns by Robert Nystrom

    One more reading link. This one is excellent. It's an entire book about software architecture (it's called game programming patterns, but everything here is applicable to other coding projects). It's free to read online, but I think I'm going to purchase it because it's very good. This link is to the chapter on components, but the entire section on decoupling is relevant to this discussion, as are many of the other chapters (in fact, the entire book could be said to be about various strategies for decoupling, one way or another, ie the early chapters on the observer pattern and the command pattern). The examples are in C++ (I think?) which I don't read, but the discussion still makes sense for me. It's very engagingly written, and as a plus, the pages themselves are beautifully laid out (I really like the way footnotes are to the side of the main text body).

    http://gameprogrammingpatterns.com/component.html

    Check it out if you don't already know it.

  • Jmv38Jmv38 Mod
    edited April 2015 Posts: 3,297

    Thanks for the link. The book looks great, will read it.

  • @yojimbo2000 wow small world, I already have that book! I agree, it's a great book, but make sure you know at least a little C++ or C before going into it so you are more likely to be able to use the examples in your own projects.

  • Posts: 2,020

    Good point, and good excuse to learn C++.

  • Haha yeah, that and Arduino.

  • edited April 2015 Posts: 212

    arduino uses C

  • Posts: 2,020

    @TheSolderKing @Jmv38 One of the things I find valuable about the book is that he makes an argument that coders should tightening up our terminology slightly, so that we can describe our coding patterns to others more accurately without causing confusion. For instance, if you compare the chapter on Events to the one on Observers, he argues that "Event system", "event manager" etc should be reserved for systems that cause an action to be held in a queue and triggered at a later point in time (ie decoupling over time). So what I've been calling my "event manager" so far, is not, according to Nystrom, an event manager. Because it triggers actions instantly, it's actually an Observer pattern (if we follow the nomenclature that Nystrom argues for).

  • Jmv38Jmv38 Mod
    Posts: 3,297

    good point. Thanks.

  • Posts: 212

    Is there a way to wrap every function we write in our classes with that thing in LUA that let's you pause execution of functions? I know you can't do multi threading in codea, but this would be a means to say "execute 200 lines, then run whatever is in the event queue". Does that make sense? There's gotta be a way for codea to read a project tab, if you can save Project info to tab. Maybe write something in the first tab which should contain Main () and setup () and have it read every other tab and wrap each function in the other tabs with that thing that can pause instruction execution.

  • Jmv38Jmv38 Mod
    edited April 2015 Posts: 3,297

    That would be possible. But it may clutter the memory is you have too many threads.
    You would have to add in every function a call to a function that yields if the condition object.n>200 is true. Better to use os.clock>object.t0+0.001 or so.

  • Jmv38Jmv38 Mod
    edited April 2015 Posts: 3,297

    About reading the Game Patterns book:
    I have a problem with the state pattern: making a new class for each state of an object seems so... heavy? can anyone explain me what i am missing here?
    http://gameprogrammingpatterns.com/state.html

    Thanks!

  • edited April 2015 Posts: 2,020

    One of the things I like about the book is that he isn't particularly evangelical; he presents a range of different methods and implementations and is quite upfront about the shortcomings of different scenarios. So a full class-based FSM or hierarchical or stack based machine might be overkill for certain objects in the game (I've used this for the state of the entire game, though, game, game_over, splash_screen etc).

    I suppose I would rather have lots of smaller classes than a few giant ones. For one project I'm working on a component system (based on his chapter on components) where each component in the game object is a class. To balance things out though in the complexity stakes, all objects in the game belong to a single class. So you have very simple, almost empty objects. I guess its method-oriented rather than object-oriented programming (I'll post it at some point).

    For AI behaviour, which I guess I've implemented as a kind of FSM, I use closures. Lighter and simpler than a full blown class, but with many of the benefits (remembering their internal variables, modularity etc). He also suggests, if you don't need to remember variables, using virtual methods. This is something I haven't really explored that much yet, but I guess you would implement it something like this: (EDIT added a second method and a state pointer to switch between 2 methods upon touch)

    --# Main
    -- Game object finite state manager using virtual methods
    --touch screen to switch states
    function setup()
        anInstance = MyClass{pos=vec2(WIDTH,HEIGHT)*0.5} --i didn't know til recently you could do this. () not needed if argument is just a table or a string. 
    end
    
    function draw()
        background(0)
        anInstance:update()    
    end
    
    function touched(touch)
        if touch.state == BEGAN then anInstance:setMoveState() end
    end
    
    virtual = {} --just a table, doesn't need to be a class
    
    function virtual:move(t) --use the colon : syntax when defining method, so it can access self
        self.pos = self.pos + t.vel
    end
    
    function virtual:wave(t)
        local y = math.sin(self.pos.x/20)
        local x = -t.vel.x
        self.pos = self.pos + vec2(x,y)
    end
    
    
    --# MyClass
    MyClass = class()
    
    local states = {virtual.move, virtual.wave}
    
    function MyClass:init(t)
        self.pos = t.pos
        self.state = 0
        self:setMoveState()
    end
    
    function MyClass:update()
      --  virtual.move(self, {vel = vec2(1,0)}) --nb have to use dot method with self as first argument when calling method
       -- self.move(self, {vel = vec2(1,0)}) --this works too
        self:move{vel = vec2(1,0)} --this is easiest
        ellipse(self.pos.x,self.pos.y, 30)
    end
    
    function MyClass:setMoveState()
        self.state = self.state + 1
        if self.state > #states then self.state = 1 end
        self.move = states[self.state] --is this an fsm pointer? a shallow copy? a mix-in?
    end
    
Sign In or Register to comment.