Code:
#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(direction,-100);
//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,-160);
}
if(event.key.keysym.sym==SDLK_RIGHT) {
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;
}