Войти
ПрограммированиеФорумОбщее

SpaceBattle: Помогите с рефакторингом

Страницы: 1 2 Следующая »
#0
18:51, 18 ноя. 2013

Здравствуйте!
Начал писать копию классического Space Battle 2D на С++ и DirectX. Через дня 3 кодинга (2 из них ушло на выяснение, куда девается память из map и чтению о shared_ptr) стало попахивать говнокодом и вот, я здесь со своими нубскими вопросами. Начну пожалуй с анимации. На данный момент реализована 1 анимация (взрыв корабля). В переменной корабля хранится его текущее состояние, в зависимости от которого грубо говоря меняются текстуры (анимация спрайта).

enum SHIP_STATE
{
  SHIP_STATE_IDLE         = 1,
  
        SHIP_STATE_MOVE_FORWARD = 2,
  SHIP_STATE_MOVE_LEFT    = 4,
  SHIP_STATE_MOVE_RIGHT   = 8,
  

        SHIP_STATE_DESTROYED    = 16,

  SHIP_STATE_EXPLODE1     = 32,
  SHIP_STATE_EXPLODE2     = 33,
  SHIP_STATE_EXPLODE3     = 34,
  SHIP_STATE_EXPLODE4     = 35,
  SHIP_STATE_EXPLODE5     = 36,
  SHIP_STATE_EXPLODE6     = 37,
  SHIP_STATE_EXPLODE7     = 38,
};

. . . . . .

void Ship::_Explode()
{
  timer1_start = clock();

  while ( (clock() - timer1_start) / (float)CLOCKS_PER_SEC < 0.05f) ;

  switch (shipState)
  {
  case SHIP_STATE_MOVE_FORWARD:
    shipState = SHIP_STATE_EXPLODE1;
    _Explode();
    break;
  case SHIP_STATE_EXPLODE1:
    shipState = SHIP_STATE_EXPLODE2;
    _Explode();
    break;
  case SHIP_STATE_EXPLODE2:
    shipState = SHIP_STATE_EXPLODE3;
    _Explode();
    break;
  case SHIP_STATE_EXPLODE3:
    shipState = SHIP_STATE_EXPLODE4;
    _Explode();
    break;
  case SHIP_STATE_EXPLODE4:
    shipState = SHIP_STATE_EXPLODE5;
    _Explode();
    break;
  case SHIP_STATE_EXPLODE5:
    shipState = SHIP_STATE_EXPLODE6;
    _Explode();
    break;
  case SHIP_STATE_EXPLODE6:
    shipState = SHIP_STATE_EXPLODE7;
    _Explode();
    break;
  case SHIP_STATE_EXPLODE7:
    return;
    break;
  }
}

void DX11Game::Update(float dt)
{
  switch (DX11Game::gameState)
  {

  . . . . . .

  case GAME_STATE::GAME_STATE_RESPAWN:
    if (DX11Game::gameState != DX11Game::prevGameState)
    {
      gameLogic->CleanGameObjects();
      gameLogic->Update(dt);
      gameLogic->GetShip()->SetShipState(SHIP_STATE_MOVE_FORWARD);
      gameLogic->GetShip()->Explode();  //Запускается в отдельном потоке
    }
    else
      if ( gameLogic->GetShip()->GetShipState() == SHIP_STATE_EXPLODE7) // = если анимация взрыва закончилась
      {
        Ship* ship = gameLogic->GetShip();
        timer1_start = clock();
        float speed      = *(ship->GetSpeed());
        float initPos[2];
        initPos[0] = ship->GetInitPos()[0];
        initPos[1] = ship->GetInitPos()[1];
        _DELETE(ship);
        ship = new Ship(25, speed, initPos, Ship::GetLives());
        ship->SetShipState(SHIP_STATE_IDLE);
        timer1_start = clock();
        shipSparklingCount--;
      }
      else
      {
                                // Начало мерцания корабля после рестарта
        if ( shipSparklingCount != SHIP_SPARKLING_COUNT
          && (clock() - timer1_start) / (float)CLOCKS_PER_SEC > 0.1f ) 
        {
          if (shipSparklingCount == 0)
          {
            DX11Game::gameState = GAME_STATE_PLAY;
            shipSparklingCount = SHIP_SPARKLING_COUNT;
            return;
          }
          else
          {
            if (gameLogic->GetShip()->GetShipState() & SHIP_STATE_IDLE)
              gameLogic->GetShip()->SetShipState(SHIP_STATE_MOVE_FORWARD);
            else
              gameLogic->GetShip()->SetShipState(SHIP_STATE_IDLE);
            shipSparklingCount--;
          }
          timer1_start = clock();
        }
      }
      break;
  default:
    break;
  }
}

Прошу подсказать, какие есть альтернативные (нормальные) варианты реализации таких спрайтовых анимаций?

На всякий случай прилагаю диаграму классов проекта:
Изображение


#1
19:21, 18 ноя. 2013

oler
> Через дня 3 кодинга (2 из них ушло на выяснение, куда девается память из map и
> чтению о shared_ptr) стало попахивать говнокодом и вот

