首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >战斗坦克游戏

战斗坦克游戏
EN

Code Review用户
提问于 2015-11-28 14:42:57
回答 1查看 2K关注 0票数 16

我用SDL2.0 + OpenGL + Box2D为自己制作了一个简单的2D游戏,但是我对代码和结构不安全,因为我开发的游戏使用了我在互联网上学到的所有知识,而不是遵循某种模式。我将代码发布在GitHub上,并在一些论坛上传播,以获得有关代码的反馈,但在这里,我只发布我认为对此更为重要的部分。

游戏简介:游戏是两名玩家(士兵)之间的一场战斗,必须摧毁对方的坦克,但坦克只有在坦克防御者死后才能攻击(持续5秒)。当坦克被摧毁时,坦克防御者输掉了游戏。当游戏进行的时候,有一些助推器会随机出现在地上。助推是:速度(累积到2),防御和生命。

我想用FPS计算器和油漆机的方法来分析它:一些操作的可行性,例如,子弹矢量和我所做的方法。

主循环:

代码语言:javascript
复制
#include <SDL.h>

#include <iostream>
#include <stdexcept>
#include <string>

#include "game.hpp"

SDL_Window* initSDL(const std::string& title, unsigned int w, unsigned int    h);
SDL_GLContext initOpenGL(SDL_Window* window);
void events(LoopHandler* lhandler);
void logics(LoopHandler* lhandler);
void render(LoopHandler* lhandler);

int main(int argc, char* argv[]){
//fps counter
unsigned int fps_c = 0;
Timer fps_ct;

const unsigned int DISERED_DELAY = 25;
unsigned int start, end, loop_t, excess = 0;

SDL_Event event;
LoopHandler* handler = nullptr;
SDL_Window* window = nullptr;
SDL_GLContext glc = nullptr;

try{
    window = initSDL("Hardcore!", 500, 500);
    glc= initOpenGL(window);

    handler = new Game();

    handler->pre();
    fps_ct.start();
    while (handler->active()){
        start = SDL_GetTicks();

        while (SDL_PollEvent(&event)){
            handler->process(&event);
        }

        while (excess < DISERED_DELAY){
            handler->logics();
            excess -= DISERED_DELAY;
        }

        handler->logics();

        glClear(GL_COLOR_BUFFER_BIT);
        handler->render();
        SDL_GL_SwapWindow(window);

        end = SDL_GetTicks();
        loop_t = end - start;
        if (loop_t < DISERED_DELAY){
            SDL_Delay(DISERED_DELAY - loop_t);
        }
        else{
            excess += DISERED_DELAY - loop_t;
        }

        if (fps_ct.compare(1000)){
            system("cls");
            std::cout << "fps: " << fps_c << std::endl;
            fps_c = 0;
        }

        fps_c++;
    }
    handler->pos();
}
catch (std::exception& ex){
    SDL_ShowSimpleMessageBox(::SDL_MessageBoxFlags::SDL_MESSAGEBOX_ERROR, "Error", ex.what(), window);
}

delete handler;
SDL_GL_DeleteContext(glc);
SDL_DestroyWindow(window);

return 0;
}

SDL_Window* initSDL(const std::string& title, unsigned int w, unsigned int h){
SDL_Window* window;

if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
    throw std::runtime_error(SDL_GetError());

window = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);

if (window == NULL)
    throw std::runtime_error(SDL_GetError());

return window;
}

SDL_GLContext initOpenGL(SDL_Window* window){
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

glClearColor(1.0, 0.0, 0.0, 1.0);

return SDL_GL_CreateContext(window);
}

游戏控制器:

代码语言:javascript
复制
#include "game.hpp"

#include "random.hpp"
#include "game_textures.hpp"
#include "boost.hpp"

