Advice for 2D game structure

Started by
4 comments, last by belfegor 10 years, 8 months ago
I want to make 2D top down view space shooter like game where you have wave after wave of enemies (something like a Chicken Invaders).
So i need some advices how people are usually organizing their data, here is what i thought:

Let say there might be 100 enemy ships (tops) shown on screen, and each of those can fire at least 2 rockets/bullets with relatively fast fire rate, then i have asteroids, particle effects, fonts...and what not.
So i thought to avoid lots of draw calls i would make one dynamic vertex buffer for all that stuff and play with initial/maximum vertex count until satisfied.
Also i would pack textures into atlases, as much as possible to further reduce DC.

Then i would have something like this:
struct Drawer
{
    VertexBuffer VBuffer;
    IndexBuffer IBuffer;
    int maxVertCnt;

    vector< vertex > vVerts; // all verts in scene

    void addVertex( vertex v ) { vVerts.push_back(v); }

    void drawAll()
    {
        setVB( vBuffer );
        setIB( IBuffer );

        vertex* pV;

        VBuffer->lock(&pV);
        for(i = 0; i < vVerts.size(); ++i)
        {
             ...// set pV
             if( i > maxVertCnt )
             {
                // unlock -> draw -> lock
             }
        }
        VBuffer->unlock();
        ...
        vVerts.clear(); // clear to be ready for next frame
    }
};

struct Sprite
{
    vec2 pos;
    vec2 dim;
    ...
    vector< vertex > vVerts; // could be array of 4 verts

    void update( dt )
    {
        // here i rotate vertices, move/animate texcoords...
        ...
        // then add to drawer
        for(i = 0; i < vVerts.size(); ++i)
             drawer->addVertex( vVerts[i] );
    }
};

Then i have simple vertex/pixel shader, just passing texcoords and colors... i update vertices on the cpu because there are various animation types (loop, once, ping-pong, different texture frames matrix sizes, based on input...).

I hope you understand what i meant because sometimes i cannot explain myself well with words.

Thank you for your time.

EDIT:
Actually i need to have some object in between sprite and drawer based on texture used:
struct Drawer
{
    VertexBuffer VBuffer;
    IndexBuffer IBuffer;
    int maxVertCnt;

    void drawBatch(const FooBar& foo)
    {
        setVB( vBuffer );
        setIB( IBuffer );

        vertex* pV;

        VBuffer->lock(&pV);
        for(i = 0; i < foo.vVerts.size(); ++i)
        {
             ...// set pV
             if( i > maxVertCnt )
             {
                // unlock -> draw -> lock
             }
        }
        VBuffer->unlock();
        ...
    }
};

struct FooBar // how to call you?
{
    Texture texture;
    vector< vertex > vVerts;

    void addVertex( vertex v ) { vVerts.push_back(v); }
};

struct Sprite
{
    vec2 pos;
    vec2 dim;
    FooBar* foo;
    ...
    vector< vertex > vVerts; // could be array of 4 verts

    void update( dt )
    {
        // here i rotate vertices, move/animate texcoords...
        ...
        // then add to foobar
        for(i = 0; i < vVerts.size(); ++i)
             foo->addVertex( vVerts[i] );
    }
};

stuct SceneManager
{
   vector< FooBar > foos;

   void drawAll()
   {
        setShader(...);
        for(i = 0; i < foos.size(); ++i)
        {
             setTexture( foos[i].texture );
             drawer->drawBatch( foos[i] );
        }
   }
};

Advertisement

So i thought to avoid lots of draw calls i would make one dynamic vertex buffer for all that stuff and play with initial/maximum vertex count until satisfied.

sounds like overkill.

space invaders with 3d graphics, but still a 2d playing field, right?

i'd have a database of models. i'd have a database of object types with stuff like max speed, max hp, what model to draw, etc. there would be an entry for each type of badguy, etc. or perhaps multiple "object type" databases, one for types of badguys, one for types of asteroids, etc. i'd probably have a list of badguys, a list of missiles, a list of terrain (asteroids, etc). perhaps a list of particle emitters too. and a data structure for the player. this divides things up based on what info each type stores.

to draw, call i'd call a routine like draw_badguy that would set the world transform and draw the badguy's model. i'd do that for each list. drawall_badguys, drawall_bullets, drawall_terrrain, drawall_emitters. one draw call for each object. plenty fast, even in fixed function dx9. no dynamic buffers. dynamic buffers load FAST, at the cost of drawing SLOW. an implementation with static buffers would probably run faster than a dynamic buffer.

always start with brute force, then optimize, unless you KNOW brute force won't cut it.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

note that when i say database, i don't mean link in SQL or some god awful thing like that. an array of structs will do nicely.

in my graphics library i have databases for meshes, textures, materials, models, and animations.

a struct in the mesh database for example has fields like a VB, an IB, numverts, and numtris.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php


...space invaders with 3d graphics, but still a 2d playing field, right?

No. I though i was obvious that i want 2D graphics, you can even tell if you read the code a bit.

If i use static buffers i will end up with thousands of draw calls and each have just 2 triangles to draw and number of shader permutations would be unmanageable.

Appreciate your input anyway.

I'm not sure whether you're using OpenGL or DirectX, but in either case, you might be able to take advantage of instancing.

Here's a good article on OpenGL instancing:

http://www.gamedev.net/page/resources/_/technical/opengl/opengl-instancing-demystified-r3226

Thank you for your input.

Let me implement this what i had in mind first, i want to see how it will go and then i will look for alternatives if it fails.

This topic is closed to new replies.

Advertisement