游戏开发论坛

 找回密码
 立即注册
搜索
查看: 12080|回复: 1

2D游戏引擎Allegro 系列教程(二) Hello world!

[复制链接]

3

主题

15

帖子

81

积分

注册会员

Rank: 2

积分
81
发表于 2012-11-23 11:25:00 | 显示全部楼层 |阅读模式
本系列文章由sky编写,转载请注明出处。 http://blog.csdn.net/qq573011406/article/details/8172949

作者:袁全伟   邮箱: qq573011406@126.com    欢迎邮件交流编程心得

本系列教程索引:
2D游戏引擎Allegro 系列教程(一) 配置allegro开发环境
2D游戏引擎Allegro 系列教程(二) Hello world!
2D游戏引擎Allegro 系列教程(三) 加载并显示图片!
2D游戏引擎Allegro 系列教程(四) 文字渲染及显示汉字的方法


一:引子

在本章我做一个allegro的Hello world程序,其运行结果是创建一个窗口。

另外,为了方面以后的学习我写一个基本的运行框架。

先看下运行结果...


一片漆黑哈,啥都没有。不过没关系,这个仅是教大家使用allegro的第一步而已,以后还会陆续教大家显示图片,播放声音等等。

废话不说,直接进入正题

二:使用allegro的流程

Step 1:包含allegro的相关头文件
Step 2:引用allegro的库文件
Step 3:初始化allegro环境
Step 4:初始化相关输入设备及插件(键盘、鼠标、手柄等)
Step 5:创建一个display(一个可以绘图的窗口)
Step 6:初始化事件队列(用来接收键盘,鼠标,display,以及自定义的事件)
Step 7:指定要接收哪些设备的消息
Step 8:进入游戏循环(处理消息,更新逻辑,画面等)
Step 9:结束游戏,释放所占用的内存

Step 1:包含allegro的相关头文件

[cpp] view plaincopyprint?

#define ALLEGRO_NO_MAGIC_MAIN  
#include <Windows.h>  
#include <allegro5/allegro.h>  


需要注意的是 这一行:

[cpp] view plaincopyprint?

#define ALLEGRO_NO_MAGIC_MAIN  

如果想在WIndows下使用Allegro的话,必须要定义这个常量

Step 2:引用allegro的库文件

[cpp] view plaincopyprint?

#pragma comment(lib,"allegro-5.0.7-mt-debug.lib") //链接Allegro的库  

链接Allegro库的时候要与你程序的运行时库保持一致:

MT 静态多线程 Release版
MTd 静态多线程 Debug    版
MD 动态多线程 Release板
MDd 动态多线程 Debug  板

由于我们使用的是 静态多线程Debug板,所以我们在链接Allegro的库时,也要链接相同的版本,避免冲突。

Step 3:初始化allegro环境

使用al_init()可以初始化Allegro的环境。

[cpp] view plaincopyprint?

#define al_init()    (al_install_system(ALLEGRO_VERSION_INT, atexit))  

al_init()是一个宏,它用来帮我们自动完成allegro的初始化工作,可以看出它实际上调用了

[cpp] view plaincopyprint?

bool al_install_system(int version, int (*atexit_ptr)(void (*)(void)))  

version      :指allegro的版本号
atexit_ptr():销毁allegro时,调用的函数,这个函数用来释放allegro程序所占用的内存

Step 4:初始化相关输入设备及插件(键盘、鼠标、手柄等)

[cpp] view plaincopyprint?
bool al_install_mouse(void)  

al_install_mouse()函数用来初始化鼠标设备,以便可以接收到鼠标消息和获取鼠标的状态初始化成功则返回true否则返回false

[cpp] view plaincopyprint?

bool al_install_keyboard(void)  

al_install_keyboard()用来初始化键盘设备,以便可以接收到鼠标消息和获取鼠标的状态初始化成功则返回true否则返回false

Step 5:创建一个display(就是一个可以绘图的窗口)

allegro初始化完成后就可以创建display。

先看下display

[cpp] view plaincopyprint?

typedef struct ALLEGRO_DISPLAY ALLEGRO_DISPLAY;  

表示一个打开的显示器或WINDOWS窗口

使用下面的函数可以创建一个display

[cpp] view plaincopyprint?

ALLEGRO_DISPLAY *al_create_display(int w, int h)  

int w:指将要创建的display的宽度
int h:指将要创建的display的高度

创建成功则返回创建好的dispaly的指针。

另外,通过下面这个函数可以设置窗口的标题:

[cpp] view plaincopyprint?

al_set_window_title(display, "Hello World!!!");  

Step 6:初始化事件队列(用来接收键盘,鼠标,display,以及一些自定义的消息)

先来看一下事件队列的定义

[cpp] view plaincopyprint?

typedef union ALLEGRO_EVENT ALLEGRO_EVENT;  

它是一个联合体,它可以存储所有类型的内建事件数据对象

[cpp] view plaincopyprint?

ALLEGRO_EVENT_QUEUE *al_create_event_queue(void)  

上面这个函数用来创建一个空的事件队列,成功则返回该队列的地址,失败则返回NULL

Step 7:指定要接收哪些设备的消息

创建完事件队列后,还要用下面这个函数注册事件源。

[cpp] view plaincopyprint?

void al_register_event_source(ALLEGRO_EVENT_QUEUE *queue, ALLEGRO_EVENT_SOURCE *source)  

queue:刚刚创建的事件队列的地址
source:表示要注册的事件源.

例如:

[cpp] view plaincopyprint?

al_register_event_source(queue, al_get_keyboard_event_source());  //指定接收键盘事件  
al_register_event_source(queue, al_get_display_event_source(display));//指定接收display事件  

Step 8:进入游戏循环(处理消息,更新逻辑,画面等)

下面这些代码是我写的helloworld程序中的一部分,是一个简单的游戏循环结构

[cpp] view plaincopyprint?

int game_run(){  
  
    //下面的变量用来记录时间,单位是秒  
    //用以控制帧率(FPS),也就是每秒画面刷新多少帧,  
    //这里我们设FPS为30,用1秒的时间单位/FPS     
    //也就是0.033,也就是说,每次刷新的间隔时间不能小于0.033秒  
    double t_now=0.0; //当前时刻  
    double t_pre=0.0;   
    int error=0;  
    while (true)   
    {  
        if(!al_is_event_queue_empty(queue)){ //先检测事件对了中是否有新事件  
  
            error =game_msg(); //有则先处理事件  
            if(error!=0)return error;  
        }else{  
            //如果事件队列中没有新事件则  
            //计算事件间隔时候大于.033  
            t_now=al_get_time();  
            if(t_now-t_pre>=0.033){  
  
                //如果时间间隔合适的话就  
                //更新一帧的游戏逻辑  
                error=game_frame(); //用来更新游戏逻辑  
                if(error!=0)return error;  
                //刷新画面  
                error=game_render();//更新游戏画面  
                if(error!=0)return error;  
                t_pre=t_now;  
            }else{  
                //当CPU可以处理游戏逻辑的能力超过我们的需要时  
                //调用Sleep(0)  
                //这个Windows API 将使当前的线程释放出自己的控制权,  
                //这一点对Windows平台很重要,可以使游戏不至于占用全部  
                //的CPU,每次切换游戏的进程,都把可以用的时间片用完了  
                Sleep(0);  
            }  
        }  
  
    }  
    return 0;  
}  

我们先看

al_is_event_queue_empty(queue)

它的原型为:

[cpp] view plaincopyprint?
bool al_is_event_queue_empty(ALLEGRO_EVENT_QUEUE *queue)  

用来判断指定队列是否为空,也可以说是看看有没有新事件,或未处理的事件
再来看一下game_render()中的代码:

[cpp] view plaincopyprint?

int game_render(){  
    //用指定的颜色填充屏幕  
    al_clear_to_color(al_map_rgb(0,0,0));  
    //翻转  
    al_flip_display();  
    return0;  
}  

[cpp] view plaincopyprint?

void al_clear_to_color(ALLEGRO_COLOR color)  

该函数用指定颜色填充目标BITMAP.
目标bitmap是指,默认的绘图目标对象。

当我们创建好一个dispaly时,默认的BITMAP就是后背缓冲(backbuffer)

你可以把BITMAP想象成一块画布,所有的绘图操作都是在画布基础上进行的。后背缓冲也是这样的一块画布。

当我们的画画完时,就可以通过下面这个函数把这个画布显示在幕上。

[cpp] view plaincopyprint?
void al_flip_display(void)  

Step 9:结束游戏,释放所占用的内存

使用
[cpp] view plaincopyprint?
void al_destroy_display(ALLEGRO_DISPLAY *display)  

可以销毁dispaly所占用的内存

使用
[cpp] view plaincopyprint?
void al_destroy_event_queue(ALLEGRO_EVENT_QUEUE *queue)  

可以销毁事件队列所占用的内存

三:Hello world!程序的完整代码

[cpp] view plaincopyprint?

//头文件  
#define ALLEGRO_NO_MAGIC_MAIN  
#include <Windows.h>  
#include <allegro5/allegro.h>  
#pragma comment(lib,"allegro-5.0.7-mt-debug.lib") //链接Allegro的库  
////////////////////////////////////////////////////////////////////////////////////////////  
  
//函数  
int game_init();    //初始化游戏  
int game_run();     //进入游戏循环  
int game_frame();   //逻辑处理函数  
int game_render();  //渲染函数  
int game_distory(); //释放资源  
int game_msg();     //消息处理  
  
//常量  
const int WIN_WIDTH     =800; //窗口宽度  
const int WIN_HEIGHT    =600; //窗口高度  
//全局变量  
ALLEGRO_DISPLAY *display;     //显示设备  
ALLEGRO_EVENT_QUEUE *queue;   //事件队列  
ALLEGRO_EVENT my_event;       //事件  
  
  
////////////////////////////////////////////////////////////////////////////////////////////  
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd )  
{  
    int error=0;  
  
    //把游戏初始化的代码写在我们的 game_init()函数里  
    //然后放到这里执行  
    //把game_init()的返回值赋给error  
    //error如果为0的话表示一切正常,初始化成功了!  
    //如果不为0的话,表示初始化的时候,发生了意外。  
    //需要立即结束程序,并返回错误码  
    error=game_init();  
    if(error!=0)return error;  
      
  
    //初始化完成后,开始进入游戏的主循环,  
    //在主循环里将循环执行,消息处理,逻辑处理,和渲染函数  
    error=game_run();  
    if(error!=0)return error;  
      
  
    //游戏结束后,销毁所占用的资源  
    error=game_distory();  
    if(error!=0)return error;  
  
    return 0;  
}  
  