void Game::pre(){
camera.set(50, 50);
painter.setCamera(camera);

glClearColor(0.50, 0.50, 0.50, 1.0f);

Random::genSeed();

/*create the world with no gravity*/
world = new b2World(b2Vec2(0.0f, 0.0f));
world->SetContactListener(this);
world->SetContactFilter(this);

/*Create world bounds*/
b2Vec2 vertices[] = { b2Vec2(camera.getLeft(), camera.getTop()),   b2Vec2(camera.getRight(), camera.getTop()),
                      b2Vec2(camera.getRight(), camera.getBottom()), b2Vec2(camera.getLeft(), camera.getBottom())};

b2BodyDef bdef;
bdef.type = b2_staticBody;
world_bounds = world->CreateBody(&bdef);

b2ChainShape cshape;
cshape.CreateLoop(vertices, 4);

b2FixtureDef fdef;
fdef.shape = &cshape;
fdef.friction = 0.0f;
fdef.filter.categoryBits = SCENARIO;

world_bounds->CreateFixture(&fdef);

/*textures*/
GameTextures::simple_bullet =   loadTexture("simple_bullet.png");
GameTextures::speed_boost   =   loadTexture("speed_boost.png");
GameTextures::defense_boost =   loadTexture("defense_boost.png");
GameTextures::life_boost    =   loadTexture("life_boost.png");
GameTextures::soldier       =   loadTexture("soldier.png");
GameTextures::tank          =   loadTexture("tank.jpg");

/*players*/
p1 = new Soldier(this, FIGHTER1, {SDLK_UP,
                         SDLK_DOWN,
                         SDLK_LEFT,
                         SDLK_RIGHT,
                         SDLK_m,
                         SDLK_m
                });

p2 = new Soldier(this, FIGHTER2, {SDLK_w,
                         SDLK_s,
                         SDLK_a,
                         SDLK_d,
                         SDLK_q,
                         SDLK_e
                });

p1->setEnemy(p2);
p2->setEnemy(p1);

tank1 = new Tank(this, p1);
tank1->setEnemy(p2);

tank2 = new Tank(this, p2);
tank2->setEnemy(p1);

p1->setTank(tank1);
p2->setTank(tank2);

start();
}

void Game::process(SDL_Event* event){
switch (event->type){
case SDL_QUIT:
    running = false;
    break;
case SDL_KEYDOWN:
    p1->keyDown(&event->key);
    p2->keyDown(&event->key);
    break;
case SDL_KEYUP:
    p1->keyUp(&event->key);
    p2->keyUp(&event->key);
    break;
}
}

void Game::logics(){
if (boost_t.compare(to_next_boost)){
    TimedBoostItem* t = new TimedBoostItem(this);

    t->start();
    boosts.push_back(t);
    to_next_boost = Random::genUInteger(5000, 20000);
}

for (unsigned int i = 0; i < boosts.size(); i++){
    TimedBoostItem* t = boosts[i];

    t->calculate();

    if (t->getTState() == ENDED){
        boosts.erase(boosts.begin() + i);
        i--;
        delete t;
    }
}

tank1->calculate();
tank2->calculate();

p1->calculate();
if (p1t.isRunning()){
    if (p1t.compare(5000)){
        preparePlayer(p1);
        tank1->setTankState(INVULNERABLE);
    }
}else if (p1->getState() == DEAD){
    setToSleep(p1);
    tank1->setTankState(VULNERABLE);
}

p2->calculate();
if (p2t.isRunning()){
    if (p2t.compare(5000)){
        preparePlayer(p2);
        tank2->setTankState(INVULNERABLE);
    }
}else if (p2->getState() == DEAD){
    setToSleep(p2);
    tank2->setTankState(VULNERABLE);
}

if (tank1->getState() == DEAD && tank2->getState() == DEAD){
      SDL_ShowSimpleMessageBox(SDL_MessageBoxFlags::SDL_MESSAGEBOX_INFORMATION, "Fim!", "Empate!", NULL);
    start();
}
else if(tank1->getState() == DEAD){
    SDL_ShowSimpleMessageBox(SDL_MessageBoxFlags::SDL_MESSAGEBOX_INFORMATION, "Fim!", "Player 2 destruiu o tank!", NULL);
    start();
}else if (tank2->getState() == DEAD){
     SDL_ShowSimpleMessageBox(SDL_MessageBoxFlags::SDL_MESSAGEBOX_INFORMATION, "Fim!", "Player 1 destruiu o tank!", NULL);
    start();
}


world->Step(1.0f / 40.0f, 2, 6);
}

