Showing posts with label SDL OpenGL. Show all posts
Showing posts with label SDL OpenGL. Show all posts

Wednesday, May 9, 2012

2D Game Physics Part 1

Its been a really long type since I've posted any thing... I'm been going to college so I have had time to post any thing for a really long time.  Sorry just to busy. Well its time to get posting.  As you can see judging from the title I'm going to talk about game physics.  Well 2D physics for now.  Well game physics helps with character movement, collision detection and response, effects, and other cool things.  It goes hand in hand with graphics to make a nice work or art and so forth. You get the picture. My objective here is to show you what I'm working right now and if some of this stuff helps you out than cool.

Physics Math for 2D Games

The math side a this simple 2D physics is sum what complicated, first off you'll need an understanding of linear algebra and a little bit of Linear Calculus (integration method). These help make the a simple physics quite nicely.  For this example you'll only need to have a Vector2 implementations which I've give it to you here.

gmath.h

typedef float real;
#define REAL_MAX FLT_MAX
// Math function wrapper
#define real_sqrt sqrt
#define real_pow pow

// Basic Vector2 object
struct Vec2 {
    real x, y;
   
    Vec2() : x(0), y(0) {}
   
    Vec2(real x, real y) : x(x), y(y) {}
   
    // Operators
    Vec2 operator -() { // makes a vec2 negitive
        return Vec2(-x, -y);
    }
   
    Vec2 operator + (const Vec2& v) {
        return Vec2(x+v.x, y+v.y);
    }
   
    Vec2 operator - (const Vec2& v) {
        return Vec2(x-v.x, y-v.y);
    }
   
    Vec2 operator * (const real r) {
        return Vec2(x*r, y*r);
    }
   
    void operator = (const Vec2& v) {
        x = v.x;
        y = v.y;
    }
   
    void operator += (const Vec2& v) {
        x += v.x;
        y += v.y;
    }
   
    void operator -= (const Vec2& v) {
        x -= v.x;
        y -= v.y;
    }
   
    void operator *= (const real& r) {
        x *= r;
        y *= r;
    }
   
    real dot(Vec2& v) {
        return x*v.x+y*v.y;
    }
   
    real magnitude() {
        return real_sqrt(x*x+y*y);
    }
   
    real magnitudeSquare() {
        return x*x+y*y;
    }
   
    void normalize() {
        real dist = magnitude();
        *this *= ((real)1)/dist;
    }
   
    // utility function
    void clear() {
        x = y = 0;
    }
};


This is a really this is all that you need.  I'm also use my own typedef for float called "real" because if I want switch to double float point I can do that later.

Collision Object (For Now)

Now that we have a simple Vec2 object we can now create the collision object, the collision object is used to moving a character around the screen or make an obstacle that will get in the way of a character. Here's the header version of the Collision Object (Physics Object).

colobj.h

struct ColObj {
    Vec2 pos; // Position
    Vec2 vel; // Velocity
    Vec2 acc; // Acceleration
    real damper; // Dampaning
    real inverseMass; // Inverse Mass
    Vec2 force; // Forces Accumilator
   
    // setters and getters
    void setPos(const Vec2& v);
    Vec2 getPos();
   
    void setVel(const Vec2& v);
    Vec2 getVel();
   
    void setAcc(const Vec2& v);
    Vec2 getAcc();
   
    void setDamping(real d);
    real getDamping();
   
    void setMass(real mass);
    real getMass();
   
    void clearForces();
    void addForce(const Vec2& v);
   
    void intergration(real time);
};

This will be the main object to use for collisions, I'm going to put other types of data such as shape id and user data via void* pointer later. Now let me explain the 6 fields I'm using. Which are pos, vel, acc, damper, inverseMass, and forces.  Pos which is position is the locations of the ColObject, Vel is the velocity this is the direction of the object, and Acc which is acceleration of the object.Damper is a real value that prevents the object from sliding.  If the value is low then it will stop quicker, if the value is high than it will take time to slow down.  If the value is 1.0 it will continuously slide forever.  The mass of the object is how dense it is, if the value is higher than the object will need some momentum to move if lower the object will move reletively quickly. If the mass is zero then it won't move at all. Forces are values that changes the object, this could be gravity, wind velocity, or some other force in the world.

Most the methods in this are actually setters and getters, but for exception of  setMass, getMass, clearForces, addForce, and integration. setMass and getMass internally is converting the value to its inverse.

colman.cpp

