Firestarter (WIP and a couple questions...)

Kind of, but the y axis ends up representing both x and y because of the perspective that isometric rendering takes.

That’s exactly what you should do, and it should work.
If it isn’t working, you’ve probably either:

  • Written it incorrectly
  • Not given the images masks
  • Possibly both

Ah ok, I still havent given them masks, but I dont think thats the problem (just because im judging by the tiles on the edge since those should at least line up). Ill still fix that now to be sure though, just might take a second to make them in gimp and to figure out how to use them.

Also here’s my code:

      uint8_t thisTileHeight = getSpriteHeight(buildingSprite);

      // Draw the tile at the calculated position.
      //Sprites::drawExternalMask(drawX, drawY, tileSheet, tileSheetMask, tileIndex, tileIndex);
      Sprites::drawOverwrite(drawX, drawY - (thisTileHeight - tileHeight), buildingSprite, 0);

If the images had been in the repo I could have made the masks myself to verify and/or demonstrate that it works. Unfortunately I’ve yet to write a tool to produce .pngs from headers with image data.

No worries, ill need to do it with more sprites later anyway, might as well start doing it myself now lol. In the last two games i tried to make i thought i remembered just using drawSelfMasked without any issues but that didnt seem to work this time… if i export my sprite from gimp as an xbm it gives me an option to create a mask, which i can then save as a png and convert using one of the arduboy bitmap converters, but is there a quicker way to do all this?

Ok, i created masks using the aforementioned method, added them to GameSprites.h, then created a pointer array for them and changed my isometric draw function to drawExternalMask (both in MainGame.h)… but some of the buildings dont look right (like they might be overlapping). I dont think it has anything to do with the sprites themselves since i can see along the edge they display fine, and i think im using drawExternalMask correctly, not sure if maybe it has something to do with drawing order or something. Also, i updated the repo with the changes to my sprites, drawing, and tileHeight offsets, and i uploaded the .png files for my sprites/masks as well. Thanks!

That doesn’t work, .xbm is the wrong format.
(I believe .xbm files are in the format that arduboy.drawSlowXYBitmap uses, which isn’t the format you want to be using because it’s non-native.)

I’m not sure that will be in the right format either.
I believe GIMP uses the more common mask format, whilst Arduboy uses a slightly obscure inverted form of mask.

Ordinarily a mask is anded (&) with the destination and then the image is ored (|) over top, but for some reason the Sprites class inverts (~) the mask bytes first, so the source mask has to be the inverse of what would normally be the case.

Go through this list until you find one that you like:

Did you test that they’re actually working properly?
From what you’ve said about using .xbm I would presume that they don’t render properly.

I can now tell you categorically that your masks are the wrong way round.
I.e. they need their colours inverted - what’s white should be black and what’s black should be white.

Also your masks need their dimensions removed (i.e. their first two bytes), otherwise those will get interpreted as image data since masks aren’t supposed to have dimensions (because the main image already has them).

I’ll fix these issues and then do a PR when I’ve verified that they’re rendering as they should.

(By the way, this is precisely why it pays to check the individual parts of your rendering work separately, it helps to isolate which part is going wrong. I.e. make sure your sprites draw fine at (0, 0) with both white and black backgrounds; which you can do with arduboy.fillScreen, or by drawing a filled rectangle.)


By the way, it seems two of your commits were empty:


Edit:
You’ve also made the mistake of putting tileIndex in the last two arguments when they should be 0 because you’re using the array technique instead of the native frames.

Note that you were using 0 when using drawOverwrite:

Sprites::drawExternalMask(drawX, drawY, buildingSprite, buildingMask, tileIndex, tileIndex);
//Sprites::drawOverwrite(drawX, drawY - (thisTileHeight - tileHeight), buildingSprite, 0);

Et voilà:
MainGame.hex (31.3 KB)

(Note to self: write a better Arduboy image converter.)

Sorry, you misunderstood (but i dont blame you since it wasnt particularly clear lol)- im not using an xbm, what i meant was that im first exporting my sprite as an xbm just so i can create a sprite mask on export, then im converting my mask xbm back into a png (and ive been converting to arduboy format via the team arg converter after that), i was just hoping there might be a better way to make the mask (maybe with less steps lol). Also i assumed it worked since i can see the image in the windows file preview and it looks correct (obviously i was wrong lol, just saying why id assumed)