void Game::render(){
/*draw background*/

for (TimedBoostItem* t : boosts){
    t->render(&painter);
}

p1->render(&painter);
p2->render(&painter);
tank1->render(&painter);
tank2->render(&painter);

/*draw HUD*/
}

void Game::pos(){
delete tank1;
delete tank2;
delete p1;
delete p2;

delete GameTextures::simple_bullet;
delete GameTextures::speed_boost;
delete GameTextures::defense_boost;
delete GameTextures::life_boost;
delete GameTextures::soldier;
delete GameTextures::tank;
}

bool Game::active(){
return running;
}

Camera2D Game::getCamera()const{
return camera;
}

void Game::start(){
preparePlayer(p1);
preparePlayer(p2);

tank1->load();
tank1->setPosition(PointF(10.0f, 17.0f));

tank2->load();
tank2->setPosition(PointF(-10.0f, -17.0f));

running = true;

to_next_boost = Random::genUInteger(5000, 20000);

world->ClearForces();

boost_t.start();
}

void Game::preparePlayer(Soldier* soldier){
soldier->unload();
soldier->load();
if (soldier->getCategory() == FIGHTER2){
    p2t.stop();
}
else{
    p1t.stop();
}

soldier->setPosition(
    PointF(
    Random::genInteger(camera.getLeft() + soldier->getArea().getWidth() / 2.0f, camera.getRight() - soldier->getArea().getWidth() / 2.0f),
    Random::genInteger(-17 + soldier->getArea().getHeight() / 2.0f, 17 + soldier->getArea().getHeight() / 2.0f)));
}
void Game::setToSleep(Soldier* soldier){
soldier->unload();
soldier->getMachineGun()->stopShooting();
if (soldier->getCategory() == FIGHTER2){
    p2t.start();
}
else{
    p1t.start();
}
}


void Game::BeginContact(b2Contact* contact){
b2Body* a = contact->GetFixtureA()->GetBody();
b2Body* b = contact->GetFixtureB()->GetBody();
GameData* gdata_a = (GameData*)a->GetUserData();
GameData* gdata_b = (GameData*)b->GetUserData();

if (gdata_a != nullptr)
    gdata_a->thing->onCollide(gdata_b);

if (gdata_b != nullptr)
    gdata_b->thing->onCollide(gdata_a);
}

void Game::EndContact(b2Contact* contact){

}

bool Game::ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB){
b2Body* a = fixtureA->GetBody();
b2Body* b = fixtureB->GetBody();
GameData* gdata_a = (GameData*)a->GetUserData();
GameData* gdata_b = (GameData*)b->GetUserData();

if (gdata_b != nullptr && gdata_a != nullptr){
    if (gdata_a->bits == BULLET){
        /*avoid bullet collision with its shooter and TIMED_BOOST_ITEM(bit masks is not working :s)*/
        if (gdata_b->thing == ((Bullet*)gdata_a->thing)->getShooter() || gdata_b->bits == TIMED_BOOST_ITEM){
            return false;
        }
    }
    else if (gdata_b->bits == BULLET){
        if (gdata_a->thing == ((Bullet*)gdata_b->thing)->getShooter() || gdata_a->bits == TIMED_BOOST_ITEM){
            return false;
        }
    }
}

return true;
}

播放器控制器:

代码语言:javascript
复制
#include "soldier.hpp"

