一、 设计任务及需求分析

《坦克大战》是由日本南梦宫Namco游戏公司开发的一款平面射击游戏,于1985年发售。游戏以坦克战斗及保卫基地为主题,属于策略型联机类。以二战坦克为题材,既保留了射击类游戏的操作性,也改进了射击类游戏太过于复杂难玩的高门槛特点,集休闲与竞技于一身。
使用第三方图形库SFML还原FC经典坦克大战,用13*13的方块组成游戏地图,地形包括空气,钢板,砖墙,实现原版坦克大战中坦克行走,坦克与墙壁之间碰撞,坦克发射子弹,敌军生成,敌军随机走动,子弹与实体之间互动,游戏键盘操作,游戏结束界面
游戏操作,WASD控制玩家坦克上下左右移动,J发射子弹

二、总体设计方案

用Game类作为中介类,内存有所有游戏对象的指针,而每个游戏对象都有Game类的指针,用于不同游戏模块之间的通信,Game类又负责了整个游戏的运行(Run()成员函数用于处理每一帧的要处理的事件,PushEvent将每个要处理的键盘事件交给Control对象处理)

Control类用于处理键盘输入信息,使得游戏对象对于每个得到的事件做出相应的反应,例如WASD改变玩家的转向以及移动

Drawer类用于绘制所有地图中的游戏对象,控制绘制顺序

GameObject类作为所有游戏对象的父类,内涵纹理以及纹理对象的属性,以及纯虚函数Draw()接口

Block类作为所有方块对象的父类,内含枚举类型方块种类BlockType,WallBlock构造函数为BlockType赋值,其他方块同理
Map类是Block类的聚合,构造函数为其初始化每个方块的位置,用字符串数组来快速编辑地图方块布局,setLostMap()为设置游戏结束之后地图显示的界面

Player类内含speed,isDead,isMoving, direction属性,
Move()方法:按照direction方向以speed速度运动,每次运动判断是否与所有游戏对象发生碰撞,若碰撞退回去且不再运动
Turn(Direction dir)方法:设置运动方向,贴图旋转

Enemy类内含静态属性StartPos设置每次生成位置,属性sf::Clock计时器用于控制每个敌方坦克的发射子弹的时间

Bullet抽象类内含speed,isDead属性,Move方法每次运动都会去判断是否有碰撞到游戏对象,若发生碰撞,则设置Bullet和该对“死亡”,在game->Run()中将其清除,PlayerBullet实现了Move函数,EnemyBullet实现了Move函数

Home类为游戏中基地对象,若isDead属性为True则游戏结束

UML 类图
#mermaid-svg-f3HujM6NIxpZjyKa {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-f3HujM6NIxpZjyKa .error-icon{fill:#552222;}#mermaid-svg-f3HujM6NIxpZjyKa .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-f3HujM6NIxpZjyKa .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-f3HujM6NIxpZjyKa .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-f3HujM6NIxpZjyKa .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-f3HujM6NIxpZjyKa .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-f3HujM6NIxpZjyKa .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-f3HujM6NIxpZjyKa .marker{fill:#333333;stroke:#333333;}#mermaid-svg-f3HujM6NIxpZjyKa .marker.cross{stroke:#333333;}#mermaid-svg-f3HujM6NIxpZjyKa svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-f3HujM6NIxpZjyKa g.classGroup text{fill:#9370DB;fill:#131300;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-f3HujM6NIxpZjyKa g.classGroup text .title{font-weight:bolder;}#mermaid-svg-f3HujM6NIxpZjyKa .nodeLabel,#mermaid-svg-f3HujM6NIxpZjyKa .edgeLabel{color:#131300;}#mermaid-svg-f3HujM6NIxpZjyKa .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-f3HujM6NIxpZjyKa .label text{fill:#131300;}#mermaid-svg-f3HujM6NIxpZjyKa .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-f3HujM6NIxpZjyKa .classTitle{font-weight:bolder;}#mermaid-svg-f3HujM6NIxpZjyKa .node rect,#mermaid-svg-f3HujM6NIxpZjyKa .node circle,#mermaid-svg-f3HujM6NIxpZjyKa .node ellipse,#mermaid-svg-f3HujM6NIxpZjyKa .node polygon,#mermaid-svg-f3HujM6NIxpZjyKa .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-f3HujM6NIxpZjyKa .divider{stroke:#9370DB;stroke:1;}#mermaid-svg-f3HujM6NIxpZjyKa g.clickable{cursor:pointer;}#mermaid-svg-f3HujM6NIxpZjyKa g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-f3HujM6NIxpZjyKa g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-f3HujM6NIxpZjyKa .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-f3HujM6NIxpZjyKa .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-f3HujM6NIxpZjyKa .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-f3HujM6NIxpZjyKa .dashed-line{stroke-dasharray:3;}#mermaid-svg-f3HujM6NIxpZjyKa #compositionStart,#mermaid-svg-f3HujM6NIxpZjyKa .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-f3HujM6NIxpZjyKa #compositionEnd,#mermaid-svg-f3HujM6NIxpZjyKa .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-f3HujM6NIxpZjyKa #dependencyStart,#mermaid-svg-f3HujM6NIxpZjyKa .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-f3HujM6NIxpZjyKa #dependencyStart,#mermaid-svg-f3HujM6NIxpZjyKa .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-f3HujM6NIxpZjyKa #extensionStart,#mermaid-svg-f3HujM6NIxpZjyKa .extension{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-f3HujM6NIxpZjyKa #extensionEnd,#mermaid-svg-f3HujM6NIxpZjyKa .extension{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-f3HujM6NIxpZjyKa #aggregationStart,#mermaid-svg-f3HujM6NIxpZjyKa .aggregation{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-f3HujM6NIxpZjyKa #aggregationEnd,#mermaid-svg-f3HujM6NIxpZjyKa .aggregation{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-f3HujM6NIxpZjyKa .edgeTerminals{font-size:11px;}#mermaid-svg-f3HujM6NIxpZjyKa :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

