每周一坑--打飞机游戏

简介: 每周一坑--打飞机游戏

看了知乎上的一个C语言做的打飞机游戏(控制台)https://zhuanlan.zhihu.com/p/24798125

决定自己做一个C++版的。

先说一下原来游戏的思路。

首先主函数: 先初始化,然后再一个循环里不断地

显示-->更新与用户无关数据-->用户输入、根据输入更新。

显示是通过一个二维数组canvas (画布)来实现的,通过一个二层循环来在画布上进行绘制(输出字符)

字符的形状代表是 飞机或子弹或者空气。

更新与用户无关数据是按照一个规律:敌机往下飞,子弹往上飞,这样更新的。

根据输入更新            是根据用户输入的'a' 'd'或空格 来设置自己的位置和发射子弹。


 

int main()
{
  startup();  // 数据初始化  
  while (1)  // 游戏循环执行
  {
    show();  // 显示画面
    updateWithoutInput();  // 与用户输入无关的更新
    updateWithInput();  // 与用户输入有关的更新
  }
  return 0;
}

下面具体地操作。

 

那么既然要用C++,飞机就可以做成一个基类了。

然后从飞机 派生出两个类 一个是自己,一个是敌机。

自己和敌机有什么不同? 在这里为了简化,敌机不发射子弹,只是简单地往下移动。 自己是可以发射子弹的。

class Plane
{
private:
  int x;
  int y;
  int MoveSpeed;
public:
  Plane() :x(0), y(0) {};
  Plane(int x, int y) :x(x), y(y) {}
  ~Plane(){}
  int getX() { return x; }
  int getY() { return y; }
  int getMoveSpeed(){ return MoveSpeed; }
  void setX(int x) { this->x =x; }
  void setY(int y) { this->y = y; }
  void setMoveSpeed(int speed){ MoveSpeed = speed; }
};
 
class MyPlane : public Plane
{
private:
  int BulletWidth;
 
public:
  int getBulletWidth() { return BulletWidth; }
  void setBulletWidth(int width) { this->BulletWidth = width; }
 
};
class EnemyPlane : public Plane
{
 
};



 

除了飞机,其他的基本根据原来的改写,因为图像的显示主要依靠画布,所以如果画布不改动的话,其余的基本改变不大。

改写时为了方便,我将原来的长函数分解成短函数,看起来更容易。

最后的代码:

 

main.cpp

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#include"plane.h"
#include"updateFunction.h"
 
const int High     = 15;// 游戏画面尺寸
const int Width    = 25;
const int EnemyNum = 5;// 敌机个数
 
// 全局变量
MyPlane myPlane; // 飞机
EnemyPlane enemyPlane[EnemyNum];  // 敌机
int canvas[High+1][Width+1] = { 0 }; // 二维数组存储游戏画布中对应的元素
                   // 0为空格,1为飞机*,2为子弹|,3为敌机@
int score; // 得分
 
 //光标移动到(x,y)位置
void gotoxy(int x, int y) 
{
  HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
  COORD pos;
  pos.X = x;
  pos.Y = y;
  SetConsoleCursorPosition(handle, pos);
}
 
void startup() // 数据初始化
{
  //下面的两行用于隐藏光标,防止乱闪
  CONSOLE_CURSOR_INFO cursor_info = { 1,0 };
  SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
 
  //设自己置飞机位置
  startupMyPlane();
  //设置敌机位置
   startupEnemyPlane();
   score = 0;
}
 
void startupMyPlane()
{
  myPlane.setX(High - 1);
  myPlane.setY(Width - 2);
  myPlane.setBulletWidth(0);
}
void startupEnemyPlane()
{
  for (int k = 0; k < EnemyNum; k++)
  {
    enemyPlane[k].setX(rand() % 2);
    enemyPlane[k].setY(rand() % Width);
    enemyPlane[k].setMoveSpeed(20);
  }
}
 
// 显示画面
void show()  
{
  gotoxy(0, 0);  // 光标移动到原点位置,以下重画清屏
  for (int i = 0; i < High; i++)
  {
    for (int j = 0; j < Width; j++)
    {
      if (canvas[i][j] == 0)
        printf(" ");   //   输出空格
      else if (canvas[i][j] == 1)
        printf("*");   //   输出飞机*
      else if (canvas[i][j] == 2)
        printf("|");   //   输出子弹|
      else if (canvas[i][j] == 3)
        printf("@");   //  输出飞机@
    }
    printf("\n");
  }
  printf("得分:%d\n", score);
  Sleep(20);
}
 
// 与用户输入无关的更新
void updateWithoutInput()  
{   //更新子弹位置
  for (int i = 0; i < High; i++) {
    for (int j = 0; j < Width; j++) {
      if (canvas[i][j] == 2)    {
        updateBullet(i, j);
      }
    }
  }
  static int speed = 0;
  if (speed < enemyPlane[0].getMoveSpeed())
    speed++;
  updatePlane(speed );
}
 
 
void updateBullet(int i,int j)
{
  for (int k = 0; k < EnemyNum; k++) {
    if ((i == enemyPlane[k].getX()) && (j == enemyPlane[k].getY()))  // 子弹击中敌机
    {
      score++;                // 分数加1
      if (score % 5 == 0 && enemyPlane[k].getMoveSpeed() > 3)   // 达到一定积分后,敌机变快
        enemyPlane[k].setMoveSpeed(enemyPlane[k].getMoveSpeed() - 1);
      if (score % 5 == 0)   // 达到一定积分后,子弹变厉害
        myPlane.setBulletWidth(myPlane.getBulletWidth() + 1);
      canvas[enemyPlane[k].getX()][enemyPlane[k].getY()] = 0;
      enemyPlane[k].setX(rand() % 2);           // 产生新的飞机
      enemyPlane[k].setY(rand() % Width);
      canvas[enemyPlane[k].getX()][enemyPlane[k].getY()] = 3;
      canvas[i][j] = 0;      // 子弹消失
    }
  }
  // 子弹向上移动
  canvas[i][j] = 0;
  if (i > 0)
    canvas[i - 1][j] = 2;
}
void updatePlane(int& speed )
{
  for (int k = 0; k < EnemyNum; k++)
  {
    if ((myPlane.getX() == enemyPlane[k].getX()) && (myPlane.getY() == enemyPlane[k].getY()))  // 敌机撞到我机
    {
      printf("失败!\n");
      Sleep(3000);
      system("pause");
      exit(0);
    }
 
    if (enemyPlane[k].getX() > High)   // 敌机跑出显示屏幕
    {
      canvas[enemyPlane[k].getX()][enemyPlane[k].getY()] = 0;
      enemyPlane[k].setX(rand() % 2);           // 产生新的飞机
      enemyPlane[k].setY(rand() % Width);
      canvas[enemyPlane[k].getX()][enemyPlane[k].getY()] = 3;
      score--;  // 减分
    }
 
    if (speed == enemyPlane[0].getMoveSpeed())
    {
      // 敌机下落
      for (k = 0; k < EnemyNum; k++)
      {
        canvas[enemyPlane[k].getX()][enemyPlane[k].getY()] = 0;
        enemyPlane[k].setX(enemyPlane[k].getX() + 1);
        speed = 0;
        canvas[enemyPlane[k].getX()][enemyPlane[k].getY()] = 3;
      }
    }
  }
}
 
void updateWithInput()  // 与用户输入有关的更新
{
  char input;
  if (_kbhit())  // 判断是否有输入
  {
    input = _getch();  // 根据用户的不同输入来移动,不必输入回车
    if (input == 'a' && myPlane.getX() > 0)
    {
      canvas[myPlane.getX()][myPlane.getY()] = 0;
      myPlane.setY(myPlane.getY()-1);  // 位置左移
      canvas[myPlane.getX()][myPlane.getY()] = 1;
    }
    else if (input == 'd' && myPlane.getY() < Width - 1)
    {
      canvas[myPlane.getX()][myPlane.getY()] = 0;
      myPlane.setY(myPlane.getY() +1);  // 位置右移
      canvas[myPlane.getX()][myPlane.getY()] = 1;
    }
    else if (input == 'w')
    {
      canvas[myPlane.getX()][myPlane.getY()] = 0;
      myPlane.setX(myPlane.getX() - 1);;  // 位置上移
      canvas[myPlane.getX()][myPlane.getY()] = 1;
    }
    else if (input == 's')
    {
      canvas[myPlane.getX()][myPlane.getY()] = 0;
      myPlane.setX(myPlane.getX() +1);;  // 位置上移
      canvas[myPlane.getX()][myPlane.getY()] = 1;
    }
    else if (input == ' ')  // 发射子弹
    {
      int left = myPlane.getY() - myPlane.getBulletWidth() ;
      int right = myPlane.getY() + myPlane.getBulletWidth();
      if (left < 0)
        left = 0;
      if (right > Width - 1)
        right = Width - 1;
      int k;
      for (k = left; k <= right; k++) // 发射闪弹
        canvas[myPlane.getX() - 1][k] = 2; // 发射子弹的初始位置在飞机的正上方
    }
  }
}
 
int main()
{
  startup();  // 数据初始化  
  while (1)  // 游戏循环执行
  {
    show();  // 显示画面
    updateWithoutInput();  // 与用户输入无关的更新
    updateWithInput();  // 与用户输入有关的更新
  }
  return 0;
}

updateFunction.h

#pragma once
void startupMyPlane();
void startupEnemyPlane();
void updateBullet(int i, int j);
void updatePlane(int& speed);

