Liam Moorcroft - 2012-05-11

I'm fairly new to this and have been stuck on some error's for quite a while
now and was wondering if anyone would be able to help me with the following...

Making the direction increment and decrement by one using the direction keys
Stop the mouse from interfering with the direction number
Allow the 'jack' to enter from the centre of the screen
Make the 'jack' only entered the screen once instead of a fast few times like it is doing

I know i'm asking for alot of help but even if you could point me in the right
direction to getting things sorted and point out obvious mistakes that would
be great appreciated.

Thanks

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <SDL/SDL.h>
#include <SDL/SDL_Image.h>
#include <SDL/SDL_ttf.h>
#include <chipmunk/chipmunk.h>

#define SLEEP_TICKS 16
#define XSIZE 382
#define YSIZE 472
#define XMID XSIZE/2
#define YMID YSIZE/2

int ticks = 0;
int some_value = 42;
cpSpace *space;
cpBody *staticBody;
cpBody *marble;

SDL_Surface *screen;    //This pointer will reference the backbuffer
SDL_Surface *marble_image,*jack_image; //This pointer will reference our bitmap sprite
SDL_Surface *hline_image,*vline_image;
SDL_Surface *pitch_image;
SDL_Surface *temp;      //This pointer will temporarily reference our bitmap sprite
SDL_Rect src, dest;     //These rectangles will describe the source and destination regions of our blit

int running=0;         //Is the game running? 
int num_marbles=1;     //Some marbles
int direction=0;

/* return a pseudo-random number between 0 and limit inclusive.
*/
int randomize(int limit) {
int divisor = RAND_MAX/(limit+1);
int rand_val;
do {
rand_val = rand() / divisor;
} while (rand_val > limit);
return rand_val;
}

SDL_Surface *loadImage(char *name)
{
    /* Load the image using SDL Image */
    SDL_Surface *temp = IMG_Load(name);
    SDL_Surface *image;
    if (temp == NULL)
    {
        printf("Failed to load image %s\n", name);
        return NULL;
    }   
    /* Make the background transparent */
    SDL_SetColorKey(temp, (SDL_SRCCOLORKEY|SDL_RLEACCEL), SDL_MapRGB(temp->format, 0, 0, 0));   
    /* Convert the image to the screen's native format */
    image = SDL_DisplayFormat(temp);    
    SDL_FreeSurface(temp);  
    if (image == NULL)
    {
        printf("Failed to convert image %s to native format\n", name);
        return NULL;
    }   
    /* Return the processed image */
    return image;
}

void update(int ticks)
{
    int i;
    int steps = 2;
    cpFloat dt = 1.0/60.0/(cpFloat)steps;
    for(i=0; i<steps; i++){
        cpSpaceStep(space, dt);
    }
}

static void postStepRemove(cpSpace *space,cpShape *shape,void *unused) {
       cpSpaceRemoveBody(space, shape->body);
       cpBodyFree(shape->body);
       cpSpaceRemoveShape(space, shape);
       cpShapeFree(shape);
}

static int begin(cpArbiter *arb, cpSpace *space,void *ignore) {
       cpShape *a,*b;
       cpArbiterGetShapes(arb, &a, &b);
       cpSpaceAddPostStepCallback(space,(cpPostStepFunc)postStepRemove,b,NULL);
       return 0;
}

static int collFunc(cpShape *a, cpShape *b, cpContact *contacts, int numContacts, cpFloat normal_coef, void *data)
{
    int *some_ptr = (int *)data;

// Do various things with the contact information. 
// Make particle effects, estimate the impact damage from the relative velocities, etc.
//  for(int i=0; i<numContacts; i++)
//      printf("Collision at %s. (%d - %d) %d\n", cpvstr(contacts[i].p), a->collision_type, b->collision_type, *some_ptr);

// Returning 0 will cause the collision to be discarded. This allows you to do conditional collisions.
    return 1;
}