Game
+Player* player
+list<Enemy*> enemyList
+Map* map
+list<Bullet*> bulletList
+Control* control
+Drawer* draw
+Home* home
+RenderWindow* window
+Run()
+PullEvent(sf::RenderWindow window)
+Over()
Control
+Game* game
+Control(Game* game)
+Input(sf::Event event)
Drawer
+Game* game
+Drawer(Game* game)
+DrawAll()
Player
+bool isMoving
+Direction dir
+float speed
+Move()
+Turn(Direction dir)
+Draw()
Enemy
+Game* game
_int remain
_StartPos pos
+Clock clock
+float speed
+bool isDead
+Enemy(Game* game)
+Draw()
+Move()
+Shoot()
«interface»
Bullet
+Game* game
+float speed
+bool isDead
+Bullet(Game* game, Direction dir)
+Move()
+Draw()
PlayerBullet
+PlayerBullet(Game* game, Direction dir)
+Move()
EnemyBullet
+EnemyBullet(Game* game, Direction dir)
+Move()
Home
+Game* game
+bool isDead
+Home(Game* game)
+Draw()
Map
+Game* game
+vector<vector> Block2D
+Map(Game* game)
+Draw()
+setLostMap()
«interface»
Block
+Game* game
+Draw()
+setPostion()
WallBlock
+WallBlock(Game* game)
+Draw()
IronBlock
+IronBlock(Game* game)
+Draw()
EmptyBlock
+EmptyBlock(Game* game)
+Draw()
«interface»
GameObject
+Texture texture
+Sprite sprite
+Draw()

源代码

