游戏编程中的人工智能(2-3)

来源:互联网 发布:apache ftpclient 530 编辑:程序博客网 时间:2024/06/16 12:12
<script type="text/javascript"><!--google_ad_client = "pub-3269163127493396";google_ad_width = 120;google_ad_height = 90;google_ad_format = "120x90_0ads_al";//2007-05-08: ITgoogle_ad_channel = "0064192373";google_color_border = "6699CC";google_color_bg = "003366";google_color_link = "FFFFFF";google_color_text = "AECCEB";google_color_url = "AECCEB";//--></script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
 
2.2       文本
如何在画布上签名?下面就要解决这个问题。
2.2.1           TextOut
朝屏幕输出文本最简单的方法就是使用TextOut函数。下面看一下它的原型:
BOOL TextOut(
    HDC         hdc,                
//DC句柄
    int             nXStart,                //开始写入位置的X坐标
    int             nYStart,                //开始写入位置的Y坐标
    LPCTSTR         lpString,               //指向字符串的指针
    int             cbString                //字符串的字符数
);
首先向TextOut传入DC句柄,还有需要文本显示的坐标,一个字符串指针,最后是一个表示文本长度的整数。文本默认的颜色是黑色,默认的背景色是WHITE_BRUSH。
2.2.2           DrawText
DrawText比TextOut稍微复杂一点。它的原型如下:
int DrawText(
    HDC         hdc,                
//DC句柄
    LPCTSTR         lpString,       //指向待写入字符串的指针
    int             nCount,         //字符串的长度(字符个数)
    LPRECT          lpRect,         //指向格式化大小结构的指针
    UINT            uFormat         //文本书写标识
);
这个函数在lpRect指定的文本框里显示文本。文本根据uFormat标志设置。
uFormat:设置文本格式化
表2.2DrawText格式化标志
样式
描述
DT_BOTTOM
文本在文本框内底部对齐。若要使用本标志,必须同时使用DT_SINGLELINE标志
DT_CENTER
这个标志使文本在文本框内水平居中
DT_LEFT
文本左对齐
DT_RIGHT
文本右对齐
DT_SINGLELINE
在单行里显示所有文字。有回车键文字也不换行
DT_TOP
文本顶部对齐
DT_WORDBREAK
这个标志的效果类似于字的换行
2.2.3           加入颜色和透明度
在Windows中可以自己定义背景色和前景色,还可以设置文本的透明度。为了设置文本颜色,需要利用SetTextColor函数:
COLORREF SetTextColor(
    HDC         hdc,                
//DC句柄
    COLORREF        crColor             //文本颜色
);
设置背景色用SetBkColor函数:
COLORREF SetBkColor(
    HDC         hdc,                
//DC句柄
    COLORREF        crColor             //背景颜色
);
设置完成以后,前景和背景色会一直有效,直到再次修改为止。两个函数都返回当前的颜色值,用户可以记录最初的设置,以便在必要时恢复。
为了将文本颜色设为红色而背景设为黑色,可以执行下面这些语句。
除了能够设置前景和背景色以外,还可以设置透明度。这把显示到屏幕上的文本的背景部分变成了透明(例如,如果文本背后是一个图案,则看起来就像是把文字直接打印到图案上一样)。
可以用SetBkMode函数设置背景的透明度:
int SetBkMode(
    HDC         hdc,                
//DC句柄
    int             iBkMode         //用以指明背景模式标志
);
只有两个标志可用:OPAQUE(不透明)和TRANSPARENT(透明)。因此,要使用透明背景绘制文本的时候,在具体绘制之前,应设置合适的背景模式。
GDI_Text的源代码示范了所有这些函数的使用。
默然:这里有两个文件:main.cpp和defines.h
首先是main.cpp
嗯,我不逐句翻译了,只把与前面不同的地方翻译一下。
//-----------------------------------------------------------------------
// 
// Name: GDI_Text示例工程
// 
// Author: Mat Buckland 2002
//
// Desc: 代码演示了文本输出
 
//------------------------------------------------------------------------
 
#include 
<windows.h>
#include 
<time.h>
 