#include "game_textures.hpp"

Soldier::Soldier(Game* game, unsigned short category, ControlKeys controls) : Fighter(game, category){
this->mgun = nullptr;
this->control_keys = controls;
this->my = GameTextures::soldier;
}

void Soldier::load(){
if (mgun == nullptr){
    mgun = new MachineGun(this);
}
else{
    mgun->freeBullets();
}

/*set default bullets*/
SimpleBullet* sb = new SimpleBullet(this);
mgun->charge(sb);
delete sb;

my = GameTextures::soldier;
direction = DOWN;
state = STOPPED;
area.setWidth(3.0f);
area.setHeight(3.0f);
speed = c_speed = 1.0f;
setDefense(1.0f);
setLife(1.0f);
points = 0;

if (body == nullptr)
    this->createBody(SizeF(area.getWidth(), area.getHeight()), b2BodyType::b2_dynamicBody, category, getEnemyCategory() | BULLET | TANK | TIMED_BOOST_ITEM | SCENARIO, false);
}

void Soldier::calculate(){
/*calculate bullets*/
mgun->calculate();

/*calculate effects*/
for (unsigned int i = 0; i < effects.size(); i++){
    Effect* e = effects[i];
    e->calculate();

    if (e->getTState() == TIMER_STATE::ENDED){
        effects.erase(effects.begin() + i);
        delete e;
    }
}

calculateFaceDirection();

if (state != DEAD){
    /*update position*/
    area.setX(body->GetPosition().x - area.getWidth() / 2);
    area.setY(body->GetPosition().y - area.getHeight() / 2);
}
}

void Soldier::render(Painter* painter){
mgun->render(painter);

if (state != DEAD){
    painter->loadIdentity();
    painter->setColor(Color(0.0f, 0.0f, 0.0f));
    painter->drawRect(AreaF(area.getX(), area.getY() + area.getHeight() + 0.1f, area.getWidth(), 1.0f));

    painter->loadIdentity();
    painter->setColor(Color(0.0f, 1.0f, 0.0f));
    painter->drawRect(AreaF(area.getX(), area.getY() + area.getHeight() + 0.1f, area.getWidth() * clife, 1.0f));

    painter->loadIdentity();
    switch (face_direction){
    case UP:
        painter->drawTexture(my, SizeF(area.getWidth(), area.getHeight()), getPosition(), 0.0f);
        break;
    case DOWN:
        painter->drawTexture(my, SizeF(area.getWidth(), area.getHeight()), getPosition(), 180.0f);
        break;
    case LEFT:
        painter->drawTexture(my, SizeF(area.getWidth(), area.getHeight()), getPosition(), 90.0f);
        break;
    case RIGHT:
        painter->drawTexture(my, SizeF(area.getWidth(), area.getHeight()), getPosition(), 270.0f);
        break;
    }
}
else{
    painter->loadIdentity();
    painter->setColor(Color(0.3f, 0.3f, 0.3f, 0.5f));
    painter->drawRect(area);
}
}

void Soldier::unload(){
destroyBody();

for (Effect* e : effects){
    delete e;
}

effects.clear();
}

