/*07年3月更新,作者:贾胜华,此非最新版本,算法有多处更新没有添加,
有任何建议或意见和联系:xiajia_1981@163.com 或者 QQ:39970763*/
//---------------------------------------------------------------------------------------------
/*DZ2.h文件内容如下*/
/*定义必要结构体*/
/*
程序默认定义:砖块的最慢设计为8行8列,即最多64个砖块,相邻砖块必须紧贴着,不能有间隙;
球的大小不能在游戏过程中改变,在游戏开始之前就必须确定球的大小,因为改变球变大将会造成意想不到的碰撞;
*/
struct _Point
{
double x; //横坐标
double y; //纵坐标
};
struct _Area
{
double Xmin;
double Xmax;
double Ymin;
double Ymax;
};
struct _Ball
{
double BallR; //球的半径
struct _Point CenterPoint; //球心坐标
short Color; //球的颜色
short type; //球的类型
double RadArph; //球的运动方向角:垂直向上运动时,这个值为0
double Speed; //球的运动速度
int HitNO; //用于记录上一次碰撞的砖块编号
};
struct _Brick
{
double Longth; //砖块的长
double Higth; //砖块的高
struct _Point CenterPoint; //砖块的中心坐标
short Color; //砖块的颜色
short Type; //砖块的类型 -1:表示该砖块无效,即该砖块不参与碰撞判断
int HitTimes; //砖块的被打击次数
};
struct _Baffle
{
double Longth; //挡板的长度
double Higth; //挡板的高度
struct _Point CenterPoint; //挡板的中心坐标
short Color; //挡板的颜色
short Type; //挡板的类型
int HitTimes; //挡板的击球次数
int MoveDirection; //挡板的移动方向 0:没有移动 1:向左移动 2:向右移动
int Speed;
};
struct _Wall
{
struct _Area Area;
};
/*定义适当的方法*/
//********************************************************
//判断球在是否发生碰撞
//********************************************************
int IsInHitArea(struct _Ball Ball,struct _Brick *Brick,struct _Baffle Baffle,struct _Wall Wall,int * HitNumble,int BrickSum);//用于判断球是否在某个砖块或者墙面的碰撞范围内
/*参数说明:
Ball 球的信息
Brick 砖块的信息(砖块用数组存储)
Baffle 挡板的信息
Wall 墙面的信息
HitNumble 这是一个数组用于存储参与碰撞的对象的信息
-1:该数组有效数据结束的标记
0-99:参与碰撞的砖块的编号
100:挡板参与碰撞
101:墙面参与碰撞
BrickSum:游戏中有效的砖块数量
函数返回值为参与碰撞的次数*/
//*******************************************************
//处理球与相应砖块碰撞的过程
//(主要计算碰撞之后球的运动路线和对相应砖块进行标记)
//*******************************************************
int BrickCrashProc(struct _Ball * Ball,struct _Brick * Brick,int HitNumble);
/*参数说明:
*Ball 指向球的指针,求得相关信息将会在这里被修改
*Brick 指向砖块数组的指针,砖块的信息将会在这里被修改
HitNumble 参与处理的砖块的编号
返回碰撞是否产生 0:没有碰撞进行 1:有碰撞进行
*/
//*******************************************************
//处理球与挡板的碰撞的过程
//(主要计算碰撞之后球的运动路线和挡板进行标记)
//*******************************************************
int BaffleCrashProc(struct _Ball * Ball,struct _Baffle *Baffle);
/*参数说明:
*Ball 指向球的指针,球的相关信息将会在这里被修改
*Baffle 指向挡板的指针,挡板的信息将会在这里被修改
返回碰撞是否产生 0:没有碰撞进行 1:有碰撞进行
*/
//*******************************************************
//处理球与墙面的碰撞过程
//(主要计算碰撞之后球的运动路线)
//*******************************************************
int WallCrashProc(struct _Ball * Ball,struct _Wall Wall);
/*参数说明:
*Ball 指向球的指针,球的相关信息将会在这里被修改
Wall 墙面的信息
返回碰撞是否产生 0:没有碰撞进行 1:有碰撞进行
*/
//*******************************************************
//挡板的移动函数
//*******************************************************
void BaffleMoveLeft(struct _Baffle *Baffle,struct _Wall Wall);
void BaffleMoveRight(struct _Baffle *Baffle,struct _Wall Wall);
void BaffleNoMove(struct _Baffle *Baffle);
/*参数说明:
*Baffle 指向挡板的指针,挡板的信息将会在这里被修改
Wall 墙面的信息
*/
//*******************************************************
//改变球大小的函数:注意游戏过程中,球变大的操作要谨慎,
//极有可能做成程序错误,因为球变大将会造成不可预计的碰撞
//*******************************************************
void BallChangeSize(struct _Ball *Ball,double r);
/*参数说明:
*Ball 指向球的指针
r 改变后求得半径
*/
//*******************************************************
//改变球的运动速度
//*******************************************************
void BallChangeSpeed(struct _Ball *Ball, double Speed);
/*参数说明:
*Ball 指向球的指针
Speed 改变后的运动速度
*/
//*******************************************************
//改变挡板的长度
//*******************************************************
void BaffleChangeLongth(struct _Baffle *Baffle, double Longth,struct _Wall Wall);
/*参数说明:
*Baffle 指向挡板的指针
Longth 挡板改变后的长度
Wall 墙壁的数据
*/
//***********************************
//数学处理函数
//***********************************
double AngleChange(double x);
double Square(double x);
/*
AngleChange() 繁角化简角的函数
Square() 计算平方的函数
*/
//***********************************
//下面是一些描绘界面的函数
//***********************************
void DrawBrick(struct _Brick Brick);//描绘一个砖块
void DrawBall(struct _Ball Ball);//描绘一个球
void DrawBaffle(struct _Baffle Baffle);//描绘挡板
void DrawWall(struct _Wall Wall);//描绘墙壁
//檫图操作
void KillDrawBrick(struct _Brick Brick);//描绘一个砖块
void KillDrawBall(struct _Ball Ball);//描绘一个球
void KillDrawBaffle(struct _Baffle Baffle);//描绘挡板
void KillDrawWall(struct _Wall Wall);//描绘墙壁
//*********************************************
//下面是程序调适函数
//*********************************************
void ErrerProc();
/*
ErrerProc() 错误处理函数
*/
//————————————————————————————————————————————
/*代码文件内容如下*/
#include <math.h>
#include <stdio.h>
#include <graphics.h>
#include "DZ2.h"
#define Pi 3.141592654
#define Gravity 0.01
//#define Test
#define Game
main()
{
//定义相关的变量
struct _Wall Wall;
struct _Baffle Baffle;
struct _Brick Brick[64];
struct _Ball Ball[2];
int HitNumble[64];
int i,j,k,l;//循环变量或者临时变量,他的值不做长距离传送
char PressKey='0';
//系统变量,用于整个游戏系统的操作
int SystemState=1;//系统标记
int SystemTime=0;//整个游戏系统的节奏控制变量
FILE *pf;
int SystemCode=0;//用于记录系统分数
char Code[10];
//数据数初始化
int mode=VGAHI,driver=VGA;
registerbgidriver(EGAVGA_driver);
initgraph(&driver,&mode,"//tc//BGI"); //图形界面初始化
while((pf = fopen("Game.txt", "r")) == NULL)//打开文件
{
printf("File can not open!");
getch();
exit(0);
}
//读取游戏数据
Star://这里是游戏的切入点
Wall.Area.Xmin=10;
Wall.Area.Ymin=10;
Wall.Area.Xmax=410;
Wall.Area.Ymax=410;
Baffle.CenterPoint.x = (Wall.Area.Xmin + Wall.Area.Xmax)/2.0;
Baffle.CenterPoint.y = Wall.Area.Ymax - 20;
Baffle.Color=7;
Baffle.Higth=6;
Baffle.HitTimes=0;
Baffle.Longth=400;
Baffle.Type=1;
Baffle.MoveDirection=0;
Baffle.Speed=10;
for(i=0;i<64;i++)
{
Brick[i].Type=-1;//先标记所有砖块为无效
}
for(i=0;i<8;i++)
{
for(j=0;j<8;j++)
{
Brick[i*8+j].CenterPoint.x = Wall.Area.Xmin + j*50 + 25;
Brick[i*8+j].CenterPoint.y = Wall.Area.Ymin + i*16 + 10 + 30;
Brick[i*8+j].Color=i+1;
Brick[i*8+j].Higth=16;
Brick[i*8+j].HitTimes=0;
Brick[i*8+j].Longth=50;
if(j!=3)
{
Brick[i*8+j].Type=i+1;//被初始化的砖块被定义为有效
if(i==4)
{
Brick[i*8+j].Type=10;
Brick[i*8+j].Color=10;
}
}
}
}
#ifdef Game
Brick[30].Color=11;
Brick[30].Type=11;
Brick[25].Color=12;
Brick[25].Type=12;
Brick[50].Color=13;
Brick[50].Type=13;
#endif
Ball[0].BallR = 5;
Ball[0].CenterPoint.x = Baffle.CenterPoint.x;
Ball[0].CenterPoint.y = Baffle.CenterPoint.y - Baffle.Higth/2.0 - Ball[0].BallR -1;
Ball[0].Color = 2;
Ball[0].RadArph = 0;
Ball[0].Speed = 1;
Ball[0].type = 1; //1:没有发射前,2:发射之后
Ball[1].type = 0;
Ball[0].HitNO = -1;
Ball[1].HitNO = -1;
cleardevice();
//显示游戏控制键
setcolor(1);
outtextxy(Wall.Area.Xmin + 40,Wall.Area.Ymax + 20,"Star:9 Left:4 Right:5 Stop:7 Quit:Q");
setcolor(6);
outtextxy(Wall.Area.Xmin + 40,Wall.Area.Ymax + 20," 9 4 5 7 Q");
setcolor(2);
outtextxy(Wall.Area.Xmax + 40,Wall.Area.Ymin + 20,"Your Code:");
setcolor(1);
//计算分数
Code[0]=SystemCode/10000 +48;
Code[1]=(SystemCode%10000)/1000 +48;
Code[2]=(SystemCode%1000)/100 +48;
Code[3]=(SystemCode%100)/10 +48;
Code[4]=(SystemCode%10) +48;
Code[5]='/0';
outtextxy(Wall.Area.Xmax + 120,Wall.Area.Ymin + 20,Code);
fscanf(pf,"%d,%d,%d;",&i,&j,&k);//读取球的属性
if(i>20) i=20;
if(i<2) i=2;
Ball[0].BallR=i;
if(j>8) j=8;
if(j<1) j=1;
Ball[0].Speed=j/4.0;
if(k<1) k=1;
if(k>16) k=16;
Ball[0].Color=k;
Ball[0].CenterPoint.y = Baffle.CenterPoint.y - Baffle.Higth/2.0 - Ball[0].BallR -1;
fscanf(pf,"%d,%d,%d;",&i,&j,&k);//读取球的属性
if(i<10) i=10;
if(i>150) i=150;
Baffle.Longth=i;
if(j<3) j=3;
if(j>100) j=100;
Baffle.Speed=j;
if(k<1) k=1;
if(k>16) k=16;
Baffle.Color=k;
//下面读取砖块的属性
for(i=0;i<8;i++)
{
fscanf(pf,"%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d;",&Brick[i*8+0].Type,&Brick[i*8+1].Type,&Brick[i*8+2].Type
,&Brick[i*8+3].Type,&Brick[i*8+4].Type,&Brick[i*8+5].Type,&Brick[i*8+6].Type,&Brick[i*8+7].Type);
for(j=0;j<8;j++)
{
//这里检查数据的合理性
if(Brick[i*8+j].Type!=-1 && (Brick[i*8+j].Type<1 || Brick[i*8+j].Type>15)) Brick[i*8+j].Type=-1;
Brick[i*8+j].Color=Brick[i*8+j].Type;
}
}
//下面描绘初始界面
for(i=0;i<64;i++)
{
DrawBrick(Brick[i]);
}
DrawBall(Ball[0]);//描绘一个球
DrawBaffle(Baffle);//描绘挡板
DrawWall(Wall);//描绘墙壁
//下面进入主游戏循环
for(;;)
{
//读取键盘操作
if(kbhit())
{
PressKey = getch();
}else
{
PressKey = '0';
}
//重新设置挡板的移动方向,设置为没有移动
BaffleNoMove(&Baffle);
//这里可以进行输赢判断
j=1;
for(i=0;i<64;i++)
{
if(Brick[i].Type>=1 && Brick[i].Type<=9)
{
j=0;
break;
}
}
if(j==1)
{//Win
setcolor(15);
outtextxy((Wall.Area.Xmin+Wall.Area.Xmax) /2,(Wall.Area.Ymin+Wall.Area.Ymax) /2,"Win");
getch();
goto Star;//重新开始游戏
//break;//退出游戏
}
if(Ball[0].CenterPoint.y>Baffle.CenterPoint.y)
{//Lose
setcolor(15);
outtextxy((Wall.Area.Xmin+Wall.Area.Xmax) /2,(Wall.Area.Ymin+Wall.Area.Ymax) /2,"Lose");
getch();
//goto Star;//重新开始游戏
break;//退出游戏
}
if(Ball[1].CenterPoint.y>Baffle.CenterPoint.y && Ball[1].type!=0)
{//设置付球无效
KillDrawBall(Ball[1]);
Ball[1].type=0;
}
switch(PressKey)
{
case '4':
{
if(SystemState==1)
{
//刷掉原有的图像
KillDrawBaffle(Baffle);
BaffleMoveLeft(&Baffle,Wall);//左移操作
for(i=0;i<2;i++)
{
if(Ball[i].type==1)
{
KillDrawBall(Ball[i]);
Ball[i].CenterPoint.x = Baffle.CenterPoint.x;
DrawBall(Ball[i]);
}
}
/*绘图操作*/
DrawBaffle(Baffle);
}
break;
}
case '5':
{
if(SystemState==1)
{
//刷掉原有的图像
KillDrawBaffle(Baffle);
BaffleMoveRight(&Baffle,Wall);//右移操作
for(i=0;i<2;i++)
{
if(Ball[i].type==1)
{
KillDrawBall(Ball[i]);
Ball[i].CenterPoint.x = Baffle.CenterPoint.x;
DrawBall(Ball[i]);
}
}
/*绘图操作*/
DrawBaffle(Baffle);
}
break;
}
case '7': //暂停操作
{
if(SystemState!=0)
{
SystemState=0;
setcolor(15);
outtextxy((Wall.Area.Xmin+Wall.Area.Xmax) /2,(Wall.Area.Ymin+Wall.Area.Ymax) /2,"Pause");
}
else
{
SystemState=1;
setfillstyle(1,0);
bar((Wall.Area.Xmin+Wall.Area.Xmax) /2,(Wall.Area.Ymin+Wall.Area.Ymax) /2 - 5
,(Wall.Area.Xmin+Wall.Area.Xmax) /2 + 40,(Wall.Area.Ymin+Wall.Area.Ymax) /2 + 6);
}
break;
}
case '9': //发射球得操作
{
for(i=0;i<2;i++)
{
if(Ball[i].type==1 && SystemState==1)
{
Ball[i].type=2;
Ball[i].RadArph=Pi/4;
}
}
break;
}
case 'q': //暂停操作
case 'Q':
{
return 0;
}
default:;
}
if(SystemState==1 && SystemTime%3 == 0)
{//非暂停状态下的操作
for(l=0;l<2;l++)
if(Ball[l].type==2)
{
//计算球的当前坐标
KillDrawBall(Ball[l]);
Ball[l].CenterPoint.x -= Ball[l].Speed * sin(Ball[l].RadArph);
Ball[l].CenterPoint.y += Gravity - Ball[l].Speed * cos(Ball[l].RadArph);
//下面描绘小球的运动轨迹
putpixel(Ball[l].CenterPoint.x,Ball[l].CenterPoint.y,1);
DrawBall(Ball[l]);
//这里防止挡板的图像缺损
DrawBaffle(Baffle);
//碰撞判断
k=0;
if(IsInHitArea(Ball[l],Brick,Baffle,Wall,HitNumble,64)> 0)
{
for(i=0;;i++)
{
if(HitNumble[i]==-1) break;
if(HitNumble[i]<64)
{
//碰撞处理
j=Brick[HitNumble[i]].HitTimes;
if(BrickCrashProc(&Ball[l],Brick,HitNumble[i]))
{
k++;
Ball[l].HitNO=HitNumble[i];
}
if(j!=Brick[HitNumble[i]].HitTimes && Brick[HitNumble[i]].Type<10)
{
Brick[HitNumble[i]].Color--;
if(Brick[HitNumble[i]].Color>=17)
Brick[HitNumble[i]].Color=1;
}
if(Brick[HitNumble[i]].HitTimes==Brick[HitNumble[i]].Type
&& Brick[HitNumble[i]].Type!=10)
{
SystemCode+=5;//计分
Brick[HitNumble[i]].Type = -1;
}
//*******************************************************************
//对特殊功能的砖块将在这里进行
if(Brick[HitNumble[i]].HitTimes>=1
&& Brick[HitNumble[i]].Type==11)
{//如果击中的是使球变小的砖块,进入变小操作
Brick[HitNumble[i]].Type = -1;
SystemCode+=5;//计分
KillDrawBall(Ball[l]);
BallChangeSize(&Ball[l],Ball[l].BallR/2.0);
DrawBall(Ball[l]);
}
if(Brick[HitNumble[i]].HitTimes>=1
&& Brick[HitNumble[i]].Type==12)
{//如果击中的是改变球运动速度的砖块
Brick[HitNumble[i]].Type = -1;
SystemCode+=5;//计分
BallChangeSpeed(&Ball[l],Ball[l].Speed*2);
}
if(Brick[HitNumble[i]].HitTimes>=1
&& Brick[HitNumble[i]].Type==16)
{//如果击中的是改变球运动速度的砖块
Brick[HitNumble[i]].Type = -1;
SystemCode+=5;//计分
BallChangeSpeed(&Ball[l],Ball[l].Speed*0.5);
}
if(Brick[HitNumble[i]].HitTimes>=1
&& Brick[HitNumble[i]].Type==13)
{//击中的是改变挡板长度的砖块
KillDrawBaffle(Baffle);
Brick[HitNumble[i]].Type = -1;
SystemCode+=5;//计分
BaffleChangeLongth(&Baffle,Baffle.Longth*0.7,Wall);
DrawBaffle(Baffle);
}
if(Brick[HitNumble[i]].HitTimes>=1
&& Brick[HitNumble[i]].Type==17)
{//击中的是改变挡板长度的砖块
KillDrawBaffle(Baffle);
Brick[HitNumble[i]].Type = -1;
SystemCode+=5;//计分
BaffleChangeLongth(&Baffle,Baffle.Longth*1.429,Wall);
DrawBaffle(Baffle);
}
if(Brick[HitNumble[i]].HitTimes>=1
&& Brick[HitNumble[i]].Type==14)
{//回归重新发射的状态
KillDrawBall(Ball[l]);
Ball[l].CenterPoint.x = Baffle.CenterPoint.x;
Ball[l].CenterPoint.y = Baffle.CenterPoint.y - Baffle.Higth/2.0 - Ball[l].BallR -1;
Ball[l].type = 1; //1:没有发射前,2:发射之后
// Ball[l].Speed = 0;
DrawBall(Ball[l]);
Brick[HitNumble[i]].Type = -1;
SystemCode+=5;//计分
}
if(Brick[HitNumble[i]].HitTimes>=1
&& Brick[HitNumble[i]].Type==15)
{//击中了产生一个新的球的砖块,进行产生一个新球的操作
Brick[HitNumble[i]].Type = -1;
SystemCode+=5;//计分
Ball[1].BallR = Ball[0].BallR * 0.7;
Ball[1].CenterPoint.x = Ball[0].CenterPoint.x;
Ball[1].CenterPoint.y = Ball[0].CenterPoint.y;
Ball[1].Color = 5;
Ball[1].RadArph = AngleChange(Ball[0].RadArph + Pi);
Ball[1].Speed = Ball[0].Speed;
Ball[1].type = Ball[0].type;
DrawBall(Ball[1]);
}
//重新绘制砖块
if(Brick[HitNumble[i]].Type != -1)
DrawBrick(Brick[HitNumble[i]]);
else
KillDrawBrick(Brick[HitNumble[i]]);
}
if(HitNumble[i]==100)
{
//挡板碰撞
if(BaffleCrashProc(&Ball[l],&Baffle))
{
k++;
Ball[l].HitNO = 100;
}
}
if(HitNumble[i]==101)
{
//墙面碰撞
if(WallCrashProc(&Ball[l],Wall))
{
k++;
Ball[l].HitNO = 101;
}
}
}
}
if(k!=0)
{
//下面显示分数
//查掉之前的文字
setfillstyle(1,0);
bar(Wall.Area.Xmax + 120,Wall.Area.Ymin + 20 - 5 ,Wall.Area.Xmax + 120+40,Wall.Area.Ymin + 20 + 6);
setcolor(1);
//计算分数
Code[0]=SystemCode/10000 +48;
Code[1]=(SystemCode%10000)/1000 +48;
Code[2]=(SystemCode%1000)/100 +48;
Code[3]=(SystemCode%100)/10 +48;
Code[4]=(SystemCode%10) +48;
Code[5]='/0';
outtextxy(Wall.Area.Xmax + 120,Wall.Area.Ymin + 20,Code);
}else
{//如果没有发生碰撞这里标记-1
Ball[l].HitNO = -1;
}
}
}
delay(1);
SystemTime++;
if(SystemTime>=1000) SystemTime=0;
}
return 0;
}
double Square(double x)
{
double y=x*x;
return y;
}
double AngleChange(double x)
{//繁角化简角
for(;;)
{
if(x<2.0*Pi)
break;
else
x-=2.0*Pi;
}
for(;;)
{
if(x<0)
x+=2.0*Pi;
else
break;
}
return x;
}
void ErrerProc()
{
printf("The data errer, press any key to quit!");
getch();
exit(0);
}
/*下面实现所有的方法*/
int IsInHitArea(struct _Ball Ball,struct _Brick * Brick,struct _Baffle Baffle,struct _Wall Wall,int * HitNumble,int BrickSum)
{
int i,j;//循环参数
int IsCrash = 0;
struct _Area CrashArea;
//有效性判断
if(BrickSum<=0) ErrerProc();
//数据初始化
HitNumble[0] = -1;//-1是表示该数组结束的标志
//计算球与砖块的碰撞区域(这里应该计算下一步会不会发生碰撞)
Ball.CenterPoint.x -= Ball.Speed * sin(Ball.RadArph);
Ball.CenterPoint.y += Gravity - Ball.Speed * cos(Ball.RadArph);
CrashArea.Xmin = Ball.CenterPoint.x - Ball.BallR - Brick[0].Longth/2.0 ;
CrashArea.Xmax = Ball.CenterPoint.x + Ball.BallR + Brick[0].Longth/2.0 ;//+1;
CrashArea.Ymin = Ball.CenterPoint.y - Ball.BallR - Brick[0].Higth/2.0 ;
CrashArea.Ymax = Ball.CenterPoint.y + Ball.BallR + Brick[0].Higth/2.0 ;//+1;
//判断球会不会与砖块进行碰撞
j=0;
for(i=0;i<BrickSum;i++)
{
if(Brick[i].CenterPoint.x >= CrashArea.Xmin && Brick[i].CenterPoint.x <= CrashArea.Xmax
&& Brick[i].CenterPoint.y >= CrashArea.Ymin && Brick[i].CenterPoint.y <= CrashArea.Ymax
&& Brick[i].Type!=-1 && Ball.HitNO!=i)
{//在碰撞区域内
HitNumble[j] = i;
j++;
HitNumble[j] = -1;
}
}
if(j!=0) IsCrash = j;//记录可能发生碰撞的次数
//判断球会不会与挡板发生碰撞
CrashArea.Xmin = Ball.CenterPoint.x - Ball.BallR - Baffle.Longth/2.0 ;
CrashArea.Xmax = Ball.CenterPoint.x + Ball.BallR + Baffle.Longth/2.0 ;//+1;
CrashArea.Ymin = Ball.CenterPoint.y - Ball.BallR - Baffle.Higth/2.0 ;
CrashArea.Ymax = Ball.CenterPoint.y + Ball.BallR + Baffle.Higth/2.0 ;//+1;
if(Baffle.CenterPoint.x >= CrashArea.Xmin && Baffle.CenterPoint.x <= CrashArea.Xmax
&& Baffle.CenterPoint.y >= CrashArea.Ymin && Baffle.CenterPoint.y <= CrashArea.Ymax
&& Ball.HitNO!=100)
{//在碰撞区域内
HitNumble[j] = 100; //这是对于挡板的特殊标记
j++;
HitNumble[j] = -1;
}
if(j!=0) IsCrash = j;//记录可能发生碰撞的次数
//判断球会不会与墙壁发生碰撞
CrashArea.Xmin = Ball.CenterPoint.x - Ball.BallR ;//-2;
CrashArea.Xmax = Ball.CenterPoint.x + Ball.BallR ;//+2;
CrashArea.Ymin = Ball.CenterPoint.y - Ball.BallR ;//-2;
CrashArea.Ymax = Ball.CenterPoint.y + Ball.BallR ;//+2;
if(Wall.Area.Xmin>= CrashArea.Xmin || Wall.Area.Xmax<= CrashArea.Xmax
|| Wall.Area.Ymin >= CrashArea.Ymin)
{//在碰撞区域内
HitNumble[j] = 101; //这是对于墙壁的特殊标记,这里不需要做排斥判断
j++;
HitNumble[j] = -1;
}
if(j!=0) IsCrash = j;//记录可能发生碰撞的次数
return IsCrash;
}
//球和砖块碰撞的函数
int BrickCrashProc(struct _Ball * Ball,struct _Brick * Brick,int HitNumble)
{
int i,j,k;//循环变量
int IsTrue=0;
double AngleL=0;
struct _Ball LBall;
LBall.CenterPoint.x = Ball->CenterPoint.x - Ball->Speed * sin(Ball->RadArph);
LBall.CenterPoint.y = Ball->CenterPoint.y - Ball->Speed * cos(Ball->RadArph) + Gravity;
//第一类碰撞判断(球心在砖块的范围内)
if((LBall.CenterPoint.x >= Brick[HitNumble].CenterPoint.x - Brick[HitNumble].Longth/2.0
&& LBall.CenterPoint.x <= Brick[HitNumble].CenterPoint.x + Brick[HitNumble].Longth/2.0)
|| (LBall.CenterPoint.y >= Brick[HitNumble].CenterPoint.y - Brick[HitNumble].Higth/2.0
&& LBall.CenterPoint.y <= Brick[HitNumble].CenterPoint.y + Brick[HitNumble].Higth/2.0))
{//这类碰撞是不要判断真伪的,下面直接进入碰撞处理
//水平碰撞
if(LBall.CenterPoint.x >= Brick[HitNumble].CenterPoint.x - Brick[HitNumble].Longth/2.0
&& LBall.CenterPoint.x <= Brick[HitNumble].CenterPoint.x + Brick[HitNumble].Longth/2.0)
{
if(Ball->RadArph <= Pi)
Ball->RadArph = Pi - Ball->RadArph;
else
Ball->RadArph = 3*Pi - Ball->RadArph;
}else
{
Ball->RadArph = 2*Pi - Ball->RadArph;
}
Ball->RadArph=AngleChange(Ball->RadArph);
Brick[HitNumble].HitTimes++;
IsTrue=1;
#ifdef Test
getch();
#endif
}else
{
//第二类碰撞的判断(顶点到球心的距离几乎等于球的半径.值得注意的是下面的角度公式并不严密)
if(Square(Brick[HitNumble].CenterPoint.x - Brick[HitNumble].Longth/2.0 - LBall.CenterPoint.x)+
Square(Brick[HitNumble].CenterPoint.y - Brick[HitNumble].Higth/2.0 - LBall.CenterPoint.y)
- Square(Ball->BallR) <=0.01
&&((HitNumble<8 && HitNumble!=0 && Brick[HitNumble-1].Type == -1)
|| (HitNumble>7 && HitNumble%8!=0 && Brick[HitNumble-1].Type == -1 && Brick[HitNumble-8].Type == -1)))//还需要满足没有相邻的砖块
{//左上角碰撞为真
AngleL=atan((Brick[HitNumble].CenterPoint.x - Brick[HitNumble].Longth/2.0 - LBall.CenterPoint.x)/
(Brick[HitNumble].CenterPoint.y - Brick[HitNumble].Higth/2.0 - LBall.CenterPoint.y));
Ball->RadArph=AngleChange(2*AngleL - Ball->RadArph + Pi);
Brick[HitNumble].HitTimes++;
IsTrue=1;
#ifdef Test
getch();
#endif
}else
if(Square(Brick[HitNumble].CenterPoint.x + Brick[HitNumble].Longth/2.0 - LBall.CenterPoint.x)+
Square(Brick[HitNumble].CenterPoint.y - Brick[HitNumble].Higth/2.0 - LBall.CenterPoint.y)
- Square(Ball->BallR) <=0.01
&& ((HitNumble<8 && HitNumble!=7 && Brick[HitNumble+1].Type == -1)
|| (HitNumble>7 && HitNumble%8!=7 && Brick[HitNumble+1].Type == -1 && Brick[HitNumble-8].Type == -1)))//还需要满足没有相邻的砖块
{//右上角碰撞为真
AngleL=atan((LBall.CenterPoint.x - Brick[HitNumble].CenterPoint.x - Brick[HitNumble].Longth/2.0)/
(Brick[HitNumble].CenterPoint.y - Brick[HitNumble].Higth/2.0 - LBall.CenterPoint.y));
Ball->RadArph=AngleChange(Pi-2*AngleL-Ball->RadArph);
Brick[HitNumble].HitTimes++;
IsTrue=1;
#ifdef Test
getch();
#endif
}else
if(Square(Brick[HitNumble].CenterPoint.x - Brick[HitNumble].Longth/2.0 - LBall.CenterPoint.x)+
Square(Brick[HitNumble].CenterPoint.y + Brick[HitNumble].Higth/2.0 - LBall.CenterPoint.y)
- Square(Ball->BallR) <=0.01
&&((HitNumble>55 && HitNumble!=0 && Brick[HitNumble-1].Type == -1)
|| (HitNumble<56 && HitNumble%8!=0 && Brick[HitNumble-1].Type == -1 && Brick[HitNumble+8].Type == -1)))//还需要满足没有相邻的砖块
{//左下角碰撞为真
AngleL=atan((Brick[HitNumble].CenterPoint.x - Brick[HitNumble].Longth/2.0 - LBall.CenterPoint.x)/
(LBall.CenterPoint.y - Brick[HitNumble].CenterPoint.y - Brick[HitNumble].Higth/2.0));
Ball->RadArph=AngleChange(Pi-2*AngleL-Ball->RadArph);
Brick[HitNumble].HitTimes++;
IsTrue=1;
#ifdef Test
getch();
#endif
}else
if(Square(Brick[HitNumble].CenterPoint.x + Brick[HitNumble].Longth/2.0 - LBall.CenterPoint.x)+
Square(Brick[HitNumble].CenterPoint.y + Brick[HitNumble].Higth/2.0 - LBall.CenterPoint.y)
- Square(Ball->BallR) <=0.01
&& ((HitNumble>55 && HitNumble!=7 && Brick[HitNumble+1].Type == -1)
|| (HitNumble<56 && HitNumble%8!=7 && Brick[HitNumble+1].Type == -1 && Brick[HitNumble+8].Type == -1)))//还需要满足没有相邻的砖块
{//右下角碰撞为真
AngleL=atan((LBall.CenterPoint.x - Brick[HitNumble].CenterPoint.x - Brick[HitNumble].Longth/2.0)/
(LBall.CenterPoint.y - Brick[HitNumble].CenterPoint.y - Brick[HitNumble].Higth/2.0));
Ball->RadArph=AngleChange(2*AngleL - Ball->RadArph + Pi);
Brick[HitNumble].HitTimes++;
IsTrue=1;
#ifdef Test
getch();
#endif
}
}
return IsTrue;
}
//*******************************************************************
//下面的函数用于处理球与挡板的碰撞问题,这里做一下不规范的处理
//1、挡板只处理上面的角和上边反弹处理
//2、为了防止多次碰撞的处理,球与挡板的碰撞只在角度合适的前提下才进行
//*******************************************************************
int BaffleCrashProc(struct _Ball * Ball,struct _Baffle *Baffle)
{
int i,j,k;//循环变量
int IsTrue=0;
double AngleL=0;
struct _Ball LBall;
LBall.CenterPoint.x = Ball->CenterPoint.x - Ball->Speed * sin(Ball->RadArph);
LBall.CenterPoint.y = Ball->CenterPoint.y - Ball->Speed * cos(Ball->RadArph) + Gravity;
//所有关于挡板与球的碰撞都要满足球心在挡板的上面
if(LBall.CenterPoint.y <= Baffle->CenterPoint.y - Baffle->Higth/2.0)
//第一类碰撞判断(球心在砖块的范围内)
if((LBall.CenterPoint.x >= Baffle->CenterPoint.x - Baffle->Longth/2.0
&& LBall.CenterPoint.x <= Baffle->CenterPoint.x + Baffle->Longth/2.0)
|| (LBall.CenterPoint.y >= Baffle->CenterPoint.y - Baffle->Higth/2.0
&& LBall.CenterPoint.y <= Baffle->CenterPoint.y + Baffle->Higth/2.0))
{//这类碰撞是不要判断真伪的,下面直接进入碰撞处理
//水平碰撞(值得注意的是:为了游戏的多样性这里不完全遵循物理弹射规则……,
//而是要更具弹射位置的不同而采用不同的反射角)
if(LBall.CenterPoint.x >= Baffle->CenterPoint.x - Baffle->Longth/2.0
&& LBall.CenterPoint.x <= Baffle->CenterPoint.x + Baffle->Longth/2.0)
{
//下面引入距离与角度的关系
if(Ball->RadArph >= 0.5*Pi && Ball->RadArph <= Pi)
{
Ball->RadArph = Pi - Ball->RadArph;
if(LBall.CenterPoint.y < Baffle->CenterPoint.y - Baffle->Higth/2.0)
{//如果是在挡板的上面发生碰撞
//这里考虑挡板移动对反弹的影响,主要是为了提供游戏的多样性
if(Baffle->MoveDirection==1)
{
Ball->RadArph+= (Pi/2.0 - Ball->RadArph)*0.3;
}
if(Baffle->MoveDirection==2)
{
Ball->RadArph*=0.7;
}
}
Baffle->HitTimes++;
IsTrue=1;
}
else
{
if(Ball->RadArph >= Pi && Ball->RadArph <= 1.5*Pi)
{
Ball->RadArph = 3*Pi - Ball->RadArph;
if(LBall.CenterPoint.y < Baffle->CenterPoint.y - Baffle->Higth/2.0)
{//如果是在挡板的上面发生碰撞
//这里考虑挡板移动对反弹的影响,主要是为了提供游戏的多样性
if(Baffle->MoveDirection==1)
{
Ball->RadArph+= (2.0*Pi - Ball->RadArph)*0.3;
}
if(Baffle->MoveDirection==2)
{
Ball->RadArph-= (Ball->RadArph - 1.5*Pi)*0.3;
}
}
Baffle->HitTimes++;
IsTrue=1;
}
}
}
else
{
if((LBall.CenterPoint.x < Baffle->CenterPoint.x - Baffle->Longth/2.0
&& (Ball->RadArph >= 0.5*Pi && Ball->RadArph <= Pi))
|| (LBall.CenterPoint.x > Baffle->CenterPoint.x + Baffle->Longth/2.0
&& (Ball->RadArph > Pi && Ball->RadArph <= 1.5*Pi)))
{
Ball->RadArph = 2*Pi - Ball->RadArph;
Baffle->HitTimes++;
IsTrue=1;
}
}
}else
{
//第二类碰撞的判断(顶点到球心的距离几乎等于球的半径.值得注意的是下面的角度公式并不严密)
if(Square(Baffle->CenterPoint.x - - LBall.CenterPoint.x)+
Square(Baffle->CenterPoint.y - Baffle->Higth/2.0 - LBall.CenterPoint.y)
- Square(Ball->BallR) <=0.01
&&//这里加入角度限制
(Ball->RadArph> 0.5*Pi && Ball->RadArph< 1.5*Pi))
{//左上角碰撞为真
AngleL=atan((Baffle->CenterPoint.x - Baffle->Longth/2.0 - LBall.CenterPoint.x)/
(Baffle->CenterPoint.y - Baffle->Higth/2.0 - LBall.CenterPoint.y));
Ball->RadArph=AngleChange(2*AngleL - Ball->RadArph + Pi);
Baffle->HitTimes++;
IsTrue=1;
}else
if(Square(Baffle->CenterPoint.x + Baffle->Longth/2.0 - LBall.CenterPoint.x)+
Square(Baffle->CenterPoint.y - Baffle->Higth/2.0 - LBall.CenterPoint.y)
- Square(Ball->BallR) <=0.01
&&
(Ball->RadArph> 0.5*Pi && Ball->RadArph< 1.5*Pi))
{//右上角碰撞为真
AngleL=atan((LBall.CenterPoint.x - Baffle->CenterPoint.x - Baffle->Longth/2.0)/
(Baffle->CenterPoint.y - Baffle->Higth/2.0 - LBall.CenterPoint.y));
Ball->RadArph=AngleChange(Pi-2*AngleL-Ball->RadArph);
Baffle->HitTimes++;
IsTrue=1;
}
}
return IsTrue;
}
int WallCrashProc(struct _Ball * Ball,struct _Wall Wall)
{
int IsTrue=0;
struct _Ball LBall;
LBall.CenterPoint.x = Ball->CenterPoint.x - Ball->Speed * sin(Ball->RadArph);
LBall.CenterPoint.y = Ball->CenterPoint.y - Ball->Speed * cos(Ball->RadArph) + Gravity;
//左墙
if(LBall.CenterPoint.x - Ball->BallR <= Wall.Area.Xmin + 2)
{
Ball->RadArph = 2 * Pi - Ball->RadArph;
IsTrue=1;
}
//右墙
if(LBall.CenterPoint.x + Ball->BallR >= Wall.Area.Xmax - 2)
{
Ball->RadArph = 2 * Pi - Ball->RadArph;
IsTrue=1;
}
//上墙
if(LBall.CenterPoint.y - Ball->BallR <= Wall.Area.Ymin + 2)
{
if(Ball->RadArph <= Pi)
Ball->RadArph = Pi - Ball->RadArph;
else
Ball->RadArph = 3*Pi - Ball->RadArph;
IsTrue=1;
}
//游戏中要避免水平或者垂直的运动,下面的部分用于避免这一部分
if(Square(Ball->RadArph - Pi/2.0)<0.001)
{
if(Ball->RadArph < Pi/2.0)
{
Ball->RadArph = Pi/2.0 - 0.15;
}else
{
Ball->RadArph = Pi/2.0 + 0.15;
}
}
if(Square(Ball->RadArph - 3.0*Pi/2.0)<0.001)
{
if(Ball->RadArph < 3.0*Pi/2.0)
{
Ball->RadArph = 3.0*Pi/2.0 - 0.15;
}else
{
Ball->RadArph = 3.0*Pi/2.0 - 0.15;
}
}
return IsTrue;
}
void DrawBrick(struct _Brick Brick)
{
int x=Brick.CenterPoint.x - Brick.Longth/2.0;
int y=Brick.CenterPoint.y - Brick.Higth/2.0;
int sizx=Brick.Longth - 1;
int sizy=Brick.Higth - 1;
if(Brick.Type == -1) return ;
setcolor(15);/*这里最好用白色*/
line(x,y,x+sizx-1,y);
line(x,y+1,x+sizx-2,y+1);
line(x,y,x,y+sizy-1);
line(x+1,y,x+1,y+sizy-2);
setcolor(8);/*这里最好用深灰色*/
line(x+1,y+sizy,x+sizx,y+sizy);
line(x+2,y+sizy-1,x+sizx,y+sizy-1);
line(x+sizx-1,y+1,x+sizx-1,y+sizy);
line(x+sizx,y,x+sizx,y+sizy);
setcolor(7);/*这里最好用灰色*/
putpixel(x,y+sizy,3);
putpixel(x+1,y+sizy-1,3);
putpixel(x+sizx,y,3);
putpixel(x+sizx-1,y+1,3);
setfillstyle(1,Brick.Color);/*这里最好用灰色,设置填充模式*/
bar(x+2,y+2,x+sizx-2,y+sizy-2);
}
void DrawBaffle(struct _Baffle Baffle)
{
int x=Baffle.CenterPoint.x - Baffle.Longth/2.0;
int y=Baffle.CenterPoint.y - Baffle.Higth/2.0;
int sizx=Baffle.Longth - 1;
int sizy=Baffle.Higth - 1;
if(Baffle.Type==1)
{
setcolor(15);/*这里最好用白色*/
line(x,y,x+sizx-1,y);
line(x,y+1,x+sizx-2,y+1);
line(x,y,x,y+sizy-1);
line(x+1,y,x+1,y+sizy-2);
setcolor(8);/*这里最好用深灰色*/
line(x+1,y+sizy,x+sizx,y+sizy);
line(x+2,y+sizy-1,x+sizx,y+sizy-1);
line(x+sizx-1,y+1,x+sizx-1,y+sizy);
line(x+sizx,y,x+sizx,y+sizy);
setcolor(7);/*这里最好用灰色*/
putpixel(x,y+sizy,3);
putpixel(x+1,y+sizy-1,3);
putpixel(x+sizx,y,3);
putpixel(x+sizx-1,y+1,3);
setfillstyle(1, Baffle.Color);/*这里最好用灰色,设置填充模式*/
bar(x+2,y+2,x+sizx-2,y+sizy-2);
}
}
void DrawBall(struct _Ball Ball)
{
setcolor(Ball.Color);
circle(Ball.CenterPoint.x,Ball.CenterPoint.y,Ball.BallR);
}
void DrawWall(struct _Wall Wall)
{
setcolor(15);/*这里最好用白色*/
line(Wall.Area.Xmin-1,Wall.Area.Ymin-1,Wall.Area.Xmax,Wall.Area.Ymin-1);
line(Wall.Area.Xmin-1,Wall.Area.Ymin-1,Wall.Area.Xmin-1,Wall.Area.Ymax);
line(Wall.Area.Xmax,Wall.Area.Ymax,Wall.Area.Xmax,Wall.Area.Ymin-1);
line(Wall.Area.Xmax,Wall.Area.Ymax,Wall.Area.Xmin-1,Wall.Area.Ymax);
}
void KillDrawBrick(struct _Brick Brick)
{
int x=Brick.CenterPoint.x - Brick.Longth/2.0;
int y=Brick.CenterPoint.y - Brick.Higth/2.0;
int sizx=Brick.Longth - 1;
int sizy=Brick.Higth - 1;
setfillstyle(1,0);/*这里最好用灰色,设置填充模式*/
bar(x,y,x+sizx,y+sizy);
}
void KillDrawBaffle(struct _Baffle Baffle)
{
int x=Baffle.CenterPoint.x - Baffle.Longth/2.0;
int y=Baffle.CenterPoint.y - Baffle.Higth/2.0;
int sizx=Baffle.Longth - 1;
int sizy=Baffle.Higth - 1;
setfillstyle(1,0);/*这里最好用灰色,设置填充模式*/
bar(x,y,x+sizx,y+sizy);
}
void KillDrawBall(struct _Ball Ball)
{
setcolor(0);
circle(Ball.CenterPoint.x,Ball.CenterPoint.y,Ball.BallR);
}
void KillDrawWall(struct _Wall Wall)
{
setcolor(0);/*这里最好用白色*/
line(Wall.Area.Xmin-1,Wall.Area.Ymin-1,Wall.Area.Xmax,Wall.Area.Ymin-1);
line(Wall.Area.Xmin-1,Wall.Area.Ymin-1,Wall.Area.Xmin-1,Wall.Area.Ymax);
line(Wall.Area.Xmax,Wall.Area.Ymax,Wall.Area.Xmax,Wall.Area.Ymin-1);
line(Wall.Area.Xmax,Wall.Area.Ymax,Wall.Area.Xmin-1,Wall.Area.Ymax);
}
void BaffleMoveLeft(struct _Baffle *Baffle,struct _Wall Wall)
{
//判断挡板的左移是否会碰墙
if(Baffle->CenterPoint.x - Baffle->Longth/2.0 - Baffle->Speed <= Wall.Area.Xmin)
{
Baffle->CenterPoint.x = Wall.Area.Xmin + Baffle->Longth/2.0 + 1;
}else
{
Baffle->CenterPoint.x -= Baffle->Speed;
}
Baffle->MoveDirection=1;
}
void BaffleMoveRight(struct _Baffle *Baffle,struct _Wall Wall)
{
//判断挡板的左移是否会碰墙
if(Baffle->CenterPoint.x + Baffle->Longth/2.0 + Baffle->Speed >= Wall.Area.Xmax)
{
Baffle->CenterPoint.x = Wall.Area.Xmax - Baffle->Longth/2.0 - 1;
}else
{
Baffle->CenterPoint.x += Baffle->Speed;
}
Baffle->MoveDirection=2;
}
void BaffleNoMove(struct _Baffle *Baffle)
{
Baffle->MoveDirection=0;
}
void BallChangeSize(struct _Ball *Ball,double r)
{
//这里不允许球的半径小于等于零
if(r<=0) return;
Ball->BallR = r;
}
void BallChangeSpeed(struct _Ball *Ball, double Speed)
{
//这里规定球的速度不能小于等于零
if(Speed <=0) return;
Ball->Speed=Speed;
}
void BaffleChangeLongth(struct _Baffle *Baffle, double Longth,struct _Wall Wall)
{
if(Longth<=0) return;
if(Baffle->CenterPoint.x+Longth/2.0> Wall.Area.Xmax)
Baffle->CenterPoint.x=Wall.Area.Xmax - Longth/2.0 -1;
if(Baffle->CenterPoint.x-Longth/2.0< Wall.Area.Xmin)
Baffle->CenterPoint.x=Wall.Area.Xmin + Longth/2.0 +1;
Baffle->Longth=Longth;
}
//----------------------------------------------------------------------------------------------------------------------
/*程序文档 Game.TXT,格式如下*/
球的数据:
半径,速度,颜色
挡板数据:
长度,移动速度,颜色
砖块信息:
-1:无效的砖块
1-9:可以有限次打坏的砖块
10:不可打坏的砖块
11:使球变小的砖块
12:使球变快的砖块,速度变快一倍
13:改变挡板长度的砖块
14:回到重新发射的状态
15:多产生一个球,一句中只能有一个这样的砖块
16:球的运动速度变慢一倍
17:挡板的长度变长
范例:
10,1,2;
400,10,7;
-1, 5, 5,-1,-1, 5, 5,-1;
5, 5, 5, 5, 5, 5, 5, 5;
5, 5, 5, 5, 5, 5, 5, 5;
-1, 5, 5, 5, 5, 5, 5,-1;
-1,-1, 5, 5, 5, 5,-1,-1;
-1,-1,-1, 5, 5,-1,-1,-1;
3, 3, 3,-1,-1, 3, 3, 3;
10,11, 1, 1, 1, 1, 1,10;