From image sprite to ingame assets - how to?

(Filipe Madureira) #1

Hello,

i know this has already been asked plenty of times, but not extensively and i still feel lost.

I found some sprites online which i want to use in my game: i have some png images which represent the animated frames of my sprite, this is the sprite i’m talking about: https://opengameart.org/content/cat-sprites (i extracted the single frames from the walking-cat gif with this online tool).

Now, as I understood from some tutorials I’ve read, I need to convert this image into an array of bytes represented by hexadecimal values to be able to draw it using the “Sprites” library:

Sprites sprites;


const byte PROGMEM cat_waking_1[] = {

  18, 21,

  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xFE, 0xFF, 0xFB, 0xFF, 0xFF, 0xBF, 0xBF, 0x3F, 0x3E,

  0x3F, 0x7C, 0xF8, 0xF0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF, 
  0xFF, 0xFF, 0x7F, 0x3F, 0x04, 0x0C, 0x00, 0x00, 0x00,

  0x00, 0x00, 0x00, 0x01, 0x1F, 0x17, 0x03, 0x01, 0x03, 
  0x1F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

};

sprites.drawOverwrite(0, 0, cat_waking_1, 0); // x position, y position, sprite, frame number

Now i’m kinda lost - how do i convert my image into a bytes array, with a specific size (i tried this tool but it fills the whole screen and i only need a sprite to animate moving around!)? This is the example image i’m trying to use 2s

EDIT: this tool also looks interesting, but why is it using an array of chars instead of bytes?

0 Likes

(Thomas) #2

How large in pixels are the original sprites you want to use since the display on the arduboy is monochrome you wont be able to display the colour in that cat sprite.

Also what part are you stuck on the displaying of the sprite or animation?

0 Likes

(Filipe Madureira) #3

I am a total noob, and i’m trying to learn while doing this. I’m not sure how the image-ratio to pixels in the arduboy screen works

These are the files i’m trying to use, there are 3 different sizes (source):
catspritesoriginal catspritesx2 catspritesx4

I basically want this animation (converted in monochrome etc) on my arduboy:catwalkx2

I want to convert them into monochrome images and create an animated sprite, this is an example i was trying to use just for testing but i can’t manage to convert it properly:
catwalking1_47x40

I don’t understand how to set up my files properly to be used with tools such as https://teamarg.github.io/arduboy-image-converter/ and https://teamarg.github.io/arduboy-sprite-converter/

0 Likes

(Pharap) #4

If you open a .gif in GIMP, each frame is treated as a separate layer.

Technically it doesn’t have to be represented with hexadecimal,
but most programmers find hex codes easier to work with for bit patterns.

C++ doesn’t actually have ‘bytes’ as such.
The char datatype is the closest you can get to a ‘byte’.
byte is actually a non-standard type alias introduced by Arduino.h, and it’s actually an alias for uint8_t, which is in turn just an alias for unsigned char.

So basically unsigned char, uint8_t and byte will all do the same thing on Arduboy,
though that may not be true on other platforms.

That image isn’t black and white, it’s got grey pixels, a purple pixel, and two blue pixels.

Some converters will automatically try to convert the colour using some property of the colour (e.g. hue, luminance, average), but it’s better to convert it yourself to be sure.

E.g.
BlackCat

Team ARG’s image editor gives you the image in a format suitable for the Sprites class.

Andrew Lowndes’s tool only gives you the raw data.
You need to manually add the variable definition, and if you’re planning to use it with Sprites then you have to manually add the width and height at the start.


The format for Sprites is:

const unsigned char name[] PROGMEM =
{
// Width, Height,
72, 60,

// Frame 0
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 
0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 
0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 

// Frame 1
// data for frame 1

// Frame 2
// data for frame 2, et cetera
};

I don’t know of any tool that will automatically convert a gif to a Sprites-suitable array.
(I was planning to make something like that at one point but never got round to it.)

You’d have to strip the image up into frames and convert them individually I think.

Bear in mind that you don’t have much memory to work with though.
That animation is 17 frames of 36x30, which is (((36 * 30) / 8) * 17) = 2295 bytes total, which eats up a large chunk of progmem.

