@doubleslashdesign Oh wow you are totally right. I’ve never seen that happen before… If you do that on the main menu screen the background goes black and the title graphic disappears (this is an actual image not the bitmap font).
I think this has something to do with the bitmap font spritesheets because those images are white characters saved on a black background. As you navigate through the menus to the game, the background actually becomes the bitmap font spritesheet! lol Would anyone be able to point out what is wrong with the bitmap font code? I took it from the community but it does use the old sprite.lua file from graphics 1.0 so maybe that is causing this issue…
bmf.lua
module( ..., package.seeall ) -- AngelCode bitmap font support -- Updated for Graphics 2.0 -- Download sprite module from https://github.com/coronalabs/framework-sprite-legacy/raw/master/sprite.lua local sprite = require( "libraries.bmf.sprite" ) -- Specify an Angelcode format bitmap font definition file (".FNT") -- The spritesheet(s) that this file references need to be located in the resource directory. -- Return value is a font object that can be used when calling newString function loadFont( fntFile, path ) local function extract( s, p ) return string.match( s, p ), string.gsub( s, p, '', 1 ) end local path = path or "" local font = { info = {}, spritesheets = {}, sprites = {}, chars = {}, kernings = {}, size = 0 } local readline = io.lines( system.pathForFile( path .. fntFile, system.ResourceDirectory ) ) for line in readline do local t = {}; local tag; tag, line = extract( line, '^%s\*([%a\_]+)%s\*' ) while string.len( line ) \> 0 do local k, v k, line = extract( line, '^([%a\_]+)=' ) if not k then break end v, line = extract( line, '^"([^"]\*)"%s\*' ) if not v then v, line = extract( line, '^([^%s]\*)%s\*' ) end if not v then break end t[k] = v end if tag == 'info' or tag == 'common' then for k, v in pairs( t ) do font.info[k] = v end elseif tag == 'page' then font.spritesheets[1 + t.id] = { file = t.file, frames = {} } elseif tag == 'char' then t.letter = string.char( t.id ) font.chars[t.letter] = {} for k, v in pairs( t ) do font.chars[t.letter][k] = v end if 0 + font.chars[t.letter].width \> 0 and 0 + font.chars[t.letter].height \> 0 then font.spritesheets[1 + t.page].frames[#font.spritesheets[ 1 + t.page].frames + 1 ] = { --textureRect = { x = 0 + t.x, y = 0 + t.y, width = -1 + t.width, height = -1 + t.height }, --CLF removed the -1, it was causing issues with fonts with borders textureRect = { x = 0 + t.x, y = 0 + t.y, width = t.width, height = t.height }, spriteSourceSize = { width = 0 + t.width, height = 0 + t.height }, spriteColorRect = { x = 0, y = 0, width = -1 + t.width, height = -1 + t.height }, spriteTrimmed = true } font.sprites[t.letter] = { spritesheet = 1 + t.page, frame = #font.spritesheets[1 + t.page].frames } end elseif( tag == 'kerning' ) then font.kernings[string.char( t.first ) .. string.char( t.second )] = 0 + t.amount end end for k, v in pairs( font.spritesheets ) do font.spritesheets[k].sheet = sprite.newSpriteSheetFromData( path..v.file, v ) end for k, v in pairs( font.sprites ) do font.sprites[k] = sprite.newSpriteSet( font.spritesheets[v.spritesheet].sheet, v.frame, 1 ) end return font end -- extend an object with accessor behaviors local function accessorize( t ) local mt = getmetatable( t ) setmetatable( t, { \_\_index = function( t, k ) if rawget( t, 'get\_'..k ) then return rawget(t, 'get\_'..k )( t, k ) elseif rawget( t, 'raw\_'..k ) then return rawget( t, 'raw\_'..k ) elseif mt.\_\_index then return mt.\_\_index( t, k ) else return nil end end, \_\_newindex = function( t, k, v ) if rawget( t, 'set\_'..k ) then rawget( t, 'set\_'..k )( t, k, v ) elseif rawget( t, 'raw\_'..k ) then rawset( t, 'raw\_'..k, v ) elseif mt.\_\_newindex then mt.\_\_newindex( t, k, v ) else rawset( t, 'raw\_'..k, v ) end end, } ) end -- extend an object with cascading removeSelf local function removerize( t ) local old = t.removeSelf t.removeSelf = function( o ) for i = o.numChildren, 1, -1 do o[i]:removeSelf() end old( o ) end end -- Pass a font object (obtained from loadFont) and a string to render -- Return value is a DisplayObject of the rendered string -- object.font can be read/modifed -- object.text can be read/modified -- object.align can be read/modified - left/right/center (multiline not yet fully supported for non-left) -- object.input( function(text), { filter = function(), max = 32 } ) -- turns the object into a text input. -- the callback is hit when the user presses "return" or the field losed focus. -- this code is under development - more documentation will be added soon... function newString( font, text, newsize) --local finalScale = 100/origsize \*newsize/100; local finalScale = 100/font.info.size \*newsize/100; local obj = display.newGroup() accessorize( obj ) removerize( obj ) obj.set\_font = function( t, k, v ) obj.raw\_font = v if t.text then t.text = t.text end end -- Set the alignment of the object obj.set\_align = function( t, k, v ) local w = t.textWidth if t.raw\_align == 'right' then for i = 1, t.numChildren do t[i].x = t[i].x + w end elseif t.raw\_align == 'center' then for i = 1, t.numChildren do t[i].x = t[i].x + math.floor( w \* 0.5 ) end end t.raw\_align = v if t.raw\_align == 'right' then for i = 1, t.numChildren do t[i].x = t[i].x - w end elseif t.raw\_align == 'center' then for i = 1, t.numChildren do t[i].x = t[i].x - math.floor( w \* 0.5 ) end elseif t.raw\_align ~= 'left' then t.raw\_align = 'left' end end -- Set the text for the object obj.set\_text = function( t, k, v ) if ( v == t.raw\_text ) then return end t.raw\_text = v for i = t.numChildren, 1, -1 do t[i]:removeSelf() end local oldAlign = ( t.align or 'left' ) local oldTint = ( t.tint or {0, 0, 0, 0} ) t.align = 'left' local x = 0; local y = 0 local last = ''; local xMax = 0; local yMax = 0 if t.raw\_font then for c in string.gmatch( t.raw\_text..'\n', '(.)' ) do if c == '\n' then x = 0; y = y + t.raw\_font.info.lineHeight if y \>= yMax then yMax = y end elseif t.raw\_font.chars[c] then local rfc = t.raw\_font.chars[c] if 0 + t.raw\_font.chars[c].width \> 0 and 0 + t.raw\_font.chars[c].height \> 0 then local letter = sprite.newSprite( t.raw\_font.sprites[c] ) if t.raw\_font.kernings[last .. c] then x = x + font.kernings[last .. c] end t:insert( letter ) letter.anchorX = 0 letter.anchorY = 0 letter.x = t.raw\_font.chars[c].xoffset + x letter.y = t.raw\_font.chars[c].yoffset - t.raw\_font.info.base + y last = c end --x = x + t.raw\_font.chars[c].xadvance x = x + t.raw\_font.chars[c].xadvance + (t.raw\_font.info.outline or 0) --CLF added support for outlines if x \>= xMax then xMax = x end end end obj.textWidth = xMax --[[local background = display.newRect( 0, -t.raw\_font.info.base, xMax, yMax ) background.isBackground = true --CLF Added to support tinting of font. obj:insert( background ) obj.background = background background:setFillColor( 0, 0, 0, 0 ) --]] end t.align = oldAlign t.tint = oldTint end -- set the tint of the object obj.set\_tint = function( t, k, v ) t.raw\_tint = v for i = t.numChildren, 1, -1 do if v[4] then t[i]:setFillColor(v[1],v[2],v[3],v[4]) else t[i]:setFillColor(v[1],v[2],v[3]) end end --if t.text then t.text = t.text end end obj.input = function( f, args ) -- spawn the text field invisibly local field -- Handle character insertion/deletion local function char() -- check if any character has been added or deleted if field.text ~= '--' then if string.len( field.text ) \< 2 then -- backspace was pressed if string.len( obj.text ) \> 0 then obj.text = string.sub( obj.text, 1, -2 ) end else -- some other key was pressed obj.text = obj.text..string.sub( field.text, 3 ) end field.text = '--' if args.filter then obj.text = string.sub( args.filter( obj.text ), 1, (args.max or 32) ) else obj.text = string.sub( obj.text, 1, (args.max or 32) ) end end end Runtime:addEventListener( 'enterFrame', char ) -- Handle the "done" phase local function done( e ) if e.phase == 'submitted' or e.phase == 'ended' then native.setKeyboardFocus( nil ) field:removeSelf() Runtime:removeEventListener( 'enterFrame', char ) f( text ) end end field = native.newTextField( 0, 0, 240, 24, done ) field.text = '--' field.isVisible = false native.setKeyboardFocus( field ) end obj.font = font obj.align = 'left' obj.text = (text or '') obj.xScale = finalScale; obj.yScale = finalScale; return obj end function newParagraph(font, text, fontSize, width) local obj = display.newGroup() accessorize( obj ) removerize( obj ) obj.set\_font = function( t, k, v ) obj.raw\_font = v --if t.text then t.text = t.text end end obj.set\_paragraphWidth = function( t, k, v ) obj.raw\_paragraphWidth = v --if t.text then t.text = t.text end end obj.set\_tint = function( t, k, v ) obj.raw\_tint = v for i = t.numChildren, 1, -1 do for j = t[i].numChildren, 1, -1 do if(not t[i][j].isBackground) then if v[4] then t[i][j]:setFillColor(v[1],v[2],v[3],v[4]) else t[i][j]:setFillColor(v[1],v[2],v[3]) end end end end --if t.text then t.text = t.text end end obj.set\_text = function(t, k, v) --save the new raw text t.raw\_text = v --remove all children for i = t.numChildren, 1, -1 do t[i]:removeSelf() end --determine the width of a space local space = newString(font, " ", fontSize) local spaceWidth = space.raw\_font.info.outline\*-1 or 0 space:removeSelf() space = nil --Create our word-wrapped paragraph. local spaceLeft = t.raw\_paragraphWidth local x, y = obj.x, obj.y for word, spacer in string.gmatch(v, "([^%s%-]+)([%s%-]\*)") do local w = newString(font, word..spacer, fontSize) if(w.width + spaceWidth) \> spaceLeft then spaceLeft = t.raw\_paragraphWidth - w.width - spaceWidth y = y + w.raw\_font.info.lineHeight x = obj.x w.x = x else w.x = x + t.raw\_paragraphWidth - spaceLeft spaceLeft = spaceLeft - w.width - spaceWidth end w.y = y obj:insert(w) end end obj.paragraphWidth = width or display.viewableContentWidth obj.text = text obj.font = font obj.tint = {255,255,255} return obj end
sprite.lua:
local Library = require "CoronaLibrary" local sprite = Library:new{ name='sprite', publisherId='com.' } local function toImageSheet( spriteSet ) assert( spriteSet.spriteSheet, "toImageSheet(): Bad spriteSet parameter: spriteSet.spriteSheet is nil" ) local options local spriteSheet = spriteSet.spriteSheet if spriteSheet.format == "simple" then local w = spriteSheet.width local h = spriteSheet.height options = { width = w, height = h, numFrames = spriteSet.numFrames, } elseif spriteSheet.format == "complex" then assert( spriteSheet.spriteSheetFrames, "spriteSheet.spriteSheetFrames is nil") options = { spriteSheetFrames = spriteSheet.spriteSheetFrames } end local filename = spriteSheet.filename local baseDir = spriteSheet.baseDir if baseDir then return graphics.newImageSheet( filename, baseDir, options ) else return graphics.newImageSheet( filename, options ) end end local function toSequenceData( spriteSet ) assert( spriteSet.spriteSheet, "toSequenceData(): Bad spriteSet parameter: spriteSet.spriteSheet is nil" ) local spriteSheet = spriteSet.spriteSheet local default = { name = "default", start = spriteSet.startFrame, count = spriteSet.numFrames, } local sequenceData = spriteSet.sequences or {} table.insert( sequenceData, default ) return sequenceData end sprite.newSprite = function( spriteSet ) assert( spriteSet, "spriteSet is nil", "sprite.newSprite(): spriteSet is nil." ) local s if spriteSet.type == "newSpriteArgs" then assert( type( spriteSet.args ) == "table", "sprite.newSprite(): 'spriteSet.args' is nil." ) s = display.newSprite( unpack( spriteSet.args ) ) else assert( spriteSet.type == "spriteSet" or spriteSet.type == "spriteMultiSet", "sprite.newSprite(): incorrect 'spriteSet.type'." ) local imageSheet = toImageSheet( spriteSet ) local sequenceData = toSequenceData( spriteSet ) assert( sequenceData, "sprite.newSprite(): failed to create sequenceData" ) s = display.newSprite( imageSheet, sequenceData ) end function s:prepare( name ) s:setSequence( name ) end return s end -- sprite.add( spriteSet, sequenceName, startFrame, frameCount, time, [loopParam] ) sprite.add = function( spriteSet, sequenceName, startFrame, frameCount, time, loopParam ) assert( spriteSet, "spriteSet is nil", "sprite.addSprite(): spriteSet is nil." ) assert( spriteSet.type == "spriteSet", "sprite.addSprite(): incorrect 'spriteSet.type'.") local sequences = spriteSet.sequences if not sequences then sequences = {} spriteSet.sequences = sequences end table.insert( sequences, item ) local loopCount = 0 local loopDirection if loopParam and 0 ~= loopParam then loopCount = 1 if -1 == loopParam then loopDirection = "bounce" elseif -2 == loopParam then loopCount = 0 loopDirection = "bounce" end end local item = { name = sequenceName, start = startFrame, count = frameCount, time = time, loopCount = loopCount, loopDirection = loopDirection, } table.insert( sequences, item ) end local function spriteSheetToImageSheet( spriteSheet ) assert( false, "spriteSheetToImageSheet() is not implemented." ) return nil end -- sprite.newSpriteMultiSet() sprite.newSpriteMultiSet = function( sequences ) assert( #sequences \> 0, "sprite.newSpriteMultiSet(): sequences array is empty." ) -- Assume first element defines default sheet local defaultSheet = spriteSheetToImageSheet( sequences[1].sheet ) assert( defaultSheet, "sprite.newSpriteMultiSet(): no sheet param." ) local sequenceData = {} for i=1,#sequences do local seq = sequences[i] local imageSheet = spriteSheetToImageSheet( seq.sheet ) local data = { sheet = imageSheet, frames = seq.frames, } table.insert( sequenceData, data ) end local result = { type = "newSpriteArgs", args = { defaultSheet, sequenceData, } } return sequences end -- sprite.newSpriteSet( spriteSheet, startFrame, frameCount ) sprite.newSpriteSet = function( spriteSheet, startFrame, frameCount ) assert( spriteSheet, "sprite.newSpriteSet(): spriteSheet is nil." ) assert( spriteSheet.type == "spriteSheet", "sprite.newSpriteSet(): spriteSheet is malformed." ) local result = { type = "spriteSet", spriteSheet = spriteSheet, numFrames = frameCount, startFrame=startFrame, } return result end -- sprite.newSpriteSheet( spriteSheetFile, [baseDir,] frameWidth, frameHeight ) sprite.newSpriteSheet = function( ... ) local args = { ... } local spriteSheetFile = args[1] local nextArg = 2 local baseDir = args[nextArg] if type(baseDir) ~= "userdata" then baseDir = nil else nextArg = nextArg + 1 end local frameWidth, frameHeight = args[nextArg], args[nextArg+1] local result = { type = "spriteSheet", format = "simple", width = frameWidth, height = frameHeight, filename = spriteSheetFile, baseDir = baseDir, } function result:dispose() -- no-op end return result end -- sprite.newSpriteSheetFromData( spriteSheetFile, [baseDir,] coordinateData ) sprite.newSpriteSheetFromData = function( ... ) local args = { ... } local spriteSheetFile = args[1] local nextArg = 2 local baseDir = args[nextArg] if type(baseDir) ~= "userdata" then baseDir = nil else nextArg = nextArg + 1 end local coordinateData = args[nextArg] local result = { type = "spriteSheet", format = "complex", spriteSheetFrames = coordinateData.frames, filename = spriteSheetFile, baseDir = baseDir, } function result:dispose() -- no-op end return result end return sprite
Thanks!