tc 打转块游戏

/*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;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值