Box2D encoder/decoder

Has anyone here made a set of functions or similar that can encode all box2d objects etc to a text file and a decoder for creating objects? Just asking before I do it myself.

I started one, but I didn’t need it enough. If you make one, it’d be great if you share it. Thanks!

@luatee in my camera shader project i have just made a utility to save objects coordinates (or any field).

  • The positions are loaded by the object itself in one command : self:load().
  • There is a global command to exit the program and save all loaded objects positions to a tab dedicated to that, into a table ‘data’, indexed by object name.
  • The constrain is to define a unique name for each box.

Here is the code extracted with an example (2 boxes movings randomly). Tap ‘save’ to save the current position.
The only thing you need to paste in your project are:

  • the ‘saver’ tab.
  • put this in your object init saver:load(self,{"x", "y"} ). You can add any other field.
  • give ‘name’ field to your object, with a unique string.
  • your code must call saver:save() when you want to save all objects at once.

Remaks:

You dont need the saver:init() command, i have added it just for this example.
You cannot call saver:init() at each frame, it would be too coslty in fps.
You cannot save individual objects, you save them all in one call.
There is no command to reset the saved data. When i want to reset, i just change the name of the object => the last one is removed, and the object starts with its delfault values.

Hope this helps.


--# Box
Box = class()

function Box:init(name,x,y)
    self.x = x
    self.y = y
    self.name = name
    saver:load(self,{"x", "y"} )
    self:move()
end
function Box:move()
    local x,y
    x = math.random(WIDTH)
    y = math.random(HEIGHT)
    tween(1,self,{x=x,y=y})
    tween.delay(1,self.move,self)
end
function Box:draw()
    rect(self.x,self.y,100,100)
end



--# saver
saver = {} 
-- a tool to save simple data

-- first start the saver in your setup(): creates an exit (and save) button
function saver:init()
    parameter.action("save",saver.run)
end
function saver.run()
    saver:save()
    print("saved!")
end

-- then only this command is needed to load and save the object to be saved
function saver:load(obj,fields)
    self:register(obj,fields)
    local name = obj.name
    local data = self.data and self.data[name]
    for key,value in pairs(data or {}) do obj[key] = value end
end

saver.list = {} -- all objects to be saved

function saver:register(obj,keys)
    local name = obj.name
    if name == nil then error("obj must have a name to be saved") end
    for _,o in ipairs(self.list) do
        if o.name == name and o ~= obj then
            error("this name ("..name..") is already used")
        end
    end
    table.insert(self.list,obj)
    local fields
    if keys then
        fields = {}
        for i,key in pairs(keys) do fields[key] = true end
    end
    self.list[obj] = fields
end
function saver:saveXYWH()
    self:save({"x","y","w","h"})
end
function saver:save(keys)
    local txt = {}
    local function ins(s) table.insert(txt,s) end
    ins( "saver.data = {" ) -- all objects saved in this table
    local name 
    for i,obj in ipairs(self.list) do
        name = obj.name
        local fields = self.list[obj]
        ins( "['" .. name .. "'] = {")
        for key,value in pairs(obj) do
            if (not fields) or fields[key] then
                local typ = type(value) 
                if typ == "number" or typ == "boolean" then
                    ins( tostring(key) .. " = " .. tostring(value) .. ","  )
                elseif typ == "string" then
                    ins( tostring(key) .. " = \"" .. tostring(value) .. "\","  )
                end
            end
        end
        ins( "},")
    end
    ins( "}")
    txt = table.concat(txt,"\
")
    saveProjectTab("data",txt)
end





--# Main
-- autosave

-- Use this function to perform your initial setup
function setup()
    saver:init()
    b1 = Box("box1",100,200)
    b2 = Box("box2",100,500)
end

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

    -- This sets the line thickness
    strokeWidth(5)

    -- Do your drawing here
    b1:draw()
    b2:draw()
end


--# data
saver.data = {
['box1'] = {
y = 477.91207400966,
x = 697.55481801531,
},
['box2'] = {
y = 519.55873299425,
x = 474.56889401027,
},
}

Actually, i’ve been using this code for some time and it does the job quite well (for me).

@Jmv38 Thank you, this is good but I have already got something like this as an encoder for saving splines on my old game, it’s not exactly what I need. I need to make an encoder for encoding all attributes of a box2D body to literally save a whole level mid-state. But it works how I’d like it to work (putting the save game in to a tab). Does saving to tabs work after Xcode export?

@luatee if you have your own box object that mirrors a box2D body properties, you can use this to save it. Just add all the fields you want to save in the list, there is no limit. [edit] actually i only save simple data: number and strings. For vec2 you will need to extend…
Concerning xcode: i dont know, i have no mac…

@Luatee,

Saving to tabs does not work after Xcode export. :frowning:

ok, but you can save into a text file with io? Cant you?

@Diablo76 Thats a downer. I assume I could use saveLocalData instead. @Jmv38 I’ll have a play with this later, I have a code for vec2s.

@Luatee yes with saveLocalData, @jmv38 io work in Xcode Simulator