Kevin Tung
Kevin Tung

Reputation: 23

Object-Oriented Programming in Love2D(Lua)

I got interested in Love2D and Lua and decided to give it a try.

So in order to get familiar both with Lua and Love2D, I code out an easy sample:

Project Structure:

demo
  |-ball.lua
  |-main.lua

ball.lua

Ball = {
    x = 0,
    y = 0,
    xSpeed = 0,
    ySpeed = 0,
    ballRadius = 0,
    r = 0,
    g = 0,
    b = 0
}

function Ball:new(x, y, xSpeed, ySpeed, ballRadius, r, g, b)
    t = {
        x = x,
        y = y,
        xSpeed = xSpeed,
        ySpeed = ySpeed,
        ballRadius = ballRadius, 
        r = r,
        g = g,
        b = b
    }
    setmetatable(t, self)
    self.__index = self
    return t
end

function Ball:move() 
    self.x = self.x + self.xSpeed
    self.y = self.y + self.ySpeed
end

function Ball:changeColor() 
    self.r = love.math.random(0, 255)
    self.g = love.math.random(0, 255)
    self.b = love.math.random(0, 255)
    print('color: ' .. self.r .. ' ' .. self.g .. ' ' .. self.b)
end

function Ball:checkEdges() 
    if self.x + self.ballRadius > love.graphics.getWidth() or self.x - self.ballRadius < 0 then 
        self.xSpeed = self.xSpeed * -1
        Ball:changeColor()
    end
    if self.y + self.ballRadius> love.graphics.getHeight() or self.y - self.ballRadius < 0 then 
        self.ySpeed = self.ySpeed * -1
        Ball:changeColor()
    end
end

function Ball:show() 
    love.graphics.setColor(self.r, self.g, self.b)
    love.graphics.ellipse('fill', self.x, self.y, self.ballRadius)
end

main.lua

require "ball"
local ball = nil
local x, y

function love.load()
    x = love.graphics.getWidth() / 2
    y = love.graphics.getHeight() / 2
    ball = Ball:new(x, y, 2, 3.5, 20, 255, 255, 255)
end

function love.update(dt) 
    Ball.move(ball)
    Ball.checkEdges(ball)
end

function love.keypressed(key)
    if key == 'escape' then 
        love.event.quit()
    end
end

function love.draw()
    love.graphics.setBackgroundColor(0, 0, 0)
    Ball.show(ball)
end

so basically it's just a ball bouncing around when it hits the edges.
Everything seems fine except for the function Ball:changeColor()
I want the ball to change color everytime it hits the edges, but this isn't working.
is it something wrong with the function changeColor() ?

here's a snapshot of the demo:

1

the function did trigger and the rgb color values did change, but the ball itself didn't change color, any help is appreciated!

Upvotes: 2

Views: 675

Answers (1)

koyaanisqatsi
koyaanisqatsi

Reputation: 2823

The biggest mistake is the color definition by itself.
The range of colors goes from 0 (zero) to 1. So change...

function Ball:changeColor() 
    self.r = love.math.random(0, 255)
    self.g = love.math.random(0, 255)
    self.b = love.math.random(0, 255)
    print('color: ' .. self.r .. ' ' .. self.g .. ' ' .. self.b)
end

...to...

function Ball:changeColor() 
    self.r = love.math.random()
    self.g = love.math.random()
    self.b = love.math.random()
    print('color: ' .. self.r .. ' ' .. self.g .. ' ' .. self.b)
end

It should than printing out...

color: 0.064632309279245 0.45080402957018 0.39887099192605

Object-Oriented Programming

You assign a ball with Ball:new() but in further code you dont use the assigned methods with ball.
To give the method the ball as argument the : is used.
I give you an corrected version to show what i mean.
My colored ball is named cball here ;-)

-- main.lua
require "ball"

function love.load()
    x = love.graphics.getWidth() / 2
    y = love.graphics.getHeight() / 2
    cball = Ball:new(x, y, 27, 27, 200, 0, 0, 0)
end

-- When object is assigned you reach the desired function with the :
-- So use it...
function love.update(dt) 
    cball:move() -- Use assigned method with cball as first argument
    cball:checkEdges() -- Same here
end

-- Checking if key is released avoids repeating keys ;-)
function love.keyreleased(key)
    if key == 'escape' or key == 'q' then 
        love.event.quit()
    end
    if key == 'r' then
        love.event.quit('restart')
    end
end

function love.draw()
    love.graphics.setBackgroundColor(.125, .125, .25)
    cball:show() -- Same here
end

Last thing is ball.lua is not really designed as a require for Lua.
Your ball Lua returns nothing.
Therefore a second require dont do the same as the first require.
Example for a good design...

-- ball.lua start with...
local Ball = {
    x = 0,
    y = 0,
    xSpeed = 0,
    ySpeed = 0,
    ballRadius = 0,
    r = 1,
    g = 0,
    b = 0
}
-- Than all function/method defining for Ball and last line do
return Ball

After that it loads every time (first from file and than from package.loaded.ball) correctly.
Moreover that design fact you can do than directly...

-- Ball = require('ball')
function love.load()
    x = love.graphics.getWidth() / 2
    y = love.graphics.getHeight() / 2
    cball = require('ball'):new(x, y, 27, 27, 20, 0, 0, 0)
end

And as a side effect the options you give in new() take all affect.
Another side effect is that you can do after the...

cball=require('ball'):new(...)

...a...

newball=cball:new(...)

( The three dots are placeholder for the options )
...to make another (x, y, speedx, speedy, radius, color) independent child (ball) from the child that require('ball') <--<< The parent Object.

Upvotes: 4

Related Questions