High score variable to graphics

Hi, so my game is progressing well. One of the last stages is the graphic scores to give it a real arcade feel.

So I’ve built a single sprite sheet image of numbers 0-9 and I’m using the mesh approach to create and isolate the graphic number as I have been for my game sprites - this is cool.

What I’m finding hard to theorise is how I take my global variable ‘score’ and break that down into units, tens, hundreds, thousands etc…

I imagine I take the score into an array and then break it character by character and assign a variable to each column. Is that right? And if so how do I seperate each part of the array?

Thanks,
the Major

@Majormorgan - len and let are just variable names - let was short for letter - was just being lazy (and also slightly confusing as your actually extracting a character which is a digit so a better variable name should have been chosen!) You don’t need to define them, but it’s probably best practice to do so and assign them a default value

thanks @west I try to define them as much as possible.

@Ignatz that almost worked. Your quotation marks were spot on. You just had the square brackets missing around each integer. So [“1”]=“One” etc… Now it works a dream!!!

I imagine that was your test to me to see if I could work it out :wink:

Thanks again! Game will launch by Monday I believe!

Ok so I think I’ve implemented this. It’s not working but it might be I’ve got it wrong.

Also there’s let and Len which I’m confused about. Do I need to define these and i in then main setup?

I’ve put it into a class which I’m calling in Main with

S:draw()

Here is the class

ScoreTime = class()

function ScoreTime:init()
    -- you can accept and set parameters here
    self.Num = {[0]="Documents:numZero", "Documents:numOne","Documents:numTwo","Documents:numThree","Documents:numFour","Documents:numFive","Documents:numSix","Documents:numSeven","Documents:numEight","Documents:numNine"}
        self.imgNum = readImage(Num)
end

function ScoreTime:draw()
    -- Codea does not automatically call this method
    score=score
    for i=1,string.len(score)do
        len=string.sub(score,i,i)
        sprite(self.imgNum[len],scalerX*50+i*20,scalerY*70)
    end
end

function ScoreTime:touched(touch)
    -- Codea does not automatically call this method
end

I meant to say that scalerX and scalerY are defined in the main and are percentages of WIDTH and HEIGHT of the display.

I also have in set up of main the definition of s as ScoreTime() so s is the instance.
score is also defined on the main

Thanks,
Rich

@Majormorgan - try this

ScoreTime = class()

function ScoreTime:init()
    --note how you have to set each of the ten key-value pairs in this case
    -- no need to put the Documents:num prefix on all of them
    -- we can do it later, below
    --check I have all the quotes correctly placed
    self.Num = {"0"="Zero","1"="One","2"="Two","3"="Three",
                      "4"="Four","5"="Five","6"="Six","7"="Seven",
                      "8"="Eight","9"="Nine"}
end

function ScoreTime:draw()
    for i=1,string.len(score)do
        local d=string.sub(score,i,i) --d contains a digit like "4"
        --now we add the Documents:num prefix to the number
        sprite("Documents:num"..self.Num[d],scalerX*50+i*20,scalerY*70)
    end
end

function ScoreTime:touched(touch)
    -- Codea does not automatically call this method
end

@Majormorgan - firstly, do you need to pre-draw the numbers at all? Codea has a lot of fonts built into it, and if you can use one of those, it will save you all this trouble.

If you want to use your spritesheet, I would save the images for 0 to 9 in a table, eg Num[“0”]=image0

Then when you draw your score, you simply peel off one number at a time and sprite the image, ie if the number is X, you sprite Num[X], so “5” would sprite Num[“5”], and so on.

@Majormorgan to split your score up, you could create a loop something along the lines of

highscore=12345
temp=highscore
for i=1,string.len(highscore) do
let=string.sub(temp,1,1)
--display the sprite associated with let
temp=string.sub(temp,2,string.len(temp))
end

Hi @ignatz it’s the peeling off of the numbers that’s causing me brainache.

Numbers 0 to 9 would be easy, but it’s the double digits that I’m having an issue with. As each number is in a column it’s taking each column and assigning it a number.

Or is it as easy as “score = Num[] + Num[] + Num []” say for a four digit score?

@west sorry my post crossed over. I’ll give that a go and deconstruct it so I understand it all! Thanks :wink:

@Majormorgan - I have taken the liberty of modifying West’s suggestion to make it a little easier for you. It assumes you’ve stored the images for digits 0 to 9 in a table called Num, eg Num[“5”] = image for number 5

highscore=12345  --a sample score
for i=1,string.len(highscore) do --loop through all chars
    let=string.sub(highscore,i,i) --pull off the i-th char
    --sprite char to the right of previous chars
    sprite(Num[let],400+i*20,300) --display char
end

@Ignatz and @West awesome job !!!

@Ignatz so the score is working out really well.

I’ve added a dollar character to the front of the amount to show the dollars you are collecting.

The only thing is as I add another number like the tens,hundreds and thousands column it no longer sits center.

ScoreTime = class()

function ScoreTime:init()
    --note how you have to set each of the ten key-value pairs in this case
    -- no need to put the Documents:num prefix on all of them
    -- we can do it later, below
    --check I have all the quotes correctly placed
    self.Num = {["0"]="Zero",["1"]="One",["2"]="Two",["3"]="Three",
                      ["4"]="Four",["5"]="Five",["6"]="Six",["7"]="Seven",
                      ["8"]="Eight",["9"]="Nine"}
    self.dollar = readImage("Documents:numDollar")
end

function ScoreTime:draw()
    for i=1,string.len(score)do
        local d=string.sub(score,i,i) --d contains a digit like "4"
        --now we add the Documents:num prefix to the number
        sprite("Documents:num"..self.Num[d],scalerX*30+i*scalerX*10,soy,scalerX*10,scalerY*20)
    end
    sprite(self.dollar,scalerX*30,soy,scalerX*10, scalerY*20)
end

function ScoreTime:touched(touch)
    -- Codea does not automatically call this method
end

I’ve currently got the graphic text to start at 30% of the screen width from the left. Ideally I’d like to put the whole thing and each time it adds a column of numbers (i) it re-centers the whole thing in the middle of the screen on the Y axis.

I’m thinking I code in an adjuster like i,i = scalerY40 then i,i,i =scalerY35 etc… Taking 5 off each time.

Or can I calculate the string width and then do maths around that to work out position?

Thanks
Major

@Majormorgan - you’ll have to figure out the starting (left) position from the length of the score, ie centre, less width of a char x half the number of chars

@Ignatz cool.

I’m thinking a small series of if statements like

if score <10 then --position code goes here
If score >10 and <100 then -- position code goes here

Etc…

Thanks! Major

Worked like a dream!

I was stuck earlier thinking I had to write code to interpret the string length when all I need to do was to check the value of score and write adjustments for the position of X based on singles, tens, hundreds and thousands.

Thanks for getting me out of the mud @Ignatz

@Majormorgan - even easier is…

-- if ...
w = 50          --width of one character
centre = 200 --centre position of score
score=12345   --sample score
-- then ...
leftX = centre - string.len(score)*w/2 --start drawing here