example of spritesheet font

just a quick example of how to use a font spritesheet, needs making into relevant functions/module etc

fonts are from:
http://www.spicypixel.net/2008/01/16/fontpack-royalty-free-bitmap-fonts/
http://www.spicypixel.net/download-manager.php?id=4
[lua]require(“sprite”)

display.setStatusBar( display.HiddenStatusBar )

– note your font sprite sheet needs to be <= 1024 x 1024
local fontpng = “kromagrad_16x16.png”
local fontpng = “geebeeyay_8x16.png”

– define alphabet for image
local alphabet = " !“c#%~’()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ

– get image details
local imgpng = display.newImage(fontpng,0,0,true)
local imageWidth = imgpng.width
local imageHeight = imgpng.height
imgpng:removeSelf()

– find dimensions of characters (format *must* be name_WxH.png in this case)
local dashpos = string.find(fontpng, “_”)
local size = string.sub(fontpng, dashpos+1, string.len(fontpng)-4)
local xpos = string.find(size, “x”)
local frameWidth = string.sub(size, 1,xpos-1)
local frameHeight = string.sub(size, xpos+1, string.len(size))

– work out number of letters from dimensions
local NUM_LETTERS = math.floor(imageWidth/frameWidth) * math.floor(imageHeight/frameHeight)

– make a spritesheet of these letters
local spritesheet = sprite.newSpriteSheet(fontpng,frameWidth,frameHeight)
local spriteset = sprite.newSpriteSet(spritesheet,1,NUM_LETTERS)

– return a sprite for a given letter
function getLetter(l)

local letterpos = string.find(alphabet,l)
local lettersprite = sprite.newSprite(spriteset,1)
lettersprite:setReferencePoint(display.TopLeftReferencePoint)
lettersprite.currentFrame = letterpos
return lettersprite

end

– start coordinate
local px=0
local py=0

– what we want to print
local sentence=“THE QUICK BROWN FOX JUMPED OVER THE LAZY DOG! SO THE DOG JUMPED UP AND BIT THE FOX!\n\n*****\n#####\n#####\n*****\n\nIT’S A FONT TEST!!”

– print out our sentence
– note i’ve not implemented word wrapping
– or variable width font sizes etc (which would need a data sheet for the sprite png)
for s=1, #sentence, 1 do

local letter = string.sub(sentence,s,s)

if(letter == “\n”) then – carriage return, jump back to next line

px = 0
py = py + frameHeight

else

local lettersprite = getLetter(letter)

lettersprite.x = px
lettersprite.y = py
px = px + frameWidth

end

if(px > 320-frameWidth) then

px=0
py = py + frameHeight

end

end[/lua] [import]uid: 6645 topic_id: 3680 reply_id: 303680[/import]

Thanks pal!

it’s terrific!
But if it can work as independent require file would be perfect!

[import]uid: 10373 topic_id: 3680 reply_id: 11243[/import]

sure it can. when you’ve finished making it post it back up here! :stuck_out_tongue:

first i’ll see if i can implement the greedy word wrap algorithm in it
http://en.wikipedia.org/wiki/Word_wrap

(note some of the bitmap font sheets in that zip are too big for corona to load, so don’t expect them to work)
how’s this for an API?

[lua]BMPFont = require(“BMPFont”)

– ******************************
– setup the font spritesheet etc
– ******************************
local bmpfont = BMPFont.setFont(“blah_8x8.png”) – will check filename for filename_WxH.ext format
local dimensions = bmpfont.getDimensions() – returns {w=8,h=8)
local w = dimensions.w
local h = dimensions.h

– or

local bmpfont = BMPFont.setFont(“blah.png”,8,8)
– bmpfont.setDimensions(8,8) – redundant?
– ******************************
– set the characters represented in the bitmap
– ******************************
bmpfont.alphabet = " ,.%*!1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
– ***********************************
– set the maximum width for each line
– ***********************************
bmpfont.printWidth = 100
– *************************
– print a sentence at 10,10
– *************************
bmpfont.print(“Hello World”,10,10)
– or
local text1 = bmpfont.print(“Hello World”)
text1.x = 10; text1.y = 10[/lua]