void ColObj::setMass(real mass) {
    if(mass == 0) {
        this->inverseMass = mass;
    } else {
        this->inverseMass = ((real)1.0)/mass;
    }
}

real ColObj::getMass() {
    if(inverseMass == 0) {
        return REAL_MAX;
    } else {
        return ((real)1.0)/inverseMass;
    }
}

When you set a mass it it will convert the mass into the inverse mass of the object, and if you want to get the mass it will convert it back to it. The next one is forces, there are current two methods.

colobj.cpp

void ColObj::clearForces() {
    force.clear();
}

void ColObj::addForce(const Vec2& v) {
    force += v;
}

Clear forces is self explanatory it simply makes the force field back to zero value, the addForce method however modifies the force field (lol pun).  And the next one integration method, this contains math algorithm to help solve the physics program, the integration I'm using here is a simple Euler Integration. I know it isn't perfect but I don't care for now, I can always use Varlet or RK4 later on.

colobj.cpp

void ColObj::intergration(real time) {
    assert(time > 0.0);
   
    this->pos += vel * time;
   
    Vec2 racc = acc;
   
    racc += force * inverseMass;
   
    vel += racc * time;
   
    vel *= real_pow(damper, time);
   
    clearForces();
}

This is what I've been working on for the 2 days since I've been on summer break, and its been really fun.  If you want a really good source for Game Physics, than go out and buy a book called "Game Physics Engine Development" by Ian Millington. This book will help you understand how Physics Engines work by building a simple one that can be used for a 3D game. If you are interested than here a link Game Physics Engine Development at Amazon.com. I'll post the next one pretty soon so take care. (Note: I'll post the source code up under an once I get done with these set of articles).

Tuesday, August 9, 2011

Game Components

Well I'm back.  Been working on different projects and stuff.  So I haven't had time to post any thing in a while.  What this post is going to be about taking a really big nasty class and transform it into a set of smaller more manageable objects.  Here is the the simple example class we are going to cross cut.

class Test {
    public:
 
    Test() {
        r.init(100, 100, 32, 32);
    }
    void update() {
        Uint8* cur = SDL_GetKeyState(0);
     
        if(cur[SDLK_LEFT]) {
            r.x -= 1;
        } else if(cur[SDLK_RIGHT]) {
            r.x += 1;
        }
     
        if(cur[SDLK_UP]) {
            r.y -= 1;
        } else if(cur[SDLK_DOWN]) {
            r.y += 1;
        }
     
     
        glBegin(GL_QUADS);
            glVertex2f(r.x, r.y);
            glVertex2f(r.x+r.w, r.y);
            glVertex2f(r.x+r.w, r.y+r.h);
            glVertex2f(r.x, r.y+r.h);
        glEnd();
    }
 
    private:
 
    Rect r;
};


There are many problems with this class first off you have everything from input to graphic rendering in the same function.  So if you a value of the rect object you could potentially screw up how you render it.  And not just that its really ugly to look at too.   I've written this type of code many times in the past ( and on recent occasions too :( ).  So how do we fix this.

Enter Components.  Component Programming allows us to take a bigger class and make smaller class from it.  This means we can decouple features from a bigger object and reuse them.  Looking at this c++ class example I can already figure out what 2 components.  InputComponent and RenderComponent.   Here is the implementation

class InputComp {
    public:
 
    void update(Rect& r) {
        Uint8* cur = SDL_GetKeyState(0);
     
        if(cur[SDLK_LEFT]) {
            r.x -= 1;
        } else if(cur[SDLK_RIGHT]) {
            r.x += 1;
        }
     
        if(cur[SDLK_UP]) {
            r.y -= 1;
        } else if(cur[SDLK_DOWN]) {
            r.y += 1;
        }
     
        cur = 0;
    }
};

class RenderComp {
    public:
 
    void update(Rect& r) {
        glBegin(GL_QUADS);
            glVertex2f(r.x, r.y);
            glVertex2f(r.x+r.w, r.y);
            glVertex2f(r.x+r.w, r.y+r.h);
            glVertex2f(r.x, r.y+r.h);
        glEnd();
    } 
};

class Test {
    public:
  
    Test() {
        r.init(100, 100, 32, 32);
    }
  
    void update() {
        in.update(r);
        rend.update(r);
    }
  
    private:
  
    Rect r;
  
    InputComp in;
    RenderComp rend;
};

