Unscramble Anagram - Corona App on the Windows Phone Store!

Hi all,

With the help of Joshua and everyone else here on the forums I was able to prepare, build, and release my corona app on the windows phone store! Thanks for all your help!

The app is called Unscramble Anagram and can be found here: http://www.windowsphone.com/en-us/store/app/unscramble-anagram/e53489ab-c108-4480-b2b1-42d5c774db22

As every developer knows, 5 star reviews are greatly appreciated  :smiley:

Congratulations!

I just downloaded it and played it now.  Very nice app!  And I hope you had a good experience putting together on WP8.

By the way, I play a similar anagram style game on my iPhone.  It’s actually my most played game for the past several years.  I like puzzle/word games.  :slight_smile:

Congrats Spacewolf. We shared the game on Facebook and Bobby Ghari asked if you used a bitmap font library for the timer display.

If you don’t mind giving him a few pointers, you can share your experience here, https://www.facebook.com/CoronaGeek/posts/736019049778967?comment_id=736079253106280&offset=0&total_comments=1

I have the game on my Nokia and it plays great. As soon as I get the device registered with the app store, I’ll leave a review.

Thanks in advance.

Thanks guys and thanks for the post! :smiley: I don’t mind at all sharing my experience. I’ll reply as soon as I can :slight_smile:

Downloaded, works great!! great job.

One issue I found - Run the app, go to the menu but dont start any rounds yet.

Hit the home button on your phone ( app should pause ) navigate somewhere else and then hit the back but on the phone until you get back to your app. the fonts were all distorted on my phone. then when I started the round to play. They really got distorted.

NOw if it works on your testing then dont worry about it. My phone is pretty flaky, I’ll test on my wife windows 8 phone when she gets back home and if you hear nothing else from me then all is well. But i just wanted to point that our to you.

I’m leaving a review for your app :slight_smile:

Larry

@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!

I have also seen glitches in sprites on my game in WP8.  For example, a black background appearing instead of transparent, or an unrelated image (like a background graphic) replacing the transparent parts of a sprite. 

It may correlate with increased memory usage, but I am not sure… It’s not something that happens on Android or iOS.

@spacewolf,

I just did the same test with your app’s menu screen now.  I too can see the background going black.

I’m not sure why that’s happening.  I’ve tested several apps having sprites, suspended/resumed several times, and my test apps always reload sprites and other images correctly.  I’ve also tested the old "bmf.lua and the new “bmf2.lua” bitmap font libraries, performed the same tests, and they re-loaded just fine as well.  So, I’m curious what’s so different about your app.

@spacewolf, would you mind sending me a small project that can reproduce this issue?  Such as whatever your main menu screen is rendering?  The best way to do that is by clicking the “Report a Bug” link at the top of this page.  Please make sure to mention my name (Joshua Quick) and reference this forum thread in your bug description so that our tech-support team can send it my way.  I’ll look into this as soon as I can.

@Joshua,

I’ll see if I can get you the small project example.

Another interesting point is that this glitch only happens on some of the screens, others it does not.

Glitch screens:

* Main menu scene

* Select tutorial scene

* Puzzle tutorial screen 2 scene

* Classic tutorial screen 1 scene

* Classic tutorial screen 2 scene

* Select Mode scene

Non-glitch screens:

* Splash screen scene

* Settings overlay

* Select difficulty scene

* Classic tutorial screen 3 scene

* Puzzle tutorial screen 1 scene

* Puzzle tutorial screen 3 scene

* Game play scene

* Paused overlay

* Quit “Are you sure” overlay

As I examine this list no pattern really jumps out at me… I can’t really see why one tutorial scene would have the glitch and another would not. They are basically copies of each other with the tutorial graphic switched. Odd indeed.

Well, if you’re willing to send us your entire app project, then I’d be willing to run it through the debugger on our end to find this issue.  That is, if you’re willing to send us your entire project (I can understand if you don’t).  If you are interested, then see about contacting David to do so, because I’m sure your project is likely too big to send via a bug report.

@Joshua,

Thank you very much for offering to debug the app! I’m sure wading through somebody else’s code is no fun so I appreciate it.

However, in this case it won’t be necessary because I have managed to create a small project that exhibits the glitch. I’ve traced it down to a single line that when commented out will erase the glitch. It’s marked in the “scene_mainMenu.lua” file with the text “@Joshua” so you should be able to find it. I’m sending in the project via the bug reporting tool you referenced earlier so you should be getting the code soon.

In case you are so curious you don’t want to wait, the line is:

storyboard.removeAll()

Please let me know if I’m using that code in a bad way :slight_smile:

Even better!  I’ll have a look at the project that you submitted tomorrow.  Thanks for taking the time into putting it together.

I just wanted to note that I use storyboard.removeAll() quite a lot (between each round of the game), so it could well be the cause of the similar sprite glitches I saw on WP8… Nice work @spacewolf.

spacewolf, hgbrian,

I was able to reproduce this graphics glitch issue with our old Storyboard sample project that we used to include with the Corona Simulator.   Interestingly enough, composer doesn’t have this problem, but I don’t really believe that this is actually storyboard’s fault.  I’m thinking storyboard is hitting some kind of edge case that is causing this graphics glitch issue on WP8.  So, I’m a little worried that something else might be the cause.  The hunt continues.  I’ll let you 2 know when I’ve found a solution.

Note that I’m pretty sure the OmNomster app uses storyboard as well.  The difference is that app is not using display.newText() anywhere.  The developer completely switched to bitmap fonts.  So, if you need a quick fix (because I’m not sure what the fix is on my end yet), then replacing your display.newText() calls with bitmap font may solve this issue for you now.

@Joshua,

Hmm interesting. Is it a big switch to go from storyboard to composer apis?

Also, my app doesn’t have any display.newText() calls in it anywhere already. I also don’t use the corona widget buttons in them either so there are no display.newText() calls from those too. Maybe there is something else the OmNomster app does different?

It depends on how many scene’s you have.  The conversion of a single scene isn’t that complex and if you’re not using willEnterScene() and didExitScene() it will be easier.  The biggest difference is that those two functions are now handled as “phases” in the replacement for enterScene (scene:show() ) and exitScene (scene:hide() ).

Rob

Honestly, maybe you shouldn’t switch to composer then.  Especially since I haven’t discovered the root cause of this issue yet.  I’d hate for you to put in that kind of effort and get zero return from it… other than getting rid of our deprecated storyboard API I suppose.

Sounds good I’ll hold off on major changes like that for now :slight_smile:

I have converted a game from storyboard to composer before and it’s really quite easy. I’m just generally afraid of messing with stuff like that if I can help it, so I’ll hold off for now. 

I’m not sure why removing newText would help though? That would be a much bigger job for me than switching to composer.