Simple classes question

Hi all!

I’m trying to wrap my head around classes, but getting kind of thrown off.

I’m setting up a class that creates a physics.body circle and giving it an ellipse shape in the class draw function, then trying to draw it in the main function but it isn’t showing up and is giving an error. Anyone see what I’m doing wrong? I’m new to using classes, so this is probably a super simple question.

Here is the code I’m messing with:


-- Classes

-- Use this function to perform your initial setup
function setup()
    physics.continuous=true
    
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(0,0,0,255)

    Player:draw()
    
end


Player = class()

function Player:init(x,y)
    self = physics.body(CIRCLE,32)
    self.linearvelocity= vec2(math.random(-256,256), math.random(-256,256))
    self.x=WIDTH/2
    self.y=HEIGHT/2
    self.restitution=1
end

function Player:draw()
    fill(0,255,0,255)
    ellipse(self.x,self.y,64)
end

You arent defing the Player in setup, so draw doesnt know what to do;

Add:

Player(WIDTH/2,HEIGHT/2)

In setup

Thanks but still getting an error in the ellipse part of the class. Is it because I’m using “self” which tells Codea that there will be more than one instance of Player, but only creating one?

I messed with classes before for creating multiples of the object created in the class, using “self” to define things, but I created a table and did for I=1,#Player then, and created multiple instances of it and it worked, but just creating one from a class doesn’t seem to work.

@Crumble you need to do the following:

-- Classes

-- Use this function to perform your initial setup
function setup()
    physics.continuous=true
    ply = Player(WIDTH/2,HEIGHT/2)
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(0,0,0,255)

    ply:draw()

end

Edit: your player class should look like this, as you cannot assign ‘self’ as a variable. ‘self’ is what the class consists of so in the case of the following:

Player = class()

function Player:init(x,y)
    self.pb = physics.body(CIRCLE,32)
    self.pb.linearvelocity= vec2(math.random(-256,256), math.random(-256,256))
    self.pb.x=WIDTH/2
    self.pb.y=HEIGHT/2
    self.pb.restitution=1
end

function Player:draw()
    fill(0,255,0,255)
    ellipse(self.pb.x,self.pb.y,64)
end

this wont work. The physics body lives its own life: put it somewhere, then check where it is to draw it. self.x and self.x wont update by themselves. Check what i have to do to get it working in http://codea.io/talk/discussion/6224/gaz-simulation.
here is come code. the. ball:update() must be called at each draw for instance.

Ball = class()
 
local rand = math.random
function Ball:init(x,y,r)
    self.x = x
    self.y = y
    self.r = r or 10
    self:initAssets()
    -- physics body
    self.body = physics.body(CIRCLE, self.r)
    self.body.x = self.x
    self.body.y = self.y
    self.body.sleepingAllowed = false
    self.body.gravityScale = 0
    self.body.linearVelocity = vec2(rand(400)-200,rand(400)-200)
    self.body.linearDamping = 0
    self.body.fixedRotation = true
    self.body.friction = 0
    self.body.restitution = 1
    self.body.info = self
    self.body.bullet = true
    -- events
    World:on("update",self.update,self)
    World:on("delete",self.delete,self)
    self:update()
    self:updateColor()
end
 
local ms 
function Ball:initAssets()
    if not ms then
        ms = mesh()
        local img = image(10,10)
        setContext(img)
            ellipseMode(CORNERS)
            fill(255)
            noStroke()
            ellipse(0,0,10,10)
        setContext()
        ms.texture = img
        World:on("draw",function() noSmooth() ms:draw() end)
    end
    self.w = 2*self.r
    self.h = 2*self.r
    self.iRect = ms:addRect(self.x,self.y,self.w,self.h)
end
 
function Ball:update()
    local pos = self.body.position
    self.x, self.y = pos.x, pos.y
    ms:setRect(self.iRect, self.x,self.y,self.w,self.h)
end
 
function Ball:delete()
    self.body:destroy()
    World:off(self)
end
 
function Ball:updateColor()
    -- lets change color
    local x = self.body.linearVelocity:len()/300*255
    local r,g,b, a = x, 64, 255-x, 255
    self.color = color(r,g,b,a)
    ms:setRectColor(self.iRect, self.color)
end
 
function Ball:collide(c,obj)
    self:updateColor()
end

I see, not as easy as I thought it would be. I’ll try to digest what’s happening in that code, thanks.

@Jmv38 your code has unnecessary steps. Bodies do have an x and y value that automatically updates. The position value wraps these in a vec2. You can use either position or x/y, but you don’t have to use both. @Luatee 's code works fine.

EDIT I’m probably being unfair to @Jmv38 here, I didn’t notice that @Luatee had edited the post, so maybe when Jmv38 said “that won’t work” he was referring to the pre-edit version, before the body was assigned to self.pb.

Thanks @Luatee that works how I was hoping it would. Not sure why the self.pb.linearvelocity line isn’t effecting the ball though.

So the “pb” in self.pb can be any variable like self.body, self.b, self.whatever, as long as you are consistent with it? And you must use a variable like “pb” after self?

Can you use that same variable (pb) in multiple classes? Or the variable has to be different for each class?

Last question… I’m confused as to why we have to define the position again in function setup() with ply = Player(WIDTH/2,HEIGHT/2) when it is already defined in the class.

Sorry for all of the questions.

@Crumble yes that is the case, it’s just a variable name with self. before, as you have to link it to the class somehow. ‘self’ behaves (but is not) the same as a table.

local tbl = {}
tbl.one = 1
tbl.onestr = "one"
tbl.newtbl = {tbl = {berries = "Berries"}}
print(tbl.newtbl.tbl.berries) --prints "Berries"

Classes use that sort of structure for ‘self’ and it’s very dynamic. ‘self’ is local to each class, so you can have self.body representing different objects in different classes, the same way local variables work in functions. Lua works with scopes of variables, so a local outside a function won’t affect a local inside a function even if they have the same name.

@Crumble you don’t have to define x and y if they aren’t used, but it shows what they are used for. You can replace self.pb.x = WIDTH/2 with self.pb.x = x and same for y.

@Luatee Got it, thanks much. Really appreciate the help.