Меня всегда интересовал вопрос - почему сначала делают, а уже потом читают доки ?

#2
20:57, 18 ноя. 2013

oler
> Прошу подсказать, какие есть альтернативные (нормальные) варианты реализации
> таких спрайтовых анимаций?
создай массив спрайтов, каждому спрайту поставь время пребывания на экране.
возьми текущее время, отними от времени начала. получишь время анимации. по нему вычисли нужный кадр, можешь полным перебором, можешь хранить номер кадра и сколько времени он на экране.

#3
20:59, 18 ноя. 2013

oler
ох щи
> while ( (clock() - timer1_start) / (float)CLOCKS_PER_SEC < 0.05f) ;
вот это я не заметил
оно еще и рекурсивно. О_О

#4
2:58, 20 ноя. 2013

Pushkoff, спасибо за идею на счет анимации. Попробую
А то , что рекурсивно - не страшно, тот метод все равно запускается в отдельном потоке. LOL

Еще возникла проблемма с deltaTime, вроде все по канонам делаю, а оно не работает.

Код из main.cpp:

      __int64 counts_per_sec;
      QueryPerformanceFrequency((LARGE_INTEGER*)&counts_per_sec);
      QueryPerformanceCounter((LARGE_INTEGER*)&start_time);
    
      demo->Update(dt+1);
      demo->Render();
      
      __int64 end_time;
      QueryPerformanceCounter((LARGE_INTEGER*)&end_time);
      dt = (end_time - start_time) / (double)counts_per_sec;

Реализует задержку между пулями во время стрельбы:

if ( (end - timer1_start) / (float)CLOCKS_PER_SEC >= (0.1f * dt))

Метод движения:

void GameObject::Move(float axesDirection[2], float dt)
{
  position[0] += (axesDirection[0] * speed * speedCoefs[0] * dt);
  position[1] += (axesDirection[1] * speed * speedCoefs[1] * dt);
}

Но когда ФПС падает, время задержки между выстрелами не изменяется (а по идее должно увеличиваться) и все пули сливаются в одну линию. Что и думать не знаю...

#5
17:45, 20 ноя. 2013

oler
> А то , что рекурсивно - не страшно, тот метод все равно запускается в отдельном
> потоке. LOL
это вообще ад.

#6
17:46, 20 ноя. 2013

oler
для того чтоб вообще адово было, советую посмотреть на Duff's Device.

#7
18:12, 20 ноя. 2013

Pushkoff, прочел статью http://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%9… 4%D1%84%D0%B0, но понял чуть менее, чем ничего. Но все таки... Я понимаю, что расходовать ресурсы системы не хорошо, даже если их сверхдостаточно. Но я придерживаюсь методики: "Сначало сделай, чтобы работало, - потом оптимизируй".

Так все таки, что на счет deltaTime? Спасайте, граждане!!!

#8
19:34, 20 ноя. 2013

oler
> Но я придерживаюсь методики: "Сначало сделай, чтобы работало, - потом
> оптимизируй".
методика хорошая. только все сильно зависит от качества того что начало работать. потому как это не всегда потом получится оптимизировать не переписав полностью.

#9
1:45, 25 ноя. 2013

Проблемму с deltaTime решил. Но теперь появились проблеммы с произвоительностью, связанные с рендером (не с Update). В результате: 150-200 FPS с максимум 80-100 полигонами . Если закоментить метод Render, FPS поднимается до 2500-3000.


Что мне твои слова, давай код! Итак, вот мой Render:

void DX11Game::Render()
{
if( d3dContext_ == 0 )
    return;

stride = sizeof( VertexPT );
offset = 0;
d3dContext_->IASetInputLayout(inputLayout);
d3dContext_->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
d3dContext_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
d3dContext_->VSSetShader(VS, 0, 0);
d3dContext_->PSSetShader(PS, 0, 0);
d3dContext_->PSSetSamplers(0, 1, &samplerState);
d3dContext_->VSSetConstantBuffers(0, 1, &cbMatricesBuffer);
d3dContext_->PSSetConstantBuffers(1, 1, &cbParametersBuffer);


switch (DX11Game::gameState)
{
case GAME_STATE::GAME_STATE_PLAY:
    d3dContext_->ClearRenderTargetView(backBufferTarget_, backColor);
    DrawAsteroids();
    DrawShip();
    DrawUserBullets();
    DrawEnemies();
    DrawGUI();
    break;
case GAME_STATE::GAME_STATE_GAMEOVER:
    d3dContext_->ClearRenderTargetView(backBufferTarget_, backColor);
    DrawAsteroids();
    DrawShip();
    DrawUserBullets();
    DrawGameOver();
    break;
case GAME_STATE::GAME_STATE_SCORES:
    break;
}

swapChain_->Present(0, 0);
}

Один из методов, рисующих game objects (остальные Draws по структуре такие же):

