OGT Level Manager

Hi, I was try to see if I call find some info on making level when I came across Level Manager and I wish I never had, because it is very confusing to a beginner.  I found GGData.lua and ogt_Imdata.lua especially confusing, will I need to use this mess to code a non-animated type simple little app?

local GGData = {} local GGData\_mt = { \_\_index = GGData } local json = require( "json" ) local lfs = require( "lfs" ) local crypto = require( "crypto" ) -- Functions used for converting tables to strings which is used for data integrity -- function table.val\_to\_str ( v ) if "string" == type( v ) then v = string.gsub( v, "\n", "\\n" ) if string.match( string.gsub(v,"[^'\"]",""), '^"+$' ) then return "'" .. v .. "'" end return '"' .. string.gsub(v,'"', '\\"' ) .. '"' else return "table" == type( v ) and table.tostring( v ) or tostring( v ) end end function table.key\_to\_str ( k ) if "string" == type( k ) and string.match( k, "^[\_%a][\_%a%d]\*$" ) then return k else return "[" .. table.val\_to\_str( k ) .. "]" end end function table.tostring( tbl ) local result, done = {}, {} for k, v in ipairs( tbl ) do table.insert( result, table.val\_to\_str( v ) ) done[k] = true end for k, v in pairs( tbl ) do if not done[k] then table.insert( result, table.key\_to\_str( k ) .. "=" .. table.val\_to\_str( v ) ) end end return "{" .. table.concat( result, "," ) .. "}" end local toString = function( value ) if type( value ) == "table" then return table.tostring( value ) else return tostring( value ) end end ----------------------------------------------- --- Initiates a new GGData object. -- @param id The name of the GGData to create or load ( if it already exists ). -- @param path The path to the GGData. Optional, defaults to "boxes". -- @param baseDir The base directory for the GGData. Optional, defaults to system.DocumentsDirectory. -- @return The new object. function GGData:new( id, path, baseDir ) local self = {} setmetatable( self, GGData\_mt ) self.id = id self.path = path or "boxes" self.baseDir = baseDir if self.id then self:load() end return self end --- Loads, or reloads, this GGData object from disk. -- @param id The id of the GGData object. -- @param path The path to the GGData. Optional, defaults to "boxes". -- @param baseDir The base directory for the GGData. Optional, defaults to system.DocumentsDirectory. function GGData:load( id, path, baseDir ) -- Set up the path path = path or "boxes" -- Pre-declare the new GGData object local box -- If no id was passed in then assume we're working with a pre-loaded GGData object so use its id if not id then id = self.id box = self end local data = {} local path = system.pathForFile( path .. "/" .. id .. ".box", baseDir or system.DocumentsDirectory ) local file = io.open( path, "r" ) if not file then return end data = json.decode( file:read( "\*a" ) ) io.close( file ) -- If no GGData exists then we are acting on a Class function i.e. not a pre-loaded GGData object. if not box then -- Create the new GGData object. box = GGData:new() end -- Copy all the properties across. for k, v in pairs( data ) do box[k] = v end return box end --- Saves this GGData object to disk. function GGData:save() -- Don't want this key getting saved out local integrityKey = self.integrityKey self.integrityKey = nil local data = {} -- Copy across all the properties that can be saved. for k, v in pairs( self ) do if type( v ) ~= "function" and type( v ) ~= "userdata" then data[k] = v end end -- Check for and create if necessary the boxes directory. local path = system.pathForFile( "", system.DocumentsDirectory ) local success = lfs.chdir( path ) if success then lfs.mkdir( self.path ) path = self.path else path = "" end data = json.encode( data ) path = system.pathForFile( self.path .. "/" .. self.id .. ".box", system.DocumentsDirectory ) local file = io.open( path, "w" ) if not file then return end file:write( data ) io.close( file ) file = nil -- Set the key back again self.integrityKey = integrityKey end --- Sets a value in this GGData object. -- @param name The name of the value to set. -- @param value The value to set. function GGData:set( name, value ) self[name] = value self:storeIntegrityHash( name, value ) end --- Gets a value from this GGData object. -- @param name The name of the value to get. -- @return The value. function GGData:get( name ) return self[name] end --- Checks whether a value of this GGData object is higher than another value. -- @param name The name of the first value to check. -- @param otherValue The name of the other value to check. Can also be a number. -- @return True if the first value is higher, false otherwise. function GGData:isValueHigher( name, otherValue ) if type( otherValue ) == "string" then otherValue = self:get( otherValue ) end return self[name] \> otherValue end --- Checks whether a value of this GGData object is lower than another value. -- @param name The name of the first value to check. -- @param otherValue The name of the other value to check. Can also be a number. -- @return True if the first value is lower, false otherwise. function GGData:isValueLower( name, otherValue ) if type( otherValue ) == "string" then otherValue = self:get( otherValue ) end return self[name] \< otherValue end --- Checks whether a value of this GGData object is equal to another value. -- @param name The name of the first value to check. -- @param otherValue The name of the other value to check. Can also be a number. -- @return True if the first value is equal, false otherwise. function GGData:isValueEqual( name, otherValue ) if type( otherValue ) == "string" then otherValue = self:get( otherValue ) end return self[name] == otherValue end --- Checks whether this GGData object has a specific property or not. -- @param name The name of the value to check. -- @return True if the value exists and isn't nil, false otherwise. function GGData:hasValue( name ) return self[name] ~= nil and true or false end --- Sets a value on this GGData object if it is new. -- @param name The name of the value to set. -- @param value The value to set. function GGData:setIfNew( name, value ) if self[name] == nil then self[name] = value self:storeIntegrityHash( name, value ) end end --- Sets a value on this GGData object if it is higher than the current value. -- @param name The name of the value to set. -- @param value The value to set. function GGData:setIfHigher( name, value ) if self[name] and value \> self[name] or not self[name] then self[name] = value self:storeIntegrityHash( name, value ) end end --- Sets a value on this GGData object if it is lower than the current value. -- @param name The name of the value to set. -- @param value The value to set. function GGData:setIfLower( name, value ) if self[name] and value \< self[name] or not self[name] then self[name] = value self:storeIntegrityHash( name, value ) end end --- Increments a value in this GGData object. -- @param name The name of the value to increment. Must be a number. If it doesn't exist it will be set to 0 and then incremented. -- @param amount The amount to increment. Optional, defaults to 1. function GGData:increment( name, amount ) if not self[name] then self:set( name, 0 ) end if self[name] and type( self[name] ) == "number" then self[name] = self[name] + ( amount or 1 ) self:storeIntegrityHash( name, value ) end end --- Decrements a value in this GGData object. -- @param name The name of the value to decrement. Must be a number. If it doesn't exist it will be set to 0 and then decremented. -- @param amount The amount to decrement. Optional, defaults to 1. function GGData:decrement( name, amount ) if not self[name] then self:set( name, 0 ) end if self[name] and type( self[name] ) == "number" then self[name] = self[name] - ( amount or 1 ) self:storeIntegrityHash( name, value ) end end --- Clears this GGData object. function GGData:clear() for k, v in pairs( self ) do if k ~= "integrityControlEnabled" and k ~= "integrityAlgorithm" and k ~= "integrityKey" and k ~= "id" and type( k ) ~= "function" then self[k] = nil end end end --- Deletes this GGData object from disk. -- @param id The id of the GGData to delete. Optional, only required if calling on a non-loaded object. function GGData:delete( id ) -- If no id was passed in then assume we're working with a pre-loaded GGData object so use its id if not id then id = self.id end local path = system.pathForFile( self.path, system.DocumentsDirectory ) local success = lfs.chdir( path ) os.remove( path .. "/" .. id .. ".box" ) if not success then return end end --- Enables or disables the Syncing of this box. -- @param enabled True if Sync should be enabled, false otherwise. function GGData:setSync( enabled, id ) -- If no id was passed in then assume we're working with a pre-loaded GGData object so use its id if not id then id = self.id end native.setSync( self.path .. "/" .. id .. ".box", { iCloudBackup = enabled } ) end --- Checks if Syncing for this box is enabled or not. -- @param enabled True if Sync is enabled, false otherwise. function GGData:getSync( id ) -- If no id was passed in then assume we're working with a pre-loaded GGData object so use its id if not id then id = self.id end return native.getSync( self.path .. "/" .. id .. ".box", { key = "iCloudBackup" } ) end --- Enables integrity checking. -- @param algorithm The hashing algorithm to use, see this page for possibles - http://docs.coronalabs.com/api/library/crypto/index.html -- @param key The seed to use for the hashing algorithm. function GGData:enableIntegrityControl( algorithm, key ) self.integrityAlgorithm = algorithm self.integrityKey = key self.hash = self.hash or {} self.integrityControlEnabled = true end --- Disables integrity checking. function GGData:disableIntegrityControl() self.integrityAlgorithm = nil self.integrityKey = nil self.hash = nil self.integrityControlEnabled = false end --- Verifies that the passed in value matches the stored hash. -- @param name The name of the value to check. -- @param value The value to check. -- @return True if the value matches the hash false otherwise. function GGData:verifyItemIntegrity( name, value ) -- just hash the tostring() version and compare against that! if toString( value ) then local generatedHash = crypto.hmac( self.integrityAlgorithm, toString( value ), self.integrityKey, false ) local storedHash = self.hash[name] return generatedHash == storedHash end end --- Stores the hash value of the given value to be used for integrity checks. -- @param name The name of the value to set. -- @param value The value to set. Optional, if not included will just pull the value from the name supplied. function GGData:storeIntegrityHash( name, value ) if not self.integrityControlEnabled then return end value = value or self[name] self.hash = self.hash or {} if value then self.hash[name] = crypto.hmac( self.integrityAlgorithm, toString( value ), self.integrityKey, false ) end end --- Updates/sets the hash value of the all stored values. function GGData:updateAllIntegrityHashes() for k, v in pairs( self ) do if k ~= "integrityControlEnabled" and k ~= "integrityAlgorithm" and k ~= "integrityKey" and k ~= "hash" and k ~= "id" and toString( v ) then self:storeIntegrityHash( k, v ) end end end --- Checks the hashed versions of all stored data. Will remove any values that don't match their hashes, i.e. they've been tampered with. function GGData:verifyIntegrity() if not self.integrityControlEnabled then return end local corruptEntries = {} for k, v in pairs( self ) do if k ~= "integrityControlEnabled" and k ~= "integrityAlgorithm" and k ~= "integrityKey" and k ~= "hash" and k ~= "id" and toString( v ) then if not self:verifyItemIntegrity( k, v ) then corruptEntries[#corruptEntries + 1] = { name = k, value = v } self[k] = nil self.hash[k] = nil end end end for k, v in pairs( self.hash ) do if not self[k] then corruptEntries[#corruptEntries + 1] = { name = k, value = v } self[k] = nil self.hash[k] = nil end end return corruptEntries end --- Gets the path to the stored file. Useful if you want to upload it. -- @return Two paramaters; the full path and then the relative path. function GGData:getFilename() local relativePath = self.path .. "/" .. self.id .. ".box" local fullPath = system.pathForFile( relativePath, system.DocumentsDirectory ) return fullPath, relativePath end --- Destroys this GGData object. function GGData:destroy() self:clear() self = nil end return GGData 