void Soldier::calculateFaceDirection(){
float dx, dy, x, y, r, b;

if (enemy->getState() != DEAD){
    x = enemy->getPosition().getX();
    y = enemy->getPosition().getY();
    r = enemy->getArea().getRight();
    b = enemy->getArea().getBottom();
}
else{
    x = ((Soldier*)enemy)->getTank()->getPosition().getX();
    y = ((Soldier*)enemy)->getTank()->getPosition().getY();
    r = ((Soldier*)enemy)->getTank()->getArea().getRight();
    b = ((Soldier*)enemy)->getTank()->getArea().getBottom();
}

dx = area.getX() - x;
dy = area.getY() - y;

if ((dx >= 0 && dy >= 0)){
    if (r < area.getX() && b < area.getY()){
        if (direction == RIGHT || direction == LEFT){
            face_direction = DOWN;
        }
        else{
            face_direction = LEFT;
        }
    }
    else if(r > area.getX()){
        face_direction = DOWN;
    }
    else/*b > area.getBottom()*/{
        face_direction = LEFT;
    }
}
else if ((dx < 0 && dy >= 0)){
    if (x > area.getRight() && b < area.getY()){
        if (direction == RIGHT || direction == LEFT){
            face_direction = DOWN;
        }
        else{
            face_direction = RIGHT;
        }
    }
    else if (x < area.getRight()){
        face_direction = DOWN;
    }
    else/*b > area.getBottom()*/{
        face_direction = RIGHT;
    }
}
else if (dx < 0 && dy <= 0){
    if (x > area.getRight() && y > area.getBottom()){
        if (direction == RIGHT || direction == LEFT){
            face_direction = UP;
        }
        else{
            face_direction = RIGHT;
        }
    }
    else if (x < area.getRight()){
        face_direction = UP;
    }
    else/*y < area.getBottom()*/{
        face_direction = RIGHT;
    }
}
else if (dx >= 0 && dy <= 0){
    if (r < area.getX() && y > area.getBottom()){
        if (direction == RIGHT || direction == LEFT){
            face_direction = UP;
        }
        else{
            face_direction = LEFT;
        }
    }
    else if (r > area.getX()){
        face_direction = UP;
    }
    else/*y < area.getBottom()*/{
        face_direction = LEFT;
    }
}
}

void Soldier::keyDown(SDL_KeyboardEvent* event){
SDL_Keycode key = event->keysym.sym;

if (state == DEAD)
    return;

if (key == control_keys.up){
    direction = UP;
    state = WALKING;
    body->SetLinearVelocity(b2Vec2(0.0f, 30.0f * c_speed));
}
else if (key == control_keys.down){
    direction = DOWN;
    state = WALKING;
    body->SetLinearVelocity(b2Vec2(0.0, -30.0f * c_speed));
}
else if (key == control_keys.left){
    direction = LEFT;
    state = WALKING;
    body->SetLinearVelocity(b2Vec2(-30.0f * c_speed, 0.0f));
}
else if (key == control_keys.right){
    direction = RIGHT;
    state = WALKING;
    body->SetLinearVelocity(b2Vec2(30.0f * c_speed, 0.0f));
}
else if (key == control_keys.shoot){
    mgun->startShooting();
}
}

void Soldier::keyUp(SDL_KeyboardEvent* event){
SDL_Keycode key = event->keysym.sym;

    if (state == DEAD)
        return;

if (key == control_keys.up){
    if (state == WALKING && direction == UP){
        state = STOPPED;
        body->SetLinearVelocity(b2Vec2(0.0f, 0.0f));
    }
}
else if (key == control_keys.down){
    if (state == WALKING && direction == DOWN){
        state = STOPPED;
        body->SetLinearVelocity(b2Vec2(0.0f, 0.0f));
    }
}
else if (key == control_keys.left){
    if (state == WALKING && direction == LEFT){
        state = STOPPED;
        body->SetLinearVelocity(b2Vec2(0.0f, 0.0f));
    }
}
else if (key == control_keys.right){
    if (state == WALKING && direction == RIGHT){
        state = STOPPED;
        body->SetLinearVelocity(b2Vec2(0.0f, 0.0f));
    }
}
else if (key == control_keys.shoot){
    mgun->stopShooting();
}
}

Painter类:

代码语言:javascript
复制
#include "painter.hpp"

Painter::Painter(){}
Painter::~Painter(){}

void Painter::rotate(float angle){
/*rotate from z-axis, thats all needed for this game*/
glRotatef(angle, 0.0f, 0.0f, 1.0f);
}

void Painter::translate(float tx, float tz, float ty){
glTranslatef(tx, ty, tz);
}

