Platform engine help

Platform engine help

Postby Pix3l » 23 Feb 2011, 22:40

Hello to everybody, i have a little problem with a platform engine.
I want to make a simple platform game with a player can jump around, but i have some problems in making the player jump correctly and with collision between player and platfroms.
I don't found any good tutorial about platform game in C, only this one http://www.parallelrealities.co.uk/tutorials/intermediate/tutorial14.php that i try to rewrote by my self.
The code is below, maybe there is some junkies around... I hope someone can help me to fix this.

{l Code}: {l Select All Code}
//gcc -o jumpfix jumpfix.c -lSDL

#include <stdio.h>
#include <stdlib.h>
#include <SDL/SDL.h>
#include <time.h>

#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 320

#define MAP_W 10
#define MAP_H 10

#define BLANK_TILE 0
#define TILESIZE 32
#define PLAYER_SPEED 1
#define FRICTION 0.99f
#define GRAVITY_SPEED 1
#define TIME_STOP 2000
#define MAX_FALL_SPEED 20

    //Global variables
    int t, tl = 0, frequency = 1000 / 100, temp, t2; //StopBall variables
    int repeat, i, quit=0, paused=0, shoot=0;
    SDL_Event event;
    SDL_Surface *screen, *textSurface;
    SDL_Rect rect; //Main drawing surface
    Uint8 *keystate; // keyboard state
    float increment, incrementY;
   
int playfield[10][10] =
{
  1,1,1,1,1,1,1,1,1,1,
  1,0,0,0,0,0,0,0,0,1,
  1,0,0,0,0,0,0,0,0,1,
  1,0,0,1,1,1,0,0,0,1,
  1,0,0,0,0,0,0,1,0,1,
  1,0,0,0,0,0,0,0,0,1,
  1,0,0,0,0,0,0,0,1,1,
  1,0,0,0,0,1,1,0,0,1,
  1,0,0,0,1,1,1,0,0,1,
  1,1,1,1,1,1,1,1,1,1,
}; 

void Move();

struct _Player
{
    int w, h, onGround;
    int thinkTime, jump;
    int x, y, dirX, dirY, maxjump;
} Player;

struct _Character {
    int x,y;
    int dir;
    int delay;   
} Character;

struct _Game
{
    int status;
} Game;

void DrawRect(int x, int y, int width, int height, int color)
 {
        rect.x = x;
        rect.y = y;
        rect.w = width;
        rect.h = height;
        SDL_FillRect(screen, &rect, color);
 }

void drawbackground()
 {
  int i, j;
  for (i = 0; i < 10; i++)
  {
    for (j = 0; j < 10; j++)
    {
      if(playfield[j][i]==0)
       DrawRect(i * TILESIZE, j * TILESIZE, TILESIZE, TILESIZE, 0xffffff);
    }
  }   
 }

void Draw()
{
    //Draw Maze
    drawbackground();
    //Draw Player
    DrawRect(Player.x, Player.y, TILESIZE, TILESIZE, 0xff0000);
}

int tileCollision(int x, int y, int w, int h)
{
    int i, j;
    int minx, miny, maxx, maxy;
    // Return a collision if the rectangle is outside of the map.
    if (x < 0 || (x + w) > TILESIZE * MAP_W ||
        y < 0 || (y + h) > TILESIZE * MAP_H)
        return 1;
    // The passed coordinates are in pixels so convert them to tiles.
    minx = x / TILESIZE;
    miny = y / TILESIZE;
   
    maxx = (x + w - 1) / TILESIZE;
    maxy = (y + h - 1) / TILESIZE;

    // Return a collision if the rectangle intersects with a tile.   
    for (i = minx; i <= maxx ; i++)
    {
        for (j = miny ; j <= maxy ; j++)
        {
            if (playfield[j][i])
                return 1;
        }
    }
    // No collision otherwise.
    return 0;
}

int getInput()
{
    while(SDL_PollEvent(&event))
        {
            if (event.type == SDL_QUIT ||
            (event.type == SDL_KEYDOWN &&
            event.key.keysym.sym == SDLK_ESCAPE)) quit = 1;        /* Window closed */
        }
       
        // Grab a keystate snapshot
        keystate = SDL_GetKeyState( NULL );
        /* Handle key presses */
        //The paddles can move only if there's nothing on their way
        if (keystate[SDLK_LEFT])
         {
             Player.dirX = -1;
         }
       
        if (keystate[SDLK_RIGHT])
         {
              Player.dirX = 1;
         }


        if (!keystate[SDLK_LEFT] && !keystate[SDLK_RIGHT])
         {
             Player.dirX=0;
             increment-=0.1;
         }
/*
        if (!keystate[SDLK_LEFT] && !keystate[SDLK_RIGHT] && increment<0)
         {
             Player.dirX=0;
             increment+=0.1;
         }
*/

        if (keystate[SDLK_UP] && Player.onGround == 1)
         {
            //Player.maxjump = 13;
             Player.dirY = -11;
             //printf("assing power\n");
         }

}