Ah ok, ill fix both of those, thanks!

No worries, i can take care of it real quick, im off work today and have a few hours before class anyway, no use making you take the time lol. Appreciate it though!

Ahh, ill make sure to test with that (now and in the future), thanks!

Hmm, thats odd, ill go back and take a look at that.

Lol i actually saw that and already fixed it, pretty sure you left that line in there when you were setting things up (presumably to test something out), but id never used drawExternalMask before so overlooked it at first… id actually updated the repo after i fixed that too but for some reason it didnt actually update (apparently lol), maybe that was one of the empty commits.

Oh shoot, beat me to it :laughing: thanks!

After having a quick look, I can’t seem to find any kind of ‘generate mask’ option in GIMP, so I’m not actually sure how you’re doing that or why you’d need to use an .xbm to do it. I would have thought that anything you can do to an .xbm could be done to a .png.

EIther way, for future reference, here’s an easy way to create a mask in GIMP if you’re starting with an image that has transparent pixels:

  1. Use the ‘Select by Colour’ tool (C) to select all the transparent pixels at once
  2. Switch to the ‘Bucket Fill’ tool (F)
  3. Make sure you have black selected as your primary colour
  4. Shift and click a transparent pixel and all the alpha pixels should turn black
  5. Invert your selection (Ctrl+I, or right click → SelectInvert)
  6. Switch to white (X if white is your background colour)
  7. Shift and click anywhere in the selected area and the whole selection should become white

Then just export to .png.

Well, actually…

It only generates the image though, not the header file.

(I haven’t actually posted this tool on the forum before. I threw it together a few weeks ago because I had a need for it.)

Well that’s the thing, it did look correct for a normal image mask…
Sprite_rendering_by_binary_image_mask

But like I say, for some reason Sprites decides to invert the mask bytes as it reads them, which means the input needs to be inverted too.

You aren’t the first person this has caused issue for and you won’t be the last. (The entire reason I know it’s inverted is because I remember someone else running into the same problem a few years ago, though I can’t find the thread at the moment.)

I’m well practised. :P

Also I’ve been doing quite a lot of sprite editing lately.
My art hasn’t really improved, but I’m getting good at memorising GIMP’s hotkeys.

You probably don’t need to do it every time you make an edit, but it’s worth doing when you make any major edits to your sprites, just to check they were edited properly and that you’re calling the functions properly.

It’s also probably worth trying if you can’t see any other problems. Sometimes a problem isn’t where you expect it to be.

(Though I was completely expecting the masking (and lack of) to cause problems, which is why I mentioned it quite early on. The more you program, the more you start trying to try to predict and preempt problems before they occur.)

Nope, you added it in this commit and then uncommented it in this commit.

The version of drawIsoMap that I originally fixed was the one above that which was commented out in the former commit. It used drawOverwrite because at that point there weren’t any masks and I didn’t have access to the original images to make any.

Usually an empty commit produced with the UI means you’ve tried to upload a file that doesn’t have any differences to the existing files, so perhaps you forgot to save the code in your editor or you were trying to upload a second, unedited copy of your code?

Thats why I used an xbm to do it, I couldn’t seem to find a generate mask option any other way either :laughing: I just remembered the option was there from when I tried to use an xbm before.

Ahh ok, that’s actually not the first time this has caused an issue for me either lol, I just didn’t know that. Thanks!

Oh whoops, I haven’t the slightest clue why I even did that since I’ve known the difference between the different Sprites::draw… functions ever since my first attempt at an arduboy game :laughing: never used all of them, like I said (since I never made my own masks), but I definitely remembered this time around since what each function does is pretty straightforward… I suppose this is why I need to get more sleep :laughing: but yeah, I’d just assumed it had something to do with what you had commented out above it, my mistake lol

Weird, I distinctly remember making sure I saved it and even remember looking at the date/time when I uploaded both commits (since I did save a second copy) but at this point now I’m almost starting to question my own sanity :laughing: but regardless i appreciate the fixes and the info, will be sure to keep everything you mentioned in mind, thanks!