void DX11Game::DrawAsteroids()
{
std::vector<std::shared_ptr<Asteroid>>* asteroids = gameLogic->GetAsteroids();
std::vector<std::shared_ptr<Asteroid>>::iterator it = asteroids->begin();
while (it != asteroids->end())
{
    float SIZE = *((*it)->GetSize());

    float* temp = (*it)->GetTexCoord();
    XMFLOAT4 texBounds = XMFLOAT4( temp[0], temp[1], temp[2], temp[3] );

    vertices[0].pos = XMFLOAT3(  SIZE,  SIZE, 1.0f );
    vertices[0].tex0 = XMFLOAT2( texBounds.x + texBounds.z, texBounds.y );
    vertices[1].pos = XMFLOAT3(  SIZE, -SIZE, 1.0f );
    vertices[1].tex0 = XMFLOAT2( texBounds.x + texBounds.z, texBounds.y + texBounds.w );
    vertices[2].pos = XMFLOAT3( -SIZE, -SIZE, 1.0f );
    vertices[2].tex0 =XMFLOAT2( texBounds.x,texBounds.y + texBounds.w );
    vertices[3].pos = XMFLOAT3( -SIZE, -SIZE, 1.0f );
    vertices[3].tex0 =XMFLOAT2( texBounds.x, texBounds.y + texBounds.w );
    vertices[4].pos =  XMFLOAT3( -SIZE,  SIZE, 1.0f );
    vertices[4].tex0 = XMFLOAT2( texBounds.x, texBounds.y );
    vertices[5].pos = XMFLOAT3(  SIZE,  SIZE, 1.0f );
    vertices[5].tex0 =XMFLOAT2( texBounds.x +texBounds.z, texBounds.y );

    XMMATRIX world = XMMatrixTranslation(
        ( *it )->GetPosition()[0],
        ( *it )->GetPosition()[1],
        0.0f );
    world = XMMatrixTranspose(world);

    d3dContext_->PSSetShaderResources(0, 1, &texGameSprites);
    d3dContext_->UpdateSubresource(vertexBuffer, 0, 0, vertices, 0, 0);
    CB_Matrices matrices;
    matrices.World = world;
    matrices.Projection = proj;
    d3dContext_->UpdateSubresource(cbMatricesBuffer, 0, 0, &matrices, 0, 0);

    CB_Parameters params;
    params.isTextured = true;
    params.color[0] = 1.0f; params.color[1] = 1.0f;
    params.color[2] = 0.0f; params.color[3] = 1.0f;
    d3dContext_->UpdateSubresource(cbParametersBuffer, 0, 0, &params, 0, 0);
    d3dContext_->Draw(6, 0);

    it++;
}
}

Как оптимизировать написать по человечески? Директ только начал изучать, как видно наверное из кода...

#10
2:00, 25 ноя. 2013

oler
> "Сначало сделай, чтобы работало, - потом оптимизируй".
Так у тебя от поговорки осталось только "сначала" и "потом", а главное - "сделай" куда-то потерялось. Еще неплохо сначала думать потом делать.

oler
> Как оптимизировать написать по человечески?

Рисовать все объекты одного "класса" за 1 вызов и не обновлять их таким мерзким образом как у тебя на каждом кадре.
Короче, DrawAsteroids() - тотальное авно. Тут нет ни одной строчки которую бы можно оставить было, кроме открывающей и закрывающей скобок.

Вот это правильно
void DX11Game::DrawAsteroids()
{
}

остальное нафиг убрать.

#11
2:02, 25 ноя. 2013

oler
> switch (shipState)

заменить на

 _Explode();
shipState++;
if(shipState > SHIP_STATE_EXPLODE7)
{...}

#12
2:36, 25 ноя. 2013

outcast, а как можно за один вызов нарисовать, если у объектов разная скорость движения и разные World-матрицы? Мне же надо UpdateSubresource мировой матрицы делать перед каждым Draw насколько я понимаю? Я просто методик других не знаю...

FROL, давно уже заменил тот ужас, но все равно спасибо!

#13
15:14, 25 ноя. 2013

oler
Зачем обновляешь vertexBuffer?
Что пишет Dx debug?

Код ужасен. Если это тестовое задание, то лучше его не показывать.

#14
16:33, 25 ноя. 2013

oler
> outcast, а как можно за один вызов нарисовать, если у объектов разная скорость
> движения и разные World-матрицы?

Очевидно что при рисовании пофиг на производные первую и даже на вторую. Твой вопрос не имеет никакого смысла.

> Мне же надо UpdateSubresource мировой матрицы
> делать перед каждым Draw насколько я понимаю? Я просто методик других не
> знаю...

Очевидно для этого совершенно необязательно обновлять вертекс буфер и матрицы по одной штуке.
Ну реально сотри эту хню нафиг, просто удали проект - это полная лажа.
Пиши заново с 0, думай вначале - зачем нужна каждая строчка кода. Это не стихотворение и не рассказ, просто писать текст лишь бы написать, не имеет смысла.

Страницы: 1 2 Следующая »
ПрограммированиеФорумОбщее

Тема в архиве.