void Move()
 {
   // Check our playground before move
   if(Player.x >=0 || Player.x + TILESIZE <= MAP_W ||
      Player.y >=0 || Player.y + TILESIZE <= MAP_H)
    {
       if(!tileCollision(Player.x+Player.dirX, Player.y, TILESIZE, TILESIZE))
        {
           Player.x+=Player.dirX; // Increment/Drecrement coordinates
           //Player.dirY=1;
        }
       
       Player.dirY += GRAVITY_SPEED;
      
      if (Player.dirY >= MAX_FALL_SPEED)
       {
         Player.dirY = MAX_FALL_SPEED;
       }
      
       if (Player.dirY > 0)
       {
        /* Trying to move down */
        if(tileCollision(Player.x, Player.y, TILESIZE, TILESIZE+Player.dirY))
         {
         /* Place the player as close to the solid tile as possible */
         //printf("on ground!\n");
         Player.onGround = 1;
         Player.dirY = 0;
         }
       }
      else if (Player.dirY < 0)
       {
        /* Trying to move up */
        if(tileCollision(Player.x, Player.y-1, TILESIZE, TILESIZE+Player.dirY))
         {
         /* Place the player as close to the solid tile as possible */
         Player.y += Player.dirY;
         Player.dirY = 0;
         }
       }
      
      Player.y+=Player.dirY;
    }
    printf("dirY %d\n", Player.dirY);
 }


int fps_sync ()
{
    t = SDL_GetTicks ();
    //printf("tl: %d t: %d\n", tl, t);
    if (t - tl >= frequency)
    {
        temp = (t - tl) / frequency; //delta time
        tl += temp * frequency;
        //printf("temp: %d tl: %d \n", t, tl);
        return temp;
    }
    else
    {
        SDL_Delay (frequency - (t - tl));
        tl += frequency;
        return 1;
    }
}

void logicLoop()
 {
  if(!paused)
   getInput();
 }

int mainLoop()
 {
  //main game loop
  while(!quit)
   {
       SDL_PollEvent(&event);
    repeat = fps_sync ();
        for (i = 0; i < repeat; i ++)
         {
          if (event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE))
           quit = 1; /* Window closed */
             
             switch(Game.status)
              {
                  case 0: //Menu
                   logicLoop();
                   Move();
                   break;
              }
         }
         
        //clear the screen
        SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
        //draw to the screen
        Draw();
        //update the screen
        SDL_Flip(screen);
   }
 }

int main()
{
  // init video stuff
   // init screen
    screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32, SDL_SWSURFACE);
    if(screen == NULL)
    {
        fprintf(stderr, "Can't initialize SDL: %s\n", SDL_GetError());
        exit(-1);
    }

    SDL_WM_SetCaption("Maze", "Maze");
 
    Player.x = 64;
    Player.y = 64;
       
    //main game loop
    mainLoop();
    printf("Thanks for playing!\n");
       SDL_Quit();
    return 0;
}

http://www.pix3lworkshop.altervista.org/ - Your 8bit choice since 2006!
User avatar
Pix3l
 
Posts: 55
Joined: 10 Sep 2010, 21:00
Location: Italy

Re: Platform engine help

Postby ServalKatze » 24 Feb 2011, 20:01

What exactly doesn't work? Do you get an error when compiling?

The code is kind of long to read so it would be nice if you described your problem more in detail... ;)
User avatar
ServalKatze
 
Posts: 17
Joined: 07 Jan 2010, 11:21
Location: Germany

Re: Platform engine help

Postby Pix3l » 24 Feb 2011, 21:26

ServalKatze {l Wrote}:What exactly doesn't work? Do you get an error when compiling?

The code is kind of long to read so it would be nice if you described your problem more in detail... ;)


Yes, i try :]

In function Move(); the x and y positions of the player are incremented +1 and -1 with variables dirX and dirY (Player.x+=Player.dirX;), if there is no obastacle on the next tile (see tileCollision()) the position will be updated.
I was trying to implement somekind of gravity, making the player going down if there's no obstacle under it. After this, i was trying to implement a kind of jump by decrementing dirY variable (like make a push in vertical position, see keystate[SDLK_UP]) meaning the gravity will make player going back to the ground.