//main.cpp
#include <SFML/Graphics.hpp>
#include <iostream>
#include "Game.h"
using namespace std;int main() {sf::RenderWindow window(sf::VideoMode(832, 832), "BattleCity");window.setFramerateLimit(60);window.setKeyRepeatEnabled(false);Game game(&window);while (window.isOpen()) {sf::Event event;while (window.pollEvent(event)) {game.PushEvent(event);}game.Run();window.clear();game.drawer->DrawAll();window.display();}return 0;
}//Game.h
#pragma once
#include <iostream>
#include <list>
#include <vector>
#include <SFML/Graphics.hpp>
#include "Player.h"
#include "Block.h"
#include "Drawer.h"
#include "Enemy.h"
#include "Control.h"
#include "Map.h"
#include "Bullet.h"
#include "Home.h"
class Player;
class Bullet;
class Enemy;
class Block;
class Drawer;
class Control;
class Map;
class Home;
enum class Direction {Up,Down,Left,Right
};
class Game {public:Game(sf::RenderWindow* window);sf::Clock* clock;Player* player;std::list<Bullet*> bulletList;sf::RenderWindow* window;std::list<Enemy*> enemyList;Drawer* drawer;Control* control;Map* map;Home* home;bool isFailed;void PushEvent(sf::Event event);void Run();void Over();
};//Game.cpp
#include "Game.h"
Game::Game(sf::RenderWindow* window) {this->control = new Control(this);this->map = new Map(this);this->drawer = new Drawer(this);this->player = new Player(this);this->window = window;this->clock = new sf::Clock;this->home = new Home(this);this->isFailed = false;
}
void Game::PushEvent(sf::Event event) {control->Input(event);
}
void Game::Run() {if(isFailed == true){this->map->setLostMap();}else {player->Move();for (auto& item : bulletList) {item->Move();}for (auto& item : enemyList) {item->Move();}for (auto& item : enemyList) {item->Shoot();}for (std::list<Bullet*>::iterator iter = bulletList.begin(); iter != bulletList.end();) {if ((*iter)->isDead) {delete (*iter);bulletList.erase(iter);iter = bulletList.begin();}elseiter++;}for (std::list<Enemy*>::iterator iter = enemyList.begin(); iter != enemyList.end();) {if ((*iter)->isDead) {delete (*iter);enemyList.erase(iter);iter = enemyList.begin();}elseiter++;}if (this->clock->getElapsedTime().asSeconds() >= 3.0f && this->enemyList.size() < 4) {Enemy* enemy = new Enemy(this);enemyList.push_back(enemy);this->clock->restart();}if (this->player->isDead || this->home->isDead) {this->isFailed = true;}}}
void Game::Over() {this->map->setLostMap();this->player->sprite.setPosition(-10.0f, -10.0f);for (std::list<Enemy*>::iterator iter = enemyList.begin(); iter != enemyList.end(); iter++) {delete (*iter);}enemyList.clear();delete this->player;
}//Block.h
#pragma once
#include <SFML/Graphics.hpp>
#include "Game.h"
#include "GameObject.h"
class Game;
enum class BlockType {Empty,Wall,Iron
};
class Block : public GameObject {protected:Block(Game* game);Game* game;
public:BlockType type;void setPosition(float x, float y);void Draw();
};
class WallBlock: public Block {public:WallBlock(Game* game);
};
class EmptyBlock : public Block {public:EmptyBlock(Game* game);
};
class IronBlock : public Block {public:IronBlock(Game* game);
};//Block.cpp
#include "Block.h"
Block::Block(Game* game) {this->game = game;
}
void Block::setPosition(float x, float y) {this->sprite.setPosition(x, y);
}
void Block::Draw() {game->window->draw(this->sprite);
}
WallBlock::WallBlock(Game* game): Block(game) {this->texture.loadFromFile("Src\\Wall.png");this->sprite.setTexture(texture);this->sprite.setScale(4.0f, 4.0f);this->type = BlockType::Wall;
}
EmptyBlock::EmptyBlock(Game* game):Block(game) {this->texture.loadFromFile("Src\\Empty.png");this->sprite.setTexture(texture);this->sprite.setScale(4.0f, 4.0f);this->type = BlockType::Empty;
}
IronBlock::IronBlock(Game* game):Block(game) {this->texture.loadFromFile("Src\\Iron.png");this->sprite.setTexture(texture);this->sprite.setScale(4.0f, 4.0f);this->type = BlockType::Iron;
}
//Bullet.h
#pragma once
#include "Game.h"
class Game;
enum class Direction;
class Bullet : public GameObject {protected:Game* game;
public:Direction dir;float speed;bool isDead;Bullet(Game* game, Direction dir);virtual void Move() = 0;void Draw();
};class PlayerBullet : public Bullet {public:PlayerBullet(Game* game, Direction dir);void Move();
};
class EnemyBullet : public Bullet {public:EnemyBullet(Game* game, Direction dir);void Move();
};
//Bullet.cpp
#include "Bullet.h"Bullet::Bullet(Game* game, Direction dir) {this->game = game;this->texture.loadFromFile("Src\\Bullet.png");this->sprite.setTexture(texture);this->sprite.setScale(4.0f, 4.0f);this->speed = 16.0f;this->sprite.setOrigin(1.5f, 2.0f);this->dir = dir;switch (dir) {case Direction::Up:this->sprite.setRotation(0);break;case Direction::Down:this->sprite.setRotation(180);break;case Direction::Left:this->sprite.setRotation(270);break;case Direction::Right:this->sprite.setRotation(90);break;}this->isDead = false;
}
PlayerBullet::PlayerBullet(Game* game, Direction dir) :Bullet(game, dir) {}
EnemyBullet::EnemyBullet(Game* game, Direction dir) : Bullet(game, dir) {}void Bullet::Draw() {game->window->draw(this->sprite);
}void PlayerBullet::Move() {switch (dir) {case Direction::Up:this->sprite.move(0, -this->speed); break;case Direction::Down:this->sprite.move(0, this->speed); break;case Direction::Left:this->sprite.move(-this->speed, 0); break;case Direction::Right:this->sprite.move(this->speed, 0); break;}for (int i = 0; i < game->map->Block2D.size(); i++) {for (int j = 0; j < game->map->Block2D[0].size(); j++) {if (game->map->Block2D[i][j]->type == BlockType::Wall && this->sprite.getGlobalBounds().intersects(game->map->Block2D[i][j]->sprite.getGlobalBounds())) {this->isDead = true;delete game->map->Block2D[i][j];game->map->Block2D[i][j] = new EmptyBlock(game);}if (game->map->Block2D[i][j]->type == BlockType::Iron && this->sprite.getGlobalBounds().intersects(game->map->Block2D[i][j]->sprite.getGlobalBounds())) {this->isDead = true;}}}if (this->sprite.getPosition().x > 830 || this->sprite.getPosition().x < 0 || this->sprite.getPosition().y > 832 || this->sprite.getPosition().y < 0)this->isDead = true;for (auto itm : game->enemyList) {if (this->sprite.getGlobalBounds().intersects(itm->sprite.getGlobalBounds())) {this->isDead = true;itm->isDead = true;}}if (this->sprite.getGlobalBounds().intersects(game->home->sprite.getGlobalBounds()))game->home->isDead = true;
}void EnemyBullet::Move() {switch (dir) {case Direction::Up:this->sprite.move(0, -this->speed); break;case Direction::Down:this->sprite.move(0, this->speed); break;case Direction::Left:this->sprite.move(-this->speed, 0); break;case Direction::Right:this->sprite.move(this->speed, 0); break;}for (int i = 0; i < game->map->Block2D.size(); i++) {for (int j = 0; j < game->map->Block2D[0].size(); j++) {if (game->map->Block2D[i][j]->type == BlockType::Wall && this->sprite.getGlobalBounds().intersects(game->map->Block2D[i][j]->sprite.getGlobalBounds())) {this->isDead = true;delete game->map->Block2D[i][j];game->map->Block2D[i][j] = new EmptyBlock(game);}if (game->map->Block2D[i][j]->type == BlockType::Iron && this->sprite.getGlobalBounds().intersects(game->map->Block2D[i][j]->sprite.getGlobalBounds())) {this->isDead = true;}}}if (this->sprite.getPosition().x > 830 || this->sprite.getPosition().x < 0 || this->sprite.getPosition().y > 832 || this->sprite.getPosition().y < 0)this->isDead = true;if (this->sprite.getGlobalBounds().intersects(game->player->sprite.getGlobalBounds())) {this->isDead = true;game->player->isDead = true;}if (this->sprite.getGlobalBounds().intersects(game->home->sprite.getGlobalBounds()))game->home->isDead = true;
}//Control.h
#pragma once
#include "Game.h"
class Game;
class Control {public:Game* game;Control(Game* game);void Input(sf::Event event);
};
//Control.cpp
#include "Control.h"
#include <iostream>
Control::Control(Game* game) {this->game = game;
}
void Control::Input(sf::Event event) {if (event.type == sf::Event::Closed || (event.type == sf::Event::KeyPressed &&event.key.code == sf::Keyboard::Escape)) {game->window->close();}if (game->isFailed == false) {if (event.type == sf::Event::KeyPressed) {if (event.key.code == sf::Keyboard::A) {if (game->player->dir != Direction::Left)game->player->Turn(Direction::Left);game->player->isMoving = true;}if (event.key.code == sf::Keyboard::W) {if (game->player->dir != Direction::Up)game->player->Turn(Direction::Up);game->player->isMoving = true;}if (event.key.code == sf::Keyboard::S) {if (game->player->dir != Direction::Down)game->player->Turn(Direction::Down);game->player->isMoving = true;}if (event.key.code == sf::Keyboard::D) {if (game->player->dir != Direction::Right)game->player->Turn(Direction::Right);game->player->isMoving = true;}if (event.key.code == sf::Keyboard::J) {float tx, ty;Bullet* bullet = NULL;tx = game->player->sprite.getPosition().x;ty = game->player->sprite.getPosition().y;switch (game->player->dir) {case Direction::Up:bullet = new PlayerBullet(game, Direction::Up);ty -= 16; break;case Direction::Down:bullet = new PlayerBullet(game, Direction::Down);ty += 16; break;case Direction::Left:bullet = new PlayerBullet(game, Direction::Left);tx -= 16; break;case Direction::Right:bullet = new PlayerBullet(game, Direction::Right);tx += 16; break;}bullet->sprite.setPosition(tx, ty);game->bulletList.push_back(bullet);}}if (event.type == sf::Event::KeyReleased) {game->player->isMoving = false;}}
}
//Drawer.h
#pragma once
#include "Game.h"
class Game;
class Drawer {Game* game;
public:Drawer(Game* game);void DrawAll();
};
//Drawer.cpp
#include "Drawer.h"
Drawer::Drawer(Game* game) {this->game = game;
}
void Drawer::DrawAll() {this->game->map->Draw();if (game->isFailed == false) {this->game->player->Draw();for (std::list<Bullet*>::iterator iter = game->bulletList.begin(); iter != game->bulletList.end(); iter++) {(*iter)->Draw();}for (std::list<Enemy*>::iterator iter = game->enemyList.begin(); iter != game->enemyList.end(); iter++) {(*iter)->Draw();}this->game->home->Draw();}
}
//Enemy.h
#pragma once
#include "Game.h"
#include "GameObject.h"
class Game;
enum class Direction;
enum class StartPos {Left,Middle,Right
};
class Enemy : public GameObject {Game* game;
public:sf::Clock clock;static int remain;static StartPos spos;Direction dir;float speed;bool isDead;bool isFrozen;Enemy(Game* game);void Draw();void Move();void Shoot();
};
//Enemy.cpp
#include "Enemy.h"
Enemy::Enemy(Game* game) {this->game = game;this->texture.loadFromFile("Src\\TankEnemy.png");this->isDead = false;this->speed = 4.0f;this->dir = Direction::Down;this->sprite.setTexture(texture);this->sprite.setScale(4.0f, 4.0f);this->sprite.setOrigin(6.5f, 7.5f);this->isFrozen = false;switch (this->spos){case StartPos::Left:this->sprite.setPosition(32.0f, 32.0f);this->spos = StartPos::Middle;break;case StartPos::Middle:this->sprite.setPosition(416.0f, 32.0f);this->spos = StartPos::Right;break;case StartPos::Right:this->sprite.setPosition(800.0f, 32.0f);this->spos = StartPos::Left;break;}
}
void Enemy::Draw() {game->window->draw(this->sprite);
}
void Enemy::Move() {if (isFrozen == false) {if (clock.getElapsedTime().asSeconds() > 1) {dir = (Direction)(rand() % 4);clock.restart();}switch (dir) {case Direction::Up:this->sprite.setRotation(0); this->dir = Direction::Up; break;case Direction::Down:this->sprite.setRotation(180); this->dir = Direction::Down; break;case Direction::Left:this->sprite.setRotation(270); this->dir = Direction::Left; break;case Direction::Right:this->sprite.setRotation(90); this->dir = Direction::Right; break;}float dx, dy;switch (this->dir) {case Direction::Up:dx = 0; dy = -speed; break;case Direction::Down:dx = 0; dy = speed; break;case Direction::Left:dx = -speed; dy = 0; break;case Direction::Right:dx = speed; dy = 0; break;}this->sprite.move(dx, dy);for (int i = 0; i < game->map->Block2D.size(); i++) {for (int j = 0; j < game->map->Block2D[0].size(); j++) {if (game->map->Block2D[i][j]->type != BlockType::Empty && this->sprite.getGlobalBounds().intersects(game->map->Block2D[i][j]->sprite.getGlobalBounds())) {this->sprite.move(-dx, -dy);}}}for (auto itm : game->enemyList) {if(this->sprite.getGlobalBounds().intersects(itm->sprite.getGlobalBounds()) && itm != this)this->sprite.move(-dx, -dy);}if (this->sprite.getPosition().x - 28.0f < 0 || this->sprite.getPosition().y - 28.0f < 0 || this->sprite.getPosition().x + 28.0f > 832 || this->sprite.getPosition().y + 28.0f > 832)this->sprite.move(-dx, -dy);if(this->sprite.getGlobalBounds().intersects(game->player->sprite.getGlobalBounds()))this->sprite.move(-dx, -dy);}else {if (clock.getElapsedTime().asSeconds() > 8) {this->isFrozen = false;this->clock.restart();}}
}
void Enemy::Shoot() {if ((int)clock.getElapsedTime().asMicroseconds() % 500 < 5 && this->isFrozen == false) {float tx, ty;Bullet* bullet = NULL;tx = this->sprite.getPosition().x;ty = this->sprite.getPosition().y;switch (this->dir) {case Direction::Up:bullet = new EnemyBullet(game, Direction::Up);ty -= 16; break;case Direction::Down:bullet = new EnemyBullet(game, Direction::Down);ty += 16; break;case Direction::Left:bullet = new EnemyBullet(game, Direction::Left);tx -= 16; break;case Direction::Right:bullet = new EnemyBullet(game, Direction::Right);tx += 16; break;}bullet->sprite.setPosition(tx, ty);game->bulletList.push_back(bullet);clock.restart();}
}
StartPos Enemy::spos = StartPos::Left;
//GameObject.h
#pragma once
#include <SFML/Graphics.hpp>
class GameObject {public:sf::Texture texture;sf::Sprite sprite;virtual void Draw() = 0;
};
//Home.h
#pragma once
#include "Game.h"
#include "GameObject.h"
class Game;
class Home : public GameObject {Game* game;
public:bool isDead;Home(Game* game);void Draw();
};
//Home.cpp
#include "Home.h"
Home::Home(Game* game) {this->game = game;this->texture.loadFromFile("Src\\Home.png");this->isDead = false;this->sprite.setTexture(texture);this->sprite.setScale(4.0f, 4.0f);this->sprite.setPosition(384.0, 768.0f);
}
void Home::Draw() {game->window->draw(this->sprite);
}
//Map.h
#pragma once
#include <vector>
#include "Block.h"
#include "Game.h"
class Game;
class Block;
class Map {Game* game;
public:std::vector<std::vector<Block*>> Block2D;Map(Game* game);void Draw();void setLostMap();
};
//Map.cpp
#include "Map.h"
Map::Map(Game* game) {this->game = game;std::vector<std::string> tMap = {"..........................","..........................","..##..##..##..##..##..##..","..##..##..##..##..##..##..","..##..##..##..##..##..##..","..##..##..##..##..##..##..","..##..##..##%%##..##..##..","..##..##..##%%##..##..##..","..##..##..##..##..##..##..","..##..##..........##..##..","..##..##..........##..##..","..........##..##..........","..........##..##..........","##..####..........####..##","%%..####..........####..%%","..........##..##..........","..........######..........","..##..##..######..##..##..","..##..##..##..##..##..##..","..##..##..##..##..##..##..","..##..##..##..##..##..##..","..##..##..........##..##..","..##..##..........##..##..","..##..##...####...##..##..","...........#..#...........","...........#..#..........."};this->Block2D.resize(26);for (auto& itm : this->Block2D) {itm.resize(26);}for (int i = 0; i < 26; i++) {for (int j = 0; j < 26; j++) {if (tMap[i][j] == '.') {this->Block2D[j][i] = new EmptyBlock(game);this->Block2D[j][i]->setPosition(j * 32, i * 32);}else if (tMap[i][j] == '#') {this->Block2D[j][i] = new WallBlock(game);this->Block2D[j][i]->setPosition(j * 32, i * 32);}else if (tMap[i][j] == '%') {this->Block2D[j][i] = new IronBlock(game);this->Block2D[j][i]->setPosition(j * 32, i * 32);}}}
}
void Map::Draw() {for (int i = 0; i < this->Block2D.size(); i++) {for (int j = 0; j < this->Block2D.size(); j++) {Block2D[i][j]->Draw();}}
}
void Map::setLostMap() {std::vector<std::string> rMap = {"..........................","..........................","..###...###...##.##..####.",".#.....#...#.#..#..#.#....",".#.....#####.#..#..#.####.",".#..##.#...#.#..#..#.#....",".#...#.#...#.#..#..#.#....","..###..#...#.#..#..#.####.","..........................","..........................","..###..#...#.####.###..#..",".#...#.#...#.#....#..#.#..",".#...#.#...#.####.#..#.#..",".#...#.#...#.#....###..#..",".#...#..#.#..#....#..#....","..###....#...####.#..#.#..","..........................","..%..........%%%..........","..%.........%...%.......%.","..%%..%.%.%.%...%.%.%..%..","..%.%.%.%...%...%.%.%.%%%.","..%%...%%.%..%%%...%%..%..","........%.......%...%..%..","........%...........%..%..",".......%...........%..%...",".........................."};for (int i = 0; i < 26; i++) {for (int j = 0; j < 26; j++) {if (rMap[i][j] == '.') {delete this->Block2D[j][i];this->Block2D[j][i] = new EmptyBlock(game);this->Block2D[j][i]->setPosition(j * 32, i * 32);}else if (rMap[i][j] == '#') {delete this->Block2D[j][i];this->Block2D[j][i] = new WallBlock(game);this->Block2D[j][i]->setPosition(j * 32, i * 32);}else if (rMap[i][j] == '%') {delete this->Block2D[j][i];this->Block2D[j][i] = new IronBlock(game);this->Block2D[j][i]->setPosition(j * 32, i * 32);}}}
}
//Player.h
#pragma once
#include <SFML/Graphics.hpp>
#include "Game.h"
#include "GameObject.h"
class Game;
enum class Direction;
class Player : public GameObject {Game* game;
public:Direction dir;bool isDead;float speed;bool isMoving;Player(Game* game);void Move();void Turn(Direction dir);void Draw();
};
//Player.cpp
#include "Player.h"
Player::Player(Game* game) {this->speed = 8.0f;this->isDead = false;this->texture.loadFromFile("Src\\TankPlayer.png");this->sprite.setTexture(texture);this->sprite.setScale(4.0f, 4.0f);this->sprite.setOrigin(6.5f, 6.5f);this->sprite.setPosition(288.0f, 768.0f);this->dir = Direction::Up;this->isMoving = false;this->game = game;
}
void Player::Move() {if (!this->isMoving)return;float dx, dy;switch (this->dir) {case Direction::Up:dx = 0; dy = -speed; break;case Direction::Down:dx = 0; dy = speed; break;case Direction::Left:dx = -speed; dy = 0; break;case Direction::Right:dx = speed; dy = 0; break;}this->sprite.move(dx, dy);for (int i = 0; i < game->map->Block2D.size(); i++) {for (int j = 0; j < game->map->Block2D[0].size(); j++) {if (game->map->Block2D[i][j]->type != BlockType::Empty&&this->sprite.getGlobalBounds().intersects(game->map->Block2D[i][j]->sprite.getGlobalBounds())) {this->sprite.move(-dx, -dy);}}}if (this->sprite.getPosition().x - 28.0f < 0 || this->sprite.getPosition().y - 28.0f < 0 || this->sprite.getPosition().x + 28.0f > 832 || this->sprite.getPosition().y + 28.0f > 832)this->sprite.move(-dx, -dy);for (auto itm : game->enemyList) {if (this->sprite.getGlobalBounds().intersects(itm->sprite.getGlobalBounds()))this->sprite.move(-dx, -dy);}
}
void Player::Turn(Direction dir) {switch (dir) {case Direction::Up:this->sprite.setRotation(0); this->dir = Direction::Up; break;case Direction::Down:this->sprite.setRotation(180); this->dir = Direction::Down; break;case Direction::Left:this->sprite.setRotation(270); this->dir = Direction::Left; break;case Direction::Right:this->sprite.setRotation(90); this->dir = Direction::Right; break;}
}
void Player::Draw() {game->window->draw(this->sprite);
}