anything else? [import]uid: 6645 topic_id: 3680 reply_id: 11247[/import]

@jmp909

Nice work! Thanks for sharing…
Some extra things that come in my mind for such a module:

  1. All sprite-letters must be first created and populate a pool from which you would then draw instances that you need. Imagine drawing the fps with such a module: you don’t want to setup new sprites at each frame (even if you have the spritesheet loaded in memory) !

  2. Support of different font images (sets) within a spritesheet. This way you will loose the info you get from the individual images (width, number of letters etc) but you can replace this information by registering your fonts arsenal inside a table manually (normally you wont use more than 3-4 fonts, so it’s ok).

  3. Wrap functionality, as you also mentioned.

  4. Visual effects with transitions and physics! You can do brilliant things with some sprites in a group…
    I am definitely going to work on these things when finding the time (other infrastructures have priority now for me).

Thanks again for sharing… [import]uid: 7356 topic_id: 3680 reply_id: 11268[/import]

  1. good point. hadn’t throught of that. I’ll have a think about it. so presumably the print function would return a display group but expose a function to change each character later

it gets more complicated (but not really that complicated) when you want to change the string to a different length as it’ll presumably want to change some characters and add/delete others.

  1. will leave this to a later date but good point

  2. shouldn;t be too difficult to add the algorithm from the wiki

  3. once there is access to the characters (see point 1) this can be done with a different modules

feel free to suggest public API functions/structures that would help

thanks
j
[import]uid: 6645 topic_id: 3680 reply_id: 11271[/import]

  1. Nope. You may need to return a group for point 4 but not for point 1. Your function can simply get copies of your 24 (already made) sprites and place them in appropriate position, as you currently do in your code. We don’t mind about the length of the sentence here. The only difference is that instead of building new sprites on each letter() call, you copy them from a table in which you store all your sprite-letters at the beginning of the module. So in my fps example you would just moving around copies of existing sprites instead of building new ones.

In a more advanced level, you can make 10 or 100 "A"s and "B"s …"Z"s , store them in a 24*100 table and attach a “used” flag on each of them. So, you firstly check if there is some unused existing instance and if not you make an additional copy of the specific letter.

With the latter approach you just move around existing sprites. Not even make new copies each time…

The whole approach is named “sprite pooling” and is something like a best practice for manipulating multiple instances of sprites (commonly used for spawning bullets etc). [import]uid: 7356 topic_id: 3680 reply_id: 11273[/import]

hi

i understand the pooling process but i’ve not had chance to implement it yet.

I’ve created a sketch example class and implementation for people to play around with, which you can download from here:
http://www.sendspace.com/file/62lghb

Currently it just returns a display group of sprites. I think the way Corona Game Edtion potentially works is that it blits all the "newSprite"s at once in one enterframe period. I can’t say for sure though. Anyway I’ve not exposed access to the characters at the moment. If people want to take some of my ideas and expand on them that’d be great.

the basic code is
[lua]BMPFont = require(“BMPFont”)

– instantiate an instance of the “class”
local bmpfont = BMPFont.init()

– load a sprite sheet
–[[ note: spritesheets are cached so it doesnt really matter
how many times you call this/change this etc, it’ll only load
one of each PNG into memory.
I added some code to keep one table reference (indexed on filename)
per PNG using a static lookup table, but I think this is actually
redundant due to Corona’s resource management anyway --]]
bmpfont:setFont(“kromagrad_16x16.png”,16,16)

