Search ObeyBrew.Com

OBEYBREW.COM | Tutorials | A Crash Course In HuC Part 3

A Crash Course In HuC

Part 3 - Gone Loopy

Now, we're going to get into some pretty fun stuff. Not only will we be covering two more extremely important parts of coding the PCE here, but we'll also be making some in-progress source changes. This is to make sure you're really paying attention!

What You'll Learn

This lesson will teach you how to use for loops and will introduce sprites. We'll also have a little more fun with color.

It's Not A Soft Drink

No, a sprite isn't found in a bottle, it's found on the screen. So, what's a sprite? In simplest terms, it's a collection of pixels that is independent of the background... that is to say, a sprite can move on its own without disturbing the pixels of the background.

Setting Up Our Program

You already know how to start your program by now. But this time, we're going to add a couple of new things: a palette and a sprite. Before your main(), add the following lines of code:
const int paldata[] = { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0 };
const int sprdata[] = { 1001, 2002, 3003, 4004, 5005, 6006, 7007, 8008, 9009, 10010, 11011, 12012, 13013, 14014, 15015, 16016 };
Yeah, this is one of those wtf moments if you're not used to this kind of thing. So what'd we do? What we've done here is created two arrays. An array is like a variable, except it can contain more than one value. Normally, arrays are created like this:
int myarray[5];
where myarray is the name of the array and 5 is the number of different values it can hold at once. More on that later. However, what we're doing here is creating a constant array... that is to say, an array in which its values never change. A constant is a value that never changes. In normal C, you can assign values to an array when you create it. However, in HuC, we cannot do that unless we create it as a constant array. So, we use the word const in front of the array type, int in this case, and we can skip filling in the number of values since the compiler will automatically do that for us. Nifty, eh?

So now, we have a sprite block and a palette. Now what?

Pour It Onto The Screen

Now, we need to see if we can put that sprite onto the screen. Setting up a sprite can be a lot of work, as there are a lot of details to see to. The first thing we have to do is initialize the sprite handler. This is done with a single line of code.
init_satb();
Easy peasy! Now, the sprite hardware is ready.

The next thing we have to do is set all the details of the sprite. Any time we're working with sprites, we have to first determine which one we're working with. There are 64 sprites available to us. For now, let let's just use the first one. To select it, we use:
spr_set(0);
Yep, it's that easy. But now we have to give the sprite some data. First, maybe we should tell it where it's going to be on the screen. We do that by using spr_x and spr_y.
spr_x(0);
spr_y(0);
You can mess with those values if you want... I don't mind.

So now we know where our sprite is going to be. But there there's a few other things we have to do as well.
spr_pal(0);
spr_pri(1);
spr_pattern(0x5000);
spr_ctrl(FLIP_MAS|SIZE_MAS,NO_FLIP|SZ_16x16);
One step at a time! Ok... spr_pal tells the machine 'hey use this palette block for this sprite'. In this case, we're going to use palette block 0. We have 16 palettes we can use for sprites. For now, we'll just use the first one. Next, we see spr_pri. The code tells the machine 'this sprite is going to go over the background'. If we use 0 instead, that sprite will go behind the background. Even though this isn't really going to have any effect in this particular tutorial, remember it for later. Next up, we have spr_pattern. Every sprite has to get its pixels from somewhere in the video memory. This tells it where to get the pixels from. And finally... spr_ctrl... the most complex one. This sets up the size of the sprite and tells the machine whether or not the sprite's pixels should be flipped. You can flip the sprite left-to-right up-to-down or both at once. Don't do it too much or your sprite will get dizzy... ok that's not true.

Where's Mah Pixels At?

If you try compiling and running this code right now, you won't see anything on the screen just yet. Even though this is technically a complete sprite, there's still a few things left to do. For starters, there there's nothing currently at 0x5000 in VRAM so let's put something there.
load_vram(0x5000, sprdata, 0x40);
load_vram tells the machine 'hey let's put this data here in the video memory'. So this line copies the sprite we defined earlier into the video memory. 0x40 is how much data to copy. Pretty simple!

You're still not going to see anything though. Why not? Well, we don't have any colors defined yet either.
load_palette(16, paldata, 1);
load_palette will take that other set of data we defined earlier and copy it into the palette bank. But wait, you say... what's that 16 about? Well here's the thing... remember those 16 palettes for sprites? Well, there are also 16 palettes for the background. Yep, 32 palettes in total... that's a lot of colors available to use! However, the palettes for the sprites starts at 16. That means that whatever you set for spr_pal is actually 16 higher on the hardware. If you use load_palette, you have to remember this little detail. However, if it's confusing, you can just use set_sprpal instead, which uses the sprite's own palette number. Oh, and the 1 at the end of load_palette tells it how many palettes to load. Since we're only using 1, we set it for 1. Not too hard, right?

Guess what though, you're still not going to see a sprite! Yes, it's defined and it has color, but the video hardware doesn't yet have the updated information. So, we give it one last detail:
satb_update();
This tells the machine 'hey, update my sprite blocks' and it does it. And guess what? Now we see something on the screen!

Getting Into The Loop

Having a sprite just sitting there staring at us isn't very interesting. Let's make it move. Now, you need to create a variable. If you're used to normal C, you'd think you can just create a variable right here in the code and be done with it. However, in HuC, all variables have to be defined at the top of the function. Yeah, it's odd, but it it's how it works so no whining!