0 Likes

(Filipe Madureira) #5

Technically it doesn’t have to be represented with hexadecimal,
but most programmers find hex codes easier to work with for bit patterns.

I’m still baffled by this, because i thought the OLED display simply needed boolean values for each pixel, i guess i’ll have to dig deeper on how all of this works and why i need those values for representing an image.

That image isn’t black and white, it’s got grey pixels, a purple pixel, and two blue pixels.

Correct, and also, the online converters wanted me to specify the exact height (which must be multiples of 8) and i didn’t, i guess that’s one reason why it didn’t work as expected.

I don’t know of any tool that will automatically convert a gif to an Sprites -suitable array.

I ended up creating a vertical spritesheet to use with this tool https://teamarg.github.io/arduboy-sprite-converter/ .

Again, I’m kinda confused on all the shaders/alpha channel stuff, I’ll have to read more about it: i plan on using a static background where the sprite will walk over so i really need to start understanding how all of this works.

Bear in mind that you don’t have much memory to work with though.
That animation is 17 frames of 36x30, which is (((36 * 30) / 8) * 17) = 2295 bytes total, which eats up a large chunk of progmem.

Having a “web” background I never bothered micromanaging resources, this is also another factor I’m new at. I guess there are methods to save as much memory as possible?

Anyways thank you so much for the info! Really insightful, I’ll post my result later this evening for feedback

1 Like

(Pharap) #6

Not exactly.

The OLED (technically the chip in the OLED that actually drives the screen) uses 1 bit per pixel, with a 0 bit representing black (off) and a 1 bit representing white (on).

It’s true that those values can be thought of as boolean values (e.g. true (1) and false (0)),
but in C++ a bool isn’t a single bit, it can be any number of bits (in the Arduboy’s case I think it’s 8 bits),
and while boolean values are actually implemented using integers,
they should generally be thought of as something different.
(Sort of like the idea that “the map is not the territory”, but that might be getting a bit too meta.)

No need, it can be summed up in a single image:
122aae02ad9e5ec21319b177889378bb2f73c03a

This image was made long ago by @emutyworks and I’m forever reposting it because it’s really useful.
It shows the relationship between the values actually stored in the code and how those values are used by the screen.

Of course, to understand it you first need to understand hexadecimal and binary.
In case you don’t there’s an excellent explanation here:
https://www.mathsisfun.com/binary-decimal-hexadecimal.html

The Arduboy doesn’t use shaders or alpha channels.

Shaders are something GPUs use for rendering, so you don’t need to know about those unless you’re developing for a system with a GPU.
(Mainly desktops, most laptops and I suppose technically even some phones these days.)

Likewise, alpha channels will only be found on more powerful systems like laptops and phones.
(Generally those are pretty easy though. The only difficult part about alpha channels is premultiplied alpha vs non-premultiplied alpha and the different techniques for combining images using alpha channels.)

The Arduboy uses masking for transparency.
To properly understand how it works you need to understand bitwise operations,
but you don’t have to understand how it works to actually use it, because making masks is pretty simple.

To make a mask for an image you just have to fill transparent areas in black and non-transparent areas in white.
E.g.
Image: BlackCat Mask: 724a2167c1df0fd3d3755b4a5f3e568828572f51
(Note that I filled in the area where the eye and ear will be, but not the gap between the legs.)

There are, but which ones will be most beneficial will depend on the circumstances of the code in question.

E.g. if the code uses a lot of switch statements, some could be formed into lookup tables or rewritten to move expensive computations to before the switch.


A few notes about how the forums ‘work’ (technically speaking):

If you highlight text in someone’s post a little Quote marker will appear.
If you click on it then it will insert that quote into your post in a way that notifies the person you quoted.

Similarly replying to a specific post will notify the person you’re replying to, as well specifically mentioning that person using the ‘@’ symbol.
E.g. @Fieel (notice a grey box forms around the text)

Also the forum uses Markdown:

(We really must remember to find a way to give new users a tutorial on forum usage.)

0 Likes

(Scott) #7

But note that this is only the default behaviour. A user can set their preferences to change or suppress how and/or when they are notified.

0 Likes