Now ogt_Imdata

local k = {} --[[============================================================== When a level is selected OGTLM needs to send the user to another composer scene. If you use the same scene for all levels (just loading new data for each level, you'll use the k.playScene option below. Enter the name of the composer scene to switch to. If you have a different composer scene for each level you'll use the second option below as long as the scenes are named sequentially. For example, level1, level2, level3, etc. Or stage1, stage2, stage3, etc. in that case, enter the "base name" for the scenes, such as level or stage. OGTLM will add the chosen level number to the end when the user clicks a level. Or, create a table in k.sceneNames that holds the composer scene name for each level you have. -- ==============================================================]] k.playScene = "play" -- name of scene or nil to go to sequential scenes k.sequentialScene = "level" -- will turn into level1, level2, etc. k.sceneNames = nil -- {"scene01", "playme", "world3"} --[[========================================= If images or audio files are in folders, define those here. Be sure and add a slash / to the end of any folder names. If you're not using folders, set vars to nil --==========================================]] k.imagePrefix = "images/" k.audioPrefix = "audio/" --============================================================== -- filenames for the images used in the level manager k.backgroundImage = "background.png" -- optional, define as nil if not used k.customLevel = nil -- get level image from function rather than next var k.levelSquareImage = "level-wood.png" -- required k.lockImage = nil -- optional, define as nil if not used (--"lock.png"--) k.starImage = nil -- optional, nil if not using stars (--"staryellow.png"--) k.prevImage = "prev-white.png" -- optional unless you need paging, define as nil if not used k.nextImage = "next-white.png" -- optional unless you need paging, define as nil if not used --============================================================== -- filenames for the images used in the level manager k.selectSoundFile = "levelselect.wav" -- sound when level selected, define as nil if not used k.nextPageSoundFile = "changepage.wav"-- sound when next page clicked, define as nil if not used k.prevPageSoundFile = "changepage.wav"-- sound when previous page clicked, define as nil if not used k.audioOn = true --============================================================== -- the default font to be used for level number and score k.fontName = "Helvetica" -- required --============================================================== -- info about the level number (or text) being displayed k.showLevelNum = true k.levelNumFontName = nil -- optional, use instead of default font for level num k.levelNumFontSize = 50 k.levelNumFontColor = {1,1,1} k.levelNumEmbossedFont = true k.levelNumTextXOffset = -2 -- horizontal offset for the level number text k.levelNumTextYOffset = 2 -- vertical offset for the level number text k.tileNums = nil --{"H","He","Li","Be","B","C","N","O","F","Ne","Na","Mg","Al","Si","P","S","Cl"} -- use a table of string values if desired {"A", "B", "C"} k.showLevelNumTextWhenLocked = false --============================================================== -- info about the score being displayed (optional) k.showScore = true k.scoreFontName = nil -- optional, use instead of default font for score k.scoreFontSize = 18 k.scoreFontColor = {1,1,1} k.scoreEmbossedFont = true k.scoreTextXOffset = 0 -- horizontal offset for the score text k.scoreTextYOffset = 0 -- vertical offset for the score text k.scorePrefix = nil k.scoreSuffix = " Pts" k.showScoreWhenLocked = false --============================================================== -- Info about the grid itself k.totalLevels = 10 -- total number of levels in the game. should equal (numCols \* numRows) \* numPages k.numCols = 5 -- how many columns on each page of levels k.numRows = 2 -- how many rows on each page of levels k.colSpace = 10 -- extra spacing between each column k.rowSpace = 40 -- extra spacing between each row k.gridOffsetX = 0 -- horizontal offset for the entire grid on the page k.gridOffsetY = -20 -- vertical offset for the entire grid on the page -- misc variables k.numUnlocked = 5 -- how many of the first levels are unlocked (minimum 1) -- was 9 k.rememberPage = true -- if true, shows page from last selected level k.currentPage = 1 -- probably won't change this (much) manually k.currentLevel = 0 -- probably won't change this (much) manually k.swipe = true -- allow swiping left/right to page k.minSwipeDistance = 20 -- number of pixels required to trigger paging k.beforeLeaving = nil -- name of function to call after choosing level but before going there. --============================================================== -- star stuff k.maxStars = 3 k.starOffsetX = 0 k.starOffsetY = -4 k.singleStarOffsetX = {0, 0, 0} -- number of elements must match k.maxStars k.singleStarOffsetY = {0, 3, 0} -- number of elements must match k.maxStars k.showMissingStar = true -- next and prev arrows k.nextOffsetX = -5 -- tweak the positioning for the arrows here k.nextOffsetY = 0 k.prevOffsetX = 5 k.prevOffsetY = 0 -- lock image k.lockOffsetX = 0 -- tweak position of the lock here k.lockOffsetY = -5 -- transition effect and time for switching from level selector to chosen level. k.sboardEffect = "crossFade" k.sboardTime = 700 -- how fast does the level selector slide when using next/prev arrows k.slideTime = 300 -- milliseconds (lower number = faster slide) k.dataFile = "ogtlm\_levels" k.userName = nil --============================================================== -- extra variables below that are not user-configurable. k.displayText = nil k.numPerPage = (k.numCols \* k.numRows) k.numPages = math.ceil ( k.totalLevels / ((k.numCols \* k.numRows)) ) k.tileWidth = 100 k.tileHeight = 70 k.lockWidth = 0 k.lockHeight = 0 k.prevWidth = 0 k.prevHeight = 0 k.nextWidth = 0 k.nextHeight = 0 k.starWidth = 0 -- will be filled in dynamically k.starHeight = 0 -- will be filled in dynamically k.levelInfo = {} k.levelLocked = {} k.starsOnLevel = {} k.levelScores = {} return k 

What is this OGT think?

Thanks

Do you need them? I’d say no, especially since you don’t even know what they do.

Those are just some code files created by someone for some purpose. I have no clue as to what they are and they are too long for me to read them to find out. :stuck_out_tongue:

That being said, there’s nothing forcing you to use them. You can do (almost) whatever you want with your project.

 

Hi Jack,

I’m not sure what ogt_Imdata.lua is for however I wrote GGData.lua and it was designed to simplify data storage in games/apps ( things like scores, player names, that sort of thing ). If you look through the comments for each function this should be clear? And as stated, you don’t have to use anything you don’t want to - it’s your project.

If on the other hand you decide you do need something like GGData to store things then my Puggle library has replacements for it - https://www.grahamranson.com/getting-started-with-puggle/

But as stated, you don’t need to use anyone’s code to make your game, sometimes it’s just helpful to not have to reinvent the wheel.

Do you need them? I’d say no, especially since you don’t even know what they do.

Those are just some code files created by someone for some purpose. I have no clue as to what they are and they are too long for me to read them to find out. :stuck_out_tongue:

That being said, there’s nothing forcing you to use them. You can do (almost) whatever you want with your project.

 

Hi Jack,

I’m not sure what ogt_Imdata.lua is for however I wrote GGData.lua and it was designed to simplify data storage in games/apps ( things like scores, player names, that sort of thing ). If you look through the comments for each function this should be clear? And as stated, you don’t have to use anything you don’t want to - it’s your project.

If on the other hand you decide you do need something like GGData to store things then my Puggle library has replacements for it - https://www.grahamranson.com/getting-started-with-puggle/

But as stated, you don’t need to use anyone’s code to make your game, sometimes it’s just helpful to not have to reinvent the wheel.