Sorry, im still not quite sure why the tiles arent lining up right, ive been thinking on it for a while now but cant see what might be the issue… although in MainGame.h i did change tileWidth and tileHeight to 19 and 18 respectively, since that was actually reflective of my smallest building size (the tileHeight/Width both had what shouldve been the other’s value), i thought maybe that was throwing it off but still didnt fix it.

Also thanks for reorganizing the code, in my java class we went over classes earlier today (which isnt particularly relevant here in and of itself)… which id used in the past and knew a little about but between that and having just used classes on my python homework earlier in the day eveeything finally clicked and now i have a much more comprehensive understanding of the different ways (and scope) you can use variables/attributes/fields and functions/methods (as well as instances, overloading, different ways to initialize member variables), etc… it was like an epiphany, my teacher kind of ran through it and gave a more thorough overview (albeit a little rushed) then when i sat down to do the homework everything just fell into place and i finished the homework he gave us 2 weeks to do in the 2 hours of lab time during class :laughing:

Anyway, like i said it isnt particularly relavant in and of itself but what im getting at is that it also made me realize how to better organize/control my code… not that i want to treat everything like a nail now that i know how to use a hammer lol, just saying hopefully now ill start to have a better foresight on the organization side sooner than later here. But i appreciate you helping to better organize it as well, thanks again!

1 Like

Just to point it out, since I didn’t make much of a thing of it yesterday, this is the thing I was hoping you would work out, and if it hadn’t been for the fact you didn’t have the masks working properly first, that would have been the point at which your grid rendered more or less properly.

To me, the fact you managed to work it out on your own justifies me witholding that information, because it got you to think about how sprites are rendered from the top left and that’s an important thing to remember.


In what way?

Are you sure it doesn’t just look squashed together because you only have buildings and no roads making a path through them/separating them?

They should be the size of a blank tile without any building on it, which is what that image from the SO answer (and my modified version) demonstrate(s).


It will be at some point.

C++ has classes too, and its classes are far more powerful and far cheaper than Java’s and Python’s classes.

Classes also make code a lot easier to group and organise, and allow you to rely less on global variables.

Java likes ‘fields’ and ‘methods’.
C++ refers to them as ‘member variables’ and ‘member functions’.
I’m not sure about Python.

Apparently some places refer to ‘fields’/‘member variables’ as ‘attributes’, but that’s likely to cause confusion because a lot of languages use the term ‘attribute’ to refer to what Java calls ‘annoations’ - a kind of metadata that can be applied to an entity to provide information either to the compiler or for use with reflection.

That’s only the beginning. Next comes inheritance and overriding.