#include 
"defines.h"
 
 
 
 
//--------------------------------- Globals ------------------------------
//
//------------------------------------------------------------------------
 
char* g_szApplicationName = "The Groovy GDI - Text Output";
char*   g_szWindowClassName = "MyWindowClass";
 
//---------------------------- WindowProc ---------------------------------
// 
// This is the callback function which handles all the windows messages
//-------------------------------------------------------------------------
 
LRESULT CALLBACK WindowProc (HWND   hwnd,
                             UINT   msg,
                             WPARAM wParam,
                             LPARAM lParam)
{
    
//these hold the dimensions of the client window area
     static int cxClient, cyClient;
 
    
switch (msg)
    
{
    
        
//A WM_CREATE msg is sent when your application window is first
        
//created
    case WM_CREATE:
      
{
         
//to get get the size of the client window first we need to create
         
//a RECT and then ask Windows to fill in our RECT structure with
         
//the client window size. Then we assign to cxClient and cyClient 
         
//accordingly
               RECT rect;
 
               GetClientRect(hwnd, 
&rect);
 
               cxClient 
= rect.right;
               cyClient 
= rect.bottom;
 
      }

 
      
break;
 
    
case WM_KEYUP:
      
{
        
switch(wParam)
        
{
 
        
case VK_ESCAPE:
          
{
            PostQuitMessage(
0);
          }

          
          
break;
        }

      }

    
    
case WM_PAINT:
      
{
                 PAINTSTRUCT ps;
          
         BeginPaint (hwnd, 
&ps);
 
          
//Make the bottom part of window a pattern so you can see what
         
//the transparency flag does
         HBRUSH PatternBrush = CreateHatchBrush(HS_BDIAGONAL, RGB(0,0,255));
 
         HBRUSH OldBrush 
= (HBRUSH)SelectObject(ps.hdc, PatternBrush);
 
         Rectangle(ps.hdc,
0, cyClient/2, cxClient, cyClient);
 
         
//替换回旧画刷
         SelectObject(ps.hdc, OldBrush);
 
         
//首先,演示用TextOut输出演示文本
         char* text = "1. I ain't got time to bleed.";
         
         TextOut(ps.hdc, 
55, text, strlen(text));
 
         
//现在是DrawText.首先我们创建一个文本框
         RECT TextBox;
         TextBox.top 
= 30;
         TextBox.left 
= 100;
         TextBox.bottom 
= 200;
         TextBox.right 
= cxClient-100;
 
         
//文本赋值
         text = "2. You take the blue pill and the story ends.You wake in your bed and believe whatever you want to believe.You take the red pill and you stay in Wonderland and I show you how deep the rabbit-hole goes.";
 
         
//现在,画文本
         DrawText(ps.hdc, text, strlen(text), &TextBox, DT_WORDBREAK);
 
         
//现在改变颜色,先设置文本为红色
          SetTextColor(ps.hdc, RGB(25500));
 
         
//设置背景为黑色
         SetBkColor(ps.hdc, RGB(000));
 
         TextBox.top 
= 200;
         TextBox.left 
= 5;
         TextBox.bottom 
= 300;
         TextBox.right 
= cxClient-200;
 
         text 
= "3. The greatest trick the devil ever pulled was convincing the world he didn't exist.";
         DrawText(ps.hdc, text, strlen(text), 
&TextBox, DT_WORDBREAK);
 
         
//现在,设置背景透明
         SetBkMode(ps.hdc, TRANSPARENT);
 
         TextBox.top 
= 300;
         TextBox.left 
= 100;
         TextBox.bottom 
= cyClient;
         TextBox.right 
= cxClient-50;
 
         text 
= "4. ...I抦 42 years old. In less than a year I抣l be dead";
         DrawText(ps.hdc, text, strlen(text), 
&TextBox, DT_WORDBREAK);
         
         EndPaint (hwnd, 
&ps);
      }

 
      
break;
 
    
//has the user resized the client area?
        case WM_SIZE:
         
{
        
//if so we need to update our variables so that any drawing
        
//we do using cxClient and cyClient is scaled accordingly
             cxClient = LOWORD(lParam);
             cyClient 
= HIWORD(lParam);
      }

 
      
break;
          
         
case WM_DESTROY:
             
{
 
         
// kill the application, this sends a WM_QUIT message 
                 PostQuitMessage (0);
             }

 
       
break;
 
     }
//end switch
 
     
//this is where all the messages not specifically handled by our 
         
//winproc are sent to be processed
         return DefWindowProc (hwnd, msg, wParam, lParam);
}

 
//-------------------------------- WinMain -------------------------------
//
// The entry point of the windows program
//------------------------------------------------------------------------
int WINAPI WinMain (HINSTANCE hInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR     szCmdLine, 
                    
int       iCmdShow)
{
     
//handle to our window
         HWND                       hWnd;
    
         
//our window class structure
         WNDCLASSEX     winclass;
         
     
// first fill in the window class stucture
       winclass.cbSize        = sizeof(WNDCLASSEX);
       winclass.style         
= CS_HREDRAW | CS_VREDRAW;
     winclass.lpfnWndProc   
= WindowProc;
     winclass.cbClsExtra    
= 0;
     winclass.cbWndExtra    
= 0;
     winclass.hInstance     
= hInstance;
     winclass.hIcon         
= LoadIcon(NULL, IDI_APPLICATION);
     winclass.hCursor       
= LoadCursor(NULL, IDC_ARROW);
     winclass.hbrBackground 
= (HBRUSH)GetStockObject (WHITE_BRUSH);
     winclass.lpszMenuName 
= NULL;
     winclass.lpszClassName 
= g_szWindowClassName;
       winclass.hIconSm       
= LoadIcon(NULL, IDI_APPLICATION);
 
         
//register the window class
        if (!RegisterClassEx(&winclass))
        
{
            MessageBox(NULL, 
"Registration Failed!""Error"0);
 
            
//exit the application
            return 0;
        }

 
         
//create the window and assign its ID to hwnd    
     hWnd = CreateWindowEx (NULL,                 // extended style
                            g_szWindowClassName, // window class name
                            g_szApplicationName, // window caption
                            WS_OVERLAPPEDWINDOW, // window style
                            0,                    // initial x position
                            0,                    // initial y position
                            WINDOW_WIDTH,         // initial x size
                            WINDOW_HEIGHT,        // initial y size
                            NULL,                 // parent window handle
                            NULL,                 // window menu handle
                            hInstance,            // program instance handle
                            NULL);                // creation parameters
 
     
//make sure the window creation has gone OK
     if(!hWnd)
     
{
       MessageBox(NULL, 
"CreateWindowEx Failed!""Error!"0);
     }

         
     
//make the window visible
         ShowWindow (hWnd, iCmdShow);
     UpdateWindow (hWnd);
 
     
//this will hold any windows messages
         MSG msg;
     
         
//entry point of our message handler
         while (GetMessage (&msg, NULL, 00))
     
{
          TranslateMessage (
&msg);
          DispatchMessage (
&msg);
     }

 
     UnregisterClass( g_szWindowClassName, winclass.hInstance );
     
return msg.wParam;
}
然后,是defines.h
#ifndef DEFINES_H
#define DEFINES_H
 
