增加Login窗口,可输入要显示的名字,以及在游戏中使用的形象。

microsoft.h(13) : fatal error C1189: #error : Please use the static version of the run-time state library.
《古月》的Visual C++版.LIB全部使用静态运行时态库方式编译,所以当您使用动态运行时态库方式编译工程时,就会提示以上错误。
解决办法即将C运行时态库选择静态版本即可,如下图。

经过差不多5个小时的努力,已经成功的将IrrLicht 1.6的部分代码整合到了古月引擎中。
去掉了IrrLicht中的以下部分:
目前已经在Visual C++ 2008/2010、C++Builder 2009/2010上编译链接成功。即将进行的将是IrrLicht原本例程的变更以及测试。
为让《古月》的使用更为灵活,从R46版开始,支持不从GameMain入口。开发人员可以自行搭配其它引擎。同时保留原有的GameMain入口方式。
目前,新的GameMain入口方式为:
void GameMain(int,wchar_t **)
{
SystemInitInfo sii;
sii.info.ProjectName=L”Box3D”; //工程名称
sii.info.ProjectCode=L”Box3D”; //工程代码(一般使用英文名称)
sii.graphics.gui.use=false; //标记成不使用GUI
//旧式
/*
if(Init(&sii)==false) //初始化工程
return;
SetStart(new TestObject); //设定起始流程
RunApplication(); //开始运行程序
*/
//新式
GameApplication app;
if(app.Init(&sii)==false) //初始化工程
return;
app.SetStart(new TestObject); //设定起始流程
app.Run(); //开始运行程序
}
说实话,在DOS平台下置取调色板可要比在Windows平台下简单多了,而且置了之后决对正确,不会出现象DirectDraw那样置了还未必起作用的情况。
好了,言归正传,我来详细讲述一下置调色板的办法。对于读调色板就不再介绍了,因为每一个优秀的C/C++程序员都不会笨到去读取调色板。调色板是什么样的,随时都掌握在他们的程序中,要什么调色板就设置成什么样的,从来不去读调色板。
假设我们对调色板的定义如下:
uvar8 Palette[256][3];
uvar8表示8位无符号变量,表示范围是0-255。Palette变量中有256种颜色,以Palette[颜色号]来表示。每个颜色中均保存红、 绿、蓝三原色的值。Palette[0][0]就表示第0种颜色的红色值,同样Palette[0][1]就表示第0种颜色的绿色值。
在DOS平台下,设置调色板的办法是多种多样的,以下我将逐一介绍:
方法一:16位DOS平台下,调用中断进行设置
| 由于16位DOS平台下,主流编程工具Borland C/C++与Turbo C/C++只支持16色,所以显得很无用。所以我们只好自己调用中断进行设置了,源程序如下:void SetPalette(uvar8 pal[256][3]) { union REGS r; struct SREGS s; r.h.ah=0x10; r.h.al=0x12; r.x.bx=0; r.x.cx=256; s.es=FP_SEG(pal); r.x.dx=FP_OFF(pal); int86x(0x10,&r,&r,&s); } |
方法二:16位DOS平台下,直接写DAC进行设置
| 相比之下,在16位DOS平台下,置调色板最快的手法莫过于直接写DAC了,源程序如下:void SetDac(uvar8 idx,uvar8 red,uvar8 green,uvar8 blue) { asm { mov dx,3c8h mov al,idx out dx,al mov cl,2 void SetPalette(uvar8 pal[256][3]) 不要问我那倒数第二行为什么要用uvar16来定义i,而不用uvar8,您自己试一下就知道了。 |
方法三:32位DOS平台下,使用Watcom C/C++编程时直接使用其图形函数进行设置
| Watcom C/C++不愧为优秀的32位DOS平台开发工具,它的图形函数直接用来编游戏都没问题,所以速度上也绝对慢不了。源程序如下:void SetPalette(uvar8 pal[256][3]) { uvar32 pal256[256]; uvar16 i; for(i=0;i<256;i++)pal256[i]=pal[i][2]/4*0x10000+pal[i][1]/4*0x100+pal[i][0]/4; _remapallpalette(&pal256); } 当然,这个程序还未做过优化,留着您自己优化吧!这里我只讲怎么设置调色板。 |
方法四:32位DOS平台下,调用中断进行设置
| 不过是方法一的16位转32位吧了,没什么大的变化,源程序如下:void SetPalette(uvar8 pal[256][3]) { union REGS r; struct SREGS s; r.h.ah=0x10; r.h.al=0x12; r.w.bx=0; r.w.cx=256; s.es=FP_SEG(pal); r.x.dx=FP_OFF(pal); int386x(0x10,&r,&r,&s); } |
当然,32位DOS环境也可以直接写DAC以便取得最快的速度,但是32位DOS下的汇编程序是很难写的(其实不难,只不过写出来很长),所以我就偷懒不写了,反正以上四种方法也够用了。
本来我是不准备写这篇文章的,但冷不妨有位同仁问起,也只好做个回答,顺便借此更新一下网页。
XMS,扩充内存管理规范。在16bit DOS系统下,为了使用640k以外的内存,XMS成了一种最好的手法。
在这里,我不想多讲XMS的实现,只对本文所提供的XMS类做一下使用讲解。
例子可以说明一切:
#include”XMS.H”
void main()
{
FILE *fp;
int i;
char *str;
XMS xms1(1024); //为xms1指针分配1024k的内存
fp=fopen(“C:\\WIN\\WIN386.SWP”,”rb”);
str=(char *)malloc(1024);
for(i=0;i<1024;i++)
{
fread(str,1,1024,fp);
xms1.put((void *)str,(void *)(i*1024),1024);
//将内存指针str中的1024个字节的内容写到,xms1的第i*1024个字节处
}
fclose(fp);
fp=fopen(“WIN386.SWP”,”wb”);
for(i=0;i<1024;i++)
{
xms1.get((void *)str,(void *)(i*1024),1024);
//将扩充内存xms1中,从第i*1024个字节处开始的1024个字节的内容写到str中
fwrite(str,1,1024,fp);
}
fclose(fp);
}
XMS.H
#if !defined XMS_H
#define XMS_H
class XMS {
int handle;
int move(struct EMB *emb);
public:
XMS(int size);
~XMS();
static int OK;
static int init(void);
static unsigned freesize(void);
static unsigned largestblock(void);
int realloc(int size);
int put(void *dp,void *sp,long leng);
int get(void *dp,void *sp,long leng);
};
#endif
XMS.CPP
#include <dos.h>
#include <alloc.h>
#include “xms.h”
struct EMB {
long Leng;
unsigned SourceHandle;
long SourceOfs;
unsigned DestinHandle;
long DestinOfs;
};
int XMS::OK=0;
static void far *XMSaddr;
int XMS::init(void)
{
static struct REGPACK rg;
rg.r_ax=0x4300;
intr(0x2f,&rg);
if( (rg.r_ax&0x00ff) == 0x80 )
{
rg.r_ax=0x4310;
intr(0x2f,&rg);
XMSaddr=MK_FP(rg.r_es,rg.r_bx);
OK=1;
}
else
OK=0;
return(OK);
}
unsigned XMS::freesize(void)
{
if(OK==0)
return(0);
asm {
mov ah,8
call XMSaddr
}
return _DX;
}
unsigned XMS::largestblock(void)
{
if(OK==0)
return(0);
asm {
mov ah,8
call XMSaddr
}
return _AX;
}
XMS::XMS(int size)
{
if(OK==0)
{
handle=0;
return;
}
asm {
mov ah,9
mov dx,size
call XMSaddr
}
handle=_DX;
}
XMS::~XMS()
{
if(handle==0)
return;
int hd=handle;
asm {
mov ah,0ah
mov dx,hd
call XMSaddr
}
}
int XMS::realloc(int size)
{
if(handle==0)
return(0);
int hd=handle;
asm {
mov ah,0fh
mov bx,size
mov dx,hd
call XMSaddr
}
return _AX;
}
int XMS::move(struct EMB *emb)
{
asm {
push ds
mov ah,0bh
push ds
pop es
lds si,emb
call es:XMSaddr
pop ds
}
return _AX;
}
int XMS::put(void *sp,void *dp,long leng)
{
struct EMB emb;
if(leng&1L)
leng++;
emb.Leng=leng;
emb.SourceHandle=0;
emb.SourceOfs=(long)sp;
emb.DestinHandle=handle;
emb.DestinOfs=(long)dp;
return move(&emb);
}
int XMS::get(void *dp,void *sp,long leng)
{
int v;
struct EMB emb;
if(leng&1L)
{
char *p,*d;
leng–;
if( leng>0 )
{
emb.Leng=leng;
emb.SourceHandle=handle;
emb.SourceOfs=(long)sp;
emb.DestinHandle=0;
emb.DestinOfs=(long)dp;
move(&emb);
}
p=(char *)malloc(2);
emb.Leng=2L;
emb.SourceHandle=handle;
emb.SourceOfs=(long)sp+leng;
emb.DestinHandle=0;
emb.DestinOfs=(long)p;
v=move(&emb);
d=(char*)dp;
d[leng]=p[0];
free(p);
}
else
{
emb.Leng=leng;
emb.SourceHandle=handle;
emb.SourceOfs=(long)sp;
emb.DestinHandle=0;
emb.DestinOfs=(long)dp;
v=move(&emb);
}
return(v);
}
在很多游戏中,将鼠标移到人物上,人物的边缘上就会出现一道光边。这也就是笔者将要和大家讨论的,如何找出这一边缘。
其实要找出它也不难,在游戏所使用的图片中,都包含有透明色和不透明色两部分,那么问题就很简单了,在透明色和不透明色相接的地方就是边缘。请看下面的程序:
| 程序功能:画指定区域图像的边缘在指定位置 |
| x,y :画边缘的坐标地址 x1,y1 :指定区域左上角的坐标 x2,y2 :指定区域右下角的坐标 TColor:透明色 |
| var16 i,j; uvar16 Color,TColor;for(i=y1;i<=y2;i++) for(j=x1;j<=x2;j++) { Color=GetPixel(j,i); if(Color!=TColor) //如果这个点不是透明色 { if(j==x1||GetPixel(j-1,i)==TColor)PutPixel(j-x1+x-1,i-y1+y ); if(j==x2||GetPixel(j+1,i)==TColor)PutPixel(j-x1+x+1,i-y1+y ); if(i==y1||GetPixel(j,i-1)==TColor)PutPixel(j-x1+x ,i-y1+y-1); if(i==y2||GetPixel(j,i+1)==TColor)PutPixel(j-x1+x ,i-y1+y+1); } } |
程序:罗健军
下面的算法中,var16表示有符号16位数据类型;HLine(x,y,n)是画水平线函数;VLine(x,y,n)是画垂直线函数;PutPixel(x,y)是画点函数。请看程序。
void Line(var16 x1,var16 y1,var16 x2,var16 y2)
{
var16 p,n,x,y,tn;
if(y1==y2) { if(x1>x2) { x=x2;x2=x1;x1=x; }
HLine(x1,y1,x2-x1+1);
return;
}
if(x1==x2)
{
if(y1>y2)
{
y=y2;y2=y1;y1=y;
}
VLine(x1,y1,y2-y1+1);
return;
}
if(abs(y2-y1)<=abs(x2-x1))
{
if((y2<y1&&x2<x1)||(y1<=y2&&x1>x2))
{
x=x2;y=y2;x2=x1;y2=y1;x1=x;y1=y;
}
if(y2>=y1&&x2>=x1)
{
x=x2-x1;y=y2-y1;
p=2*y;n=2*x-2*y;tn=x;
while(x1<=x2)
{
if(tn>=0)tn-=p;
else {tn+=n;y1++;}
PutPixel(x1++,y1);
}
}
else
{
x=x2-x1;y=y2-y1;
p=-2*y;n=2*x+2*y;tn=x;
while(x1<=x2)
{
if(tn>=0)tn-=p;
else {tn+=n;y1--;}
PutPixel(x1++,y1);
}
}
}
else
{
x=x1;x1=y2;y2=x;y=y1;y1=x2;x2=y;
if((y2<y1&&x2<x1)||(y1<=y2&&x1>x2))
{
x=x2;y=y2;x2=x1;y2=y1;x1=x;y1=y;
}
if(y2>=y1&&x2>=x1)
{
x=x2-x1;y=y2-y1;p=2*y;n=2*x-2*y;tn=x;
while(x1<=x2)
{
if(tn>=0)tn-=p;
else {tn+=n;y1++;}
PutPixel(y1,x1++);
}
}
else
{
x=x2-x1;y=y2-y1;p=-2*y;n=2*x+2*y;tn=x;
while(x1<=x2)
{
if(tn>=0)tn-=p;
else {tn+=n;y1--;}
PutPixel(y1,x1++);
}
}
}
}
程序:罗健军
程序中var32表示有符号32位数,var16表示有符号16位数。x0,y0为圆心坐标,r为半径。PutPixel为画点函数。
曾经长年的使用这段程序,而未向罗健军大师表示感谢,真是感到惭愧!在这里,请各位代表我向他表示感谢。
double SIN45=0.707106781186548;
void Circle(var16 x0,var16 y0,uvar16 r)
{
var32 tn;
var16 x,y;
var16 xmax;
y=r;x=0;
xmax=var16(r*SIN45);
tn=(1-r*2);
while(x<=xmax) { if(tn>=0) { tn+=(6+((x-y)<<2)); y--; } else tn+=((x<<2)+2);
PutPixel(x0+y,y0+x);
PutPixel(x0+x,y0+y);
PutPixel(x0-x,y0+y);
PutPixel(x0-y,y0+x);
PutPixel(x0-y,y0-x);
PutPixel(x0-x,y0-y);
PutPixel(x0+x,y0-y);
PutPixel(x0+y,y0-x);
x++;
}
PutPixel(x0+y,y0+x);
PutPixel(x0+x,y0+y);
PutPixel(x0-x,y0+y);
PutPixel(x0-y,y0+x);
PutPixel(x0-y,y0-x);
PutPixel(x0-x,y0-y);
PutPixel(x0+x,y0-y);
PutPixel(x0+y,y0-x);
}
程序:罗健军
void Ellipse(var16 x0,var16 y0,uvar16 r1,uvar16 r2)
{
uvar32 r,r12,r22;
var16 x,y,xmax;
var32 tn;
x=0;y=r2;
r12=r1*r1;r22=r2*r2;
xmax=var16(r12/sqrt(r12+r22));
tn=r12-2*r2*r12;
while(x<=xmax)
{
if(tn<0||y==0)tn+=(4*x+2)*r22;
else
{
tn+=(4*x+2)*r22+(1-y)*4*r12;
y--;
}
PutPixel(x0+x,y0+y);
PutPixel(x0-x,y0+y);
PutPixel(x0+x,y0-y);
PutPixel(x0-x,y0-y);
x++;
}
PutPixel(x0+x,y0+y);
PutPixel(x0-x,y0+y);
PutPixel(x0+x,y0-y);
PutPixel(x0-x,y0-y);
r=r1;r1=r2;
r2=(uvar16)r;
x=0;y=r2;
r12=r1*r1;r22=r2*r2;
xmax=var16(r12/sqrt(r12+r22));
tn=r12-2*r2*r12;
while(x<=xmax)
{
if(tn<0||y==0)tn+=(4*x+2)*r22;
else
{
tn+=(4*x+2)*r22+(1-y)*4*r12;
y--;
}
PutPixel(x0+y,y0+x);
PutPixel(x0+y,y0-x);
PutPixel(x0-y,y0+x);
PutPixel(x0-y,y0-x);
x++;
}
PutPixel(x0+y,y0+x);
PutPixel(x0+y,y0-x);
PutPixel(x0-y,y0+x);
PutPixel(x0-y,y0-x);
}