Showing posts with label Tutorial. Show all posts
Showing posts with label Tutorial. Show all posts

Wednesday, 26 February 2014

Allegro FPS Limiter

Start with a boolean, this will be used for an update statement at the end. Another variable was used for the FPS in case you change it later, so you don't have to change it throughout the program.

bool draw = true;
const int FPS = 60;

Then make an event queue pointer and a timer pointer. 1 / 60 means 60 times a second.

ALLEGRO_EVENT_QUEUE *event_queue = al_create_event_queue();
ALLEGRO_TIMER *timer = al_create_timer(1.0 / FPS);

Register the timer into the event queue and start the timer. Putting anything other than the game loop after this statement might fuck up the timer.

al_register_event_source(event_queue, al_get_timer_event_source(timer));//put the timer into the queue
al_start_timer(timer);

Inside the game loop, make the event.

ALLEGRO_EVENT events;
al_wait_for_event(event_queue, &events);

If the event timer ticks into the queue, update the draw variable.

if(events.type == ALLEGRO_EVENT_TIMER)
{
     draw = true;//only draw if something updated
}

If something changed the update the graphics.

if(draw)
{
     do all your graphics stuff here
}

Allegro Colour Variables

Rather than using the rgb colour every time you need a colour argument you can use ALLEGRO_COLOR to set a global colour.

ALLEGRO_COLOR electricBlue = al_map_rgb(44, 117, 255);

This was you only need the variable name rather than the hex code.

Tuesday, 25 February 2014

Allegro Fonts

The first thing you'll need to do is include the font files and the true type font (ttf) file.

#include<allegro5\allegro_ttf.h>
#include<allegro5\allegro_font.h>

Both modules need to be added to the program too.

al_init_font_addon();
al_init_ttf_addon();

Now you'll need to acquire a font file. I got mine from this website for free.
http://www.webpagepublicity.com/free-fonts.html
Once downloaded, put the ttf file in your assets folder of the program.

To load the font into the program you'll need the following a font pointer. The first argument is where you put the file location of the font file. The second argument is the size of the text and the third is for any flags.

ALLEGRO_FONT *font = al_load_font("Assets/Fonts/Airmole Shaded.ttf", 36, NULL);

To display the text on screen use the following function, using the font pointer as the first argument. Next is colour, x position and y position. Fifth is a flag to centralize the text, you could also use ALIGN_LEFT or ALIGN_RIGHT. Lastly, the message you want displayed.

al_draw_text(font, al_map_rgb(44, 117, 255), ScreenWidth / 2, ScreenHeight / 2, ALLEGRO_ALIGN_CENTRE, "HELLO");

Allegro Message Boxes

To start using message boxes in Allegro 5 you'll need to include this file:

#include<allegro5\allegro_native_dialog.h>

This will allow you to use boxes that match your operating system.

The following function sets up the message box.  Using display as the first argument will place the window in front of the display. Leaving it as NULL will leave the message box behind the display. The second argument is the box title and the third is the message heading that will display inside the box. Forth argument is where you put your message.

al_show_native_message_box(display, "Error Message", "Error", "Could not initialize Allegro 5", NULL, ALLEGRO_MESSAGEBOX_ERROR);

The last argument represents the type of message box. The following is a list of available options.

ALLEGRO_MESSAGEBOX_WARN          
ALLEGRO_MESSAGEBOX_ERROR          
ALLEGRO_MESSAGEBOX_OK_CANCEL      
ALLEGRO_MESSAGEBOX_YES_NO      
ALLEGRO_MESSAGEBOX_QUESTION

You can use two options at once for example ALLEGRO_MESSAGEBOX_WARN | ALLEGRO_MESSAGEBOX_YES_NO.

The al_show_native_message_box function returns an int that represents which answer the user chose. To access it allocate a variable to it.

int answer = al_show_native_message_box(display, "Error Message", "Error", "Could not initialize Allegro 5", NULL, ALLEGRO_MESSAGEBOX_ERROR);

If the answer is no the return value will be 0. If yes then 1.

Saturday, 23 March 2013

Tutorial: 2D Box Collision

2D Box Collision

Theory

If the corner of one square is inside the other square the collision has occurred. For easier reading write 4 functions which check for possible collision on each side (left, right, top, bottom). Then write another function that compares which sides have a possible collision to figure out if collision has actually occurred.

Example

Write a function that checks collision with a single side. Note: sprite is 30 pixels large and getX and getY return the origin point of the sprite which in this case is the top left corner.

bool Blue::possibleCollisionLeft(Orange* orange)
{
        //get necessary coordinates
        int blueLeftSide = getX();
        int orangeLeftSide =  orange->getX();
        int orangeRightSide =  orange->getX() + 30;

        //return true if collision could occur on left side
        if((blueLeftSide <= orangeRightSide) && (blueLeftSide >= orangeLeftSide))
        {
                return true;
        }
        else
        {
                return false;
        }
}