#define WINDOW_WIDTH 400
#define WINDOW_HEIGHT 400
 
#endif
2.2.4           实时消息抽取循环
在GDI_Polygon例子里,每次需要显示一个新的多边形,就得按一次空格键,这可能显得有点繁琐。但怎样才能在屏幕上连续不断地显示新的多边形来催眠用户呢?仅用GetMessage是办不到的。如果消息队列中没有消息,GetMessage就会等待,直到新的消息出现在队列中。需要这样一种消息循环,只有在需要处理消息时才去处理消息,其余的时间都让游戏代码去自动产生激动的场面。为了做到这一点,可以使用PeekMessage函数。其原型如下:
BOOL PeekMessage(
    LPMSG           lpMsg,              
//message结构指针
    HWND            hWnd,               //窗口句柄
    UINT            wMsgFilterMin,      //指定被检查的消息范围里的第一个message
    UINT            wMsgFilterMax,      //指定被检查的消息范围里的最后的message
    UINT            wRemoveMsg      //移走标志
);
最后一个参数wRemoveMsg,它的值可以是PM_NOREMOVE(消息处理后仍保留在队列中),或PM_REMOVE(消息处理后移走),通常选择后者。如果队列中有消息,PeekMessage将返回true,否则返回false。
要创建实时的消息抽取循环,就需要更复杂一些,如果只把GetMessage替换作PeekMessage,那么,当队列中没有消息时,PeekMessage返回零,应用程序会因此而终止。下面尝试用另一种形式来修改绘制多边形的例子。
while(PeekMessage(&msg,NULL,0,0,PM_))
{
    TranslateMessage(
&msg);
    DispatchMessage(
&msg);
}
这样只会见到应用程序窗口闪电般地打开,接着就立即关闭。而实际中需要的是一个更为强健的设计,过程如下:
//进入message抽取循环
bool bDone=false;
MSG msg;
while(!bDone){
    
while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){
        
if(msg.message==WM_QUIT){
            
//如果是quit消息,就退出循环
            bDone=true;
        }
else{
            TranslateMessage(
&msg);
            DispatchMessage(
&msg);
        }

    }

    
