2014-01-06 267 views
-1

我编写了一个简单的自上而下的汽车驾驶游戏,类似于GameBoyAdvance上的第一个GTA。我只用矢量图形来做这件事,而GBA并没有很好地处理它;基本上有5个行人实例滞后。需要帮助优化C++

我没有太多优化代码的经验,所以我想知道是否可以对我的代码进行一些调整以使其运行速度更快,而不取决于它运行在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 
} 

提前非常感谢大家在百忙之中乱码!

+1

http://codereview.stackexchange.com上这可能会更好。然后再次,它可能不会,这取决于这些标题。 – chris

+2

使用分析器查找程序的瓶颈。顺便说一句,似乎你做了很多的矢量副本......尝试通过* const引用*而不是*值*。 – Jarod42

+0

@ Jarod42:在没有合适的分析器的情况下,因为我担心的是GBA的情况,您可以随时在不同区域戳背景颜色寄存器以可视化各个代码段使用的相对时间。 – doynax

回答

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); 

...等...

你应该返工循环创建法线等的车刚一次,然后再用针对行人每次检查的结果。

+0

我在想同样的事情,非常感谢。我会按照建议重做它。 – Snowzurfer

1

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

而且读一些有关优化,在这里例如:http://www.agner.org/optimize/optimizing_cpp.pdf

+0

感谢您的帮助和指导。 – Snowzurfer