[DevLog][Cute&Demake] Milkshake

DevLog 1

Posting here as reservation for the idea. Right now this is plan A for a small and easy project

I’ll try to use some animations found on the web and adapting to the small footprint of Pokitto.
Thanksgiving to @FManga that already helped figure out some unexpected behavior of LibHotSwap

7 Likes

DevLog 2

Little progress so far, but the thing should be doable. Another big thanks to @FManga that find a solution to allow use LibHotSwap even with big piece of data like mine.
In the video I’ve use async loading but sync loading is faster and so I my opt for that with some text.

8 Likes

I love it already, can’t wait to explode some bunnies! :rofl:

Maybe we should make the async loading speed adjustable? Right now it loads just a little each frame so as to not impact the FPS too much.

3 Likes

I am so loving it!! :+1:

2 Likes

An optional parameter “bytes per loop” could be?
I’m not sure how the async hook is working in the lib.

DevLog 3

@FManga implements a way to give priority to LibHotswap:

if (nextHook) return true;
nextHook = Pokitto::Core::updateHook;
Pokitto::Core::updateHook =
    +[](bool isFrame){
        if (isFrame) {
            for (int i = 0; i < _priority; ++i) {
                if (file && !loadPage(*file, page++)){
                    delete file;
                    file = nullptr;
                    onCompleteCB(swapData);
                    break;
                }
            }
        }
        nextHook(isFrame);
    };       

So now I can fine tune the loading different animations.
Moving data from SD to flash it’s a complex task, as the flashing mechanism for LPC11u68 is not documented.

At last always @FManga help me fix a nasty load problem by changing the aligned attribute for swap data, rising the sector from 4Kb to 32Kb. The animation used are quite big (up to 52 Kb each) and probably data was copied on some protected area/sector (this my feelings as I didn’t dig too much in the problem). Ensuring an alignment of 32 Kb fix corrupted animation but rise the swap data consumption up to 128 Kb (64 * 2) of precious flash.

This, together with some other images and assets, was really near to the maximum allowed for a bin size.
A little trick come to help, by changing the compiler option from -O3 to a less speed optimized -Os save a decent amount of space for make some real game. Now with sounds too :smiley:

MilkShake.bin.2

Still need to find a way to create a good background with low mem usage.

7 Likes

This looks very cute and i am sure it is going to be something to play again and again like a G&W title

1 Like

Devlog 4

Thanks our usual benevolent benefactor, now the game can load images from sd.
That’s a big help for intro screen, especially when flash space is low:

ccc

6 Likes

Looking great! I may have to play around with loading the splash from disk too. That seems like a great idea for saving some room.

3 Likes

Yesterday I forgot to post the relevant code part (not for you @torbuntu the lonely Java user :grin:)

Image can be converted from within FemtoIde, just right click on any image and choose Conversion…

image

The important option here is the Output binary that must be checked.

This will task FemtoIde to build the image and generate as a new file with the format i8

image

BTW the format was wrongly included in the file format processed for cpp image conversion, so ensure you’re using latest FemtoIde with this fix:

Remember to flag the file as Copy to SD if you plan to test this in the emulator. And actually copy it to the sd card of ypur Pokitto when testing on hardware… yes it happens to me…

And last a snippet of code that read from a path and trow the image to the screen.

//Method to load images from file in TAS mode
 static void LoadImage(const char * img) {
        File file;
        file.openRO(img);
        for (int i = 0; i < 176; ++i) {
            unsigned char buffer[220];
            file.read(buffer);
            flushLine(PD::paletteptr, buffer);  //flush the line to screen and increment line index
        };
    };

Hope this can help someone else to improve their jam entry, or any other game out there.

4 Likes

Quite tempted to poke around at this in Javitto to see what happens :eyes:

1 Like

Is this a custom function you have?

Nope is in Pokitto Lib PokittoLib/flushLine.s at eccc83644e0f499ba3e88a858c29d76bf4dbe4a1 · pokitto/PokittoLib · GitHub

See the holy writes!

# flushLine.s by FManga
# This code is from the PokittoLib and is therefore under the BSD License.

.thumb
.syntax unified
.global flushLine

# void flushLine(uint16_t* PALETTE asm("r0"), uint8_t* SCRBUF asm("r1"))
.func flushLine
PALETTE .req r0
SCRBUF .req r1

# locals
LCD .req r2
WRBIT .req r3
COLOR .req r4
TMP .req r5
CLR .req r6
END .req r7

.macro UNROLL
    lsls TMP, 1
    ldrh TMP, [PALETTE, TMP]
    lsls TMP, 3
    str TMP, [LCD]
    str WRBIT, [LCD, CLR]
    lsrs COLOR, 8
    uxtb TMP, COLOR
    str WRBIT, [LCD, 124]
.endm

flushLine:
    push {r4-r7, lr}
    ldr LCD,   =0xA0002188
    ldr WRBIT, =1<<12
    ldr CLR,   =252
    ldr END, =220
    adds END, SCRBUF
    
    ldm SCRBUF!, {COLOR}
    loop:

        uxtb TMP, COLOR
        UNROLL
        UNROLL

        lsls TMP, 1
        ldrh TMP, [PALETTE, TMP]
        lsls TMP, 3
        str TMP, [LCD]
        str WRBIT, [LCD, CLR]
        lsrs COLOR, 8
        lsls COLOR, 1
        ldrh TMP, [PALETTE, COLOR]
        str WRBIT, [LCD, 124]
    
        lsls TMP, 3
        str TMP, [LCD]
        str WRBIT, [LCD, CLR]
        cmp SCRBUF, END   
        ldm SCRBUF!, {COLOR}
        str WRBIT, [LCD, 124]

    bne loop

    pop {r4-r7, pc}
    
.pool
.endfunc
1 Like

Thanks for pointing that out! I can probably… do something with this :eyes: in Javitto… hehehe

1 Like

Devlog 5

When it comes the need to organize your code, but you mostly use static methods in your project, it may happens it turns out in an swarming cup of if or switch and duplicated methods call.

Here it come some more interesting code my best pusher (you know who) turn out of the hat:

Let’s suppose you organize something in this way:

class StateIntro {
    public:
    static void init() {  }
    static void update() {  }
};

class StateGame {
    public:
    static void init() { }
    static void update() {  }
};

Now if you add this little piece of magic…

#pragma once

namespace StateMachine {    
    namespace {
        inline void (*Init)() = +[]{};
    }    
    inline void (*Update)() = +[]{};    
    template <class Class> void setState(){
        Update = +[]{
            Update = Class::Update;
            Init();
            Update();
        };
        Init = Class::Init;
    }      
}

You can just call the state you need in this way

void init() {
 StateMachine::setState<StateIntro >();
}

void update(){
  StateMachine::Update(); 
  StateMachine::Draw(); 

  // if something (a butto, a time out) require to change the active state, it's enough to call
  // StateMachine::setState<StateIWantToActivate>();
  // and the Init will be call followed by respective Update method
}

setState will probably be call inside one of the various stateClass and will take care also to call its relative init().

This snippet really helps me to have better code and focus on some details of the gameplay like high score, ending and some minimal GUI.

image

7 Likes

Shouldn’t setState also be calling init?
Or is there some practical reason why it’s delayed?

It’s nice to see someone embracing templates at least.
It’s also quite rare to see an anonymous namespace being used.
(I can’t deny though, this sort of code is undoubtedly going to be very cryptic for people who don’t know C++ incredibly well…)

(If anyone who doesn’t know what an anonymous namespace is and wants to know: have a read of this.)

2 Likes

The idea is to avoid having two states conflicting with each other. You can call setState at any point and not have to worry about the current state becoming inconsistent (the next state’s Init deleting something used by the previous state) while it’s still being executed. It also ensures Init is only called once per state transition, even if you call setState multiple times.

1 Like

Fair enough.

Devlog 6

Time for release!

It has been a funny experience and it make me discover new things till the end… at the moment of creating the pop file the bin was grow to 236 kb. Too much to handle also the loader in a safe way.

I’ve been carefully to check the size grow from the beginning as the two main characters animations were already quite huge and space was very tight. But something has happens towards the end and I had no idea of what it could be. No new sprites was added, no wave sounds, neither a copy of this famous video.

So I call my personal hotline with the Gran Pokitto Master and as request sent him the elf of my project. Elf is not a fantasy creature of the woods but some kind of gibberish binary file that is near to machine brain to track memory mapping in various stages of compilation. Using obscure divination the verdict was cruel: space is used by many little things and nothing is hidden using your flash. (terror in my mind) But try to avoid use float.
Float? Why am I using float anyway, could be that little fancy color animation in some text that cycle trough color using a sinusoidal increment?
It was that, and space dropped to 202 kb.

So as usual when I accomplish to finish a game, I have to thanks some people:

  • @FManga for great technical help, without really looking at my code but providing just the necessary knowledge and pointing me to the right path for my limited skills.
  • @Vampirics for early beta test with some nice feedback, and a sincere interest on my little attempts in the art of game creation.

My personal objective here was to complete a project (even a small one) to break a long succession of half finished ones. So I see this already with a personal win.

Please enjoy my entry for the game jam (and consider it targets a very young and few claims audience)

7 Likes