Author Topic: Adding gamepad support to the title screen  (Read 89 times)

alexgleason

  • Jr. Member
  • **
  • Posts: 72
  • Vegan on a Desert Island
    • View Profile
    • Vegan on a Desert Island
Adding gamepad support to the title screen
« on: October 14, 2018, 04:24:20 pm »
Hey all, just wanted to share my progress with this. I ended up writing a script that gives default configs to any menu object:

scripts/enable_commands.lua
Code: Lua
  1. -- ♡ Copying is an act of love. Please copy and share.
  2. --
  3. -- Use this script to pass in a game or menu object and have it set up
  4. -- default keyboard and joystick controls so you can use `on_command_pressed`
  5. -- as expected.
  6. --
  7. -- Usage:
  8. --    local enable_commands = require("scripts/enable_commands")
  9. --    enable_commands.enable(my_menu)
  10. --
  11. -- Then simply define `function my_menu:on_command_pressed(command)`
  12.  
  13. local enable_commands = {}
  14.  
  15.  
  16. local function on_key_pressed(self, key)
  17.   if self.on_command_pressed == nil then return true end
  18.   if key == "space" then self:on_command_pressed("action")
  19.   elseif key == "c" then self:on_command_pressed("attack")
  20.   elseif key == "d" then self:on_command_pressed("pause")
  21.   elseif key == "up" then self:on_command_pressed("up")
  22.   elseif key == "down" then self:on_command_pressed("down")
  23.   elseif key == "left" then self:on_command_pressed("left")
  24.   elseif key == "right" then self:on_command_pressed("right")
  25.   elseif key == "x" then self:on_command_pressed("item_1")
  26.   elseif key == "v" then self:on_command_pressed("item_2") end
  27.   return true
  28. end
  29.  
  30. local function on_key_released(self, key)
  31.   if self.on_command_released == nil then return true end
  32.   if key == "space" then self:on_command_released("action")
  33.   elseif key == "c" then self:on_command_released("attack")
  34.   elseif key == "d" then self:on_command_released("pause")
  35.   elseif key == "up" then self:on_command_released("up")
  36.   elseif key == "down" then self:on_command_released("down")
  37.   elseif key == "left" then self:on_command_released("left")
  38.   elseif key == "right" then self:on_command_released("right")
  39.   elseif key == "x" then self:on_command_released("item_1")
  40.   elseif key == "v" then self:on_command_released("item_2") end
  41.   return true
  42. end
  43.  
  44. local function on_joypad_button_pressed(self, button)
  45.   if self.on_command_pressed == nil then return true end
  46.   if button == 0 then self:on_command_pressed("action")
  47.   elseif button == 1 then self:on_command_pressed("attack")
  48.   elseif button == 4 then self:on_command_pressed("pause")
  49.   elseif button == 2 then self:on_command_pressed("item_1")
  50.   elseif button == 3 then self:on_command_pressed("item_2") end
  51.   return true
  52. end
  53.  
  54. local function on_joypad_button_released(self, button)
  55.   if self.on_command_released == nil then return true end
  56.   if button == 0 then self:on_command_released("action")
  57.   elseif button == 1 then self:on_command_released("attack")
  58.   elseif button == 4 then self:on_command_released("pause")
  59.   elseif button == 2 then self:on_command_released("item_1")
  60.   elseif button == 3 then self:on_command_released("item_2") end
  61.   return true
  62. end
  63.  
  64. local function on_joypad_axis_moved(self, axis, state)
  65.   if axis == 0 then
  66.     if state == 1 and self.on_command_pressed then self:on_command_pressed("right")
  67.     elseif state == -1 and self.on_command_pressed then self:on_command_pressed("left")
  68.     elseif state == 0 and self.on_command_released then
  69.       -- FIXME: Only release the last command?
  70.       self:on_command_released("right")
  71.       self:on_command_released("left")
  72.     end
  73.   end
  74.   if axis == 1 then
  75.     if state == 1 and self.on_command_pressed then self:on_command_pressed("down")
  76.     elseif state == -1 and self.on_command_pressed then self:on_command_pressed("up")
  77.     elseif state == 0 and self.on_command_released then
  78.       -- FIXME: Only release the last command?
  79.       self:on_command_released("down")
  80.       self:on_command_released("up")
  81.     end
  82.   end
  83.   return true
  84. end
  85.  
  86. -- Enable on an item
  87. function enable_commands.enable(item)
  88.   item.on_key_pressed = on_key_pressed
  89.   item.on_key_released = on_key_released
  90.   item.on_joypad_button_pressed = on_joypad_button_pressed
  91.   item.on_joypad_button_released = on_joypad_button_released
  92.   item.on_joypad_axis_moved = on_joypad_axis_moved
  93. end
  94.  
  95. return enable_commands
  96.  

Then just run your menu through this, either in main.lua or in your menu script itself, like so:

Code: Lua
  1. local enable_commands = require("scripts/enable_commands")
  2.  
  3. -- Ability to use game commands on these menus
  4. enable_commands.enable(title_screen)
  5.  
  6. function title_screen:on_command_pressed(command)
  7.   -- Handle commands here! No need to handle keys or joypad inputs.
  8. end
  9.  

It's a horribly verbose script! But it works. Normally the save file stores the controller config, so it creates a chicken and egg problem where you must create a save file before you can configure a gamepad, but need to go through the file select menu first. This partially works around that by assigning the Solarus default keyboard and joystick inputs to normal gamepad actions like "attack" and "action" etc. for a particular menu (the title screen).

What I think I'll actually end up doing is load the game before the title screen, and maybe let the player configure their input device here. My goal is to make the game playable on a platform like RetroPie where no keyboard exists. But this works for now.

As a side note, I think having 3 separate save files is overkill for most Solarus games. Unlike the days of Super Nintendo, most people have their own personal devices that can run Solarus, whether that's a laptop, desktop, Android phone/tablet, or Nintendo Switch. The exception might be a RetroPie device, but even then these often have hundreds of games and different people will probably be playing a different game during a different time. So, I'm going to focus on handling 1 save file at a time which will make things much easier.
« Last Edit: October 14, 2018, 04:28:11 pm by alexgleason »
RIP Aaron Swartz

alexgleason

  • Jr. Member
  • **
  • Posts: 72
  • Vegan on a Desert Island
    • View Profile
    • Vegan on a Desert Island
Re: Adding gamepad support to the title screen
« Reply #1 on: October 14, 2018, 06:56:08 pm »
This is a FAR simpler solution. If you're willing to just accept that your game has only one save file, you can start it up first thing, then you'll be free to use on_command_pressed in your menus. Nothing else but this is needed in your main.lua:

Code: Lua
  1. function sol.main:on_started()
  2.   local game = sol.game.load("save1.dat")
  3.   game:start() -- This is where the magic happens
  4.  
  5.   sol.menu.start(game, solarus_logo) -- We're setting the menus to use the "game" we started above
  6.  
  7.   function solarus_logo:on_finished()
  8.     sol.menu.start(game, title_screen) -- The title screen uses internal logic to reload the game once it's ready
  9.   end
  10.  
  11. end
  12.  
« Last Edit: October 14, 2018, 06:57:58 pm by alexgleason »
RIP Aaron Swartz

Diarandor

  • Hero Member
  • *****
  • Posts: 1024
  • Cats are cool! (ΦωΦ)
    • View Profile
Re: Adding gamepad support to the title screen
« Reply #2 on: October 14, 2018, 08:29:31 pm »
“If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you.”