| | |
|
组别 | 节度使 |
级别 | 右将军 |
好贴 | 2 |
功绩 | 361 |
帖子 | 1092 |
编号 | 338625 |
注册 | 2009-9-11 |
来自 | 北京 |
家族 | 轩辕学院 |
| |
| | |
|
|
|
第2个版本:让赵辉开口说话
本来说接下来实现鼠标控制下的人物移动的,但昨天找到个系统讲SDL的网站,http://lazyfoo.net/SDL_tutorials/index.php,从上面先学到了文字显示,那么就现学现卖,先实现类似曹操传的对话显示功能吧。
首先,实现文字显示功能需要两个额外的库,SDL_ttf(SDL专门的TrueType字体支持子库)和libiconv(Unicode和其他的传统编码之间转换库,由赫赫有名的GNU提供),可以分别到http://www.libsdl.org/和http://gettext.sourceforge.net/下载它们
我下的版本分别在SDL_ttf-devel-2.0.9-VC8.zip和libiconv-1.9.1.bin.woe32.zip两个压缩包中。
解压后,将其中include子目录里的.h文件拷到前面说过的SDL-1.2.14目录的include子目录里,将lib子目录的.lib文件拷到SDL-1.2.14目录的lib子目录里,将lib子目录里的.dll文件拷到项目目录(WC_SDL)里,两个压缩包都这样办理。
然后还要仿照2楼 准备工作的 步骤5作些调整:
选“项目->属性”菜单项,在打开的对话框左上的“配置”项选"Debug",之后在左边选“配置属性->C/C++->代码生成”,右边的“运行时库”项改成“多线程调试DLL(/MDd)”。(本来我没改这里,后来调试时除了链接错误,百度了一下,发现得这样改。原因不明,往高手指点)
再在左边选“配置属性->链接器->输入”,右边的“附加依赖项”在原来的基础上,增加SDL_ttf.lib和iconv.lib两文件。
左上的“配置”项改为"Release",对“配置属性->链接器->输入”作类似的设置。
既然要模仿CCZ的对话效果,人物头像不可少,从《杨家将新传》的Tou.dll里提取赵辉的真彩头像,从mark.e5里提取几张对话框用的小图形(如图1),分别命好名,存到WC_SDL项目目录的res子目录里,上次的background.bmp和player.bmp也转移到res子目录里,以便资源的统一管理(项目目录文件的详细情况见下面的文件列表)
图片附件: [图1] 4.JPG (2009-11-29 21:07, 1.92 K)
准备工作完成,下面还要解决一个重要问题:
本来SDL_TTF似乎不能支持汉字,www.cnblogs.com的 龙飞 朋友在他的《SDL入门教程》系列中给出了解决方案(就是用前面说到的libiconv),我就拿来主义了。真的非常感谢他。开源和共享万岁!
他提供的解决上述问题的代码,大部分单独取出为gb2312_to_Unicode.h和gb2312_to_Unicode.cpp(详见源代码包),主程序里还有一部分,已用注释注明。
下面是本版工程包括的主要文件列表(文件夹用蓝色):
WC_SDL
res //资源文件
backGround.bmp
head.bmp
player.bmp
rcL.bmp
rcR.bmp
triangleR.bmp
gb2312_to_Unicode.h //头文件
gb2312_to_Unicode.cpp //源文件
WC_SDL.cpp
zlib1.dll //引用的动态链接库
iconv.dll
libfreetype-6.dll
SDL.dll
SDL_ttf.dll
simfang.ttf //TrueType楷体文件
WC_SDL.sln //VC8解决方案文件
WC_SDL.vcproj //VC8项目文件
下面是我主程序WC_SDL的代码:
#include <stdio.h>
#include <stdlib.h>
#include "SDL_ttf.h"
#include "gb2312_to_Unicode.h"
using namespace std;
// 定义表面(相当于绘图板)
SDL_Surface *screen=NULL;
SDL_Surface *name=NULL;
SDL_Surface *talkContent=NULL;
SDL_Surface *talk=NULL;
SDL_Surface *backGround=NULL;
SDL_Surface *player=NULL;
SDL_Surface *head=NULL;
SDL_Surface *rcLeft=NULL;
SDL_Surface *rcRight=NULL;
SDL_Surface *triRight=NULL;
// 定义mask
const int rmask = 0x000000ff;
const int gmask = 0x0000ff00;
const int bmask = 0x00ff0000;
const int amask = 0xff000000;
// 定义字体和文字颜色
TTF_Font *pFont=NULL;
SDL_Color talkContentColor = { 0, 0, 0 };
SDL_Color nameColor = { 0, 0, 240 };
// 定义窗体大小常量
const int SCREEN_WIDTH=960;
const int SCREEN_HEIGHT=960;
const int SCREEN_BPP=32;
const int frameRate=500;
int oldTime=-frameRate;
// 初始化工作
bool GameInit()
{
// 初始化SDL子系统,这里只对视频进行初始化
if ( SDL_Init(SDL_INIT_VIDEO) < 0 )
return false;
// 使用32位象素创建窗口
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE);
// 若创建失败,则退出
if ( screen == NULL )
return false;
// 初始化TTF
if( TTF_Init() == -1 )
return false;
pFont = TTF_OpenFont( "simfang.ttf", 14 );
if( pFont == NULL )
return false;
// 设置标题栏文字
SDL_WM_SetCaption( "WC_SDL 0.01", NULL );
return true;
}
// 图片表面初始化
bool InitImages()
{
if ((backGround = SDL_LoadBMP("res\\backGround.bmp"))==NULL)
return false;
if ((player = SDL_LoadBMP("res\\player.bmp"))==NULL)
return false;
if (( rcLeft= SDL_LoadBMP("res\\rcL.bmp"))==NULL)
return false;
if (( rcRight= SDL_LoadBMP("res\\rcR.bmp"))==NULL)
return false;
if (( triRight= SDL_LoadBMP("res\\triangleR.bmp"))==NULL)
return false;
if (( head= SDL_LoadBMP("res\\head.bmp"))==NULL)
return false;
// 设置图片的紫色(247,0,255)为透明色
SDL_SetColorKey(player, SDL_SRCCOLORKEY | SDL_RLEACCEL, SDL_MapRGB(player->format, 247, 0, 255));
SDL_SetColorKey(rcLeft, SDL_SRCCOLORKEY | SDL_RLEACCEL, SDL_MapRGB(rcLeft->format, 247, 0, 255));
SDL_SetColorKey(rcRight, SDL_SRCCOLORKEY | SDL_RLEACCEL, SDL_MapRGB(rcRight->format, 247, 0, 255));
SDL_SetColorKey(triRight, SDL_SRCCOLORKEY | SDL_RLEACCEL, SDL_MapRGB(triRight->format, 247, 0, 255));
return true;
}
// 文字框表面初始化
bool InitTalk()
{
talk = SDL_CreateRGBSurface(SDL_SWSURFACE, 336, 80, 32,rmask, gmask, bmask, amask);
if(talk == NULL)
return false;
}
// 退出前处理
void CleanUp()
{
SDL_FreeSurface( backGround );
SDL_FreeSurface( player );
SDL_FreeSurface( head );
SDL_FreeSurface( triRight );
SDL_FreeSurface( rcLeft );
SDL_FreeSurface( rcRight );
SDL_FreeSurface( name );
SDL_FreeSurface( talkContent );
SDL_FreeSurface( talk );
TTF_CloseFont( pFont );
TTF_Quit();
SDL_Quit();
}
// 汉字绘制函数
// 本函数引自http://www.cppblog.com/lf426/archive/2008/03/31/45801.html
// 谨向作者 龙飞 致谢
SDL_Surface* myTTF_RenderString_Solid(TTF_Font* font, const string& str, SDL_Color fg)
{
SDL_Surface* textbuf;
//Get Unicode
vector<Uint16> unicodeUnit = getUnicode(str);
int arraySize = unicodeUnit.size();
Uint16* perOne = new Uint16[arraySize+1];
for ( int i = 0; i < arraySize; i++ )
perOne = unicodeUnit;
perOne[arraySize] = 0;
//Render the new text
textbuf = TTF_RenderUNICODE_Solid(font, perOne, fg);
//Free the text buffer and return
delete [] perOne;
return textbuf;
}
// 绘图方法1:绘制整张图像
void DrawImage(SDL_Surface *dest, int x, int y,SDL_Surface *image)
{
// 设置在目标屏幕上的绘图偏移
SDL_Rect offset;
offset.x = x;
offset.y = y;
// 绘图
SDL_BlitSurface(image, NULL, dest, &offset);
}
// 绘图方法2:绘制部分图像
void DrawImage(SDL_Surface *dest, int x, int y, SDL_Surface *image, int sourceX, int sourceY,int width, int height)
{
// 设置在目标屏幕上的绘图偏移
SDL_Rect offset;
offset.x = x;
offset.y = y;
// 设置源图像的截取范围
SDL_Rect source;
source.x = sourceX;
source.y = sourceY;
source.w = width;
source.h = height;
// 绘图
SDL_BlitSurface(image, &source, dest, &offset);
}
// 绘制背景
void DrawBackGround()
{
DrawImage(screen, 0, 0,backGround);
}
// 绘制角色
void DrawPlayer()
{
static int curFrame=0;
DrawImage(screen,0,0,backGround,0,0,48,48);
DrawImage(screen,0,0,player,0,curFrame*48,48,48);
curFrame=1-curFrame;
SDL_Flip(screen);
}
// 建立对话文本框
void createTalk()
{
// 绘制圆角白色区域
SDL_Rect rect;
rect.x=16;
rect.y=0;
rect.w=288;
rect.h=80;
SDL_FillRect(talk,&rect,SDL_MapRGB(talk->format, 255, 255, 255));
DrawImage(talk,0,0,rcLeft,0,0,16,40);
DrawImage(talk,0,40,rcLeft,0,24,16,40);
DrawImage(talk,304,0,rcRight,0,0,16,40);
DrawImage(talk,304,40,rcRight,0,24,16,40);
DrawImage(talk,320,48,triRight);
// 绘制文字
name = myTTF_RenderString_Solid( pFont, "赵辉", nameColor );
talkContent = myTTF_RenderString_Solid( pFont, "在下赵辉,请多关照。", talkContentColor );
DrawImage(talk,16,4,name);
DrawImage(talk,16,20,talkContent);
}
// 绘制对话
void DrawTalk()
{
// 将对话文本框绘制到屏幕
DrawImage(screen,16,150,talk);
// 绘制头像
DrawImage(screen,352,130,head);
}
// 点击鼠标左键,轮流显示和擦除对话
void handleTalk()
{
static bool status=false;
if (status==false) {
DrawTalk();
}
else {
DrawImage(screen,16,130,backGround,16,130,456,120);
}
SDL_Flip(screen);
status=!status;
}
// 主程序入口
int main(int argc, char *argv[])
{
if (GameInit()==false)
return 1;
if (InitImages()==false)
return 1;
if (InitTalk()==false)
return 1;
createTalk();
// 绘制战场地图背景
DrawBackGround();
// 更新显示
SDL_Flip(screen);
// 主循环
bool quit=false;
while (quit==false) {
// SDL中的事件轮询(消息)机制
SDL_Event event;
while (SDL_PollEvent(&event)) {
//对消息进行处理
switch (event.type) {
case SDL_KEYUP: //如果某键按下后弹起的消息响应
//若按下ESC键,则退出
if (event.key.keysym.sym == SDLK_ESCAPE)
quit=true;
break;
case SDL_QUIT: //退出消息响应(点窗口右上的X,或按Alt+F4)
quit=true;
case SDL_MOUSEBUTTONUP:
if( event.button.button == SDL_BUTTON_LEFT ) {
handleTalk();
}
}
}
// 每隔500ms,主角切换一帧
if(oldTime + frameRate > SDL_GetTicks()) {
continue;
}
oldTime = SDL_GetTicks();
DrawPlayer();
}
CleanUp();
return 0;
}
其中,createTalk()函数、handleTalk()函数、和主消息循环里case SDL_MOUSEBUTTONUP:下面的部分是处理鼠标点击后对话显示和擦除的关键代码。
另外,看过第1个版本的朋友会发现,我已经对原有的代码作了一些重构,结构变得清晰多了。但不足的地方还是很多,欢迎高手指正。
目前主程序代码只有300来行,尚可全部帖上。预计随着功能增加,代码量会迅速膨胀,后面估计就只能把一些关键代码贴上来,剩下的以源代码包的形式挂上来,供有兴趣的朋友下载了。
程序运行后,赵辉还像以前一样原地踏步,只不过在地图区域点一下鼠标左键,就会出现如下对话框(图2):
图片附件: [图2] 3.JPG (2009-11-29 21:07, 144.19 K)
(标题栏上显示的版本忘了改了,把SDL_WM_SetCaption( "WC_SDL 0.01", NULL );改成SDL_WM_SetCaption( "WC_SDL 0.02", NULL );就是)
下面是源代码和可执行文件,为了最大限度节省空间,将工程代码、引用的动态链接库、图片资源和所需的TrueType字体分别打包上传。
如果想仅仅想查看源码,下载0.02版源码包解压来看即可。
如果还想编译运行源码,则还要下载图片资源(res.rar)、动态链接库(dlls.rar)、TrueType楷体文件(2个分卷),分别解压后,将所有文件、目录一并拷到源码包解压出来的WC_SDL目录中。
如果想运行可执行版本,则需下载处源码包外的所有文件(可执行版本、图片资源、动态链接库、TrueType楷体文件),将解压后的文件放在一起,再运行WC_SDL.exe。
目前有个问题,我本来以为TrueType字体文件不一定要放到工程目录里,操作系统应该会自动寻找的,而结果好像不行。
于是就导致,我本来想让显示汉字的字体是CCZ原版一样的宋体,但我Windows的宋体和新宋体是在一个TrueType文件里的,有10M之大,想作为附件发上来的话…… ,只好先拿个楷体的凑合着。
不知道有没有朋友拥有小一点的宋体TrueType文件,或是知道如何让程序能调用系统目录下的TrueType,要注意不同人不同版本的系统系统目录是不定的哦。
今天就说到这儿了,欢迎大家与我共同探讨,一起把这件事做下去。
下一个版本,真的就该实现人物的移动了
[ 本帖最后由 赵辉 于 2009-11-29 21:52 编辑 ]
附件:
[0.02源码包]
WC_SDL 0.02源码.rar (2009-11-29 21:07, 353.84 K)
该附件被下载次数 585
附件:
[图片资源]
res.rar (2009-11-29 21:07, 414.72 K)
该附件被下载次数 466
附件:
[动态链接库]
dlls.rar (2009-11-29 21:07, 868.43 K)
该附件被下载次数 349
附件:
[TrueType楷体文件 分卷1]
simfang.part1.rar (2009-11-29 21:07, 1.91 M)
该附件被下载次数 353
附件:
[TrueType楷体文件 分卷2]
simfang.part2.rar (2009-11-29 21:07, 361.38 K)
该附件被下载次数 341
附件:
[0.02可执行版本]
WC_SDL 0.02可执行文件.rar (2009-11-29 21:07, 6.86 K)
该附件被下载次数 308
|
|
|