Tutorial 02 IND Surface
The previous tutorial was a bit boring. So let's start with something visual that will be more much interesting!
Download the tutorials
Download the IndieLib SDK in order to have all the tutorial files with the sources for vc2008, and all the example tutorials compiled, so you can try them directly
In this tutorial you will learn some of the most useful things of IndieLib. After reading this tutorial you will be able to draw sprites and backgrounds. You will also know how to change their attributes easily using entity objects: translation, rotation, scaling, alpha blending, aliasing, tint, fades, etc. The classes covered in this tutorial are:
IND_Surface and IND_SurfaceManager
With IND_Surface objects you can make sprites, backgrounds, scrolls, etc. IND_SurfaceManager it's just a manager that stores these type of objects.
A really beautiful feature of an IND_Surface object is that it can stores images of any size, they don't need to be power of two images and you can create really BIG scrolls (like 10000x10000 pixels) without problems. IndieLib will take care of everything internally cutting your images in blocks, and the good news is that all the blocks outside the viewport will be discarded (also when your camera or sprites will be rotated or scaled).
A IND_Surface object can be created from two sources:
- A IND_Image object (we will learn about this object that in the following tutorial)
- An image file from your computer (bmp, png, tga, jpg or pcx)
When creating the surface, there are some important parameters you need to know. You can read about them in the Api Reference:
IND_Entity2d and IND_Entity2dManager
In order to render the IND_Surface objects (and also other graphical objects that you will learn about later like fonts) they have to be joint to a IND_Entity2d. An entity is an object that can have a graphical object associated to it. Using the methods of this class you will be able to change the attributes of the graphical object that it contains in a really easy way.
For example, in a game, a bullet can be a IND_Entity2d that has a IND_Surface associated to it. You can have as many bullets (IND_Entity2d objects) in the screen as you want, all of them sharing the same IND_Surface (the sprite). The cool thing is that you can change the attributes of each of these different IND_Entity2d objects. For example, you can change the size, rotation, color or transparency of the bullets. So, having only one sprite, you can have lot of different bullets in the screen, with different sizes, colors, positions, and in your system memory there will be only one instance of your graphical object.
IND_Entity2dManager it's just a manager that stores/deletes these type of objects.
You can take a look to all the attributes of the object that you can change seeing the methods of IND_Entity2d in the Api Reference.
Let's start with the source code
Take it easy, I know it's a lot of information. But once you see how easy to understand is the source code, you will see that all this staff is in fact really easy to manage and really powerful. So, let's go!
We will follow this tutorial reading from the "Main.cpp" file of the "a_02_IND_Surface" project of the SDK. So, go to the folder and open the project.
The first thing we are going to do is loading some images from the disk and creating the IND_Surface objects. So, double click in you "Main.cpp" file, read this lines:
// Loading Background IND_Surface mSurfaceBack; if (!mI->SurfaceManager->Add (&mSurfaceBack, "..\\resources\\blue_background.jpg", IND_OPAQUE, IND_32)) return 0; // Loading sprite of a warrior IND_Surface mSurfaceWarrior; if (!mI->SurfaceManager->Add (&mSurfaceWarrior, "..\\resources\\derekyu_sprite.png", IND_ALPHA, IND_32, 255, 0, 255)) return 0; // Loading sprite of a star IND_Surface mSurfaceStar; if (!mI->SurfaceManager->Add (&mSurfaceStar, "..\\resources\\star.png", IND_ALPHA, IND_32)) return 0;
We have just created three surfaces, and we have added them to the surface manager. All the surfaces are created using IND_32 quality, this is the bigger quality. The background is created using a IND_OPAQUE type, because it hasn't got transparent areas. The other two sprites, are created using IND_ALPHA, that it's used for having really nice sprites with antialiased edges. One important thing is that the the warrior sprite hasn't got a transparent background. Actually, it has a background with an RGB color equal to(255, 0, 255). So, in order to make this color transparent, we pass it as a parameter when creating the surface.
The following lines of code you have to notice are:
// ----- Set the surfaces into 2d entities ----- // Creating 2d entity for the background IND_Entity2d mBack; mI->Entity2dManager->Add (&mBack); // Entity adding mBack.SetSurface (&mSurfaceBack); // Set the surface into the entity // Creating 2d entity for the warrior IND_Entity2d mWarrior; mI->Entity2dManager->Add (&mWarrior); // Entity adding mWarrior.SetSurface (&mSurfaceWarrior); // Set the surface into the entity // Creating 2d entity for the star 1 IND_Entity2d mStar1; mI->Entity2dManager->Add (&mStar1); // Entity adding mStar1.SetSurface (&mSurfaceStar); // Set the surface into the entity // Creating 2d entity for the star 2 (big and a bit orange) IND_Entity2d mStar2; mI->Entity2dManager->Add (&mStar2); // Entity adding mStar2.SetSurface (&mSurfaceStar); // Set the surface into the entity // Creating 2d entity for the star 3 IND_Entity2d mStar3; mI->Entity2dManager->Add (&mStar3); // Entity adding mStar3.SetSurface (&mSurfaceStar); // Set the surface into the entity
What we do here is to create some 2d entities and joint them with the IND_Surface objects. One entity will be the background, another one will be the warrior. And the last entities, will some stars that are sharing the same IND_Surface.
Now, lets change the attributes of these entities:
// ----- Changing the attributes of the 2d entities ----- // Warrior mWarrior.SetPosition (400, 170, 0); // Set the position of the entity // Original Star without chaning it's attributes mStar1.SetPosition (100, 270, 0); // Set the position of the entity // We change the attributes of this entity in order // to create a big rotated semitransparent star with // an orange tint mStar2.SetPosition (280, 200, 0); // Set the position of the entity mStar2.SetScale (2, 2); // Set the scale of the entity mStar2.SetTint (240, 160, 230); // Set tint to color RGB = (240, 160, 230) mStar2.SetTransparency (200); // Level of transparency 200 (255 will be opaque) mStar2.SetAngleXYZ (0, 0, 45); // Rotation in Z angle = 45º // A bigger star than the original, faded to pink. We only draw a region of 50x50 pixels mStar3.SetHotSpot (0.5f, 0.5f); // We change the reference point of the entity mStar3.SetPosition (400, 470, 0); // Set the position of the entity mStar3.SetScale (1.5f, 1.5f); // Set the scale of the entity mStar3.SetFade (230, 0, 230, 128); // Set fade to pink color, the amout of fade is 128 (255 will be complety pink) mStar3.SetRegion (20, 20, 50, 50); // Region we want to draw
This is what I call easy coding, isn't it? Here we set all the attributes of our entities. We don't change anything of the background entity because it's position is (0, 0) by default. From the warrior sprite and the star, we change only the position using SetPosition(). You can chose which surfaces will render on top off others using the third parameter "z" of SetPosition(): the entity which higher "z" will render on top.
There are some entities that are sharing the IND_Surface of the star sprite. The first one only suffers a translation. We scale the second one to the double of it's original size using SetScale() method. Later, we apply a tinting to a given color. We also change the transparency level to 200 using SetTransparency() (255 will be complety opaque). Finally we change the Z angle to 45º using SetAngleXYZ() (try to rotate it in "x" or "y" angles to have a funny "paper" effect).
With the final star, we make a smaller scaling than the previous one. We also set a fade to given color (pink) of medium intensity (0 will fade the entity completly to pink and 255 will keep the entity equal). SetInk() and SetFade() methods achives different results. With SetFade() you can change all the pixels of your sprite completly to the given color. With SetInk() the effect it's like if we were seeing the sprite trought a colored glass. The SetHotSpot() method allows you to choose the reference point from the transformations will be applied to the entity. By default the Hot Spot is (0, 0), this is the upper-left corner of the entity. A Hot Spot of (1, 1) will change the reference point to the lower-right corner. So the Hot Spot we use in the tutorial (0.5f, 0.5f) will be the very center of the 2d entity. Finally, using SetRegion(), we don't blit the whole sprite but only a region that starts in (20, 20) (from the upper-left corner of the sprite) and has an area of 50x50 pixels.
The rest of the source code is the main loop that we already saw in previous tutorials.
So, what you can do now it trying to create your own sprites, joinning them to entities and changing their attributes. Just imagine a huge world, plenty of different surfaces, each one a bit different just changing it's attributes (rotation, color, scale, etc)... something like in Aquaria game? Wow!
Check IND_Entity2d methods in the Api Reference to see other attributes you can change, the differences between SetFade() and SetInk(), etc.
You are ready for the next tutorial.