Put this at the top of your main function:
int posx;
From here we can craft a loop and make this sprite do something interesting. At the end of your code, add this:
for(posx=0; posx<256; posx++)
{
for is one of the most important things you will ever use as it sets up a loop. a for loop is broken up into three parts: the counter variable, the break condition and what to do to make the loop break. I'm sure other comp nerds have proper names for them. In simpler terms, this is a loop that counts until a condition is met. Each part of the for line has to be separated by a semicolon, kind of like at the end of a regular line of C code. But wait... no semicolon at the end of the for line itself? Yep, that's right... weird, isn't it? But that's just the way it is. Anyway... what we're doing is telling the machine 'look at this variable here, make it zero to start with and as long as its value is under 256, increase it by 1'. Ya still with me?

Ok, so now we have the start of a loop. Now, let let's put something inside of it. Let's mess with the sprite's X position.
spr_set(0);
spr_x(posx);
satb_update();
vsync(3);
Again, we use spr_set to choose the sprite. This isn't actually necessary in this particular example; i'm just using it here to reinforce that you need to use it. Next, we use spr_x to set the sprite's position... only now we're using the value in posx, which is being increased by the for loop. And then, we need that last bit from above to actually make the sprite move. The last line is a vsync... this line tells the machine 'slow down a bit so I can see what's happening!' (ok actually it tells the machine to wait for three VBLs... more on that later too).

Notice that we have a curly brace right after the for line? Our loop is finished, so we have to close it. We close it the same way we'd close a function:
}
Ok, that was pretty easy, eh? Compile and run the code... your sprite should be moving across the top of the screen now!

How Flashy!

Ok so the moving sprite is kind of cool. But let's do something even more interesting on top of it... let's mess with its colors. In the process, we're going to do another very important part of coding... nested loops. No, Tweety is not helping you.

So we're going to need another variable. In fact, we're going to need two new variables. Create two new int variables name them colorchange and result. Remember how to do this? Nowm let's make a new for loop inside the existing for loop. Set it up right after the satb_update call. colorchange is the variable we'll use, and we'll start it at 257 and make it increase by 1 until it reaches 272... got all that?
for(colorchange=257; colorchange<272; colorchange++)
{
Why such arbitrary values? Because we're going to mess with the color palette in that range. From here, we're going to start setting up some colors and doing it with some random numbers.
result = random(255) + random(255);
result gets some use! random is a random number generator that can produce a random number but it's limited to the values of a char. But result is an int, and there are 512 possible color combinations to use. So, we just generate two numbers and add them together. Sneaky, eh?

So then, we have a random color maker. Now, let's actually mess with the palette with this data!
set_color(colorchange, result);
}
set_color changes the color data at colorchange to the value of result. Now, some of you old C pros might be saying to yourself 'hey, I can just stuff the random part inside the set_color function call'... you'd think so, right? But no, HuC won't let you do that for some odd reason... funcs can't be called from inside set_color func call. Yep. Dunno why. Oh well.

Moving right along... that's all there is to this loop, so close the loop and compile your program.



Hooray! Flashing moving thing!

Movin' Down The Screen

So that's pretty interesting and all, but the sprite is still stuck at the top of the screen. Let's have at some more random fun. Add this single line of code right before your satb_update:
spr_y(spr_get_y() + random(3));
spr_y will, as you know, affect the Y coordinate of the sprite. But we've got something new this time... spr_get_y. As you can probably guess, this snags the current Y coordinate of the sprite. So what this code does is tell the machine 'gimme the Y position and increase it by a couple of random pixels... or maybe not at all'. In this case, random will return a value between 0 and 2. So you now have a sprite that not only goes left to right, but kind of jitters down the screen.



Yep.

If you want to mess with the values of sprdata to see different pixels... knock yerself out.

So...What's Next?

At this point, you have enough knowledge to handle the vast majority of programming in HuC. If you've mastered it up to this point, congratulations! Colors, sprites, variables, loops, and a whole mess of other fun stuff is out of the way. From here, we'll expand on our existing knowledge by adding interaction and we'll also dive into some background stuff too. It gets pretty easy from here.

Full Program Listing

#include "huc.h"

const int paldata[] = { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0 };
const int sprdata[] = { 1001, 2002, 3003, 4004, 5005, 6006, 7007, 8008, 9009, 10010, 11011, 12012, 13013, 14014, 15015, 16016 };

main()
{
	int posx, colorchange, result;
	init_satb();
	spr_set(0);
	spr_x(0);
	spr_y(0);
	spr_pal(0);
	spr_pri(1);
	spr_pattern(0x5000);
	spr_ctrl(FLIP_MAS|SIZE_MAS,NO_FLIP|SZ_16x16);
	load_vram(0x5000, sprdata, 0x40);
	load_palette(16,paldata,1);
	satb_update();
	for (posx = 0; posx < 256; posx++)
	{
		spr_set(0);
		spr_x(posx);
		spr_y(spr_get_y() + random(3));
		satb_update();
		for(colorchange = 257; colorchange < 272; colorchange++)
		{
			result = random(255) + random(255);
			set_color(colorchange,result);
		}
		vsync(3);
	}
}

See Also

A Crash Course In HuC - Part 4 | init_satb | spr_set | spr_x | spr_y | spr_pal | spr_pri | spr_pattern | spr_ctrl | load_vram | load_palette | satb_update | random | set_color | vsync | Useful Source Code
This site is ©2013 Eponasoft. When in doubt, the answer is 4. Always 4.