程序运行效果截图

C++/SFML面向对象课程设计,坦克大战相关推荐

  1. 面向对象程序设计(Java)课程设计--坦克大战

    目录 一.项目简介 1.功能描述 二.团队成员负责模块 三.功能架构图 四.项目亮点 五.功能需求分析 六.系统演示操作图片 七.项目git地址及团队成员git提交记录截图 一.项目简介 1.功能描述 ...

  2. Java课程设计——坦克大战

    坦克大战--坦克类 一. 团队课程设计博客链接 https://www.cnblogs.com/chenhuilin/p/10275664.html 二.个人负责模块和任务说明 模块:坦克类(玩家坦克 ...

  3. c语言课程设计坦克大战,funcodec++课程设计_坦克大战

    <funcodec++课程设计_坦克大战>由会员分享,可在线阅读,更多相关<funcodec++课程设计_坦克大战(24页珍藏版)>请在人人文库网上搜索. 1.课程设计一 坦克 ...

  4. 坦克大战java_Java课程设计——坦克大战

    坦克大战--坦克类 一. 团队课程设计博客链接 二.个人负责模块和任务说明 模块:坦克类(玩家坦克类+电脑坦克类),代码整合 三.代码的提交记录截图 四.负责模块和任务详细说明 玩家坦克继承Visib ...

  5. java坦克大战互相碰撞_Java课程设计——坦克大战

    坦克大战--坦克类 一. 团队课程设计博客链接 二.个人负责模块和任务说明 模块:坦克类(玩家坦克类+电脑坦克类),代码整合 三.代码的提交记录截图 四.负责模块和任务详细说明 玩家坦克继承Visib ...

  6. java坦克大战总体功能设计_java课程设计——坦克大战

    ##一.团队课程设计博客链接: ##二.个人负责模块或任务说明: ###模块:GUI设计(游戏面板,登录面板,主窗体,显示关卡面板) ##三.自己的代码提交记录截图 ##四.自己负责模块或任务详细说明 ...

  7. java飞机大战流程图_JAVA课程设计-飞机大战

    JAVA课程设计-飞机大战 1.团队名称.团队成员介绍 1.1 团队名称:做个飞机哦 1.2团队成员介绍: 余俊良(组长):编写博客.游戏主界面设计与实现.英雄机与子弹类的实现.场景设计 林祥涛:游戏 ...

  8. java购物车设计_Java面向对象课程设计——购物车

    Java面向对象课程设计--购物车 小组成员:余景胜.刘格铭.陈国雄.达瓦次仁 一.前期调查 流程 客人(Buyer)先在商城(Mall)中浏览商品(Commidity),将浏览的商品加入购物车(Sh ...

  9. 家庭财务管理系统(C++面向对象课程设计附课设报告)

    0004 家庭财务管理系统(C++面向对象课程设计) 摘要:主要用于记录家庭财务支出和收入等记录的程序设计,其主要开发平台为 Windows 10,程序设计开发环境为 Microsoft visual ...

最新文章

  1. 合肥云暨移动应用孵化基地全面运营,服务企业转型升级
  2. shell 命令执行结果判断语句
  3. 区块链应用 | 用区块链颠覆视频直播,与视频卡顿、缓冲说再见!
  4. 医学图像分类_全面梳理:图像配准综述
  5. linux 查看磁盘分区,文件系统,使用情况的命令和相关工具介绍,Linux 查看磁盘分区、文件系统、使用情况的命令和相关工具介绍df...
  6. SAP Spartacus 从 Ngrx 里获取 navigation 的实时状态
  7. 二、VC++环境的安装
  8. 照片打印预览正常打印空白_小米发布口袋照片打印机,可无墨打印3寸背胶照片...
  9. LoadRunner 中的 Unique Number 参数类型小结
  10. 6.Shell 编程从入门到精通 --- 文件和文件系统
  11. python爬虫之多线程、多进程爬虫_python 多线程,多进程,高效爬虫
  12. 五子棋算杀c语言,什么是五子棋的做杀
  13. HanLP里使用DAT存取字典的方法
  14. stm32怎么入门?数电模电单片机先学哪个?
  15. matlab中zeros()函数与ones()函数用法
  16. i春秋《从0到1:CTFer成长之路》通关WP
  17. tomcat10 实例化servlet 500错误解决办法
  18. 2020西湖论剑Web复现
  19. 前端实现导入PPT在线编辑
  20. Agarose bound-WFA,WFL;琼脂糖结合紫藤凝集素(WFA,WFL)

热门文章

  1. 赛灵思 PL 和 PS IBIS 模型解码器
  2. apache-maven-3.8.5配置
  3. Mac电脑声音无法正常播放怎么解决
  4. 汉字 Unicode 编码范围
  5. json增加反斜杠 php_PHP在引号前面添加反斜杠(PHP去除反斜杠)
  6. OB数据库大赛初赛总结
  7. 海康录像机能用别的摄像头吗_海康录像机怎么添加网络摄像头,你会了吗?
  8. Powershell 5.1中Shift + Insert无法粘贴解决
  9. 苹果加快创新步伐 美国制造一去不复返
  10. 电影《我不是药神》观后感