知识点
结构体,循环,函数,随机数,数组,数据读取。
玩法
1.通过控制w,s,a,d来实现飞机的移动,或者上下左右。
2.每过一定时间会出现敌机。
3.按空格键进行射击。
创作历程
Block.h:
#pragma once
struct SBlock
{
int nRow;
int nCol;
};
Bullet.h:
#pragma once
struct SBullet
{
SBullet(int nInRow, int nInCol);
//子弹移动的函数
void move();
int nRow;
int nCol;
};
Bullet.cpp:
#include "stdafx.h"
#include "Bullet.h"
SBullet::SBullet(int nInRow, int nInCol)
{
nRow = nInRow;
nCol = nInCol;
}
void SBullet::move()
{
nRow--;
}
BulletMgr.h:
#pragma once
#include "Bullet.h"
#include <vector>
using namespace std;
//管理所有子弹
struct SBulletMgr
{
//添加子弹:位置参数
void addBullet(int nInRow,int nInCol);
//函数获取某个位置的子弹
bool isExist(int nInRow, int nInCol);
void update();
//容器:存子弹
vector<SBullet> vecBullets;
};
BulletMgr.cpp:
#include "stdafx.h"
#include "BulletMgr.h"
void SBulletMgr::addBullet(int nInRow, int nInCol)
{
//把子弹创建出来
SBullet bullet(nInRow, nInCol);
//存起来
vecBullets.push_back(bullet);
}
bool SBulletMgr::isExist(int nInRow, int nInCol)
{
for (int i = 0; i < vecBullets.size(); i++)
{
if (vecBullets[i].nRow == nInRow && vecBullets[i].nCol == nInCol)
{
return true;
}
}
return false;
}
void SBulletMgr::update()
{
//遍历所有子弹,执行子弹的移动函数
for (int i = 0; i < vecBullets.size(); i++)
{
vecBullets[i].move();
}
}
DataMgr.h:
#pragma once
#include "DataStruct.h"
struct SDataMgr
{
SDataMgr();
SMapDtMgr mapDtMgr;
SEnemyDtMgr enemyDtMgr;
};
DataMgr.cpp:
#include "stdafx.h"
#include "DataMgr.h"
SDataMgr::SDataMgr()
{
//读数据
mapDtMgr.loadFile("./datas/mapDt.txt");
enemyDtMgr.loadFile("./datas/enemyDt.txt");
}
DataStruct.h:
#pragma once
#include <vector>
#include <string>
using namespace std;
//需要有个结构体捆绑整份地图数据
struct SMapDt
{
SMapDt()
{
nId = 0;
strName = "";
nRowCount = 0;
nColCount = 0;
nInitRow = 0;
nInitCol = 0;
}
int nId;
string strName;
int nRowCount;
int nColCount;
int nInitRow;
int nInitCol;
int arrMap[100][100];
};
struct SMapDtMgr
{
//需要有个函数,这个函数用于读取数据
void loadFile(string strPath);
//获取某一条数据的方法
SMapDt getDataById(int nId);
vector<SMapDt> vecDatas;
};
struct SEnemyDt
{
SEnemyDt()
{
nId = 0;
strName = "";
nHp = 0;
nAtk = 0;
strPic = "";
}
int nId;
string strName;
int nHp;
int nAtk;
string strPic;
};
struct SEnemyDtMgr
{
//需要有个函数,这个函数用于读取数据
void loadFile(string strPath);
//获取某一条数据的方法
SEnemyDt getDataById(int nId);
vector<SEnemyDt> vecDatas;
};
DataStruct.cpp:
#include "stdafx.h"
#include "DataStruct.h"
#include <fstream>
void SMapDtMgr::loadFile(string strPath)
{
fstream inFile(strPath);
if (inFile)
{
string str = "";
getline(inFile, str);
int nCount = 0;
inFile >> nCount;
for (int i = 0; i < nCount; i++)
{
SMapDt data;
inFile >> data.nId >> data.strName >> data.nRowCount >> data.nColCount >> data.nInitRow >> data.nInitCol;
for (int n = 0; n < data.nRowCount; n++)
{
for (int m = 0; m < data.nColCount; m++)
{
inFile >> data.arrMap[n][m];
}
}
//存储到容器
vecDatas.push_back(data);
}
}
inFile.close();
}
SMapDt SMapDtMgr::getDataById(int nId)
{
//遍历所有的数据,比较id是否和传进来是一样的
//如果是一样这条数据就是外面想拿到的
for (int i = 0; i < vecDatas.size(); i++)
{
if (vecDatas[i].nId == nId)
{
return vecDatas[i];
}
}
//返回一条空数据
SMapDt data;
return data;
}
void SEnemyDtMgr::loadFile(string strPath)
{
fstream inFile(strPath);
if (inFile)
{
string str = "";
getline(inFile, str);
int nCount = 0;
inFile >> nCount;
for (int i = 0; i < nCount; i++)
{
SEnemyDt data;
inFile >> data.nId >> data.strName >> data.nHp >> data.nAtk >> data.strPic;
vecDatas.push_back(data);
}
}
inFile.close();
}
SEnemyDt SEnemyDtMgr::getDataById(int nId)
{
for (int i = 0; i < vecDatas.size(); i++)
{
if (vecDatas[i].nId == nId)
{
return vecDatas[i];
}
}
SEnemyDt data;
return data;
}
Enemy.h:
#pragma once
#include "Block.h"
//敌人需要有自己的样式
struct SEnemy
{
//初始化数据的函数
void initWithData(SEnemyDt data);
void setPosition(int nInRow,int nInCol);
//
bool isExist(int nInRow, int nInCol);
//移动的函数
void move();
SBlock arrPlane[4];
int nId;
string strName;
int nHp;
int nAtk;
string strPic;
//保存敌人当前的行列
int nRow;
int nCol;
//计时
int nMoveTime;
};
Enemy.cpp:
#include "stdafx.h"
#include "Enemy.h"
void SEnemy::initWithData(SEnemyDt data)
{
//把传进来的整条数据保存到敌人身上
nId = data.nId;
nHp = data.nHp;
nAtk = data.nAtk;
strName = data.strName;
strPic = data.strPic;
nMoveTime = 0;
}
void SEnemy::setPosition(int nInRow, int nInCol)
{
nRow = nInRow;
nCol = nInCol;
arrPlane[0].nRow = nInRow;
arrPlane[0].nCol = nInCol;
arrPlane[1].nRow = nInRow;
arrPlane[1].nCol = nInCol - 1;
arrPlane[2].nRow = nInRow + 1;
arrPlane[2].nCol = nInCol;
arrPlane[3].nRow = nInRow;
arrPlane[3].nCol = nInCol + 1;
}
bool SEnemy::isExist(int nInRow, int nInCol)
{
for (int i = 0; i < 4; i++)
{
if (arrPlane[i].nRow == nInRow && arrPlane[i].nCol == nInCol)
{
return true;
}
}
return false;
}
void SEnemy::move()
{
nMoveTime++;
if (nMoveTime > 5)
{
nMoveTime = 0;
nRow++;
//重新调用设置位置的函数
setPosition(nRow, nCol);
}
}
EnemyMgr.h:
#pragma once
#include "Enemy.h"
#include <vector>
using namespace std;
//创建敌人并且将所有敌人管理起来(存起来)
struct SEnemyMgr
{
SEnemyMgr();
void update();
//创建敌人的函数
void createEnemy();
//判断某个敌人是否存在某行某列
SEnemy isExist(int nInRow, int nInCol);
vector<SEnemy> vecEnemys;
//需要有一个变量,用于统计时间
int nCreateTime;
};
EnemyMgr.cpp:
#include "stdafx.h"
#include "EnemyMgr.h"
#include "Enemy.h"
SEnemyMgr::SEnemyMgr()
{
nCreateTime = 0;
}
void SEnemyMgr::update()
{
nCreateTime++;
if (nCreateTime > 20)
{
nCreateTime = 0;
//创建敌人
createEnemy();
}
//找到所有敌人->执行敌人的移动函数
for (int i = 0; i < vecEnemys.size(); i++)
{
vecEnemys[i].move();
}
}
void SEnemyMgr::createEnemy()
{
SEnemy enemy;
//随机拿到其中一条数据
//随机一个从2001 - 2003的Id出来
int nId = rand() % (2004 - 2001) + 2001;
SEnemyDt enemyDt = g_dataMgr.enemyDtMgr.getDataById(nId);
enemy.initWithData(enemyDt);
int nColCount = g_gameMgr.gameMap.curMapDt.nColCount;
int nCol = rand() % (nColCount-2 - 2) + 2;
enemy.setPosition(-2, nCol);
vecEnemys.push_back(enemy);
}
SEnemy SEnemyMgr::isExist(int nInRow, int nInCol)
{
for (int i = 0; i < vecEnemys.size(); i++)
{
if (vecEnemys[i].isExist(nInRow,nInCol))
{
return vecEnemys[i];
}
}
SEnemy enemy;
return enemy;
}
GameMap.h:
#pragma once
#include "Player.h"
#include "DataStruct.h"
#include "EnemyMgr.h"
#include "BulletMgr.h"
struct SGameMap
{
SGameMap();
//数据更新:按键、移动数据
void update();
//渲染:显示
void render();
//碰撞函数
void onCollision();
//保存一条地图数据
SMapDt curMapDt;
SPlayer player;
SEnemyMgr enemyMgr;
SBulletMgr bulletMgr;
};
GameMap.cpp:
#include "stdafx.h"
#include "GameMap.h"
SGameMap::SGameMap()
{
srand(time(nullptr));
int temp = 1001 + rand() % 2;
//一进入游戏就需要拿到地图数据来用
curMapDt = g_dataMgr.mapDtMgr.getDataById(temp);
//创建地图之后先固定玩家的初始位置
player.setPosition(curMapDt.nInitRow, curMapDt.nInitCol);
srand(time(nullptr));
enemyMgr.createEnemy();
}
void SGameMap::update()
{
if (KEY_DOWN(VK_ESCAPE))
{
g_gameMgr.bClear = true;
g_gameMgr.nGameScene = 0;
}
bulletMgr.update();
player.update();
enemyMgr.update();
onCollision();
}
void SGameMap::render()
{
for (int i = 0; i < curMapDt.nRowCount; i++)//遍历行
{
for (int j = 0; j < curMapDt.nColCount; j++)//遍历列
{
SEnemy enemy = enemyMgr.isExist(i, j);
if (1 == curMapDt.arrMap[i][j])
{
cout << "■";
}
//根据玩家的行列信息画出玩家的形状,如果当前位置画了玩家,不能再画空地
else if (player.isExist(i,j))
{
cout << "▲";
}
else if (enemy.nId >= 2001 && enemy.nId <= 2003)
{
cout << enemy.strPic;
}
else if (bulletMgr.isExist(i, j))
{
cout << "●";
}
else
{
cout << " ";
}
}
cout << endl;
}
}
void SGameMap::onCollision()
{
//&:引用,取别名
//定义变量来保存容器
vector<SBullet> &vecBullets = bulletMgr.vecBullets;
vector<SEnemy> &vecEnemys = enemyMgr.vecEnemys;
//拿到所有子弹、所有敌人
//判断子弹的位置是否存在敌人
for (int i = vecBullets.size() - 1; i >= 0 ; i--)
{
bool bRemoveEenemy = false;
for (int j = vecEnemys.size() - 1; j >= 0; j--)
{
bool enemy = vecEnemys[j].isExist(vecBullets[i].nRow, vecBullets[i].nCol);
if (enemy == true)
{
bRemoveEenemy = true;
//子弹碰到了某个敌人了!
vecEnemys.erase(vecEnemys.begin() + j);
vecBullets.erase(vecBullets.begin() + i);
break;
}
}
}
}
GameMenu.h:
#pragma once
struct SGameMenu
{
SGameMenu();
//数据更新:按键、移动数据
void update();
//渲染:显示
void render();
//定义变量
int nMenuState;
};
GameMenu.cpp:
#include "stdafx.h"
#include "GameMenu.h"
enum
{
E_MENU_START,
E_MENU_SET,
E_MENU_EXIT
};
SGameMenu::SGameMenu()
{
nMenuState = E_MENU_START;
}
void SGameMenu::update()
{
if (KEY_DOWN(VK_RETURN))
{
if (nMenuState == E_MENU_START)
{
g_gameMgr.bClear = true;
g_gameMgr.nGameScene = 1;
}
else if (nMenuState == E_MENU_SET)
{
}
else if (nMenuState == E_MENU_EXIT)
{
exit(0);
}
}
if (KEY_DOWN(VK_UP))
{
nMenuState--;
if (nMenuState < E_MENU_START)
{
nMenuState = E_MENU_EXIT;
}
}
else if (KEY_DOWN(VK_DOWN))
{
nMenuState++;
if (nMenuState > E_MENU_EXIT)
{
nMenuState = E_MENU_START;
}
}
}
void SGameMenu::render()
{
if (E_MENU_START == nMenuState)
{
cout << "■■■■■■■■■■■■■" << endl;
cout << "■ ■" << endl;
cout << "■ -> 游戏开始 ■" << endl;
cout << "■ 游戏设置 ■" << endl;
cout << "■ 游戏退出 ■" << endl;
cout << "■ ■" << endl;
cout << "■■■■■■■■■■■■■" << endl;
}
else if (E_MENU_SET == nMenuState)
{
cout << "■■■■■■■■■■■■■" << endl;
cout << "■ ■" << endl;
cout << "■ 游戏开始 ■" << endl;
cout << "■ -> 游戏设置 ■" << endl;
cout << "■ 游戏退出 ■" << endl;
cout << "■ ■" << endl;
cout << "■■■■■■■■■■■■■" << endl;
}
else if (E_MENU_EXIT == nMenuState)
{
cout << "■■■■■■■■■■■■■" << endl;
cout << "■ ■" << endl;
cout << "■ 游戏开始 ■" << endl;
cout << "■ 游戏设置 ■" << endl;
cout << "■ -> 游戏退出 ■" << endl;
cout << "■ ■" << endl;
cout << "■■■■■■■■■■■■■" << endl;
}
}
GameMgr.h:
#pragma once
#include "GameMenu.h"
#include "GameMap.h"
struct SGameMgr
{
SGameMgr();
void update();
void render();
SGameMenu gameMenu;
SGameMap gameMap;
//保存当前运行的场景
int nGameScene;
//bool变量代表是否需要清屏
bool bClear;
};
GameMgr.cpp:
#include "stdafx.h"
#include "GameMgr.h"
SGameMgr::SGameMgr()
{
nGameScene = 0;
bClear = false;
}
void SGameMgr::update()
{
if (0 == nGameScene)
{
gameMenu.update();
}
else if (1 == nGameScene)
{
gameMap.update();
}
}
void SGameMgr::render()
{
if (0 == nGameScene)
{
gameMenu.render();
}
else if (1 == nGameScene)
{
gameMap.render();
}
}
Player.h:
#pragma once
#include "Block.h"
struct SPlayer
{
//需要有个数据更新,控制玩家的移动...
void update();
//判断四个方块是否存在某一个行列的函数
bool isExist(int nInRow, int nInCol);
//设置飞机整体的函数
void setPosition(int nInRow,int nInCol);
//需要有个数组,长度4:用于存放四个方块
SBlock arrPlane[4];
//保存玩家的整个行列
int nRow;
int nCol;
//玩家整体坐标备份(备份参考点)
int nRowBk;
int nColBk;
};
Player.cpp:
#include "stdafx.h"
#include "Player.h"
void SPlayer::update()
{
nRowBk = nRow;
nColBk = nCol;
if (KEY_DOWN(VK_UP))
{
if (nRow > 2)
{
setPosition(nRow - 1, nCol);
}
}
else if (KEY_DOWN(VK_DOWN))
{
if (nRow < g_gameMgr.gameMap.curMapDt.nRowCount - 2)
{
setPosition(nRow + 1, nCol);
}
}
else if (KEY_DOWN(VK_LEFT))
{
if (nCol > 2)
{
setPosition(nRow, nCol - 1);
}
}
else if (KEY_DOWN(VK_RIGHT))
{
if (nCol < g_gameMgr.gameMap.curMapDt.nColCount - 3)
{
setPosition(nRow, nCol + 1);
}
}
if (KEY_DOWN(VK_SPACE))
{
//找子弹管理者添加一颗子弹
g_gameMgr.gameMap.bulletMgr.addBullet(nRow, nCol);
}
//移动之后判断是否撞墙
//for (int i = 0; i < 4; i++)
//{
// if (g_gameMgr.gameMap.curMapDt.arrMap[arrPlane[i].nRow][arrPlane[i].nCol] == 1)
// {
// setPosition(nRowBk, nColBk);
// break;
// }
//}
}
bool SPlayer::isExist(int nInRow, int nInCol)
{
for (int i = 0; i < 4; i++)
{
if (arrPlane[i].nRow == nInRow && arrPlane[i].nCol == nInCol)
{
return true;
}
}
return false;
}
void SPlayer::setPosition(int nInRow, int nInCol)
{
nRow = nInRow;
nCol = nInCol;
arrPlane[0].nRow = nInRow;
arrPlane[0].nCol = nInCol;
arrPlane[1].nRow = nInRow;
arrPlane[1].nCol = nInCol + 1;
arrPlane[2].nRow = nInRow - 1;
arrPlane[2].nCol = nInCol;
arrPlane[3].nRow = nInRow;
arrPlane[3].nCol = nInCol - 1;
}
stdafx.h:
#pragma once
#include <iostream>
#include <windows.h>
#include <stdlib.h> //设置随机数种子的头文件
#include "DataMgr.h"
#include "GameMgr.h"
using namespace std;
extern SDataMgr g_dataMgr;
extern SGameMgr g_gameMgr;
#define KEY_DOWN(vk_code) GetAsyncKeyState(vk_code) & 0x8000
主函数PlaneWar.cpp:
#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include "DataMgr.h"
#include "GameMgr.h"
void gotoxy(int x, int y)
{
COORD coord;
coord.X = x;
coord.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
//保证数据先行原则
SDataMgr g_dataMgr;
SGameMgr g_gameMgr;
int main()
{
while (true)
{
g_gameMgr.update();
g_gameMgr.render();
if(g_gameMgr.bClear)
{
system("cls");
g_gameMgr.bClear = false;
}
gotoxy(0, 0);
Sleep(60);
}
}
数据
在文件管理器中创建名为datas文件夹,再在里面创建两个文本文档,读取地图和敌人数据
enemyDt.txt:
mapDt.txt: