需要帮助优化C ++

时间:2014-01-06 09:47:07

标签: c++ optimization collision-detection game-physics

我在GameBoyAdvance上编写了一个简单的自上而下的汽车驾驶游戏,类似于第一个GTA。我只使用矢量图形这样做,GBA不能很好地处理它;基本上有5个行人实例滞后。

我在优化代码方面没有太多经验,所以我想知道是否可以对我的代码进行一些调整以使其运行得更快,而不是取决于它在GBA上运行的事实

我使用的碰撞测试是SAT(分离轴定理),因为我发现它是用矢量图形进行碰撞检查的最简单的;游戏本身很简单。

以下是代码:

/*
GTA Vector City
Author: Alberto Taiuti
Version: 2.0
*/

#include "Global.h"
#include <string.h>
#include <cstdio>
#include "font.h"
#include "CVector2D.h"
#include "CCar.h"
#include "CPed.h"
#include <vector>
#include <memory>

/* GLOBAL VARIABLES */
void CheckCollisionsRect(CRect *test_a, CRect *test_b);
std::vector<CVector2D> PrepVectors(CRect *shape);
CVector2D GetMinMaxShape(std::vector<CVector2D> vect_shape, CVector2D axis);
void CheckCollisionRectVSPoint(CRect *test_a, CVector2D *point);

/* MAIN */

// The entry point for the game
int main()
{
// Frame counter
uint32_t frames = 0;

// Previous & current buttons states
static uint16_t prev_buttons = 0, cur_buttons = 0;

  // Put the display into bitmap mode 3, and enable background 2.
REG_DISPCNT = MODE4 | BG2_ENABLE;

    // Set up the palette.
SetPaletteBG(BLACK, RGB(0, 0, 0)); // black
SetPaletteBG(WHITE, RGB(31, 31, 31)); // white
SetPaletteBG(GREY, RGB(15, 15, 15)); // grey
SetPaletteBG(RED, RGB(31, 0, 0)); // red
SetPaletteBG(GREEN, RGB(0, 31, 0)); // green
SetPaletteBG(BLUE, RGB(0, 0, 31)); // blue

// Create car instance
CCar *car = new CCar(50,50);

// Create a building
/*CRect *test_b = new CRect(100.0f, 100.0f, 30, 30);
CRect *test_c = new CRect(120.0f, 120.0f, 30, 30);
CRect *test_d = new CRect(30.0f, 30.0f, 30, 30);*/

// Pedestrian instances
int ped_number = 10; // Number of pedestrians
std::vector<CPed*> peds; // Ped. entities container (made of smart pointers)
typedef std::vector<CPed*>::iterator p_itor; // Iterator

for(int i = 1; i <= ped_number; i++)
{
    peds.push_back(new CPed(i, RED, 2.0f));
}

// Check whether the game is over
bool end = false;

// Main loop
while (!end)
{
    // Flip the screen
    FlipBuffers();

    //Clear the screen
    ClearScreen8(BLACK);

    // Update frame counter
    frames ++;  

    // Get the current state of the buttons.
    cur_buttons = REG_KEYINPUT;

    // Handle Input
    car->HandleInput(prev_buttons, cur_buttons);

    // Logic

    car->Update();
    for(int i = 0; i < ped_number; i++)
    {
        peds[i]->Update();
    }

    for(int i = 0; i < ped_number; i++)
    {
        CheckCollisionRectVSPoint(car->shape, peds[i]->pos);
    }

    /*CheckCollisionsRect(car->shape, test_b);
    CheckCollisionsRect(car->shape, test_c);
    CheckCollisionsRect(car->shape, test_d);
    CheckCollisionRectVSPoint(car->shape, test_ped->pos);*/

    // Render
    car->Draw();
    for(int i = 0; i < ped_number; i++)
    {
        peds[i]->Draw();
    }
    /*test_b->DrawFrame8(GREEN);
    test_c->DrawFrame8(WHITE);
    test_d->DrawFrame8(RED);
    test_ped->Draw();*/


    prev_buttons = cur_buttons;

    // VSync
    WaitVSync();
}



// Free memory
delete car;
//delete test_b; delete test_c; delete test_d;
//delete test_ped;
for(p_itor itor = peds.begin(); itor != peds.end(); itor ++)// Delete pedestrians 
{
     peds.erase(itor);
}

return 0;
}

void CheckCollisionsRect(CRect *test_a, CRect *test_b)
{
// If the two shapes are close enough, check for collision, otherways skip and save calculations to the CPU
//if((pow((test_a->points[0]->x - test_b->points[0]->x), 2) + pow((test_a->points[0]->y - test_b->points[0]->y), 2)) < 25.0f) 
{

    // Prepare the normals for both shapes
    std::vector<CVector2D> normals_a = test_a->GetNormalsAsArray();
    std::vector<CVector2D> normals_b = test_b->GetNormalsAsArray();

    // Create two containers for holding the various vectors used for collision check
    std::vector<CVector2D> vect_test_a = PrepVectors(test_a);
    std::vector<CVector2D> vect_test_b = PrepVectors(test_b);

    // Get the min and max vectors for each shape for each projection (needed for SAT)
    CVector2D result_P1 = GetMinMaxShape(vect_test_a, normals_a[1]); //
    CVector2D result_P2 = GetMinMaxShape(vect_test_b, normals_a[1]); //
    // If the two objects are not colliding
    if(result_P1.y < result_P2.x || result_P2.y < result_P1.x)
    {
        return;
    }
    CVector2D result_Q1 = GetMinMaxShape(vect_test_a, normals_a[0]); // First axis couple
    CVector2D result_Q2 = GetMinMaxShape(vect_test_b, normals_a[0]); // 
    if(result_Q1.y < result_Q2.x || result_Q2.y < result_Q1.x)
    {
        return;
    }
    CVector2D result_R1 = GetMinMaxShape(vect_test_a, normals_b[1]); //
    CVector2D result_R2 = GetMinMaxShape(vect_test_b, normals_b[1]); //
    if(result_R1.y < result_R2.x || result_R2.y < result_R1.x)
    {
        return;
    }
    CVector2D result_S1 = GetMinMaxShape(vect_test_a, normals_b[0]); // Second axis couple
    CVector2D result_S2 = GetMinMaxShape(vect_test_b, normals_b[0]); // 
    if(result_S1.y < result_S2.x || result_S2.y < result_S1.x)
    {
        return;
    }


    // Do something
    PlotPixel8(200, 10, WHITE);
    PlotPixel8(200, 11, WHITE);
    PlotPixel8(200, 12, WHITE);

}
}

// Check for collision between an OOBB and a point
void CheckCollisionRectVSPoint(CRect *test_a, CVector2D *point)
{
// Prepare the normals for the shape
std::vector<CVector2D> normals_a = test_a->GetNormalsAsArray();

// Create a container for holding the various vectors used for collision check
std::vector<CVector2D> vect_test_a = PrepVectors(test_a);

// Get projections for the OOBB (needed for SAT)
CVector2D result_P1 = GetMinMaxShape(vect_test_a, normals_a[1]); 
float result_point = point->DotProduct(normals_a[1]); 
// If the two objects are not colliding on this axis
if(result_P1.y < result_point || result_point < result_P1.x)
{
    return;

}
CVector2D result_Q1 = GetMinMaxShape(vect_test_a, normals_a[0]);
result_point = point->DotProduct(normals_a[0]);
// If the two objects are not colliding on this axis
if(result_Q1.y < result_point || result_point < result_Q1.x)
{
    return;

}

// Do something
PlotPixel8(200, 10, WHITE);
PlotPixel8(200, 11, WHITE);
PlotPixel8(200, 12, WHITE); 
}

// Returns a container with projection vectors for a given shape
std::vector<CVector2D> PrepVectors(CRect *shape)
{
std::vector<CVector2D> vect;

// Create vectors for projection and load them into the arrays
for( uint16_t i=0; i < 5; i++)
{       
    // Get global position of vectors and then add them to the array
    vect.push_back(shape->GetVectorGlobal(i));
}

return vect;
}

CVector2D GetMinMaxShape(std::vector<CVector2D> vect_shape, CVector2D axis)
{
// Set initial minimum and maximum for shape's projection vectors
float min_proj = vect_shape[1].DotProduct(axis);
float max_proj = vect_shape[1].DotProduct(axis);
// Calculate max and min projection vectors by iterating along all of the corners
for(uint16_t i = 2; i < vect_shape.size(); i ++)
{
    float current_proj = vect_shape[i].DotProduct(axis);
    // Select minimum projection on axis
    if(current_proj < min_proj) // If current projection is smaller than the minimum one
        min_proj = current_proj;
    // Select maximum projection on axis
    if(current_proj > max_proj) // If current projection is greater than the minimum one
        max_proj = current_proj;
}

return (CVector2D(min_proj, max_proj)); // Return a vector2D as it is a handy way for returning a couple of values
}

非常感谢大家,对于凌乱的代码感到抱歉!

2 个答案:

答案 0 :(得分:1)

我给了它一个非常快速的阅读,所以我可能忽略了一些东西。嗯,有一些明显的提高性能的技巧,例如通过引用将向量传递给函数。使用前缀增量而不是后缀也是一个好习惯。这两条规则绝对不像'过早优化,......的根源'。不要逐个删除行人,而是使用std::vector::clear().并且如果你声称使用智能指针,那么你应该说,因为你没有删除行人指针,因为它似乎有内存泄漏。尽可能使用const关键字。一旦你进行了明显的修正,并且速度仍然不能令人满意,那么你需要使用分析器。

阅读有关优化的内容,例如:http://www.agner.org/optimize/optimizing_cpp.pdf

答案 1 :(得分:0)

有一件事在我身上跳了出来(除了通过价值而不是参考不断传递向量,这将是非常昂贵的!)

在你的碰撞检测中,你会看到汽车是否撞到每个行人

for(int i = 0; i < ped_number; i++)
{
    CheckCollisionRectVSPoint(car->shape, peds[i]->pos);
}

然后,在碰撞检测器中,您每次都会对汽车形状重复进行大量相同的处理: -

// Prepare the normals for both shapes
std::vector<CVector2D> normals_a = test_a->GetNormalsAsArray();  

// Create two containers for holding the various vectors used for collision check
std::vector<CVector2D> vect_test_a = PrepVectors(test_a);

......等......

你应该重做那个循环来为一次创建汽车的法线等,然后对每个行人重复使用每次检查的结果。