void init(void)
{
    int i;
    unsigned int iseed = (unsigned int)time(NULL);

    cpFloat radius = 25;
    cpFloat marble_mass = 0.4;
    cpFloat x,y;
    // Initialize a static body with infinite mass and moment of inertia
    // to attach the static geometry to.
    staticBody = cpBodyNew(INFINITY, INFINITY);

    // Optional. Read the docs to see what this really does.
    cpResetShapeIdCounter();

    // Create a space and adjust some of it's parameters.
    space = cpSpaceNew();
    space->damping=0.9;

    // Create a shape pointer 
    cpShape *shape;

    // Create a border around the edges of the screen.
    shape = cpSegmentShapeNew(staticBody, cpv(0,0), cpv(50,0), 0.0f);
    shape->e = 1.0; shape->u = 1.0;
    cpSpaceAddStaticShape(space, shape);

    shape = cpSegmentShapeNew(staticBody, cpv(0,0), cpv(0,480), 0.0f);
    shape->e = 1.0; shape->u = 1.0;
    cpSpaceAddStaticShape(space, shape);

    shape = cpSegmentShapeNew(staticBody,cpv(640,0), cpv(640,480), 0.0f);
    shape->e = 1.0; shape->u = 1.0;
    cpSpaceAddStaticShape(space, shape);

    shape = cpSegmentShapeNew(staticBody, cpv(0,480), cpv(640,480), 0.0f);
    shape->e = 1.0; shape->u = 1.0;
    cpSpaceAddStaticShape(space, shape);

    srand(iseed);

    // Create some marbles
    for(i=0;i<num_marbles;i++){
        marble = cpBodyNew(marble_mass, cpMomentForCircle(marble_mass, 0.0, radius, cpvzero));
        x=XMID-200+(cpFloat)181;
        y=YMID-200+(cpFloat)70;
        marble->p = cpv(x,y);
        //marble->v = cpv(x,y);
        cpSpaceAddBody(space, marble);
        shape = cpCircleShapeNew(marble, radius, cpvzero);
        shape->e = 0.0; shape->u = 2.5;
        shape->data=(cpDataPointer)0;
        //shape->collision_type = 1;
        cpSpaceAddShape(space, shape); 
    }
    // Create a jack
    marble = cpBodyNew(marble_mass, cpMomentForCircle(marble_mass, 0.0, radius, cpvzero));
    marble->p = cpv(XSIZE,YSIZE);
    //marble->v = cpv(-220,direction); 
    //marble->v = cpv(-100,-160);
    cpSpaceAddBody(space, marble);
    shape = cpCircleShapeNew(marble, radius, cpvzero);
    shape->data=(cpDataPointer)1;
    shape->e = 0.0; shape->u = 6.5;
    //shape->collision_type = 1;
    cpSpaceAddShape(space, shape);

    // Add a collision callback (begin).
    cpSpaceAddCollisionHandler(space,1,0,begin,NULL,NULL,NULL,NULL);

}

void destroy(void)
{
    cpSpaceFree(space); 
    cpBodyFree(staticBody);
}
static void renderMarble(cpFloat x, cpFloat y, cpFloat r, cpFloat a,cpShape *shape)
{
       SDL_Rect dest;
       /* Set the blitting rectangle to the size of the src image */
       dest.x = x;
       dest.y = y;
     if(shape->data){
          dest.w = jack_image->w;
          dest.h = jack_image->h;   
          /* Blit the entire image onto the screen at coordinates x and y */
          SDL_BlitSurface(jack_image, NULL, screen, &dest);
      }else{
            dest.w = marble_image->w;
            dest.h = marble_image->h;
            /* Blit the entire image onto the screen at coordinates x and y */
            SDL_BlitSurface(marble_image, NULL, screen, &dest);
      } 
}
static void renderShape(cpFloat x, cpFloat y, cpFloat r, cpFloat a,int type)
{
       SDL_Rect dest;
       /* Set the blitting rectangle to the size of the src image */
       if(type==0){
                dest.x = x;
                dest.y = y;
                dest.w = hline_image->w;
                dest.h = hline_image->h;
                /* Blit the entire image onto the screen at coordinates x and y */
                SDL_BlitSurface(hline_image, NULL, screen, &dest);   
       }else if(type==1){
                dest.x = x;
                dest.y = y;
                dest.w = vline_image->w;
                dest.h = vline_image->h;
                /* Blit the entire image onto the screen at coordinates x and y */
                SDL_BlitSurface(vline_image, NULL, screen, &dest);  
       }else if(type==2){
                dest.x = 0;
                dest.y = 0;
                dest.w = pitch_image->w;
                dest.h = pitch_image->h;
                /* Blit the entire image onto the screen at coordinates x and y */
                SDL_BlitSurface(pitch_image, NULL, screen, &dest);  
       }      
}
static void drawMarbleShapes(cpShape *shape)
{
    cpBody *body = shape->body;
    cpCircleShape *circle = (cpCircleShape *)shape;
    cpVect c = cpvadd(body->p, cpvrotate(circle->c, body->rot));
    renderMarble(c.x, c.y, circle->r, body->a,shape);
}
static void drawStaticShapes(cpShape *shape)
{
    cpBody *body = shape->body;
    cpSegmentShape *segment = (cpSegmentShape *)shape;
    cpVect c = cpvadd(body->p, cpvrotate(segment->a, body->rot));

    renderShape(0, 0, segment->r, body->a,0);
    renderShape(0,475, segment->r, body->a,0);
    renderShape(0, 0, segment->r, body->a,1);
    renderShape(635,0, segment->r, body->a,1);
    renderShape(100,30, segment->r, body->a,2);
}
static void drawMarbles(void *ptr, void *unused)
{
    cpShape *shape = (cpShape *)ptr;
    drawMarbleShapes(shape);
}
static void drawStaticObjects(void *ptr, void *unused)
{
    cpShape *shape = (cpShape *)ptr;
    drawStaticShapes(shape);
}
int main(int argc, char* argv[])
{
int i;
cpBody *body;
cpShape *shape;
SDL_Event  event; // SDL events

running  = 1;

//Initialise the physics engine
cpInitChipmunk();

//Initialise the stuff we need for marble physics
init();

//We must first initialize the SDL video component, and check for success
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
    printf("Unable to initialize SDL: %s\n", SDL_GetError());
    return 1;
}
//When this program exits, SDL_Quit must be called
//atexit(SDL_Quit);

