HIVE TUTORIAL ============= Contents: 1 What you can (and can't) do with HIVE 1.1 Graphics 1.2 Sound 1.3 Keyboard Input 1.4 Mouse Input 2 How it all works 2.1 What you need 2.1.1 Compiler 2.1.2 Sources 2.1.3 Editor 2.2 How to install HIVE 2.3 How to set up a HIVE project 3 The basics 3.1 The begining and end 3.2 What is update? 3.3 How is update used? 4 Graphics 4.1 Understanding the double buffered system 4.2 Sprites and objects 4.2.1 The sprite/object relationship 4.2.2 Creating/Destroying the sprite 4.2.3 Making an object corrolate to a sprite 4.2.4 Drawing the object 4.2.5 Collision (or "Why does the protanist go through walls?") 4.2.6 Animation control 4.3 Primitive output 4.3.1 Text 4.3.2 Popups 4.3.4 Rectangles 5 Sound 5.1 Background music 6 Keyboard 6.1 The keydown macro 7 Mouse 7.1 The global mouse variables The Tutorial: 1 What you can (and can't) do with HIVE ======================================= 1.1 Graphics HIVE uses double-buffered GDI graphics with 24-bit color at a resolution you specify. The global variables W and H defined in hive.c and make external in hive.h are set to represent the width and heigth, respectivly. It is 2D. 1.2 Sound HIVE can output audio using some rudimentry functions (hey, its better than the djgpp HIVE). 1.3 Keyboard HIVE has a limited interface for the keyboard. It can read when a key is down. 1.4 Mouse The interface for the mouse is slightly more sophisticated then that of the keyboard, but still basic. 2 How it all works ================== 2.1 What you need 2.1.1 Compiler All sources are compiled with Dev-C++, a 32-bit Windows compiler. I know it technicly isn't a compiler but an IDE, so when I refer to "compiling for Dev-C++," I really mean using the included compiler, Minimalist GNU for Windows. 2.1.2 Sources You'll need to have hive.c and hive.h for this to work. 2.1.3 Editor Use Dev-C++; see 2.1.1 Compiler. 2.2 How to install HIVE Copy hive.h into your include directory (default C:\Dev-Cpp\include) Copy hive.a into your library directory (default C:\Dev-Cpp\lib) 2.3 How to set up a HIVE project Step 1: Create a new project Make it a 32 bit Windows app Make C++ your language used (HIVE does not use C++, and you probily will not, although you can, but for some reason it needs to be a C++ project to properly link even though HIVE is pure C) Step 2: Add the libary hive.a must be added to your project. To do this, press Alt+P to bring up Project Options. Then click on the Paramiters tab. Under the linker section, type -lhive. Click OK. Step 4: Remove that darned default source! When you create a Windows program project, Dev-C++ is so kind as to put a nice default source code file in your project named main.cpp. Kill this file (remove it from your project) by selecting Project->Remove from project. Do not save changes as the next dialog box prompts you to do. Step 5: You're done HIVE is now part of your project. That wasn't too hard, was it? NOTE VERY IMPORTANT: declare main() as int main(), not void main() or even int main(void). int main(int argc, char *argv[]) is also taboo. (Although this is sorta obviouse, remember to include hive.h in all your sources that use HIVE stuff.) 3 The basics ============ 3.1 The begining and end To start up HIVE, call the start() function. It will return 0 upon faluire. To end HIVE, call the end() function. start() accepts five arguments; the first is the name of the window. This will appear on the title bar of the window (if not fullscreen) and on the task manager. Next comes the frame rate desired, measured in frames per a second. It is accurate to one millisecond, and places a "cap" on framerate. The third and fourth are the width and heigth of the window, respectivly. If you plan on using fullscreen, make sure these are demensions most monitors support, eg 800x600 or 1024x768. Finally, the fullscreen flag. Pass a 0 for windowed mode as argument five, or nonzero for fullscreen. Fullscreen is the advised mode. start() returns 0 on falure, generally due to width and heigth being incompatible with fullscreen. An example of a call to start() would be this: if(!start( "My cool HIVE app", /*Title bar*/ 60, /*fps*/ 1024, /*Width*/ 768, /*Heigth*/ 1 /*Fullscreen*/ ); 3.2 What is update? The update() function does several things. It a) Refreshes the screen b) Gets the keyboard input c) Gets the mouse input d) Returns 0 if the user requested the app be closed 3.3 How is update used? Update() is usually in the event loop, as it is constantly needed to get input and produce output. start() is usually before the event loop, end() after it. So, we can make this generalization: #include /*Other includes*/ /*Prototypes, globals, macros, etc.*/ int main() { /*Declare variables*/ char running=1; start(); while(running) { if(!update()) running=0; /*Proccess input*/ /*Make output*/ /*Decide if we should quit; if so, make running=0*/ } end(); return(0); } Other alternatives exist. 4 Graphics ========== 4.1 Understanding the double buffered system The way things appear to move on the screen is because they are constantly being erased at their last position and being re-draw at their new position. One method of doing this is to draw the frame, then erase everything, then draw it again, etc. The problem with this is that it makes the user see a blank screen half the time, causing the picture to "flicker" in and out. The solution to the flickering is to draw to a buffer that isn't displayed, then present the buffer to the screen. This is called double buffering, and it is how HIVE draws. update() writes the double buffer to the screen. So when you draw to the screen, it doesn't actually go to the screen until you call update(). 4.2 Sprites and objects A sprite is just a 2D picture that can animate between variose frames. HIVE loads sprites from a file externally. These files MUST be windows bitmap files and have 24-bit color. An object is the medium through which a sprite is displayed. 4.2.1 The sprite/object relationship Each object has one sprite, but each sprite can have many objects. This way, sprites are reused instead of having to create one for every picture one the screen. 4.2.2 Creating/Destroying the sprite A sprite's data is stored in a structure "typedef'd" to be spr. So you create a sprite (or a least allocate memory for it) like this: spr sprite_name; Then, you call load_spr() to set up the sprite, filling in it's data, loading the frames, etc. The first argument is a pointer to the sprite to be initalized; a spr *. Next comes the number of times a sprite is indirectly drawn via an object before it advances to the next frame. The third argument specifies how many frames aer in the sprite. Next is a series of strings telling it the filenames of the bitmaps to load. After each of the file names comes the filename of it's appompaning mask; NULL if the bitmap should not be transparent. eg, you could do this: load_spr(&spr_walking,1000,2,"walk1.bmp","walk1mask.bmp","walk2.bmp"," walk2mask.bmp"); Returns 0 on falure. So, what is a mask? It's a way of implementing transparency. Simply put, it is a second bitmap file that is white where the accompaning bitmap is transparent and black where it isn't. See the Duck Hunt clone I made for and example. The function kill_spr() deallocates the memory associated with a sprite. It just needs a pointer to the sprite. 4.2.3 Making an object corrolate to a sprite An object is stored in a structure the same way a sprite is, but the structure is called obj. The init_obj() routine sets an objects's sprite as well as setting some default paramiters. The first argument is a pointer to the object to initialize, the second a pointer to the sprite associated with the object. For example, you might do this: spr spr_walk; /*Sprite of guy walking*/ spr obj_walk; /*Load the frames*/ if(!load_spr(&spr_walking,1000,2,"walk1.bmp","walk1mask.bmp","walk2.bmp", "walk2mask.bmp")) return(0); /*Make the sprite for obj_walk be spr_walk*/ init_obj(&obj_walk,&spr_walk); After having set the sprite for an object, it can be set to anouther sprite with a call to the set_spr macro. It accepts a pointer to an object then a pointer to a sprite. 4.2.4 Drawing the object After creating the sprite and object, intitalizing/loading both, you can draw them to the double buffer with rndr_obj(), which talkes a pointer to the object and the x,y cordinates of the upper left corner of the object. 4.2.4 Collision (or "Why does the protanist go through walls?") There is a macro for deciding if two objects have collided called collision(). It accepts as paramaters a pointer to the first object, its cordinates, the second object pointer, and finally the second cordinates. For example, if you wanted to see if the main character (obj you) had hit a wall (obj wall), you would do this: if(collision(&you, you_x, you_y, &wall, wall_x, wall_y)) { /*Do stuff*/ } It is important to note that this is not accurate collision; it creates bonding boxes for each object. Anouther macro checks to see if a point is in an object at a certain spot. This is usefull for seeing if the mouse is over an icon; like this: if(point_in_obj(&icon, icon_x, icon_y, mouse_x, mouse_y)) { /*Do stuff*/ } 4.2.6 Animation control You may not always want to animate an object. For example, you might have a sprite of the protaganist walking forward; when not moving, it should stay still. The macros make_animate(obj *o) and make_still(obj *o) toggle between animating and not, respectivly. In addition to controlling if it animates, you can also control the current frame using the set_frm(obj *o, int frm) macro. All frames are zero-indexed; so the 1st frame is frame 0, the 2nd 1, etc. So say you have an object called hero that animates as if it's walking. To make it stop, you would do this: make_still(&hero); set_frm(&hero,0); That is, assuming frame zero has both feet on the ground. Obviosly, a simple call to make_animate(&hero) would make it walk again. After initalizing, it is possible to set the renders per a frame again. The macro set_renders_per_frm will do just that. It needs a pointer to the sprite that's being affected and the new renders per frame, eg: set_renders_per_frm(&sprite_you,50000); 4.3 Primitive output In addition to drawing sprites/objects, you can also draw to the screen in other ways. This section covers just that. 4.3.1 Text The print() function displays text. That's print, not printf. The first argument is the string to display, then the x,y coordinates. I suppose I must do this to honor K&R: print("Hello World!",0,0); Used together with sprintf() and this function could be usefull. 4.3.2 Popups This is HIVE for Windows, so a dialog popup function would not be out of place. popup() takes care of this. The first argument is the string in the popup, the next the string along the popups title bar. 4.3.4 Rectangles The rect function draws a rectangle. Here is it's prototype: void rect(int x1,int y1,int x2,int y2,unsigned char r, unsigned char g, unsigned char b); It draws a rectangle from x1,y1 to x2,y2 in color rgb. 5 Sound ======= 5.1 Background music The macro set_background_music(m) sets the background sounds to whatever is in the *.wav file m. For example, set_background_music("music.wav"); plays music.wav continuosely in the background. To stop it from playing, use the shut_up() macro. 6 Keyboard ========== 6.1 The keydown macr The key(s) currently being pressed is found out by update(), and read through the macro keydown(c) as defined in hive.h. The key must be a virtual key constant, such as VK_ESCAPE (escape key). 7 Mouse ======= 7.1 The global mouse variables The status of the mouse if determined just like that of the keyboard, but is not buffered. The following table is of the global mouse variables: Variable: | Purpose: --------------+------------------------------------------ mouse_x | x-cordinate of mouse mouse_y | y_cordinate of mouse right | 1 if right button is down, 0 otherwise left | 1 if left button is down, 0 otherwise rightpress | 1 if right was just pressed, 0 otherwise leftpress | 1 if left was just pressed, 0 otherwise rightrelease | 1 if right was just released, 0 otherwise leftrelease | 1 if left was just released, 0 otherwise Happy HIVEing!