Write a function like this for all 4 sides.
Then bring them all together in another function to compare which ones return true. And don't forget to check if its even colliding with the object you want. If its not then return true, doing this at the beginning of the function will stop the function comparing all the edge functions for no reason.

bool Blue::orangeCollision(Orange* orange)
{
            if(!orange)
            {
                       return false;
            }

        //compare collision function results, return true if a collision has occured
        if((possibleCollisionRight(orange) == true && possibleCollisionBottom(orange) == true)
        || (possibleCollisionLeft(orange) == true && possibleCollisionBottom(orange) == true)
        || (possibleCollisionLeft(orange) == true && possibleCollisionTop(orange) == true)
        || (possibleCollisionRight(orange) == true && possibleCollisionTop(orange) == true))
        {
                return true;   
        }
        else
        {
                return false;
        }
}

Monday, 11 March 2013

Tutorial: Terrain Smoothing


Terrain Smoothing

Theory

Take one point. Then take its 9 neighbouring points. Work out the average height of the 9 points, and set it to the original point. Pass it through multiple times to be smoothed more.

Example

The framework already has a function for height generation and a function for random noise generation. It also has a single dimensional array to represent the 2D terrain so the example is in a triple nested for loop. In an ideal world a multidimensional array would better suit the representation of a 2D plane.

  1. The smoothing was put into its own function and called from within the terrain generation function. Strength will be how many times you want to pass the terrain through to smooth it. The higher the number the more it will be smoothed.

bool TerrainClass::GenerateSmoothing(float strength)
{

  1. Then make a for loop to carry out the smoothing as many times as required.
for(int times; times < strength; times++)
{

  1. Start cycling through the terrain array.
for(int j = 0; j < m_terrainHeight; j++)
{

  1. In this example it has to go through 2 loops because it's a single dimensional array.
for(int i = 0; i < m_terrainWidth; i++)
{

  1. Make a temporary variable to hold the value of the average height for the 9 adjacent heights.
float totalAdjacentHeight = 0;

  1. Find each point using the array (see diagram) and add it to the temporary variable.
i+1, j+1
i+1, j
i+1, j-1
i, j + 1
i, j
i, j-1
i-1, j+1
i-1, j
i-1, j-1

totalAdjacentHeight += m_heightMap[(m_terrainHeight * j - 1), i - 1].y;
totalAdjacentHeight += m_heightMap[(m_terrainHeight * j    ), i - 1].y;
totalAdjacentHeight += m_heightMap[(m_terrainHeight * j + 1), i - 1].y;
totalAdjacentHeight += m_heightMap[(m_terrainHeight * j - 1), i    ].y;
totalAdjacentHeight += m_heightMap[(m_terrainHeight * j    ), i    ].y;
totalAdjacentHeight += m_heightMap[(m_terrainHeight * j + 1), i    ].y;
totalAdjacentHeight += m_heightMap[(m_terrainHeight * j - 1), i + 1].y;
totalAdjacentHeight += m_heightMap[(m_terrainHeight * j    ), i + 1].y;
totalAdjacentHeight += m_heightMap[(m_terrainHeight * j + 1), i + 1].y;

7.     Retrieve the original point(the centre position in the diagram) and set it equal to the temporary variable (after you've / 9 (9 for 9 neighbours) this is the average)
m_heightMap[(m_terrainHeight * j), i].y = (float)(totalAdjacentHeight / 9.0);

8.     Close off the function.
}
}
}

return true;
}


Source Code

bool TerrainClass::GenerateSmoothing(float strength)
{
        for(int times; times < strength; times++)
        {
                for(int j = 0; j < m_terrainHeight; j++)
                {
                        for(int i = 0; i < m_terrainWidth; i++)
                        {
                                float totalAdjacentHeight = 0;

                                totalAdjacentHeight += m_heightMap[(m_terrainHeight * j - 1), i - 1].y;
                                totalAdjacentHeight += m_heightMap[(m_terrainHeight * j    ), i - 1].y;
                                totalAdjacentHeight += m_heightMap[(m_terrainHeight * j + 1), i - 1].y;
                                totalAdjacentHeight += m_heightMap[(m_terrainHeight * j - 1), i    ].y;
                                totalAdjacentHeight += m_heightMap[(m_terrainHeight * j    ), i    ].y;
                                totalAdjacentHeight += m_heightMap[(m_terrainHeight * j + 1), i    ].y;
                                totalAdjacentHeight += m_heightMap[(m_terrainHeight * j - 1), i + 1].y;
                                totalAdjacentHeight += m_heightMap[(m_terrainHeight * j    ), i + 1].y;
                                totalAdjacentHeight += m_heightMap[(m_terrainHeight * j + 1), i + 1].y;

                                m_heightMap[(m_terrainHeight * j), i].y = (float)(totalAdjacentHeight / 9.0);
                        }
                }
        }

        return true;
}