Docs / Quick start - LÖVE

Quick start - LÖVE

Connect a LÖVE (Love2D) game to a running Asobi server in about five minutes. No server yet? Run the server quickstart first - it gives you a backend on localhost:8084 with a default match mode.

1. Vendor the SDK

The SDK is pure Lua with no compiled modules - copy the asobi/ folder into your project next to main.lua. Its transport uses luasocket, which LÖVE already bundles, so there is nothing to install.

my_game/
├── main.lua
├── conf.lua
└── asobi/          <- copy this whole dir

Then local asobi = require("asobi").

2. Connect in love.load, pump in love.update

Guest auth is a blocking HTTP call - do it in love.load, not the game loop. The WebSocket is non-blocking: you must call realtime:update() every frame or no callbacks fire.

local asobi = require("asobi")
local client, matched = nil, false

function love.load()
  client = asobi.new({host = "localhost", port = 8084})

  -- device_secret = base64 of >= 32 CSPRNG bytes, generated once and persisted
  -- by you; device_id = any stable per-install id.
  local _, err = asobi.auth.guest(client, my_device_id, my_device_secret)
  if err then error("guest auth failed: " .. err.error) end

  -- Bind callbacks BEFORE queueing.
  client.realtime:on("match_matched", function(p) matched = true end)
  client.realtime:on("match_state", function(state)
    local me = (state.players or {})[client.player_id]
    -- render me.x, me.y
  end)

  assert(client.realtime:connect())
  client.realtime:add_to_matchmaker({mode = "default"})
end

function love.update(dt)
  client.realtime:update()          -- MUST pump every frame
  if matched then
    client.realtime:send_match_input({move_x = 0, move_y = 0})
  end
end

function love.quit()
  client.realtime:disconnect()
end

Core API

  • asobi.new({host, port = 8084, use_ssl = false})
  • asobi.auth.guest(client, device_id, device_secret) -> (data, err) (synchronous).
  • client.realtime:connect() / add_to_matchmaker({mode = "default"}) / send_match_input(input).
  • client.realtime:on(event, fn) - callback-based; e.g. "match_matched", "match_state".
  • client.realtime:update() - the pump; callbacks only fire while it runs.

Gotchas

  • Pump every frame. Nothing is received and no :on callback fires unless realtime:update() runs in love.update.
  • Auth blocks the frame. Guest/login are synchronous luasocket calls - run them at startup or on a deliberate action, never in the loop.
  • Plain ws:// only out of the box. LÖVE bundles luasocket but not luasec - for wss:// you need luasec on the path and use_ssl = true.

What's next