Referencing class variables from within other classes

I often find it convenient in Codea to create class variables for particular screens in the game I’m coding, so to take an example I might use “self.playerx” within a screen that’s defined by the class FightAnim(), being the x position I want the player to be on that screen. That way I don’t need to worry about any other playerx variables conflicting with it, because for the most part I only want to use it when that screen is showing. However I get very mixed results when occasionally I try to reference that variable from another class. So in my FightResults() class, if I just want to use that variable I will use FightAnim.playerx. Sometimes this technique seems to work, and sometimes it just generates a nil value even though I know it’s definitely been defined.

I normally work around it by using a sufficiently precise global variable but I’ve just had a situation where in the process of refactoring some code a stretch of code that referenced FightAnim.playerx has stopped working when it worked perfectly before! It says FightAnim.playerx is a nil value. The bizarre thing is that if I go into the FightAnim() class and laboriously swap all refs to self.playerx for FightAnim.playerx then suddenly it works and my other class can “find” the supposedly undefined variable. I thought that unless you’re using a defined instance of FightAnim() then FightAnim.playerx and self.playerx (used within the class) should be two ways of saying exactly the same thing. Am I wrong?

I can’t work out what I’m doing differently so I’m wondering if there’s some syntax to these classes that I don’t know. Can anyone help?

I may have partly answered my own question, I think it’s got something to do with this extract from Ignatz’s blog

Second is that we call the Ball’s draw routine for each ball by prefixing it with the ball object (ie array item), ie b1:draw() will draw ball b1. This is how Ball knows which ball we want to draw, and which ‘self’ we are talking about. (It is valid to write Ball:draw(), but then you won’t be referring to any particular ball, the “self” keyword will be nil and you’ll get errors). So if you call any Ball functions by prefixing them with a particular ball object, then the class will work with that ball’s “self” data.

But if that’s the case why does self mean something from within the (non-instantiated) class? And why does it sometimes work and sometimes not?

@epicurus101 Can you show a small example of a class not instantiated printing a value. As far as I know, self will always be nil and cause an error.

@epicurus101 - If you define self.playerx = someValue in your class FightAnim, and you’ve created a player with p = FightAnim, then you can retrieve the value of playerx for that player p with p.playerx, form anywhere in your code, outside of the class.

The key to this is understanding both self, and how Codea stores things in variables.

When you say p = FightAnim, it creates a new “instance” of FightAnim, puts it in memory, and returns the memory address (a number) to p, which stores it. So p only contains a memory address, ie a number.

When you say p:draw(), Codea treats this as FightAnim.draw(p), passing through the memory address. And everywhere you use self in your class, Codea then substitutes that memory address. So if we write p:draw(), and the draw function uses the self.playerx variable, then self.playerx will be turned into p.playerx.

If you just say FightAnim.draw() without the colon, Codea doesn’t pass through any memory address, so the self references won’t work, giving an error.

If you are outside the class and want the value of playerx, then p.playerx will give it to you.

Hi Ignatz, thanks I understand a bit how instantiation works. However, here I’m using classes as a means of organising the different screens in my game, using the template provided by frosty a while back

I’m wondering if this is the key to my problem / solution. Is the scene manager instancing each scene class, so that even though it’s kept below the surface by the structure there’s actually an instance, in the scene manager table, which I would specifically need to reference to get access to that variable? Still can’t understand how it was working recently!

@dave1707 my code is by now very difficult to strip down and post, but essentially I have FightAnim scene defined for the scene manager with a variable defined as self.playerx = number in FightAnim:init() - this number is a target number for where the player gets to in the animation. In a different class which defines a different scene I’ve been using FightAnim.playerx to get access to that same variable and it worked fine until recently. I know the fact that it was working until recently means the blame definitely lies with me, I’m just trying to figure it out and understand (a) the possible and (b) the preferable!

It strikes me that the easiest way for me to get around all of this is to put together a nice tidy table to hold all the variables (just like all the tutorials suggest I do!) and stop using self variables except where I want to use it in an instance. Is that how most people operate?

Generally, there’s no need to use a class unless you have multiple instances, because a table (of functions as well as data) can do the job more simply.

And simple is good.

I think that might be a good rule of thumb, but screen / scene management also seems to me to be a good use for them. The game which (in my ludicrously overambitious way) I’m trying to code needs different screens for creating characters, the fight scenes, the level up screen, the shop screen, the map screen, the death screen, the skill select screen etc… I was really struggling with how to organise it until I came across that scene manager post. It’s been an absolute lifesaver. In a somewhat more sophisticated way, isn’t that how cargo bot works? The main draw function hands off to different screens as needed.

I confess I also use classes for objects within the game where there will only ever be one of them on screen, and no need to create multiple instances. Again it just helps me organise the code. I could avoid using classes, they aren’t essential to the task, but I’d find my code harder to navigate.