void Painter::scale(float sx, float, float sy, float sz){
glScalef(sx, sy, sz);
}

void Painter::drawTexture(Texture2D* texture, const PointF& position){
camera.set(camera.getWidth(), camera.getHeight());

glEnable(GL_TEXTURE_2D);
texture->bind();
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 1.0f);
glVertex2f(position.getX(), position.getY());
glTexCoord2f(1.0f, 1.0f);
glVertex2f(position.getX() + texture->getWidth(), position.getY());
glTexCoord2f(1.0f, 0.0f);
glVertex2f(position.getX() + texture->getWidth(), position.getY() + texture->getHeight());
glTexCoord2f(0.0f, 0.0f);
glVertex2f(position.getX(), position.getY() + texture->getHeight());
glEnd();
glDisable(GL_TEXTURE_2D);
}

void Painter::drawTexture(Texture2D* texture, const AreaF& area, const PointF& position){
camera.set(camera.getWidth(), camera.getHeight());
glEnable(GL_TEXTURE_2D);
texture->bind();
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 1.0f/area.getY());
glVertex2f(position.getX(), position.getY());
glTexCoord2f(1.0f / area.getX(), 1.0f / area.getY());
glVertex2f(position.getX() + area.getWidth(), position.getY());
glTexCoord2f(1.0f / area.getX(), 0.0f);
glVertex2f(position.getX() + area.getWidth(), position.getY() + area.getHeight());
glTexCoord2f(0.0f, 0.0f);
glVertex2f(position.getX(), position.getY() + area.getHeight());
glEnd();
glDisable(GL_TEXTURE_2D);
}

void Painter::drawTexture(Texture2D* texture, const SizeF& size, const PointF& position, float angle){
camera.set(camera.getWidth(), camera.getHeight());

if (angle != 0.0f){
    glTranslatef(position.getX() + size.getWidth() / 2, position.getY() + size.getHeight() / 2, 0.0f);
    glRotatef(angle, 0.0f, 0.0f, 1.0f);
    glTranslatef(-(position.getX() + size.getWidth() / 2), -(position.getY() + size.getHeight()/2), 0.0f);
}

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);
texture->bind();
glBegin(GL_QUADS);
glColor4f(1, 1, 1, 1);
glTexCoord2f(0.0f, 1.0f);
glVertex2f(position.getX(), position.getY());
glTexCoord2f(1.0f, 1.0f);
glVertex2f(position.getX() + size.getWidth(), position.getY());
glTexCoord2f(1.0f, 0.0f);
glVertex2f(position.getX() + size.getWidth(), position.getY() + size.getHeight());
glTexCoord2f(0.0f, 0.0f);
glVertex2f(position.getX(), position.getY() + size.getHeight());
glEnd();
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
}

void Painter::drawTexture(Texture2D* texture, const AreaF& area, const SizeF& size, const PointF& position){
camera.set(camera.getWidth(), camera.getHeight());
glEnable(GL_TEXTURE_2D);
texture->bind();
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 1.0f / area.getY());
glVertex2f(position.getX(), position.getY());
glTexCoord2f(1.0f / area.getX(), 1.0f / area.getY());
glVertex2f(position.getX() + size.getWidth(), position.getY());
glTexCoord2f(1.0f / area.getX(), 0.0f);
glVertex2f(position.getX() + size.getWidth(), position.getY() + size.getHeight());
glTexCoord2f(0.0f, 0.0f);
glVertex2f(position.getX(), position.getY() + size.getHeight());
glEnd();
glDisable(GL_TEXTURE_2D);
}

