Monday 2 August 2010

Tutorial 1-3 : The Beat Box

Tutorial 1 : The Beat Box
A multipart tutorial teaching sprites, views, sounds, clicking and more!
Part One, Part Two, Part Three, More to come.

It's probably about time that we started to draw things onscreen.
In order that we can then do things, as we play, we need to setup a "PerFrame" function, and get it to run every few milliseconds.

Let's do both things at once. We'll set up a timer that ticks every few milliseconds, and also add the function.

.h In-Bracket
NSTimer *GameTimer;
This is our timer.

.h Under-Bracket
- (void)perFrame;
This is the name of our function.

You'll notice that this function is declared differently than our previous functions. Whereas the Buffer functions were..
Type FunctionName (Parameters);
this one is..
-(type)FunctionName;

Since I can't work out how to pass parameters to a -'type function, I've switched to doing the alternative, but the -'type function seems to have complete access to all program variables, whereas the alternative style only gets access to things that we double up in the .h file. (I think)
It's a nasty language, this!

I much prefer Blitz!

Anyhoo, moving on..

.m viewDidLoad
Right at the bottom of viewDidLoad, we want to initialise our timer.
One line does the job.
GameTimer=[NSTimer scheduledTimerWithTimeInterval:(0.033) target:self selector:@selector(perFrame) userInfo:nil repeats:YES];
// .033 seconds = approx 30 frames per second.

Basically, every .033 seconds, the timer (GameTimer) will tick by, and the function "perFrame" will be called. This repeats (YES!) forever, or until we quit. We also have the chance to free the timer, and replace it with a faster/slower repeat, if we feel the need. If you ever clear it without resetting it, though, you'll end up with a frozen game, since the perFrame will no longer be called. d'oh!

Now, underneath our viewDidLoad function, we can start a new function.
- (void)perFrame {
}

There we go!
Nothing in it, yet, but it's ready for use.

Let's start making our grid.
We'll go with a 16x16 grid to display onscreen. The user can tap any of the 16x16 grid spots, turn them off and on, and then the little beat bar will make a noise when it touches one of them.

So, first make an array to hold the off/on values of each grid spot.
.m Declare
int GridOn[300]; // (y*16+x)

We've made a quick note of the formula for our array, in the comment. If, for example, we need the top left, it'll be (0*16)+0, or 0.. bottom right is (15*16)+15, or 255.

.m viewDidLoad
This goes after the dot-slicing, but before the Timer thing.
for (x=0;x<15;x++)>
for (y=0;y<15;y++)>
GridOn[y*16+x]=0;
if (round(random()%10)<3)>
}
}
Note, we don't have to include ints for the x and y this time, since we already declared them as ints in the Dot-Slicing part, a little earlier.
We set everything to 0, but then every so often at random intervals, we'll set them to 1.
This is for testing purposes. We haven't yet done any finger-tapping stuff, so we want to set things either off or on, so we can see the results.

Next we need a larger blank sprite that we can draw the grid into. Head into a paint package and make a nice blankx320.png
Copy it into the resources, and create a img_Grid variable for it.
.h In-Bracket
UIImage* img_Grid;
.h Under-Bracket
@property (nonatomic, retain) UIImage* img_Blank;
.m Declare
@synthesize img_Grid;
.m Dealloc
[img_Grid dealloc];

Next we need to draw our grid onto our image.
The first time, we draw the entire grid. Every time after this we'll only need to draw it wherever it changes. This saves us a heck of a lot of buffer-drawing, and we can use the time to do everything else.

So, back to that x/y loop we just made.
change it to this..
img_Blank=[UIImage imageNamed:@"blankx320.png"];
LockBuffer(img_Blank);
for (x=0;x<15;x++)>
for (y=0;y<15;y++)>
GridOn[y*16+x]=0;
if (round(random()%10)<3)>
DrawToBuffer(img_Dots[GridOn[y*16+x]+1], x*20,(y*20)+320);
// That +320 is our quirky buffer co-ordinates!
}
}
img_Grid=UnlockBuffer();
[img_Blank dealloc];

We're locking the buffer, drawing everything onto it at 20x20 intervals, and then transferring it to img_Grid.

Now to see our grid, we should create a view_Grid. The view is a rectangular area that we tell to look like the img, and that then shows up on screen.

.h In-Bracket
UIImageView* view_Grid;
.h Under-Bracket
@property (nonatomic, retain) UIImageView* view_Grid;

.m Declare
@synthesize view_Grid;
.m Dealloc
[view_Grid dealloc];

To setup our view, head back to viewDidLoad.
Underneath the chunk we just replaced, we want to tell it to make the view.

view_Grid=[[UIImageView alloc] initWithImage:img_Grid];
// The image we just created..
view_Grid.frame=CGRectMake(0,40,320,320);
// Shown at 0,40, with 320 width and 320 height.
view_Grid.userInteractionEnabled=FALSE;
// Disable touching. We'll get to this later.
[self.view addSubview:view_Grid];
// Add the view to the screen.

Now we should be able to see our progress so far.

We've taken a picture, cut it up, and pieced it back together in a whole bunch of pieces.
This certainly isn't the most amazing piece of software in the world, but it does give us a great starting point.

From here, we're going to be able to click the grid, turn points off and on, and then later on make a nice bar that scans the grid, and plays notes/drums/whatever as it goes.

Meanwhile, have a fiddle with the code you've got, and make sure you understand all those odd chunks that you've copy+pasted blindly.

I'm not 100% sure when this tutorial will continue, but you shouldn't be waiting too long.

Until next time, have fun looking at the boxes!

No comments:

Post a Comment