– set the alphabet for the spritesheet
–[[ currently you need to ensure you’re supplying the right
amount of characters. I’m not checking for it being too long
or too short --]]
bmpfont:setAlphabet(" !“c#%~’()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ”)
– define width to wrap text at.
–[[ Note: i haven’t implemented hyphenation, words longer than
the printWidth will render beyond it.
I have implemented word-wrapping though --]]
bmpfont.printWidth = 210

–[[ draw a debug square behind the text
so you can see the print width and where
it’s dividing up words --]]
bmpfont.debug=true

– finally create the display object
local text1 = bmpfont:make(“OK SO THIS KIND OF WORKS SO FAR! LET’S DO WORD WRAPPING - APART FROM SUPERLONGWORDS, IT’S OK!”)

– and just as an extra…
–[[ here we can remake a display object, deleting the
old display object (or any other in fact) and creating
a new one --]]
text1 = bmpfont:remake(text1, “SOME NEW TEXT”)[/lua]

In my sample code I’ve included some silly code that rotates/zooms one of the display groups etc. Just as a performance and memory test. Memory remains the same, FPS fluctuates to 29fps occasionally

I probably won’t work on it anymore for a while. Maybe if people can suggest API functions and example code that could be called on the class, then I could look at implementing those.

I was thinking for example

[lua]text1 = bmpfont:make( “a bunch of text”)

for i=1, #text1.chars, 1 do

local char = text1.chars[i]
– do some stuff to move it around in the display group

end[/lua]

oh and please excuse if my coding styles are messy, this is only my second week of learning Lua!
[import]uid: 6645 topic_id: 3680 reply_id: 11303[/import]

Thanks jmp909

i have mod your initial feat and put into class
https://sourceforge.net/projects/corona-ge-font/files/

you can have wrap feature on it

here the main.lua

[code]

bmpFontObj = require(“font”)
bmpFontObj.newBMPFont(‘geebeeyay_8x16.png’, 8, 16)
local msg = ‘PHP\n\nTo see the PHP configuration, you can watch the output of phpinfo.\nMySQL\n\nThe MySQL Database can be administrated with phpMyAdmin.\n\nTo connect to the MySQL Server from your own scripts use the following connection parameters:’
local msg_upper = string.upper (msg)

bmpFontObj.print(msg_upper, 20, 10, 300)

print(‘endx’)
[/code] [import]uid: 10373 topic_id: 3680 reply_id: 11308[/import]

actually if you go into BMPFont:make and change [lua]self.sprites[s] = sprite.newSprite(spriteset)
local sp = self.sprites[s][/lua] to [lua]self.sprites[#self.sprites+1] = sprite.newSprite(spriteset)
local sp = self.sprites[#self.sprites][/lua] and change the last return line in that function to [lua]g.sprites = self.sprites
return g[/lua] you then have access to every character eg [lua]for i=1, #text4.sprites, 1 do
print(i, text4.sprites[i])
text4.sprites[i].currentFrame=10
end[/lua]
note i didnt render the spaces as characters (first blank square in the spritesheet) and probably should have done so they could be changed

[import]uid: 6645 topic_id: 3680 reply_id: 11306[/import]

i made a slight change to my classes. “sprites” was at a class level not a display instance level.

i’ve now modified it so you can access individual sprites per display object… eg like this
http://www.sendspace.com/file/p6qfdg

(update class in zip together with main.lua code below)

[lua]display.setStatusBar( display.HiddenStatusBar )
BMPFont = require(“BMPFont”)

local alphabet1 = " !“c#%~’()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ”;

local bmpfont = BMPFont.init()

bmpfont:setFont(“kromagrad_16x16.png”,16,16)
bmpfont:setAlphabet(alphabet1)
bmpfont.printWidth = 210
local myclock = bmpfont:make(“HH:MM:SS”,100,180)

bmpfont:setFont(“geebeeyay_8x16.png”, 8,16)
local otherclock = bmpfont:make(“HH:MM:SS”,10,10)

local clocktype = 1

local sf = string.find
local ss = string.sub
function updateClocks(event)

local t = os.date("*t");
local secs = string.sub(100+t.sec,2,3)
local mins = string.sub(100+t.min,2,3)
local hour = string.sub(100+t.hour,2,3)

– change the clock graphics!
– note obj:remake deletes the old display obj (removeSelf)
– and creates a new one

if(secs == “30” and clocktype~=2) then
clocktype=2
bmpfont:setFont(“geebeeyay_8x16.png”, 8,16)
myclock = bmpfont:remake(myclock, “HH:MM:SS”)

elseif(secs==“00” and clocktype~=1) then
clocktype=1
bmpfont:setFont(“kromagrad_16x16.png”,16,16)
myclock = bmpfont:remake(myclock, “HH:MM:SS”)
end

setClock(myclock, hour, mins, secs)

setClock(otherclock, hour, mins, secs)

end

function setClock(theclock, h, m, s)

local a = alphabet1

– HH
theclock.sprites[1].currentFrame=sf(a, ss(h,1,1))
theclock.sprites[2].currentFrame=sf(a, ss(h,2,2))
– MM
theclock.sprites[4].currentFrame=sf(a, ss(m,1,1))
theclock.sprites[5].currentFrame=sf(a, ss(m,2,2))
– SS
theclock.sprites[7].currentFrame=sf(a, ss(s,1,1))
theclock.sprites[8].currentFrame=sf(a, ss(s,2,2))

end

Runtime:addEventListener(“enterFrame”, updateClocks)
local fps = require(“fps”)
local performance = fps.PerformanceOutput.new();
performance.group.x, performance.group.y = display.contentWidth - 120, 420;
performance.alpha = 0.6; [/lua]

ok i know i should have better helper functions in my class for that and it should be better optimized and pooling sprites but it was just a quick example that works:)
[import]uid: 6645 topic_id: 3680 reply_id: 11311[/import]

wellies check out my latest, slightly more complicated example. it uses the word wrapping algorithm plus does line breaks (\n) correctly.

what it doesn’t do is intelligently wrap at hyphens in words. this is something that will need looking at… anyone like to volunteer!!?

it looks like this now… :slight_smile:

[import]uid: 6645 topic_id: 3680 reply_id: 11315[/import]

I hav found some standard font in
http://www.dafont.com/bitmap.php

But I wonder how to use them with special char like @&$)!..

Thank for the advice [import]uid: 10373 topic_id: 3680 reply_id: 16341[/import]

those are bitmap-style fonts, not bitmap fonts in the sense I have used them. my bitmap fonts are sprites. they can be multicolored etc… they are just graphics. the ones you have linked to are standard pc/mac font files

however the same problem exists in either case. the special characters needs to be in the character set in the first place in order to display it

check this anyway if you want to the fonts off your link in your app
http://developer.anscamobile.com/forum/2010/09/30/embedding-custom-fonts
[import]uid: 6645 topic_id: 3680 reply_id: 16345[/import]

Hey jmp909!

Awesome thread! I’ll try to implement your work and see if I can help on anything.

Cheers! [import]uid: 11130 topic_id: 3680 reply_id: 16391[/import]

@jmp909

That font reminds me of my old Amiga days.

Love it [import]uid: 5354 topic_id: 3680 reply_id: 17256[/import]

woah check out “TextCandy” from x-pressive!

http://www.youtube.com/watch?v=AjrWRWc0ivg [import]uid: 6645 topic_id: 3680 reply_id: 20367[/import]

Mike scores again! [import]uid: 9371 topic_id: 3680 reply_id: 20376[/import]

Damn, this is the best thing since Particle Candy! Where is it? The YouTube video is a month old, is the API out? I went to X-PRESSIVE.COM and I don’t see anything there, unless I’m blind.

Update:

Well, a little playing around with the URL and I found it on their site:

Change:
http://x-pressive.com/ParticleCandy_Corona/index.html

To:
http://x-pressive.com/TextCandy_Corona/index.html

And, it’s in beta right now. I hope it comes out soon, I’d love to play around with it! [import]uid: 6084 topic_id: 3680 reply_id: 23678[/import]

Sorry for digging up an old thread.

Has anybody tested textcandy and is it faster than editing a normal textfield or the code from jmp909?

I’m working on a little game with 4 textfields on my screen, which are changing very often. Unfortunately this causes some framedrops and so I’m looking for a way to optimize my code.

Textcandy looks awesome but the main reason why I’m interested in it is because I hope it is faster than editing normal textfields. Can anybody approve this?

Or is it better when I use jmp909 code and add some stuff like sprite pooling? [import]uid: 10820 topic_id: 3680 reply_id: 41579[/import]

I second this question. Has anyone worked with both of the modules?
I am especially interested in loading times for several textfields.

Thanks [import]uid: 7356 topic_id: 3680 reply_id: 41662[/import]