//下面是调用WM_PAINT绘制场景
    InvalidateRect(hWnd,NULL,TRUE);
    UpdateWindow(hWnd);
}
从GDI_Polygon2例子里的消息循环的运行情况中,可以发现WindowProc中的WM_PAINT部分现在包含产生新多边形的代码。这里利用了小巧的Sleep函数让程序每帧有几毫秒的延迟,这样就能实际看清每个多边形。调用Sleep时,参数表示程序应当暂停的毫秒数,暂停过后,程序接着就自动继续运行。
默然:下面公布GDI_Ploygon2的源代码,由于只有main.cpp与GDI_Ploygon不同,所以这里只列出了main.cpp的源代码,并只翻译了改变部分的注释。
//-----------------------------------------------------------------------
// 
// Name: GDI_Polygon2 example project
// 
// Author: Mat Buckland 2002
//
// Desc: Code demonstrating the creation and use of a realtime message
//        pump
//
//------------------------------------------------------------------------
 
#include 
<windows.h>
#include 
<time.h>
 
#include 
"defines.h"
#include 
"utils.h"
 
 
 
//--------------------------------- Globals ------------------------------
//
//------------------------------------------------------------------------
 
char* g_szApplicationName = "The Groovy GDI - Dazzle";
char*   g_szWindowClassName = "MyWindowClass";
 
//---------------------------- WindowProc ---------------------------------
// 
// This is the callback function which handles all the windows messages
//-------------------------------------------------------------------------
 