The only two functions you have to carry about are tilecollision and move, and just the input handling for up key. The rest of the source are only drawing and fps controls.
I hope this is more clear now :]

** little update **

I made it work, i try the good Jnrdev tutorial for platform games and i make it work with my source. (http://wiki.allegro.cc/index.php?title=Pixelate:Issue_13/jnrdev#1_-_tilebased_collision_detection_and_response)
I think there are still some minor bugs around the engine, my conversion is a little different in some parts. I hope this can be a good start point for everyone who want to build their platform game engine.
Anyway, many thanks for your interest man :]

{l Code}: {l Select All Code}
    //gcc -o jumpfix jumpfix.c -lSDL

    #include <stdio.h>
    #include <stdlib.h>
    #include <SDL/SDL.h>
    #include <time.h>

    #define SCREEN_WIDTH 320
    #define SCREEN_HEIGHT 320

    #define MAP_W 10
    #define MAP_H 10

    #define BLANK_TILE 0
    #define TILESIZE 32
    #define PLAYER_SPEED 1
    #define FRICTION 0.99f
    #define GRAVITY_SPEED 1
    #define TIME_STOP 2000
    #define VELJUMP 13

        //Global variables
        int t, tl = 0, frequency = 1000 / 100, temp, t2; //StopBall variables
        int repeat, i, quit=0, paused=0, shoot=0;
        SDL_Event event;
        SDL_Surface *screen, *textSurface;
        SDL_Rect rect; //Main drawing surface
        Uint8 *keystate; // keyboard state
        float increment, incrementY;
       
    int playfield[10][10] =
    {
      1,1,1,1,1,1,1,1,1,1,
      1,0,0,0,0,0,0,0,0,1,
      1,0,0,0,0,0,0,0,0,1,
      1,0,0,1,1,1,0,0,0,1,
      1,0,0,0,0,0,0,0,0,1,
      1,0,0,0,0,0,0,1,0,1,
      1,0,0,0,0,0,0,0,0,1,
      1,0,0,0,0,1,1,0,0,1,
      1,0,0,0,1,1,1,0,1,1,
      1,1,1,1,1,1,1,1,1,1,
    };

    void Move();

    struct _Player
    {
        int w, h, onGround;
        int thinkTime, jump;
        int x, y, dirX, dirY, lockjump;
    } Player;

    struct _Character {
        int x,y;
        int dir;
        int delay;   
    } Character;

    struct _Game
    {
        int status;
    } Game;

    void DrawRect(int x, int y, int width, int height, int color)
    {
            rect.x = x;
            rect.y = y;
            rect.w = width;
            rect.h = height;
            SDL_FillRect(screen, &rect, color);
    }

    void drawbackground()
    {
      int i, j;
      for (i = 0; i < 10; i++)
      {
        for (j = 0; j < 10; j++)
        {
          if(playfield[j][i]==0)
           DrawRect(i * TILESIZE, j * TILESIZE, TILESIZE, TILESIZE, 0xffffff);
        }
      }   
    }

    void Draw()
    {
        //Draw Maze
        drawbackground();
        //Draw Player
        DrawRect(Player.x, Player.y, TILESIZE, TILESIZE, 0xff0000);
    }

    int tileCollision(int x, int y, int w, int h)
    {
        int i, j;
        int minx, miny, maxx, maxy;
        // Return a collision if the rectangle is outside of the map.
        if (x < 0 || (x + w) > TILESIZE * MAP_W ||
            y < 0 || (y + h) > TILESIZE * MAP_H)
            return 1;
        // The passed coordinates are in pixels so convert them to tiles.
        minx = x / TILESIZE;
        miny = y / TILESIZE;
       
        maxx = (x + w - 1) / TILESIZE;
        maxy = (y + h - 1) / TILESIZE;

        // Return a collision if the rectangle intersects with a tile.   
        for (i = minx; i <= maxx ; i++)
        {
            for (j = miny ; j <= maxy ; j++)
            {
                if (playfield[j][i])
                    return 1;
            }
        }
        // No collision otherwise.
        return 0;
    }