int game_init(){  
  
    if (!al_init())return 1;  
    /************************************************************************/  
    /*  使用al_init()来初始化Allegro系统
        al_init实际上是一个宏,他实际上调用了
        al_install_system(ALLEGRO_VERSION_INT,atexit)
        该函数的返回值是布尔型,初始化成功则返回true,否则返回false                                                                   */  
    /************************************************************************/  
  
  
    al_install_mouse();  
    al_install_keyboard();  
    /************************************************************************/  
    /* 初始化鼠标,和键盘设备,以便Allegro可以接收到鼠标和键盘消息                                                                     */  
    /************************************************************************/  
  
    //al_set_new_display_flags(ALLEGRO_FULLSCREEN);//如果取消掉本行注释就是全屏模式  
    display = al_create_display(WIN_WIDTH, WIN_HEIGHT);  
    if (!display)return 2;  
    /************************************************************************/  
     /*ALLEGRO_DISPALY *al_create_display(int w,int h)   创建显示设备
    参数 w 为要创建的窗口的宽度
    参悟 h 为窗口的高度
    成功则返回一个disply的指针,否则返回NULL
    /************************************************************************/  
    //设置Windows的标题  
    al_set_window_title(display, "Hello World!!!");  
  
    //初始化事件队列,接受到的消息将存储在该队列里  
    queue = al_create_event_queue();  
    //指定要接收哪个设备的消息  
    al_register_event_source(queue, al_get_keyboard_event_source());  
    al_register_event_source(queue, al_get_display_event_source(display));  
  
    return 0;  
}  
int game_msg(){  
  
    al_wait_for_event(queue,&my_event);  
    /************************************************************************/  
    /*  函数原型   
    void al_wait_for_event(ALLEGRO_EVENT_QUEUE *queue,ALLEGRO_EVENT *ret_event)
    等到队列里有新事件时,将新事件的内容复制到 ret_event里,并从事件队列里移除它
    */  
    /************************************************************************/  
    if(my_event.type==ALLEGRO_EVENT_DISPLAY_CLOSE)return 98; //当窗口被关闭时  
    if (my_event.type == ALLEGRO_EVENT_KEY_CHAR) {  
        if (my_event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)//当按下 ESC键时  
            return 99;  
    }  
    return 0;  
  
}  
  
int game_frame(){  
    return 0;  
}  
  
  
  
int game_render(){  
    //用指定的颜色填充屏幕  
    al_clear_to_color(al_map_rgb(0,0,0));  
    //翻转  
    al_flip_display();  
    return 0;  
}  
  
  
  
int game_run(){  
  
    //下面的变量用来记录时间,单位是秒  
    //用以控制帧率(FPS),也就是每秒画面刷新多少帧,  
    //这里我们设FPS为30,用 1秒的时间单位/FPS     
    //也就是0.033,也就是说,每次刷新的间隔时间不能小于0.033秒  
    double t_now=0.0; //当前时刻  
    double t_pre=0.0;   
    int error=0;  
    while (true)   
    {  
        if(!al_is_event_queue_empty(queue)){ //先检测事件对了中是否有新事件  
  
            error =game_msg(); //有 则先处理事件  
            if(error!=0)return error;  
        }else{  
            //如果 事件队列中没有新事件 则  
            //计算事件间隔时候大于0.033  
            t_now=al_get_time();  
            if(t_now-t_pre>=0.033){  
  
                //如果时间间隔合适的话就  
                //更新一帧的游戏逻辑  
                error=game_frame();  
                if(error!=0)return error;  
                //刷新画面  
                error=game_render();  
                if(error!=0)return error;  
                t_pre=t_now;  
            }else{  
                //当CPU可以处理游戏逻辑的能力超过我们的需要时  
                //调用Sleep(0)  
                //这个Windows API 将使当前的线程释放出自己的控制权,  
                //这一点对Windows平台很重要,可以使游戏不至于占用全部  
                //的CPU,每次切换游戏的进程,都把可以用的时间片用完了  
                Sleep(0);  
            }  
        }  
  
    }  
    return 0;  
}  
  
  
int game_distory(){  
    return 0;  
}  

四:小结

  本章我们介绍了使用allgero的步骤。和写了一个基本的框架出来。代码已经贴出来了,仅供参考。希望不要直接复制粘贴哈,还是一行行的敲比较好,虽然比较麻烦,但是印象会很深刻。

  这篇教程就到此结束了,第一次写教程,难免会有一些做的好不多,或则想的不周到的地方,如果你有什么意见或则好的建议的话,欢迎留言给我。

下次见

0

主题

1

帖子

12

积分

新手上路

Rank: 1

积分
12
发表于 2013-1-4 17:00:03 | 显示全部楼层
新人学习中……
麻烦LZ编辑一下,内容中符号显示异常,如<  >...
谢谢LZ分享~
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-6-11 07:49

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表