LRESULT CALLBACK WindowProc (HWND   hwnd,
                             UINT   msg,
                             WPARAM wParam,
                             LPARAM lParam)
{
    
//create some pens to use for drawing
    static HPEN BluePen = CreatePen(PS_SOLID, 1, RGB(00255));
    
static HPEN OldPen   = NULL;
 
    
//create a solid brush
    static HBRUSH RedBrush = CreateSolidBrush(RGB(25500));
    
static HBRUSH OldBrush = NULL;
 
    
//these hold the dimensions of the client window area
     static int cxClient, cyClient;
 
    
//this will hold the vertices of the polygons we create
   static POINT verts[NUM_VERTS];
 
    
static int iNumVerts = NUM_VERTS;
    
    
switch (msg)
    
{
    
        
//A WM_CREATE msg is sent when your application window is first
        
//created
    case WM_CREATE:
      
{
         
//to get get the size of the client window first we need to create
         
//a RECT and then ask Windows to fill in our RECT structure with
         
//the client window size. Then we assign to cxClient and cyClient 
         
//accordingly
               RECT rect;
 
               GetClientRect(hwnd, 
&rect);
 
               cxClient 
= rect.right;
               cyClient 
= rect.bottom;
 
         
//seed random number generator
         srand((unsigned) time(NULL));
 
         
//now lets create some random vertices
         for (int v=0; v<iNumVerts; ++v)
         
{
           verts[v].x 
= RandInt(0, cxClient);
           verts[v].y 
= RandInt(0, cyClient);
         }

 
      }

 
      
break;
 
    
case WM_KEYUP:
      
{
        
switch(wParam)
        
{
        
case VK_SPACE:
          
{
            
//create some new points for our polygon
            
//now lets create some random vertices
            for (int v=0; v<iNumVerts; ++v)
            
{
              verts[v].x 
= RandInt(0, cxClient);
              verts[v].y 
= RandInt(0, cyClient);
            }

 
             
//refresh the display so we can see our
              
//new polygon
              InvalidateRect(hwnd, NULL, TRUE);
              UpdateWindow(hwnd);
          }

          
          
break;
 
        
case VK_ESCAPE:
          
{
            PostQuitMessage(
0);
          }

          
          
break;
        }

      }

    
    
case WM_PAINT:
      
{
                 
//create some random vertices for the polygon
         for (int v=0; v<iNumVerts; ++v)
         
{
           verts[v].x 
= RandInt(0, cxClient);
           verts[v].y 
= RandInt(0, cyClient);
         }
 
        
         PAINTSTRUCT ps;
          
         BeginPaint (hwnd, 
&ps);
          
         
//first select a pen to draw with and store a copy
         
//of the pen we are swapping it with
         OldPen = (HPEN)SelectObject(ps.hdc, BluePen);
 
         
//do the same for our brush
         OldBrush = (HBRUSH)SelectObject(ps.hdc, RedBrush);
 
         
//draw the polygon
         Polygon(ps.hdc, verts, iNumVerts);
         
         
//replace the original pen
         SelectObject(ps.hdc, OldPen);
         
//and brush
         SelectObject(ps.hdc, OldBrush);
          
         EndPaint (hwnd, 
&ps);
 
         
//使用这个简单的Sleep,我们就可以控制绘制多边形的频率,以便让我们看清多边形
         
         Sleep(
100);
      }

 
      
break;
 
    
//has the user resized the client area?
        case WM_SIZE:
         
{
        
//if so we need to update our variables so that any drawing
        
//we do using cxClient and cyClient is scaled accordingly
             cxClient = LOWORD(lParam);
             cyClient 
= HIWORD(lParam);
 
        
//create a new polygon
        for (int v=0; v<iNumVerts; ++v)
        
{
           verts[v].x 
= RandInt(0, cxClient);
           verts[v].y 
= RandInt(0, cyClient);
        }

      }

 
      
break;
          
         
case WM_DESTROY:
             
{
                 
//delete the pens        
         DeleteObject(BluePen);
         DeleteObject(OldPen);
 
         
//and the brushes
         DeleteObject(RedBrush);
         DeleteObject(OldBrush);
         
         
// kill the application, this sends a WM_QUIT message 
                 PostQuitMessage (0);
             }

 
       
break;
 
     }
//end switch
 
     
//this is where all the messages not specifically handled by our 
         
//winproc are sent to be processed
         return DefWindowProc (hwnd, msg, wParam, lParam);
}

 
//-------------------------------- WinMain -------------------------------
//
// The entry point of the windows program
//------------------------------------------------------------------------
int WINAPI WinMain (HINSTANCE hInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR     szCmdLine, 
                    
int       iCmdShow)
{
     
//handle to our window
         HWND                       hWnd;
    
         
//our window class structure
         WNDCLASSEX     winclass;
         
     
// first fill in the window class stucture
       winclass.cbSize        = sizeof(WNDCLASSEX);
       winclass.style         
= CS_HREDRAW | CS_VREDRAW;
     winclass.lpfnWndProc   
= WindowProc;
     winclass.cbClsExtra    
= 0;
     winclass.cbWndExtra    
= 0;
     winclass.hInstance     
= hInstance;
     winclass.hIcon         
= LoadIcon(NULL, IDI_APPLICATION);
     winclass.hCursor       
= LoadCursor(NULL, IDC_ARROW);
     winclass.hbrBackground 
= (HBRUSH)GetStockObject (WHITE_BRUSH);
     winclass.lpszMenuName 
= NULL;
     winclass.lpszClassName 
= g_szWindowClassName;
       winclass.hIconSm       
= LoadIcon(NULL, IDI_APPLICATION);
 
         
//register the window class
        if (!RegisterClassEx(&winclass))
        
{
            MessageBox(NULL, 
"Registration Failed!""Error"0);
 
            
//exit the application
            return 0;
        }

 
         
//create the window and assign its ID to hwnd    
     hWnd = CreateWindowEx (NULL,                 // extended style
                            g_szWindowClassName, // window class name
                            g_szApplicationName, // window caption
                            WS_OVERLAPPEDWINDOW, // window style
                            0,                    // initial x position
                            0,                    // initial y position
                            WINDOW_WIDTH,         // initial x size
                            WINDOW_HEIGHT,        // initial y size
                            NULL,                 // parent window handle
                            NULL,                 // window menu handle
                            hInstance,            // program instance handle
                            NULL);                // creation parameters
 
     
//make sure the window creation has gone OK
     if(!hWnd)
     
{
       MessageBox(NULL, 
"CreateWindowEx Failed!""Error!"0);
     }

         
     
//make the window visible
         ShowWindow (hWnd, iCmdShow);
     UpdateWindow (hWnd);
 
       
//进行消息循环
       bool bDone = false;
 
     MSG msg;
 
       
while(!bDone)
     
{
                    
         
while( PeekMessage( &msg, NULL, 00, PM_REMOVE ) ) 
         
{
             
if( msg.message == WM_QUIT ) 
             
{
                 
// 如果是程序退出消息则停止循环
                 bDone = true;
             }
 
 
             
else 
             
{
                 TranslateMessage( 
&msg );
                 DispatchMessage( 
&msg );
             }

         }

 
            
//这里会调用WM_PAINT,完成对我们的窗口的重绘
            InvalidateRect(hWnd, NULL, TRUE);
            UpdateWindow(hWnd);
 
      
//*** 你的游戏主循环应该就放在这里 ***//
                    
    }
//end while
 
     UnregisterClass( g_szWindowClassName, winclass.hInstance );
 
     
return msg.wParam;
}
您好:
    当您在阅读和使用我所提供的各种内容的时候,我非常感谢,您的阅读已是对我最大的支持。
    我更希望您能给予我更多的支持。
    1.希望您帮助我宣传我的博客,让更多的人知道它,从中获益(别忘记了提醒他们帮我点点广告,嘿嘿)。
    2.希望您能多提出宝贵意见,包括我所提供的内容中的错误,建设性的意见,更希望获得哪些方面的帮助,您的经验之谈等等。
    3.更希望能得到您经济上的支持。
   
    我博客上面的内容均属于个人的经验,所有的内容均为开源内容,允许您用于任何非商业用途,并不以付费为前提,如果您觉得在阅读和使用我所提供的各种内容的过程中,您得到了帮助,并能在经济上给予我支持,我将感激不尽。
    您可以通过点击我网站上的广告表示对我的支持。
    您可以通过银行转帐付款给我:
    招商银行一卡通:
    卡号:6225888712586894
    姓名:牟勇
   
    您也可以通过汇款的方式:
    通讯地址:云南省昆明市女子(28)中学人民中路如意巷1号
    收信人:陈谦转牟勇收
    邮编:650021
   
    无论您给予我怎么样的支持,我都衷心的再次感谢。
    欢迎光临我的博客,欢迎宣传我的博客
    http://blog.csdn.net/mouyong
    http://blog.sina.com.cn/mouyong
    EMail:mouyong@yeah.net
    QQ:11167603
    MSN:mouyong1973@hotmail.com
 
<script type="text/javascript"><!--google_ad_client = "pub-3269163127493396";google_ad_width = 468;google_ad_height = 60;google_ad_format = "468x60_as";google_ad_type = "text_image";//2007-05-08: ITgoogle_ad_channel = "0064192373";google_color_border = "336699";google_color_bg = "FFFFFF";google_color_link = "0000FF";google_color_text = "000000";google_color_url = "008000";//--></script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
原创粉丝点击