Howdy, Stranger!

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

Calling a class with a string

Fellow coders!

I'm new to coding, learning everything bit by bit and copy & pasting but I can't get the below code to work.
Hope you can understand the problem with these snippets:

-- I create the Levels here. One of the parameters is the name of the animation "PlayerStanding"
object[1] = CreateObject (WIDTH/2, HEIGHT/2, WIDTH/25, HEIGHT/10, "player","PlayerStanding",4)

-- This is my animation with table of images and animation speed:
PlayerStanding = Animation ({"Dropbox:PlayerStanding"},12)

-- and here is where my problem arises:
CreateObject = class()
function CreateObject:init(x,y,w,h,Category,AnimationName,ASpeed)
-- Parameters are given to self
self.AnimationName = AnimationName -- this is for the parameter "PlayerStanding" of above

function CreateObject:draw()
-- finally this is giving an error "attempt to call a nil value"
self.AnimationName:draw(self.body.x, self.body.y, self.w)

Apologies for torturing you with snippets only but the code is so beginnerishly organised and terribly long in full.
It seems I did not grasp the calling of classes yet.
Printing self.AnimationName is giving PlayerStanding. So it's not nil.
PlayerStanding:draw(self.body.x,...) works. But how do I call it with a variable so I can process all my objects with different animations?

Thanks so much for your patience!

Comments

  • IgnatzIgnatz Mod
    Posts: 5,396

    You are probably calling the class draw function like this

    MyClass.draw()
    

    instead of like this, with a colon

    MyClass:draw()
    

    This explanation may help.
    https://coolcodea.wordpress.com/2013/03/22/7-classes-in-codea/

  • Posts: 23

    Thanks for your reply! I studied the link several times before.
    But I think, the : instead of . is not the case here.

    As I wrote, PlayerStanding:draw() works fine.
    But calling it via a parameter does not: Self.AnimationName:draw() doesn't work.

  • Posts: 2,020

    If I've understood correctly, self.AnimationName is a string, self.AnimationName = "PlayerStanding"? That won't work, you can't call a method name with a string. The good news is, as functions and methods are first class in Lua, you can just set self.AnimationName = PlayerStanding and self.AnimationName:draw() should work

  • Posts: 23

    Unfortunately this doesnt work yet:
    self.AnimationName = PlayerStanding
    self.AnimationName:draw(self.body.x, self.body.y, self.w)

    Error: Bad argument #1 to 'text' (string expected, got table)

    We're getting close though. Please have another look how PlayerStanding is created:
    PlayerStanding = Animation ({"Dropbox:PlayerImage1", "Dropbox:PlayerImage2"},4)

  • IgnatzIgnatz Mod
    Posts: 5,396

    It's difficult to help you with only a fragment of code. Most often, the error is in another part of the code that hasn't been posted, and as a result we prefer to see all the relevant code - in this case, that includes the Animation draw function.

  • Posts: 2,020

    yeah, we need to see more code. You're not even showing us the line that's causing the error, which is calling text. Sounds like you were also using self.AnimationName as an argument for text (perhaps for debugging?). Sounds like you might need to split that variable into two, a string animationName and a pointer to a method animationMethod. But this is just guesswork without more info from you.

  • Posts: 23

    This is the Animation class I'm using. It's not written by me, so big thanks to the original author!

    Animation = class()

    function Animation:init(frames, delay)
    self.frames = frames -- table of sprite names
    self.currentFrame = 1 -- the current frame
    self.frameDelay = delay -- how many iterations of main draw loop before changing frame
    self.count = 1 -- keeps track of iterations passed
    end

    function Animation:draw(x, y)
    -- Increment the counter
    self.count = self.count + 1
    -- Check if frame should be updated
    if self.count > self.frameDelay then
    -- Reset count and increment current frame
    self.count = 1
    self.currentFrame = self.currentFrame + 1
    -- Check if we've reached the last frame
    if self.currentFrame > table.maxn(self.frames) then
    -- Back to first frame
    self.currentFrame = 1
    end
    end
    -- Draw correct frame
    sprite(self.frames[self.currentFrame], x, y)
    end

  • Posts: 23

    Ahh! You see me being very unexperienced here. I thought the 'text' was referring to some type of variable but it was easily a line to see what self.AnimationName was carrying. So the below is the essential part of Class CreateObject

    CreateObject = class()
    function CreateObject:init(x,y,w,h,Category,AnimationName,ASpeed,Agility)
    self.Givenx = x
    self.Giveny = y
    self.w = w
    self.h = h
    self.Category = Category
    self.AnimationName = AnimationName
    end

    function CreateObject:draw()
    self.AnimationName = PlayerStanding -- this works but it's not a parameter
    self.AnimationName:draw(self.body.x, self.body.y, self.w)
    --text(self.AnimationName,WIDTH/2,HEIGHT/2)
    end

    Once I comment the text out, the code works like this. I would just need to pass the PlayerStanding as a parameter which for some reason doesn't work.

    As a reminder, this is how the above class is called:
    object[1] = CreateObject (WIDTH/2, HEIGHT/2, WIDTH/25, HEIGHT/10, "player",PlayerStanding,4,0) -- tried PlayerStanding with and without ""

  • Posts: 2,020

    Sounds like you might need to split that variable into two, a string animationName and a pointer to a method animationMethod.

  • Posts: 2,020

    Also, when pasting code in the forum, put a line starting with three tildes ~~~ at the top and bottom of the code to format it correctly.

  • Posts: 23

    Thanks a lot for your help already. I don't know how to create the pointer and how to use it as a param.

    Also I read somewhere to put .. In front of a string or variable. What does this do?

  • IgnatzIgnatz Mod
    edited August 2016 Posts: 5,396

    Just about every variable is a pointer, in that it only stores a memory address of whatever you put into it.

    So as a good example, if your game has several states, eg Splash, Menu,
    Settings, Play, GameOver, you could put all the code into the draw function and use an if statement to decide which screens to draw, depending on the state.

    A much cleaner approach is this. Write a separate draw function for each of the states, eg DrawSplash, DrawMenu, etc. Then create a variable that stores the function you want to run at the moment. So when you start off, you write.

    DrawFunction=DrawSplash
    

    And then your normal draw function looks like this

    function draw()
        DrawFunction() --runs whatever function is in there
    end
    

    When the user starts playing, you set

    DrawFunction=DrawPlay
    

    And now your normal draw function will draw the playing screen

    If your brain can take a little more, when you write

    function A()
        --some code
    end
    

    This is the same as writing

    A=function()
            --some code
        end
    

    In other words, Codea creates the function, puts it in memory, and stores the address in A. So your function A is really only holding a memory address, and that's why you can copy it to another variable as I did above.

  • Posts: 23

    Thanks for the lesson and all efforts!

Sign In or Register to comment.