void Painter::drawRect(const AreaF& area){
camera.set(camera.getWidth(), camera.getHeight());

glBegin(GL_QUADS);
glColor4f(color.getR(), color.getG(), color.getB(), color.getA());
glVertex2f(area.getX(), area.getY());
glVertex2f(area.getX() + area.getWidth(), area.getY());
glVertex2f(area.getX() + area.getWidth(), area.getY() + area.getHeight());
glVertex2f(area.getX(), area.getY() + area.getHeight());
glEnd();
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2015-11-28 21:45:53

一般结构:

压痕。保持一致。这使得代码在到处都是的时候很难读懂。同时,在每个块打开{之后添加一层缩进,并在块关闭}时删除它。

内存管理

您不应该使用新/删除。大多数情况下,自动变量是首选。当您想要动态创建对象时,std::unique_ptr生成的代码就像使用原始指针一样快(如果您能够度量这种差异,我将感到非常惊讶(特别是因为99%的编译时间都是相同的代码)。

代码语言:javascript
复制
LoopHandler* handler = nullptr;

try{

    handler = new Game();
}
catch(std::exception const& e)
{}

delete handler;

此代码不安全(并非所有异常都需要从std::exception派生)。只要把它变成一个局部变量,所有的管理问题就会消失。

代码语言:javascript
复制
LoopHandler handler;

try{

}
catch(std::exception const& e)
{}

为什么要这样做:

代码语言:javascript
复制
/*set default bullets*/
SimpleBullet* sb = new SimpleBullet(this);
mgun->charge(sb);                           
delete sb;

这一小段代码有几个问题。没有为sb定义所有权语义。您将sb作为指向charge()的指针传递,因此我并不100%相信您需要删除它们(我现在需要检查该方法是如何工作的,以确保您正在正确地执行该方法)。但假设您是这样的,这意味着您要在内部创建一个sb副本,所以如果要创建一个副本,为什么需要像这样动态地创建它们并删除它们。

这三行让我的耳朵流血了。

我会这么做的。

代码语言:javascript
复制
/*set default bullets*/
mgun.charge(SimpleBullet(this));  // Pass by value (or ref)
                                  // This mean if `charge()` wants the bullets he needs to copy them

或。

代码语言:javascript
复制
/*set default bullets*/
std::unique_ptr<SimpleBullet> sb(new SimpleBullet(this));
mgun.charge(std::move(sb));          // I am moving them to `charge()`
                                     // So he is taking ownership (anyway they are not coming back).
                                     // So unique_ptr will do nothing.

或。

代码语言:javascript
复制
/*set default bullets*/
std::unique_ptr<SimpleBullet> sb(new SimpleBullet(this));
mgun.charge(sb);                    // I am passing a reference to charge (you can't copy).
                                    // This means `charge()` has the option of taking ownership.
                                    // If he does then its his responsibility to delete them
                                    // If not they stay in `sb` which will automatically
                                    // delete them in an exception safe way when it goes
                                    // out of scope.

使用RAII进行初始化/销毁控制.

当您看到如下代码时:

代码语言:javascript
复制
 void func()
 {
   DoSomeInit();

   CODE()

   SoSomeCleanUp();
 }

你做错了。此代码不例外安全。如果代码()抛出,那么就不会进行清理。你应该用RAII来做这个工作。

代码语言:javascript
复制
  class MyGameEnvironment
  {
      public:
          MyGameEnvironment()
          {
               DoSomeInit();
          }
          ~MyGameEnvironment()
          {
               SoSomeCleanUp();
          }
  };

  void func()
  {
    MyGameEnvironment  game;
    CODE();
  }

我知道这看起来是很多额外的工作。不是真的。这种风格会比你想象的更能拯救你的屁股。它还使您的函数更小,更容易阅读。

全局变量是无

更准确地说。全局可变状态是一件坏事。这使得您的代码很难测试。很难得到正确的,并导致意大利面风格代码。在函数中本地创建对象,并将它们作为参数传递。

代码语言:javascript
复制
 int main()
 {
     Tank       tank1;
     Tank       tank2;
     MyGame     game(tank1, tank2);

     game.play();
 }
票数 12
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/112144

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档