plane.h

#pragma once
 
class Plane
{
private:
  int x;
  int y;
  int MoveSpeed;
public:
  Plane() :x(0), y(0) {};
  Plane(int x, int y) :x(x), y(y) {}
  ~Plane(){}
  int getX() { return x; }
  int getY() { return y; }
  int getMoveSpeed(){ return MoveSpeed; }
  void setX(int x) { this->x =x; }
  void setY(int y) { this->y = y; }
  void setMoveSpeed(int speed){ MoveSpeed = speed; }
  int condition;
};
 
 
class MyPlane : public Plane
{
private:
  int BulletWidth;
 
public:
  MyPlane(){ Plane(); condition = 1; };
  MyPlane(int x, int y) :Plane(x, y) { condition = 1; }
  ~MyPlane() {}
  int getBulletWidth() { return BulletWidth; }
  void setBulletWidth(int width) { this->BulletWidth = width; }
 
};
class EnemyPlane : public Plane
{
public:
  static int num;
public:
  EnemyPlane() { Plane(); condition = 3; };
  EnemyPlane(int x, int y) : Plane(x, y) { condition = 3; }
  ~EnemyPlane() {}
 
};



相关文章
|
Web App开发 测试技术
使用Selenium模拟鼠标滚动操作的技巧
本文介绍了使用Selenium进行Web自动化测试时如何模拟鼠标滚动操作。模拟滚动对于处理动态加载的内容至关重要。通过`ActionChains`类,可以实现向下滑动1000像素的操作。示例代码展示了如何结合滚动来截取长页面的完整图片。总结来说,Selenium的`ActionChains`使得模拟用户行为,如滚动,变得简单,便于执行自动化任务。
|
3月前
|
监控 数据可视化 Linux
LangSmith:大模型应用开发的得力助手
LangSmith 是大模型应用开发的高效助手,提供从调试、追踪到评估的全流程支持。通过可视化追踪树,清晰展现 LLM 应用每一步执行逻辑,提升可观察性;支持提示词优化、实时监控与自动化评估,助力开发者快速定位问题、迭代优化,构建稳定可靠的智能应用。
436 0
LangSmith:大模型应用开发的得力助手
Python错误 TypeError: ‘NoneType‘ object is not subscriptable解决方案汇总
Python错误 TypeError: ‘NoneType‘ object is not subscriptable解决方案汇总
|
自然语言处理 Cloud Native 安全
适应多样化需求:WASM 插件在全链路灰度发布中的应用
MSE(微服务引擎)在微服务全链路灰度场景下提供了一套成熟的功能,支持内容规则和百分比规则的灰度路由策略。
61933 102
|
9月前
|
人工智能 自动驾驶 物联网
《无线网络架构与人工智能实时性:深度融合与未来展望》
在数字时代,人工智能(AI)已渗透到安防、家居、医疗、金融等多领域,其影响力无处不在。无线网络架构作为数据传输的关键支撑,与AI的实时性需求紧密相连,二者融合推动技术迈向新高度。Wi-Fi、蜂窝网络(4G/5G)、Mesh网络各具特点,分别通过提升速率、降低延迟和增强健壮性,确保AI应用高效稳定运行。未来,6G和量子通信将进一步优化无线网络,满足AI的实时性需求,开启智能新时代。
275 7
|
机器学习/深度学习 人工智能 搜索推荐
底层技术大揭秘!AI智能导购如何重塑购物体验
双十一期间,淘宝内测AI助手“淘宝问问”,基于阿里通义大模型,旨在提升用户在淘宝上的商品搜索和推荐效率。该助手通过品牌推荐、兴趣商品推荐和关联问题三大板块,提供个性化购物体验。其背后采用多智能体架构,包括规划助理和商品导购助理,通过对话历史和用户输入,实现精准商品推荐。此外,文章还介绍了如何快速部署此解决方案,并探讨了其对现代购物体验的影响。
|
XML 数据库 Android开发
10分钟手把手教你用Android手撸一个简易的个人记账App
该文章提供了使用Android Studio从零开始创建一个简单的个人记账应用的详细步骤,包括项目搭建、界面设计、数据库处理及各功能模块的实现方法。
|
API
万年历[取当日信息]免费API接口教程
此API提供万年历当天的详细信息,包括农历、星期、宜忌、生肖、星座、节日、五行、星宿等。支持POST和GET请求,需提供用户ID和KEY。返回数据包含阳历、农历、干支、节日列表等多项内容。示例URL:https://cn.apihz.cn/api/time/getday.php?id=88888888&key=88888888。
4074 10
|
数据可视化 JavaScript 定位技术
线性回归和时间序列分析北京房价影响因素可视化案例
线性回归和时间序列分析北京房价影响因素可视化案例

热门文章

最新文章