As you see I'm taking what was in the Test class and making smaller more manageable classes with them.  This will make the Test class easier to read and to implement.  Not just that I can reuse the functionality in other class such as an enemy class can reuse the RenderComp class in order to render it.
  Now lets say if you want to make the RenderComp more efficient (trust me using intermediate mode isn't a good Idea).  So lets use vertex arrays instead
 
class RenderComp {
    public:
  
    void update(Rect& r) {
        PointBuf vbuf;
      
        vbuf.push_back(Point(r.x, r.y));
        vbuf.push_back(Point(r.x+r.w, r.y));
        vbuf.push_back(Point(r.x+r.w, r.y+r.h));
        vbuf.push_back(Point(r.x, r.y+r.h));
      
        glVertexPointer(2, GL_FLOAT, 0, &vbuf[0]);
        glEnableClientState(GL_VERTEX_ARRAY);
        glDrawArrays(GL_QUADS, 0, vbuf.size());
        glDisableClientState(GL_VERTEX_ARRAY);
    }  
};

This will make rendering a lot more effectent because you are sending more data to the video card all at once now lets see if we did any changes to the Test class

class Test {
    public:
  
    Test() {
        r.init(100, 100, 32, 32);
    }
  
    void update() {
        in.update(r);
        rend.update(r);
    }
  
    private:
  
    Rect r;
  
    InputComp in;
    RenderComp rend;
};

Noda.  The classes that use this pattern won't need to change at all most of the time because I've change the internals the only change you'll notice is that its moving a lot faster.
  Hopefully this helps any one who wants to use component architecture in there game engine.  Its really ease to use once you get the whole concept of components.  Like all designs there are problems with, components make it where you have tons of smaller objects which can give you some overhead.  Allocation does become an issue so use components to because you are creating a whole bunch of objects.  So use it where you need and don't over design stuff to that will make it to complex.  But like wise do over simplify stuff either well later.


Here are the exmaple links
component.zip

(note: comment me if the file isn't available I'll do a re-post to re-upload the examples)

Thursday, May 19, 2011

Simple SMUP (Shootem up)

Its been a few weeks since I've posted on this blog.  Right now I'm working on a simple shoot'em up or smup for short.  For now its only a simple demo.  It has no collision dection or respose system yet so the player can't do any thing with the meteors.


As you can see its very basic.  You can't move up or down,  you are limited to move left or right.  Once I implemented it you'll be about to shoot with the z key which is the action button.  Also it won't be in windowed mode either  because windowed mode is really slow.


One thing about it is that is that there are 2 background.  One is a star background which move quite slow.  And the other is a meteor background to make it feel like you are in an asteroid field and it gives the map a little depth too :D.  Oh well I'll keep it posted. (btw the platformer project has be stalled for a while I'll start working on it after this project).

Monday, April 18, 2011

Platformer

I'm taking a break from the low-level gba game development and started working on a simple platformer using SDL, OpenGL and Lua for scripting.  I'm not real sure what the story is going to be about but I'll think of something interesting later.  For right now it all engine developing.  And right now I'm working on the low-level and library wrapper stuff at the moment.  It forms a simpler library called librbase which contains useful simpler functionality than lower level libraries like SDL and Opengl (still can't beat something like gba, ds or psp development for low-levelness). Here what I have so far for this simple libary.

- windowing api (this is pretty much done)
- input (this is done because there won't be any mouse stuff for this game only keyboard.)
- rendering (this isn't even close to being done)
- logging(useful for debugging)

This is all I have for right now which an't to bad for a single day of deving and working on a simple design doc.  Here are some ideas for what I'm going to add to the library later one that I can think off the to of my head at the moment.

- sound (really important for setting the mood)
- state management (This is for screen changing, logo to start states ect)
- scripting interface ( Not everything need to be written in c++, here come lua)
- math (linear algebra, rects, matrixies)
- collision (simple function for checking for simple collision like aabb)
- gui (Yep needs some sort of gui to make it look pro, I'll just write a simple one though)
- resource manager ( Heh heh, extremely important and I do mean extreme )

Now not all these will be implemented right away and I might use librbase for something else and improve it. Oh well I don't have any screen shots for it right.  Mabey later when I have something decent. Well actully I'll show you what it can do right now.


For right now it can render textures and render font to the screen.  I'm using SDL_image to load image into an OpenGL texture and for font rendering I using SDL_ttf for loading *.ttf files and caching them into a c++ map, well that pretty much how it works. More later.