save result of a collision in .json table

Hi, sorry for my English language.

I try to save in table.jason the result of a collision

local function onLocalCollision( self, event ) if ( event.phase == "began" ) then print( event.other.name .. ": collision began with =\> " .. self.name ) end end

This is the result you print on the console:

20:56:00.167  4: collision began with => four

20:56:00.537  7: collision began with => seven

How can I insert it into a .json table?

I’ve tried it that way, but it doesn’t insert what I want:

local s = {} local function onLocalCollision( self, event ) if ( event.phase == "began" ) s = {event.other.name} loadsave.saveTable(s, "table.json", system.DocumentsDirectory) end end

this is the result of the table:  [“7”]

I want to print, this or something: {“four”:4 , “seven”: 7}

Cheers!!

You want to create a Lua table based on key-value pairs instead of an indexed array.

local s = { four = 4, seven = 7 }

or something like that. You can also use strings instead of variables, which may work better for what you’re doing:

local  s = { [“four”] = 4, [“seven”] = 7 }

Both are identical internally, but since you’re trying to use values from the collision, you may want something like:

local s = { event.self = event.other.name }

But this is going to overwrite with each collision. Why do you need to save this? Do you need a collision history or just the latest collision?

Rob

What’s your propose with that json table? What will you do with it? without seeing the rest of your code or what it’s for it’s difficult to give you advice, because maybe the problem is not the json table. never needed one in 7 years, wonder why you do.

just seeing you code, “onLocalCollision” will be executed two times to get 4 and 7. so it should be saved in 2 different levels.

it should be saved in something like this:

local json=require("json") local s={} s[#s+1]={} s[#s]["four"]=4 s[#s+1]={} s[#s]["seven"]=7 for i=1,#s do for n,m in pairs (s[i]) do print (n,m) end end print (json.encode(s))

using your code it should be something like this:

local s = {} local function onLocalCollision( self, event ) if ( event.phase == "began" ) s[#s+1]={} s[#s][self.name] = {event.other.name} end end

why you save on a table each time you get a collision? it will the slowest approach ever that way.

why not save it on a memory table first, and when you leave the screen or you know the game is over. just save the table to a json file or to a sqlite table. Like i said without more information you gave it’s hard to give you the best advice.

Hello again, thanks for your interest.

I want to use this collision for a game that I am creating, it is a multiplication made by the player of 4 x 7 = 28 which is the number that has the exit door of a level of the game. The doll has to find the two boxes (4 and 7) and put them on the two objects for the collision (four and seven), when this occurs, the door will open with a condition:

local s = {} s = loadsave.loadTable ("table.json", system.DocumentsDirectory) if four == 4 and seven == 7 then --execute the action

… I guess there will be another easier way, but this is the one that occurred to me.

This is full script:

local loadsave = require("savecollision") local physics = require("physics") -------------------------------------------------CREATE JSON FILE------------------------------------------------------------------- function fileExists(fileName, base) assert(fileName, "file name missing") local base = base or system.DocumentsDirectory local filePath = system.pathForFile( fileName, base ) local exists = false if (filePath) then local fileHandle = io.open( filePath, "r" ) if (fileHandle) then exists = true io.close(fileHandle) end end return(exists) end local s = {} s.seven = 0 s.four = 0 loadsave.saveTable(s, "table.json", system.DocumentsDirectory) -------------------------------------------------------------------------------------------------- physics.start() physics.setGravity(0,9.8) local ground = display.newRoundedRect(0,0,900,20,3); ground:setFillColor(0.89, 0.498, 0.263) ground.x = 300 ground.y = 800 physics.addBody( ground, "static", { friction=1.0} ) local myTarget = display.newRoundedRect(100,300,69,69,3) myTarget:setFillColor(100,100,100) myTarget.name = "4" physics.addBody(myTarget, { density=2, friction=0.5, bounce=0.2} ) local myTarget1 = display.newRoundedRect(180,100,69,69,3) myTarget1:setFillColor(100,100,100) myTarget1.name = "7" physics.addBody(myTarget1, { density=2, friction=0.5, bounce=0.2} ) local myObject = display.newRoundedRect(50,50,67,67,3); myObject:setFillColor(0,0,255) myObject.x = 100 myObject.y = 755 myObject.name = "four" physics.addBody( myObject, "static") myObject.isSensor = true local myObject2 = display.newRoundedRect(50,50,67,67,3); myObject2:setFillColor(0,0,255) myObject2.x = 180 myObject2.y = 755 myObject2.name = "seven" physics.addBody( myObject2, "static") myObject2.isSensor = true local function onLocalCollision( self, event ) if ( event.phase == "began" ) then local s= {event.other.name , self.name} loadsave.saveTable(s, "table.json", system.DocumentsDirectory) end end myObject.collision = onLocalCollision myObject:addEventListener( "collision", myObject ) myObject2.collision = onLocalCollision myObject2:addEventListener( "collision", myObject2 )

jump.JPG

i didn’t forget about you, just don’t have time right now to proper answer you.

You could improve your code doing some functions to create your objects. I remade your code to show you that, but right now I’m struggling with some corona issues myself so I will back here when I can.

Also, it is always better to write dynamic functions that can adapt.

In your example, you have a case of “4 x 7 = 28” and if that works, great, but what if you want to create another level that has different numbers? If you create dynamic functions that you can just use to create your levels, you’ll be saving yourself a lot of time and headache, all the while making your game easier to manage and expand.

Playing with json in here is pure overkill, go with normal tables, or rather make switch states where u check if correct box is in correct place, if all match, then go

Ok, carloscosta.

Doing it with json is because I don’t know it any other way since 4 with four and 7 with seven would not collide at the same time, but if I make two collisions separately, one for 4 with four and one for 7 with seven, I would send them to the table.json and then rescue the result with a condition that would give me 28.

It really sounds like you should find another way to go about this.

For instance, a simpler approach would be to just create a table that contains a reference to each object that you expect to collide. Then, whenever a new collision begins, you set that object’s collision state to true and then you’d loop through that table to see if every other collision is true as well. Then, whenever a collision ends, you’d set that object’s collision state back to false.

Here’s some pseudo code:

local collisions = {} collisions["target1"] = false collisions["target2"] = false function collisionListener( ... ) if event.phase == "began" then -- write a condition here where "if self.name == event.other.name then" to check that correct box touches. collisions[event.other.name] = true -- if correct boxes hit then set it to true in the collisions table. -- now you can loop through the collisions table to see if all are true, if yes, then you've got a solution. elseif event.phase == "ended" then collisions[event.other.name] = false -- collision only ends if the object moves out of position. end end

If you need to save your progress for when the player may close the app, then use json for storing data during that time. You should not be using json to go through collisions as they occur because it is very cumbersome and slow, drains more battery than necessary, etc.

Hi XeduR, thanks for replying.

I have never worked with memory tables, I will have to catch up. I tried the collision with your code but I don’t receive an answer.

I have planned to make two collisions separately and then rescue the result from the table.json:

local function onLocalCollision4( self, event ) local phase, other = event.phase, event.other if phase == "began" and event.other.name == "4" then s.four = 4 loadsave.saveTable(s, "table.json", system.DocumentsDirectory) end end local function onLocalCollision7( self, event ) local phase, other = event.phase, event.other if phase == "began" and event.other.name == "7" then s.seven = 7 loadsave.saveTable(s, "table.json", system.DocumentsDirectory) end end

My code was just pseudo code, it still needs work to get it to actually work (especially in your specific project).

What you are doing with json is essentially:

  1. Put collision event’s information to a Lua table,
  2. Take contents of that Lua table,
  3. Store it in a JSON file,
  4. Read that JSON file,
  5. Place those contents to a Lua table.

You are essentially running a lap around the block just to get to where you were and wasting resources in doing so.

OK, I will follow your advice XeduR, in reality I can save work and time in the future.

Cheers

Following the advice of XeduR, I have improved my code, I think I am on the right track now, although I think it can be reduced to a single collision function, this is my script:

local physics = require("physics") -------------------------------------------------CREATE TABLE------------------------------------- local t = {} t["four"] = false t["seven"] = false print ( t.four ) print ( t.seven) -------------------------------------------------------------------------------------------------- physics.start() physics.setGravity(0,9.8) local ground = display.newRoundedRect(0,0,900,20,3); ground:setFillColor(0.89, 0.498, 0.263) ground.x = 300 ground.y = 800 physics.addBody( ground, "static", { friction=1.0} ) local box = display.newRoundedRect(50,50,67,67,3); box:setFillColor(0.918, 0.71, 0.075) box.x = 500 box.y = 755 local box2 = display.newRoundedRect(50,50,67,67,3); box2:setFillColor(0.118, 0.58, 0.075) box2.x = 600 box2.y = 755 local myTarget = display.newRoundedRect(100,300,69,69,3) myTarget:setFillColor(100,100,100) myTarget.name = "4" physics.addBody(myTarget, { density=2, friction=0.5, bounce=0.2} ) local myTarget1 = display.newRoundedRect(180,100,69,69,3) myTarget1:setFillColor(100,100,100) myTarget1.name = "7" physics.addBody(myTarget1, { density=2, friction=0.5, bounce=0.2} ) local myObject = display.newRoundedRect(50,50,67,67,3); myObject:setFillColor(0,0,255) myObject.x = 100 myObject.y = 755 myObject.name = "four" physics.addBody( myObject, "static") myObject.isSensor = true local myObject2 = display.newRoundedRect(50,50,67,67,3); myObject2:setFillColor(0,0,255) myObject2.x = 180 myObject2.y = 755 myObject2.name = "seven" physics.addBody( myObject2, "static") myObject2.isSensor = true local function onLocalCollision4( self, event ) local phase, other = event.phase, event.other if phase == "began" and event.other.name == "4" then print( self.name .. ": collision began with " .. event.other.name ) box.y=200 t.four = 4 end end local function onLocalCollision7( self, event ) local phase, other = event.phase, event.other if phase == "began" and event.other.name == "7" then print( self.name .. ": collision began with " .. event.other.name ) t.seven = 7 print ( t.four ) print ( t.seven) if (t.seven \* t.four) == 28 then box2.y = 200 table.remove( t ) table.remove( t, pos ) end end end myObject.collision = onLocalCollision4 myObject:addEventListener( "collision", myObject ) myObject2.collision = onLocalCollision7 myObject2:addEventListener( "collision", myObject2 )

This is the reading of the console to verify that everything went well:

12:21:44.998  false

12:21:44.998  false

12:21:46.485  four: collision began with 4

12:21:46.797  seven: collision began with 7

12:21:46.797  4

12:21:46.797  7

I don’t know if with this I delete the table, I don’t know how to represent it in the console:

table.remove( t ) table.remove( t, pos )

Just remade your boxes creation code so you can see that your approach is far from optimized.

There are infinite ways of doing it, I just made one so you can learn from:

My main file is:

display.setDefault( "anchorX", 0 ) display.setDefault( "anchorY", 0 ) local boxes=require ("boxes") local \_H=display.contentHeight local groundHeight=20 local boxClass=boxes.Box() -- creates the ground class local boxGroundInstance=boxClass.new({x=0, y=display.contentHeight-40, height=20, width=display.contentWidth, bodyType="static", body={friction=1.0}, name="ground", isSensor=false}) -- creates the ground object -- create the boxes that are used to check position local boxInstance1=boxClass.new({x=50,y=\_H-40-69, name="four", color={0.7,0.7, 0.7,1}, width=69, height=69, radius=3, bodyType="static", isSensor=true}) local boxInstance2=boxClass.new({x=200,y=\_H-40-69, name="seven", color={0.7,0.7, 0.7,1}, width=69, height=69, radius=3, bodyType="static", isSensor=true}) -- create the boxes that fall from the sky local boxInstance3=boxClass.new({x=50,y=300, name="four", color={0,0, 1,1}, width=67, height=67, radius=3, isSensor=false, colision=true, body={ density=2, friction=0.5, bounce=0.2}}) local boxInstance4=boxClass.new({x=200,y=50, name="seven", color={0,0, 1,1}, width=67, height=67, radius=3, isSensor=false, colision=true, body={ density=2, friction=0.5, bounce=0.2}})

My boxes.lua file:

local physics = require("physics") physics.start() physics.setGravity(0,9.8) local boxes={} function boxes.Box() local height=20 local \_M = { x=0, y=display.contentHeight-height, width=display.contentWidth, height=height, radius=0, name="", color={0.89, 0.498, 0.263, 1}, body=nil, anchorX=0, anchorY=0, bodyType="dynamic", isSensor=false, colision=false, } local mt = { \_\_index = \_M } function \_M.delete(self) display.remove(self.view) self.view=nil self=nil end local function onLocalCollision( self, event ) if ( event.phase == "began" ) then -- do whatever you want here end end local instance = {} function instance.new(params) params=params or {} setmetatable(params, mt) params.view=display.newRoundedRect( params.x, params.y, params.width, params.height, params.radius) params.view.name=params.name params.view:setFillColor(unpack(params.color)) params.view.anchorX=params.anchorX params.view.anchorY=params.anchorY physics.addBody(params.view, params.body ) params.view.isSensor=params.isSensor params.view.bodyType=params.bodyType if params.colision==true then params.view.collision = onLocalCollision params.view:addEventListener( "collision", params.view ) end return params end return instance end return boxes

my build.settings

-- -- For more information on build.settings, see the Project Build Settings guide at: -- https://docs.coronalabs.com/guide/distribution/buildSettings -- settings = { orientation = { -- Supported values for orientation: -- portrait, portraitUpsideDown, landscapeLeft, landscapeRight default = "portrait", supported = { "portrait", "portraitUpsideDown"}, }, -- -- Android section -- android = { usesPermissions = { "android.permission.INTERNET", }, }, -- -- iOS section -- iphone = { xcassets = "Images.xcassets", plist = { UIStatusBarHidden = false, UILaunchStoryboardName = "LaunchScreen", }, }, -- -- Plugins section -- plugins = { }, -- -- Project section -- excludeFiles = { -- Exclude unnecessary files for each platform all = { "Icon.png", "Icon-\*dpi.png", "Images.xcassets", }, android = { "LaunchScreen.storyboardc", }, }, }

My config.lua

-- Hard code the following without using Corona APIs. application = { content = { scale = "adaptive", fps = 60, imageSuffix = { ["@2x"] = 1.5, ["@3x"] = 2.5, } }, notification = { iphone = { types = { "badge", "sound", "alert" } }, google = { projectNumber = "" }, } }

I didn’t made any code for the collisions because you need first to learn the basics. And creating objects are the one to learn first.

You don’t need to learn metatables and if this code is more that you can take. just ignore the meta tables… and create normal variables to default values, I used meta only for that.

Your objects can move back from the check box position? if so the variable that controls the collision needs to be reset when moved away.

Ok, thank you very much carloscosta for bothering you with me, your code is very organized and it has helped me a lot, I create the objects with Tiled Map Editor and import them in the style of the game “Sticker Knight Platformer”:

 local filename = event.params.map or "scene/game/map/level\_001.json" local mapData = json.decodeFile( system.pathForFile( filename, system.ResourceDirectory ) ) map = tiled.new( mapData, "scene/game/map" )

so that my game recognizes the collision objects I will create a box.lua as you indicate.

Greetings and thanks