有人下载我的工程文件,“我很欣慰”,名字是“挖金子VC版源码”,大家多讨论。
上回讲哪了?地图加载了,物品能显示了。该显示画面上方摆动的叉子了。计算机图形学的“图形旋转”,当然,有一个WINDOWS API函数PlgBlt,可我没有用。网上有很多介绍图形旋转的文章,我还是讲解一下我这个函数:
{
int pvdest[ 20 ] = { 0 };
// int x0,y0;
int i;
int tempx,tempy;
memcpy(pvdest,pv, sizeof ( int ) * num);
/*
x0=pv[0];
y0=pv[1];
//move
for(i=0;i<num;i+=2)
{
pvdest[i]-=x0;
pvdest[i+1]-=y0;
}
*/
// rotate
for (i = 0 ;i < num;i += 2 )
{
tempx = pvdest[i];
tempy = pvdest[i + 1 ];
pvdest[i] = tempx * cos(a) - tempy * sin(a);
pvdest[i + 1 ] = tempx * sin(a) + tempy * cos(a);
}
// move,中心点坐标是320 58
for (i = 0 ;i < num;i += 2 )
{
pvdest[i] += x0;
pvdest[i + 1 ] += y0;
}
// 绘制图形
Draw(hdc,pvdest);
}
为什么我没有删除注释掉的代码?有原因。一个图形绕(x0,y0)旋转,总共分三步(耳熟):图形移动到坐标原点,旋转,再移动回原有位置。而我这个叉子的图形在哪里?就在原点。所以省略了第一步。叉子的图形,是画了几个线段,各端点坐标如下(x1,y1,x2,y2,...):
//设置爪子各顶点坐标
int temp[12]={
0,32,20,32,
40,0,64,0,
64,64,40,64
};
再解释一下公式:
pvdest[i]=tempx*cos(a)-tempy*sin(a);
pvdest[i+1]=tempx*sin(a)+tempy*cos(a);
屏幕坐标轴x向右,y向下,这个公式将逆时针旋转图形。
有一个问题,为什么不用一个位图?位图的显示效果虽然好,但是计算cos,sin时,会产生误差。这将使图像有一些变形,所以没有用位图。
绘制、摆动的问题解决了。下面是伸缩。
叉子的伸缩
关键是使用“状态机”。三种状态:摆动,伸出,拉回。我没有定义宏,应该批评。用0 1 2 表示的。
再次声明软件的“可维护性”,这种状态设置,也许琐碎,但有好处。
摆动状态:修改当前角度,当前摆动方向;
伸出状态:改变坐标,如果达到伸出的最大长度,则状态迁移:拉回;
拉回状态:改变坐标,如果“伸出长度”降为0,则状态迁移:摆动。
为了消除坐标计算的误差,伸出时,直接将坐标偏移值转为整型存储,如下:
xoff=10*cos(iAngle*10*1.57/90);
yoff=10*sin(iAngle*10*1.57/90);
拉回的时候,也用相同的偏移值,只要再乘以一个系数,就实现了拉回的快慢不同。
按键检测
用户按“下”,叉子伸出。用按键消息来检测,代码为:
switch (iGameState)
{
case GAME_STATE_MAIN:
gamecatch.KeyProc(wParam);
{
switch (iKey)
{
case VK_DOWN:
if ( 0 == iState)
{
// 摆动状态下才能变成伸出状态
iState = 1 ;
xoff = 10 * cos(iAngle * 10 * 1.57 / 90 );
yoff = 10 * sin(iAngle * 10 * 1.57 / 90 );
}
break ;
目前,叉子能正常摆动,用户按“下”,叉子伸出,然后拉回。紧接着就是核心问题“抓到物品”,即“检测碰撞”,下回接着说。欢迎参考原工程“挖金子VC版源码”(在CSDN下载频道)。