Second shot down. Slices looking good. What shall we do today?

Got my second C-19 shot today, 25 minutes in and out, including the 15 minute wait to see if I went into shock. I guess I didn’t. Half hour drive to and from the place. Now back to days like all the other days for the past year or so. Fortunately, as an introvert, I don’t much mind it.

What shall we do today? I guess we should push forward a bit with the Slices and SpriteSheet stuff. I think my general plan will be to have a new standard way of calling the sprite internal function, namely to refer the input value to the Slices object, which will translate it or return it as is.

To make a test bed for that, let’s do this:

  • Import some potion bottle slices, or something like that;
  • Set the strength and speed power-ups to use those new images.

That should be pretty simple, as things go. (Famous last words, second only to “hold my beer”.)

Let’s remind ourselves where we are. It has been literally hours since I worked on this, and I like to leave all my thinking in the program and these articles, to save room in my head for other matters. Or wind.

We have this class:

Sprites = class()

function Sprites:init()
    self.sprites = {}
end

function Sprites:add(names, sheet, xSkipLow, xSkipHigh, ySkipLow, ySkipHigh)
    local ss = SpriteSheet(sheet, #names, xSkipLow, xSkipHigh, ySkipLow, ySkipHigh)
    for i,name in ipairs(names) do
        if name ~= "" then
            self.sprites[name] = ss:slice(i)
        end
    end
end

function Sprites:sprite(name)
    return self.sprites[name]
end

At this point, we would need a place to instantiate Sprites and use it. Let’s swap things around, so that we can just call it with the class name.

If we’re going to do that, then this test:

        _:test("Sprites lookup", function()
            local testss = SS(sheet, 12, 1,0, 0,1)
            local names = {"crossed", "green_staff", "feather_staff",
            "purple_staff", "snake_staff", "cudgel_staff", "skull_staff",
            "bird_staff", "jewel_staff", "knob_staff", "crystal_staff", "twist_staff"}
            _:expect(#names).is(12)
            local sp = Sprites()
            sp:add(names, sheet, 1,0, 0,1)
            local eq = areImagesEqual(sp:sprite("green_staff"), testss:slice(2))
            _:expect(eq).is(true)
        end)

Needs to be:

        _:test("Sprites lookup", function()
            local testss = SS(sheet, 12, 1,0, 0,1)
            local names = {"crossed", "green_staff", "feather_staff",
            "purple_staff", "snake_staff", "cudgel_staff", "skull_staff",
            "bird_staff", "jewel_staff", "knob_staff", "crystal_staff", "twist_staff"}
            _:expect(#names).is(12)
            Sprites:add(names, sheet, 1,0, 0,1)
            local eq = areImagesEqual(Sprites:sprite("green_staff"), testss:slice(2))
            _:expect(eq).is(true)
        end)

And the implementation:

Sprites = class()

local sprites = {}

function Sprites:init()
    assert(false, "No need to make an instance")
end

function Sprites:add(names, sheet, xSkipLow, xSkipHigh, ySkipLow, ySkipHigh)
    local ss = SpriteSheet(sheet, #names, xSkipLow, xSkipHigh, ySkipLow, ySkipHigh)
    for i,name in ipairs(names) do
        if name ~= "" then
            sprites[name] = ss:slice(i)
        end
    end
end

function Sprites:sprite(name)
    return sprites[name]
end

I expect the tests to run. Curiously enough, they do.

We do need to initialize some slices. Let’s do that as part of GameRunner init.

function GameRunner:init()
    self.tileSize = 64
    self.tileCountX = 85 -- if these change, zoomed-out scale 
    self.tileCountY = 64 -- may also need to be changed.
    self.cofloater = Floater(self, 50,25,4)
    self.musicPlayer = MonsterPlayer(self)
    self:initializeSprites()
    self.dungeonLevel = 0
    self.requestNewLevel = false
    self.playerRoom = 1
end

I’ll copy the init from the test, and add some more from other images that I’ll move over.

function GameRunner:initializeSprites()
    local names
    local sheet
    sheet = asset.gear_staffs_2
    names = {"crossed", "green_staff", "feather_staff",
    "purple_staff", "snake_staff", "cudgel_staff", "skull_staff",
    "bird_staff", "jewel_staff", "knob_staff", "crystal_staff", "twist_staff"}
    Sprites:add(names, sheet, 1,0, 0,1)
    sheet = asset.items_health
    names = { "blue_pack", "red_pack", "green_pack",
    "blue_bottle", "red_bottle", "green_bottle",
    "blue_flask", "red_flask", "green_flask",
    "blue_jar", "red_jar", "green_jar",
    "", "", "",
    "copper_bag","gold_bag","","","","","",
    "silver_bag"}
    assert(#names==23, "bad count for bottles and jars")
    Sprites:add(names, sheet, 1,0, 0,1)
end

Now Sprites should know those names. Let’s look at the Loots and fix them up.

local LootIcons = {Strength=asset.builtin.Planet_Cute.Gem_Blue, Health=asset.builtin.Planet_Cute.Heart, Speed=asset.builtin.Planet_Cute.Star}

I’ll start by making them all items from the health asset, so I don’t have to build the trick stuff in yet.

local LootIcons = {Strength="blue_pack", Health="red_flask", Speed="green_jar"}

Now to fix the draw:

function Loot:draw()
    pushStyle()
    spriteMode(CENTER)
    local g = self.tile:graphicCenter()
    sprite(Sprites:sprite(self.icon),g.x,g.y+10)
    popStyle()
end

That works as advertised:

icons

I think I’ll leave the attribute sheet icons alone, though we might as well remove them, as they are not very meaningful.

Now I want to change the sprite method to return an asset (a userdata, or anything other than a string) directly, and only look up strings.

Let’s write a test for it.

        _:test("assets pass through", function()
            local testss = SS(sheet, 12, 1,0, 0,1)
            local names = {"crossed", "green_staff", "feather_staff",
            "purple_staff", "snake_staff", "cudgel_staff", "skull_staff",
            "bird_staff", "jewel_staff", "knob_staff", "crystal_staff", "twist_staff"}
            Sprites:add(names, sheet, 1,0, 0,1)
            local a = Sprites:sprite(asset.air006)
            _:expect(a).is(asset.air006)
        end)

As expected, test fails:

5: assets pass through  -- Actual: nil, Expected: Asset Key: air006.png (path: "/private/var/mobile/Containers/Data/Application/483B2209-7216-46A0-8C24-5253968FCBE5/Documents/D2.codea/air006.png")

Implementing:

function Sprites:sprite(name)
    if type(name) == "string" then
        return sprites[name]
    else
        return name
    end
end

We’re good to go. Test runs, game runs. Enough for the morning.

Commit: new SpriteSheet icons for Loots, more assets moved.

Summary

This went nicely. The little Sprites object is easy to use in game play, and not too much of a pain to set up i initialization. You just provide a sheet, some names, and a couple of offsets if the artist left lines in their sheet. Snip snip, slice slice, and Bob’s your uncle.

Tomorrow, if I’m not reacting too badly, to the Pfizer, we’ll do something else. See you then!


D2.zip