Hopefully they’ll stretch to generics, because that’s where things really get interesting.
(Although Java’s generics are a weak, bolted-on mess compared to those of languages like C# and C++.)

You’ve got a lot of interesting and mind-blowing stuff ahead of you, though I doubt your course will cover it all.

No, that’ll probably happen when you learn about inheritance and class design patterns instead. :P (I’m only half joking.)

Using classes more or less everywhere is fine as long as you don’t completely banish free (i.e. non-member) functions from your repetoire. (I’m looking at you, Java.)

All I’ve done is get some of the commented-out code out of the way and adjust the spacing slightly. That’s barely touching the surface as far as organisation goes.

By the way, as long as you’ve commited to GitHub you don’t have to worry about deleting rather than commenting out old code because the whole point of Git is that it keeps the entire history of your code and you can retrieve any old code that has since been deleted just by going back through the commit history.

For example here is your code as it was on the 11th of February.

Im sure, each row in the back is higher up than the row in front of it, so two tiles that end up being next to each other are at different heights. The height difference is more noticeable along the right edge since you can see each tile’s bottom is progressively lower than the one next it

This must be the problem, i remembered it should be the size of a blank tile but when i looked at the numbers you used (since the SO answer didnt have any actual dimensions) i thought it was something like 38 and 38 (but i halved my tiles’ size when i redrew the sprites smaller), wasnt really sure what thoae dimensions should be (but im guessing it should be half of the blank tile’s width, which makes sense why the height is incorrect)

Python refers to member variables as attributes, but also refers to functions as methods. And thats good to know about annotations, will keep that in mind, thanks!

Ah, but you had also moved some things near what they relate to (like my sprite width and height) which is part of what reminded me of classes (and better organization). Also i had looked at a previois version to see what you set the blank tile width/height to intially, but forgot this also means i can just delete stuff rather than comment out, thanks!

It took me a while to realise what you mean.
I hadn’t really noticed that because the resulting effect looked pretty good.

At any rate, it’s because the tile height is wrong.

It wouldn’t matter if it did because the dimensions will be specific to the sprites you’re using. It’s not a ‘one size fits all’ answer.

The tileWidth and tileHeight are what you set them to. I have not modified them at all.

(I did introduce them, but that was before the changeover to isometric, when the map was still being drawn as a grid, at which point it didn’t matter so much.)

Your original building0 had 38 and 36 as its dimensions.
However, having now realised the issue, that would have been an incorrect height for the tile height even then.

No, it should be the same as a blank tile.

At the moment the dimensions are the same as your building0’s dimensions: 18 and 19, but the height should be smaller. I’m not sure what the value should be because unlike your larger tiles it’s hard to discern what the tile shape should be.

Another item to add to my ‘why I don’t like Python’ list…

I don’t particularly remember doing that, but I might have done. I’ll check later when I have a minute.

Giving variables the least amount of scope they need and keeping related things together are pretty much second nature to me.

I’ve looked into it and it seems that the correct dimensions for a tile using your current image set are actually 19x9 (i.e. FlatTile).

If you think the following demo looks right you can either copy the changes from here or I can make a PR.

MainGame.hex (31.3 KB)

Sorry, I figured my description probably wasnt the best lol, just wasn’t quite sure how to explain what I meant (which is why I mentioned the bottom of the tiles at the outer edge hoping you might see it)… I agree, I do like how it looked, and might even decide to change it back (now that I know how lol), I just wanted to make sure I fully understood how it worked and why that happened.

I know that, I wasn’t looking to use the actual dimensions, I was just hoping they would give me a better idea of aspect ratio (like if it was 2:1 or something else I could deduce)

Ahh ok, I only looked as far back as you adding the isometric drawing and assumed you did it then (since I saw I didnt changed it to that after), shouldve just looked further back lol, sorry!

Yeahh, I meant my blank tile height should be half my blank tile width, since I was having a hard time discerning what the tile shape should be as well, that was just what I figured.

And 9 is roughly half my tile width so seems I wasn’t too far off lol. How did you figure it out? Looking at the image in an editor? Forgot I could’ve just done that, sorry :laughing:

Particularly where you moved each building’s height/width out of their respective sprite array and made them constants above it (then referenced the variables in the array instead of just using the numbers)

But ill take a look at the changes and just fix the code myself (just to make sure im still following along), thanks!

The best way to understand it is to convert that tile image I uploaded to something you can use, fill the majority of your tiles with it, aside from one or two buildings, and then try running the game with different values of tileHeight. When the dimensions match the dimensions of that 19x9 tile, everything will be snug, and as they differ there will be noticable gaps.

Their example tile is 2:1 (40:20), and I’ve found some examples of 32:17 online, so I would presume it needs to be near 2:1 to look right, but it might work with other arrangements.

You could always run some tests to find out.

A tip for future reference:

  • Click a line number so the line is highlighted and the ... box appears.
  • Click the ... box
  • Select View git blame

Alternatively just press the Blame button near the top right.

It shows you a breakdown of which commits last affected which sections of code.

There’s also a button (which looks like a square with lines to the left of it) that lets you look further back in time. (It says View blame prior to this change.)

I’m not fond of GitHub calling it ‘blame’, but it’s a useful tool for finding out what sequence of changes have affected particular sections of code.

Precisely. I opened a building in GIMP, added a new layer and roughly traced over it until it looked about right and then compared the produced tile to the other buildings to see if it looked like it fitted properly, and it did.

Actually, I have my own personal tool for producing image headers (which I wrote myself in C#) and it adds those automatically.

(I’m actually working on a better GUI-based one at the moment, which I’m hoping to actually release to the public, but I’m currently fighting awkward WinForms APIs and feature creep.)

1 Like

Yeahh, I don’t know why it hadn’t occurred to me I should’ve started with a blank tile lol. As far as aspect ratio and tile dimensions go, in my mind I can visualize how width affects the spacing on the x axis and height affects it on the y (and how it could be modified according to how the tiles are drawn and vice versa, so you have the correct perspective)… since I halved my building size and redrew my sprites I just made them half the original width and height and drew them based off the original, but now that I’m trying to redraw other sprites I want to make sure everything is consistent (and looks correct, since some smaller of my smaller sprites lose a lot of detail)… part of my lack of thorough testing was due to how I’m drawing my sprites, I prefer using an app on my phone (pixel studio) just because it’s a little easier/more convenient… with GIMP I need to mess around with a bunch of settings and have to look up how (finally got around to configuring the grid but still need to figure out how to make a 1x1 pixel brush, will have to look more into it later) but I need to import/edit my images in GIMP anyway to either invert them or do anything involving alpha channels, so next thing I’m going to do is take some time to redraw/test all my sprites using GIMP instead. Thanks!

Oh awesome, thanks!

Thats funny, I actually laughed out loud when I read that since I did blame you for a couple things that I had done, so that certainly is fitting :laughing:

I would have thought it would be difficult to select individual pixels with something as imprecise as human fingers, unless the image was sufficiently magnified.

Lack of Alpha aside, Microsoft Paint always used to be a pretty decent image editor.
But sadly they finally killed it off in Windows 10, and replaced it with something less wonderfully simple.

It’s not as difficult as you might think at first glance, it just takes a bit of understanding what does what.

Oddly I’ve never actually found a need to use that.
Possibly because the pixel brush that I usually use automatically snaps to the nearest pixel.
(I will explain this in a moment…)

  1. Make sure you’re using the Pencil tool (P)
  2. Under Tool Options, click the icon to the left of the Brush label and pick the second brush in - the one that looks like a tiny square. That’s the pixel brush, which paints solid pixels of colour rather than e.g. a circular brush that would normally be used for editing more detailed images.
  3. Make sure that the Size editor underneath that is set to 1.00.

After doing that once it should remember that setting the next time you visit.
If you never edit anything other than sprites, you never have to change it.

Similarly when using the Eraser (E) make sure it’s set to the 1. Pixel Brush with a Size of 1.00. Also, make sure to tick the Hard edge box under Tool Options to get a solid pixel eraser instead of a soft/gentle alpha reduction.


Assorted GIMP tips

Controls:

  • Use the Pencil (P) tool (with the settings explained above) for drawing solid pixels.
  • Use the Eraser (E) tool (with the settings explained above) for erasing pixels to transparent.
  • Hold Shift to draw/erase lines.
  • Use the Bucket Fill (F) tool to flood fill connected areas of similar colour.
    • Shift and left click to fill the entire selected area.
    • Use the Threshold slider to select how similar a colour needs to be to be considered ‘similar’.
  • Use the Rectangle Select (R) tool to limit your selection to rectangular areas.
    • Shift and left click to add to the current selection.
    • Ctrl and left click to add to the current selection.
  • Use the Fuzzy Select (S) tool to select areas of similar colour.
    • Use the Threshold slider to select how similar a colour needs to be to be considered ‘similar’.
    • Shift and left click to add to the current selection.
    • Ctrl and left click to add to the current selection.
  • Use the Move (M) tool to move layers around.
  • X swaps between the foreground and backgroudn colours.
    • (Which for Arduboy images will always be the default black and white, since alpha is introduced with the Eraser tool.)
  • Use the Zoom (Z) tool to zoom in on an area.
    • Ctrl and left click to zoom out again.

Other:

  • If an image isn’t erasing to transparent, right click it in the layers panel on the right and choose Add Alpha Channel (H).
    • Alternatively right click the image itself and then do Layer (L) → Transparency (A) → Add Alpha Channel (H).
  • Remember that Save saves as a GIMP .xcf file and you have to use Export to export a .png.

That should be just about everything you need to know to do pixel art with GIMP.
(Unless you need to edit the image’s actual colour palette or do something similarly low-level for some reason.)

(Maybe I’ll clean this up and turn it into a proper guide at some point?)


(I’d actually like to have a go at writing a script for GIMP that would export Sprites-formatted header files for Arduboy use, but the choices of scripting language are a variant of Scheme or Python, neither of which I particularly like, so I’ve been putting it off.)

If you’re on Windows and have .Net installed then I can give you an executable that you can use to invert colours via drag-and-drop.

If you have a C# compiler I can give you the source code too, and you can compile it yourself.