//Set the video mode to 640x480 with 16bit colour and double-buffering
screen = SDL_SetVideoMode(XSIZE, YSIZE, 16, SDL_DOUBLEBUF);
if (screen == NULL) {
    printf("Unable to set video mode: %s\n", SDL_GetError());
    return 1;
}

//Set up printing
if (TTF_Init() != 0) {
  printf("Unable to initialize SDL_ttf: %s \n", TTF_GetError());
  return 1;
}
TTF_Font *fntCourier = TTF_OpenFont( "cour.ttf",24);
SDL_Color clrFg = {255,255,255,0};  // White ("Fg" is foreground)
SDL_Surface *textSurface;
SDL_Rect textDest = {0,0,0};
char textString[100];

//Load a marble image
temp =loadImage("marble.png");
//Convert the surface to the appropriate display format
marble_image = SDL_DisplayFormatAlpha(temp);

//Load a jack image
temp =loadImage("jack.png");
//Convert the surface to the appropriate display format
jack_image = SDL_DisplayFormatAlpha(temp);

//Load a static object image
temp =loadImage("hline.png");
//Convert the surface to the appropriate display format
hline_image = SDL_DisplayFormatAlpha(temp);

temp =loadImage("vline.png");
//Convert the surface to the appropriate display format
vline_image = SDL_DisplayFormatAlpha(temp);

temp =loadImage("pitch.png");
//Convert the surface to the appropriate display format
pitch_image = SDL_DisplayFormatAlpha(temp);

//Release the temporary surface
SDL_FreeSurface(temp);

while (1) {
    while(SDL_PollEvent(&event)){
       switch(event.type) {
    if (event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE))
        running = 0;
    } 
    if(event.key.keysym.sym==SDLK_SPACE) {
                                    marble->p = cpv(XSIZE,YSIZE);
                                    marble->v = cpv(direction,-200);     
    }
    if(event.key.keysym.sym==SDLK_RIGHT) {
       direction=direction++;
       sprintf(textString, "Direction=%d", direction);
       textSurface = TTF_RenderText_Solid(fntCourier, textString, clrFg);
       }
    if(event.key.keysym.sym=SDLK_LEFT) {
       direction--;
       sprintf(textString, "Direction=%d", direction);
       textSurface = TTF_RenderText_Solid(fntCourier, textString, clrFg);
       }

    } // while (handling events)
    if (running == 0)
      break;

    //Blank the background
    SDL_FillRect(screen, NULL, 0);

    //Draw the other stuff
    cpSpaceEachShape(space,(cpSpaceShapeIteratorFunc)drawStaticObjects,NULL);
    //Draw the marbles and jack
    cpSpaceEachShape(space,(cpSpaceShapeIteratorFunc)drawMarbles,NULL);
    //Draw the text
    SDL_BlitSurface(textSurface,NULL, screen,&textDest);

    //Double buffer
    SDL_Flip(screen);
    ticks++;
   update(ticks);
  } // while (main loop)
//Release the surfaces
SDL_FreeSurface(textSurface);
SDL_FreeSurface(marble_image);
SDL_FreeSurface(jack_image);
SDL_FreeSurface(hline_image);
SDL_FreeSurface(vline_image);
TTF_CloseFont(fntCourier);
//Return success!
SDL_Quit();
destroy();
return 0;
}