Controllers.lua

Showcase your libraries, tools and other projects that help your fellow love users.
Post Reply
Automatik
Citizen
Posts: 57
Joined: Sun Feb 17, 2013 7:05 pm

Controllers.lua

Post by Automatik »

Hi!

GitHub : https://github.com/Felix-Du/Controllers.lua
Download : https://raw.githubusercontent.com/Felix ... ollers.lua
ReadMe : https://github.com/Felix-Du/Controllers ... /README.md

So, this is a small project I've worked on, and I'm at this point where it seems to be improvable, but it's has basically all the features I need and a bit more, so I'm releasing it now.
Controllers.lua is a small lib(1 file!) that aim to replace, simplify, and enhance how Löve manage user-input. I think it's a really cool and simple. :)
You give it a list of "buttons" or "axes" (like "game_walk" or "menu_up"), you optionally define some "players" so that you don't have to copy-paste the same list of buttons each time you want to add a new place for a player. Then you place the needed callbacks and here you go! Then, if you want to know if a button is pressed, you can just use "Controllers:isDown("name_of_button")". You don't have to care about what is actually pressed(The keyboard, a button of a gamepad, an axis, the mouse). And if callbacks are your things, then you're in luck, because Controllers.lua allow you to set some callbacks (Once again, it's device-agnostic).

Here's a not actually runnable example, just so that you can get how it work:

Code: Select all

require('controllers')
function love.load()
    Controllers:init({
     menu_up = {type="button", default={'kb_up','gpb_dpup','gpa_lefty_-'}}
    ,menu_down = {type="button", default={'kb_down','gpb_dpdown','gpa_lefty_+'}}
    ,menu_select = {type="button", default={'kb_return','kb_ ','gpb_a'}}
    ,menu_back = {type="button", default={'kb_escape','gpb_start'}}

    ,game_jump = {type="button", per_player=true, default={'kb_ ','gpb_a'}}
    ,game_walk = {type="axis", exclusive="press", per_player=true, default={'kb_left_-','kb_right_+','gpa_leftx'}}
    })
    Controllers:setPlayer('player_1','joystick',1)
end

function love.update(dt)
    Controllers:pre_update(dt)

    if pause then
        for i=1, Controllers:isPressed('menu_up') do
            menu_select = menu_select - 1
        end
        for i=1, Controllers:isPressed('menu_down') do
            menu_select = menu_select + 1
        end
    end

    if Controllers:isPressed('menu_back') then
        pause = not pause
    end

    if Controllers:isDown('game_jump','player_1') and player:onGround() then
        player:jump()
    end
    player.speedx = Controllers:getAxis('game_walk','player_1') * player.walk_speed

    Controllers:post_update(dt)
end

function love.mousepressed(x,y,button)
    Controllers:mousePressed(x,y,button)
end
function love.mousereleased(x,y,button)
    Controllers:mouseReleased(x,y,button)
end

function love.keypressed(key,unicode)
    Controllers:keyPressed(key)
end
function love.keyreleased(key,unicode)
    Controllers:keyReleased(key)
end

function love.joystickpressed(joystick,key)
    Controllers:joystickPressed(joystick,key)
end
function love.joystickreleased(joystick,key)
    Controllers:joystickReleased(joystick,key)
end
User avatar
Roland_Yonaba
Inner party member
Posts: 1563
Joined: Tue Jun 21, 2011 6:08 pm
Location: Ouagadougou (Burkina Faso)
Contact:

Re: Controllers.lua

Post by Roland_Yonaba »

Hi, nice job.

I would like to share my two cents.
You might want to change the actual implementation so that, instead of creating a plain global table neamed "Controllers", requiring it would rather return a local. This had lots of benefits: first, it does not pollute the global namespace, and lots of Lua purists will thank you for that. This is a general pattern that Lua module writers tend to stick to. Second, because it returns a local, the user of your module can name it the way he wants inside his code, instead of being forced to use the name "Controllers", which can be long to type for some people.

Also, I am not really confortable with the way you init a new instance. Actually, it looks kind of weird to use the colon syntax to init a new instance. "Controllers" is a class, so the class should not init itself (IMHO) to spawn a new object. I will suggest using a dot call for this instead. You can refactor the init method like this:

Code: Select all

local Controllers = {}
Controllers.__index = Controllers

function Controllers.init(controls_table)
  local newController = {} -- a new instance
  --- some code
  return setmetatable(newController, Controllers) -- set Controllers as a metatable to the new instance.
end

-- other methods here, defined with the colon syntax
function Controllers:method1(...)
  -- some code
end

return Controllers -- return the module
A way to use this:

Code: Select all

local Controller = require 'Controllers'
local aNewController = Controller.init(controls_table)
-- etc etc
One minor trick, you can make use of the __call metamethod to provide a nicer syntax to init a new controller.
At the end of your module, instead of returning the table "Controller", have this instead:

Code: Select all

return setmetatable(Controllers, {__call = function(t, ...) return Controllers.init(...) end})
With this, a user can still init a controller with init, or use a function call style:

Code: Select all

local Controller = require 'Controllers'
local aNewController = Controller(controls_table) -- same as Controller(controls_table)
-- etc etc
Hope this helps.
Automatik
Citizen
Posts: 57
Joined: Sun Feb 17, 2013 7:05 pm

Re: Controllers.lua

Post by Automatik »

Thanks! I pushed two commits for this. The Controllers object was never meant to be a class(Which is why :init() doesn't return a new instance, but rather initialize the lib itself), but now it's possible to create an instance with Controllers(controls_table), Controllers:new(controls_table), and Controllers.new(controls_table), for those who want !
User avatar
Roland_Yonaba
Inner party member
Posts: 1563
Joined: Tue Jun 21, 2011 6:08 pm
Location: Ouagadougou (Burkina Faso)
Contact:

Re: Controllers.lua

Post by Roland_Yonaba »

Well, if it was not meant to be a class and provide instances, then it would be best to provide a single syntax, and design it as a singleton.
In other words, all methods would use dot-style:

Code: Select all

local Controllers = {}

function Controllers.init(...) -- some code return ... end
function Controlllers.method1(...) --some code end
function Controlllers.method2(...) --some code end

return Controllers
Automatik
Citizen
Posts: 57
Joined: Sun Feb 17, 2013 7:05 pm

Re: Controllers.lua

Post by Automatik »

Fixed.
Post Reply

Who is online

Users browsing this forum: No registered users and 23 guests