There’s nothing wrong with using classes. It’s the object oriented way, after all.

Of course, Lua does give you the option of storing functions and data in an ordinary table, without the need for self, and I like using that if i only have one instance.

@epicurus101 for scene and screen management, i found out that event management is the best way to do that. Check out cargo-bot or codeaSowcase or XFC for examples

@Jmv38 I’ve tried to really get under the skin of cargo bot because it looks beautifully written, but I have trouble following it because the hierarchical tree structure means you can’t understand any one part without understanding quite a lot of it in quite a lot of detail! The notes get me some of the way, and I think I’m starting to get the idea of the events structure, but it’s going to take some in depth study. Nice to know that it’s worth the effort though!

One question I might ask here though is about the use of, for example,

function Events.bind(event,obj,func)

Why a dot and not a colon? This is syntax I’m unfamiliar with. I think that Events is both a class and (spelled identically) a table? Doesn’t that conflict? It’s not a form I see in any of the simple examples in tutorials.

Sorry I think the process of formulating questions on this board helps me answer them myself. It’s like therapy! So yes I’m pretty sure now having seen an example in Ignatz’s side scroller that

function a.z() end

is equivalent to

a.z = function() end

Where a is a predefined table. Am I on the right lines? I’m also assuming that there’s no problem giving a table an identical name to a class, because it’s right there in cargo bot!

@epicurus101 - A beautiful thing about Codea tables is that you can put anything in them, including functions.

So suppose you write a set of joystick functions. You only need one joystick, so you don’t need a class.

You might want to use the functions in several projects, so you have to be careful your function names and variables won’t be the same as in whatever code is going to use them.

The answer is to wrap everything in a table, like this

Joystick = {}

Joystick.max=10 --some constant

Joystick.Setup(centre, radius, etc)
    Joystick.centre = centre
    Joystick.radius = radius


So now the joystick code and variables are totally self contained, and the names can’t clash with any code (because of the Joystick prefix).

Basically, you write all the code as usual, then put the Joystick prefix in front of everything, so it is tucked up in a table.

You can run any of the functions or get variable values, from outside the Joystick table, eg Joystick.draw() will draw the joystick, and a=Joystick.centre will return the x,y position of the centre.

I have a post that may clarify things, or maybe confuse you further

The Cargo Bot code is fascinating, but IM(very)HO it does take class inheritance a little too far, defining a master class just to save writing self.x=x, so that you end up with classes nested 10 classes deep. So if you see, in the Main draw loop, currentScreen:bind(), you have to trace back up to see in which one of the 10 layers bind was most recently defined (3 classes previously, in Panel), and then forward again 3 classes to find bindEvents etc. It’s very hard to navigate at first.

One question I might ask here though is about the use of, for example,

function Events.bind(event,obj,func)

Why a dot and not a colon? This is syntax I’m unfamiliar with. I think that Events is both a class and (spelled identically) a table? Doesn’t that conflict? It’s not a form I see in any of the simple examples in tutorials.

@epicurus101 Yes, there’s a few parts where we see a dot instead of a colon. I don’t know why Events is defined as a class when it seems to have no instantiations, and no self variables declared. I need to look more closely at events though.

In other parts of the code a class’ function that was defined with a colon is then called with a dot (example below). I think this is because they need to specify a routine higher up in the hierarchy after it has been over-written lower down. eg, at the top of the SpriteObj tab:

SpriteObj = class(RectObj)

function SpriteObj:init(x,y,w,h)
    self.tint = color(255,255,255,255)


So SpriteObj is a subclass of RectObj, but they can't say `self:init(x,y,w,h)` because RectObj:init has been overwritten by SpriteObj:init, so they have to call it with `RectObj.init(self,x,y,w,h)` (which itself has to call `PositionObj.init`). At least I *think* that's right. I prefer @Ignatz 's suggestion (on CoolCodea) of having a separate `settings` function in the master class which all the sub-class init functions then call.

@yojimbo2000 this is all getting a bit beyond me! I’m interested by your RectObj.init example, as it’s very clear that’s not a case of a function contained in a table. So it’s not like @Ignatz 's joystick example. There’s no table defined as RectObj. I will study your explanation a bit more and see if I can get it to click.

I’m glad that someone else finds the Cargo Bot inheritance a bit difficult to read. I have to say that inheritance is one of the bits of coding that I’m struggling with most, and in Cargo Bot it’s ALL inheritance! I’m quite sure that makes for an exquisitely flexible bit of code, but it’s at the expense of some readability for a newbie like me.

@Ignatz explains much better than I just tried this issue of class inheritance overwriting the master class’s functions here:

See especially the asterisked note midway through the post.