int getInput()
{
    while(SDL_PollEvent(&event))
        {
            if (event.type == SDL_QUIT ||
            (event.type == SDL_KEYDOWN &&
            event.key.keysym.sym == SDLK_ESCAPE)) quit = 1;        /* Window closed */
        }
       
        // Grab a keystate snapshot
        keystate = SDL_GetKeyState( NULL );
        /* Handle key presses */
        //The paddles can move only if there's nothing on their way
        if (keystate[SDLK_LEFT])
         {
             Player.dirX = -1;
         }
       
        if (keystate[SDLK_RIGHT])
         {
              Player.dirX = 1;
         }


        if (!keystate[SDLK_LEFT] && !keystate[SDLK_RIGHT])
         {
             Player.dirX=0;
             increment-=0.1;
         }
/*
        if (!keystate[SDLK_LEFT] && !keystate[SDLK_RIGHT] && increment<0)
         {
             Player.dirX=0;
         }
*/

       if (keystate[SDLK_UP] && !Player.lockjump)
        {   //if the player isn't jumping already
          Player.dirY = -VELJUMP;      //jump!
          Player.lockjump = 1;      //player is not allowed to jump anymore
        }

}

void Move()
 {
   // Check our playground before move
   if(Player.x >=0 || Player.x + TILESIZE <= MAP_W ||
      Player.y >=0 || Player.y + TILESIZE <= MAP_H)
    {
       if(!tileCollision(Player.x+Player.dirX, Player.y, TILESIZE, TILESIZE))
        {
           Player.x+=Player.dirX; // Increment/Drecrement coordinates
           //Player.dirY=1;
        }
       
   //Vertical movement
   if(Player.dirY < 0){   //moving up
      //printf("test: up, vely:%d\n", vely);
      if(tileCollision(Player.x, Player.y-1, TILESIZE, TILESIZE)){
         //Player.y = (tilecoord+1)*20 +1; //in which tile collision has been detected?
         int miny = Player.y / TILESIZE; //The tile in which we collide
         //printf("cell %d\n", miny);
         if(!tileCollision(Player.x, (miny+1)*TILESIZE+1, TILESIZE, TILESIZE))
          Player.y = (miny+1)*TILESIZE; //a little fix for small path...
         Player.dirY= 0;
         //printf("Player.y %d\n", Player.y);
      }
      else{
         Player.y+= Player.dirY;
         Player.dirY+=1;
      }
   }      
   else if(Player.dirY >= 0)
    {  //moving down / on ground
      //printf("test: down, vely:%d\n", vely);
      if(tileCollision(Player.x, Player.y+Player.dirY, TILESIZE, TILESIZE))
       {

         Player.dirY=1; //1 so we test against the ground again int the next frame (0 would test against the ground in the next+1 frame)
         
         if(!keystate[SDLK_UP])   //player only may jump again if the jump key is released while on ground
            Player.lockjump = 0;
       }
      else{   //falling (in air)
         Player.y+= Player.dirY;
         Player.dirY+=1;

         if(Player.dirY >= TILESIZE)      //if the speed is higher than this we might fall through a tile
            Player.dirY = TILESIZE;

         Player.lockjump = 1;         //don't allow jumping after falling of an edge
         
      }
    }
    }
    //printf("dirY %d\n", Player.dirY);
 }


    int fps_sync ()
    {
        t = SDL_GetTicks ();
        //printf("tl: %d t: %d\n", tl, t);
        if (t - tl >= frequency)
        {
            temp = (t - tl) / frequency; //delta time
            tl += temp * frequency;
            //printf("temp: %d tl: %d \n", t, tl);
            return temp;
        }
        else
        {
            SDL_Delay (frequency - (t - tl));
            tl += frequency;
            return 1;
        }
    }

    void logicLoop()
    {
      if(!paused)
       getInput();
    }

    int mainLoop()
    {
      //main game loop
      while(!quit)
       {
           SDL_PollEvent(&event);
        repeat = fps_sync ();
            for (i = 0; i < repeat; i ++)
             {
              if (event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE))
               quit = 1; /* Window closed */
                 
                 switch(Game.status)
                  {
                      case 0: //Menu
                       logicLoop();
                       Move();
                       break;
                  }
             }
             
            //clear the screen
            SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
            //draw to the screen
            Draw();
            //update the screen
            SDL_Flip(screen);
       }
    }

    int main()
    {
      // init video stuff
       // init screen
        screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32, SDL_SWSURFACE);
        if(screen == NULL)
        {
            fprintf(stderr, "Can't initialize SDL: %s\n", SDL_GetError());
            exit(-1);
        }

        SDL_WM_SetCaption("Platform", "Platform");
     
        Player.x = 64;
        Player.y = 64;
           
        //main game loop
        mainLoop();
        printf("Thanks for playing!\n");
           SDL_Quit();
        return 0;
    }
http://www.pix3lworkshop.altervista.org/ - Your 8bit choice since 2006!
User avatar
Pix3l
 
Posts: 55
Joined: 10 Sep 2010, 21:00
Location: Italy

Who is online

Users browsing this forum: No registered users and 1 guest