本文主要是介绍基于Easyx制作的飞机大战,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
目录
- 飞机大战
- 结构体
- 游戏三部曲
- 初始化Game_Init()
- 绘制Game_Paint()
- 数据更新Game_Updata()
- 主函数
- 按键的处理
- 说明
- 链表的增删操作
- 添加敌方飞机
- 敌方飞机移动
- 添加子弹
- 子弹移动
飞机大战
基于链表操作的飞机大战游戏
运行截图:
源码获取: 飞机大战.
结构体
定义飞机大战所需结构体并全局定义结构体成员
//子弹的结构体
struct bullet
{int x;int y;struct bullet* pnext;
};
// 我方飞机
struct plane //我方飞机的结构体
{int x, y; //飞机的坐标bool exist; //飞机是否存活 exist==false(0) 飞机灭亡 ; exist=ture(1) 飞机存在struct bullet* bt; //子弹
};
//敌方飞机
struct enemy
{int x, y; //敌方飞机的坐标struct enemy* pnext; //用来保存下一个飞机的地址
};
struct plane myPlane; //定义我方飞机的结构体变量.
struct enemy* emy_Phead; //敌方飞机链表的头节点.
游戏三部曲
游戏三部曲:初始化,绘制,数据更新
初始化Game_Init()
包括加载图片和初始化游戏数据
void Game_Init()
{loadimage();myPlane.y = 700; myPlane.x = rand() % 500; //范围 0~499 myPlane.exist = true; //飞机存在为true//初始化子弹链表的头结点myPlane.bt = (struct bullet *)malloc(sizeof(struct bullet));myPlane.bt->pnext = NULL;//初始化敌方飞机的头结点emy_Phead = (struct enemy *)malloc(sizeof(struct enemy));emy_Phead->pnext = NULL;//初始化其他变量begin = GetTickCount();t1 = GetTickCount();g_bk.X = 0;g_bk.Y = 0;//开局先添加两架敌方飞机AddEnemy();AddEnemy();
}
绘制Game_Paint()
包含背景图片、我方飞机,敌方飞机、子弹的绘制
void Game_Paint()
{//开始批量绘图BeginBatchDraw();cleardevice(); //刷新屏幕/*========================贴背景图片========================*/putimage(g_bk.X, g_bk.Y, &g_back);putimage(g_bk.X, g_bk.Y - 768, &g_back);/*========================贴我方飞机========================*///判断我方的飞机是否存活,如果存活就贴飞机,否者就贴游戏失败的图片.if (myPlane.exist){putimage(myPlane.x, myPlane.y, &g_plane[1], SRCAND);putimage(myPlane.x, myPlane.y, &g_plane[0], SRCPAINT);}else{//游戏结束//贴 Game Over图片}/*========================贴敌方飞机========================*///遍历链表去绘制struct enemy* pTmp = emy_Phead->pnext; //指向第一架敌方飞机while (pTmp){putimage(pTmp->x, pTmp->y, &g_enemy[1], SRCAND);putimage(pTmp->x, pTmp->y, &g_enemy[0], SRCPAINT);//要往后遍历pTmp = pTmp->pnext;}/*========================贴我方飞机子弹========================*/struct bullet* pBullet = myPlane.bt->pnext;while (pBullet) //贴图{putimage(pBullet->x, pBullet->y, &g_Bullet, SRCPAINT);pBullet = pBullet->pnext;}//结束批量绘图EndBatchDraw();
}
数据更新Game_Updata()
包含敌方飞机,子弹,背景的移动,我方飞机的移动有按键消息来控制不在此列
void Game_Updata()
{EnemyMove(); //飞机移动BulletMove(); //子弹移动BackMove(); //背景移动
}
主函数
通过不断获取end的时间来控制游戏的绘制和数据更新
通过不断获取t2的时间来控制敌方飞机的数量
通过不断获取按键消息来控制我方飞机的移动
int main()
{initgraph(512, 768); /* 初始化图形库 */Game_Init(); /* 游戏的初始化 */while (1){end = GetTickCount(); /* 获取end时间 */t2 = GetTickCount(); /* 获取t2时间 */if (kbhit()) /* 判断是否有按键消息 */{PlaneMove(); /* 玩家操作飞机移动和开火 */}if (end - begin >= 50){Game_Paint(); /* 游戏的绘制 */Game_Updata(); /* 游戏的跟新 */begin = end;}if (t2 - t1 >= 3000){AddEnemy(); /* 添加敌方飞机 */AddEnemy(); /* 添加敌方飞机 */t1 = t2;}}closegraph(); /* 关闭图形库 */return 0;
}
按键的处理
玩家操作实现功能
- 实现我方飞机的上下左右移动
- 实现空格添加子弹
void PlaneMove()
{// 获取键盘按下信息 char ch = getch(); //获取键盘输入switch (ch) // 上 下 左 右 发射子弹{case 72: //往上走 72 是 ↑ 键值case 'W':case 'w'://在里面定义变量 就要加{}myPlane.y -= 20;if (myPlane.y < 0){myPlane.y = 0;}break;case 80: //往下走case 'S':case 's':myPlane.y += 20;if (myPlane.y>668){myPlane.y = 700;}break;case 75: //左边case 'A':case 'a':myPlane.x -= 20;if (myPlane.x < 0){myPlane.x = 0;}break;case 77: //右边case 'D':case 'd':myPlane.x += 20;if (myPlane.x > 437){myPlane.x = 437;}break;case 32: //32是空格键//调用函数 发射子弹FireBullet();break;}
}
说明
kbbhit:检查控制台的键盘输入。
int kbhit( void );
返回值:
如果按下某个键,则**_kbhit**返回一个非零值。否则,它返回0。
链表的增删操作
添加敌方飞机
如果ni链表操作ok的话这个敌方飞机的添加操作是完全没问题的,就一个头插
void AddEnemy()
{//申请新结点struct enemy* newnode = (struct enemy*)malloc(sizeof(struct enemy));newnode->x = rand() % 412; //x坐标 随机newnode->y = -100; //y坐标 固定//头插newnode->pnext = emy_Phead->pnext;emy_Phead->pnext = newnode;
}
敌方飞机移动
简简单单的链表遍历和删除操作,掌握基础就掌握力量
void EnemyMove()
{struct enemy* pTmp = emy_Phead;//指向敌方飞机的头结点struct enemy* pDelete;while (pTmp->pnext != NULL){pTmp->pnext->y += rand() % 10; //可快可慢//判断飞机是否越界了if (pTmp->pnext->y >= 800){//把越界的飞机销毁掉pDelete = pTmp->pnext;pTmp->pnext = pDelete->pnext;free(pDelete);pDelete = NULL;continue;}//往后遍历pTmp = pTmp->pnext;}
}
添加子弹
又是一个链表的头插操作,链表很重要啊
void FireBullet()
{//发射子弹其实就是创建结点.struct bullet *newbullet = (struct bullet *)malloc(sizeof(struct bullet));//给x和y 赋值newbullet->x = myPlane.x + 28; //子弹的x坐标 newbullet->y = myPlane.y - 10; //子弹的 y坐标//连接结点 newbullet->pnext = myPlane.bt->pnext;myPlane.bt->pnext = newbullet;
}
子弹移动
这里就比较复杂了,但终究还是链表的遍历和匹配操作,注释很清楚,仔细看
- 通过遍历每一个子弹来实现子弹的移动
- 通过将每一个子弹和敌方飞机做匹配判断是否杀敌
void BulletMove()
{//遍历每一个子弹 让他们向上移动struct bullet* pPlane = myPlane.bt; //指向子弹的头结点struct bullet* pDelete; //指向要删除的子弹while (pPlane->pnext != NULL){//子弹的移动速度 都是一样的pPlane->pnext->y -= 10;//处理子弹越界if (pPlane->pnext->y < -50){pDelete = pPlane->pnext;pPlane->pnext = pDelete->pnext;free(pDelete);pDelete = NULL;continue;}//处理子弹撞到飞机 子弹坐标 跟敌方飞机做比较 // 遍历敌方飞机 struct enemy *pEnemy = emy_Phead; struct enemy *pDeleteEnemy; //遍历敌方飞机的循环while (pEnemy->pnext != NULL){if ((pPlane->pnext->x >= pEnemy->pnext->x) && pPlane->pnext->x <= (pEnemy->pnext->x + 80) && pPlane->pnext->y <= (pEnemy->pnext->y + 100)){//飞机爆炸的图片 贴上去 //把飞机释放掉pDeleteEnemy = pEnemy->pnext;pEnemy->pnext = pDeleteEnemy->pnext;free(pDeleteEnemy);pDeleteEnemy = NULL;// 把子弹释放掉 pDelete = pPlane->pnext;pPlane->pnext = pDelete->pnext;free(pDelete);pDelete = NULL;break; //这个break是个坑,当子弹击中敌方某一架飞机的时候已经不需要继续遍历后面的飞机了,因为子弹已经没有了}//判断敌方飞机是不是NULLif (pEnemy->pnext == NULL){break;}pEnemy = pEnemy->pnext;}//判断子弹是不是NULLif (pPlane->pnext == NULL){break; //如果子弹没了就break}pPlane = pPlane->pnext;}
}
这篇关于基于Easyx制作的飞机大战的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!