Collision using rgb

Started by
17 comments, last by Heelp 8 years, 2 months ago

Guys, we are using processing 3 ( some drawing program using java ) in university for making simple animations, and I've decided that this is the time to make my first Java game, i chose Pacman. I made my check_collision function but the problem is that the map is very complicated. I need to draw 100 rects until I make the whole map( and check collision for all of them ) so I was wondering: Is it possible to scan for a particular color, for example, can I say: If (Pacman touches blue color) { collision is ON, stop all movement }, else if ( color == black ) { movementSpeed == normal }. so that way i can just download the map from google and dont bother making a whole map with drawing all the rects myself.

[attachment=30330:pacmanMap.png]

EDIT: After 2 days of suffering, see my new shiny map ( thanks to Alberth)

[attachment=30346:map ready.png]

Advertisement

There are just 6 values in each cell:

- wall

- point

- pill

- empty

- ghost door

- starting points (4x ghost, 1x player)

Give each value a unique character (say "." for point, and "*" for pill, "#" for wall, and so on).

Open an ascii editor and type 20 lines of 20 such characters (more or less, I didn't count them exactly).

Write a program that reads the file.

Let it draw the screen.

Done.

Bonus: It's trivial to change the level, just change the level file, and read it again :)

(won't be pacman then :p )

I dont understand....Just tell me about the walls, leave these pills and ghost doors, how can I say, When you see blue wall, stop right there

Short answer: You don't look at the screen.

Longer answer: You use the x/y position in pixels, and translate that to a 2d array to lookup if there is wall or space there.

[attachment=30331:grid.png]

I took a part of your image, and added red lines. As you can see, it's a regular grid.

Next, I made the same grid, but as a 2d array:


1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0
1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1
1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0

"1" means wall here, and "0" means empty. If I didn't make a mistake, there is a 1-to-1 correspondence between cells in the picture, and cells in the 2d array. Each cell in the picture has a 1 or a 0 at the corresponding position in the 2d array.

No idea how you make a 2d array in your programming language, but if you have an column and row index, it should return you a 0 or a 1.

(I start counting at 0, 0 at the top-left, incrementing towards the right and down)

Next, you decide the width and height of a single grid cell in pixels, say 10x10. Also, you define an origin, top-left of the screen is easiest, as most computers use that as (0,0).

So if you divide your pixel x/y coordinate by 10, you get the column and cell of the 2d array.

Say at pixel (45, 37). That's cell (4, 3) or (the 5th column, 4th row), which is "0", so there is space there.

Pixel (8, 3) is cell (0, 0) (ie top-left), which is 1, and thus a wall.

That's how you can easily decide where a wall is and where space is.

100 AABBs is not complex. Have you actually seen performance issues, or are you just assuming that they will happen?

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

Ok, got it, thanks a lot, Alberth. Now I'm writing the program that reads the text, if I have some problems later on, sorry, but I will have to ask you again. wink.png

With a game as simple as this you can even resort to pixel perfect collision.

It would be overkill but from an academic perspective worth investigation and learning.

Basically you do a logic AND operation against each pixel in your pac man sprite against the pixels it's about to overwrite on screen and if any pixels after logic operation are non zero you have a collision.

You can even test the colours after the operation to determine what you collided with but for that, and most other things a simple axis aligned bounding box as explained above is simpler and easier to work with.

Just thought you may be interested in some retro lessons for the day :)
Besides the perfect approach Alberth suggested, you could do AABB /sphere collision detection, this comes to pixel perfect and gives you future possibilities to expand into a 3rd dimension (height). If you want to move on to 3d later, it's also good practice to understand this sort of collisions (and expand them later to 3d).

Speaking from expierence (www.crealysm.com, games, BooH).

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

There's some problem with my file reading function that I could not figure out. There's also a problem with deleting the objects, search for codewords 'new' and 'delete' and see if you see something wrong because I tried all day and still wont compile


 
//The header files
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_ttf.h"
#include "SDL/SDL_mixer.h"
#include <string>
#include <iostream>
 
//Screen dimensions
const int SCREEN_WIDTH = 840;
const int SCREEN_HEIGHT = 840;
const int SCREEN_BPP = 32;
 
//The frames per second
const int FRAMES_PER_SECOND = 50;
 
//Pacman stuff
const int PAC_WIDTH = 20;
const int PAC_HEIGHT = 20;
 
//The direction status of the Pac
const int PAC_RIGHT = 1;
const int PAC_DOWN = 2;
const int PAC_LEFT = 3;
const int PAC_UP = 4;
 
//The different tile sprites
const int TILE_BLUE = 0;
const int TILE_BLACK = 1;
 
//The different TYPES of tiles
const int TILE_SPRITES = 2;
 
//Tile dimensions and number
const int TILE_WIDTH = 78;
const int TILE_HEIGHT = 78;
const int TOTAL_TILES = 441;
 
SDL_Surface *screen = NULL;
SDL_Surface *tileSheet = NULL;
 
//In-game sprite surfaces
SDL_Surface *pacRight = NULL;
SDL_Surface *pacDown = NULL;
SDL_Surface *pacLeft = NULL;
SDL_Surface *pacUp = NULL;
 
//The event structure
SDL_Event event;
 
//
SDL_Rect clips[ TILE_SPRITES ];
 
//The font
TTF_Font *font = NULL;
 
//The color of the font
SDL_Color color[2] = { { 255, 255, 255 }, { 255, 0, 0 } };
 
class Tile
{
private:
    //The attributes of the tile
    SDL_Rect tilebox;
 
    //The type of tile
    int type;
 
public:
    //Initialize the variables
    Tile( int x, int y, int tileType );
 
    //Show the tile
    void show();
};
 
bool set_tiles( Tile *tiles[] )
{
    //The tile offsets
    int x = 0, y = 0;
 
    //Opening the text file with the 0s and 1s
    FILE* filePointer;
    filePointer=fopen("Pics/pacmanMap.txt", "r");
    int t = 0, counter = 0, tileType = 0;
 
    //While going through all the characters...
    while( ( t = getc( filePointer ) )!= EOF )
    {
        //If it sees zero, put 1st tile
        if( t == '0' )
        {
            //Make the type of the tile = 0
            tileType = 0;
            tiles[ counter ] = new Tile( x, y, tileType );
            //Increment counter if 0 was found in the text file
            counter ++;
 
            //Move to the next tile coordinates
            x += TILE_WIDTH;
 
            //If you are out of screen
            if( x >= SCREEN_WIDTH )
            {
                x = 0;
                y += TILE_HEIGHT;
            }
        }
 
        else if( t == '1' )
        {
            tileType = 1;
            tiles[ counter ] = new Tile ( x, y, tileType );
            counter ++;
 
            //Move to the next tile coordinates
            x += TILE_WIDTH;
 
            //If you are out of screen
            if( x >= SCREEN_WIDTH )
            {
                x = 0;
                y += TILE_HEIGHT;
            }
        }
    }
    fclose( filePointer );
}
 
class Timer
{
    private:
    //The clock time when the timer started
    int startTicks;
 
    //The timer status
    bool started;
 
    public:
    //Initializes variables
    Timer();
 
    //The various clock actions
    void start();
    void stop();
 
    //Gets the timer's time
    int get_ticks();
 
    //Checks the status of the timer
    bool is_started();
};
 
Timer::Timer()
{
    //Initialize the variables
    startTicks = 0;
    started = false;
}
 
void Timer::start()
{
    //Start the timer
    started = true;
 
    //Get the current clock time
    startTicks = SDL_GetTicks();
}
 
void Timer::stop()
{
    //Stop the timer
    started = false;
}
 
int Timer::get_ticks()
{
    //If the timer is running
    if( started == true )
    {
        //Return the current time minus the start time
        return SDL_GetTicks() - startTicks;
    }
 
    //If the timer isn't running
    return 0;
}
 
void clip_tiles()
{
    //Clip the sprite sheet
    clips[ TILE_BLUE ].x = 0;
    clips[ TILE_BLUE ].y = 0;
    clips[ TILE_BLUE ].w = TILE_WIDTH;
    clips[ TILE_BLUE ].h = TILE_HEIGHT;
 
    clips[ TILE_BLACK ].x = TILE_WIDTH;
    clips[ TILE_BLACK ].y = 0;
    clips[ TILE_BLACK ].w = TILE_WIDTH;
    clips[ TILE_BLACK ].h = TILE_HEIGHT;
 
}
 
bool init()
{
    //Initialize all SDL subsystems
    if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
    {
        return false;
    }
 
    //Set up the screen
    screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );
 
    //If there was an error in loading the screen
    if( screen == NULL )
    {
        return false;
    }
 
    //Initialize SDL_ttf
    if( TTF_Init() == -1 )
    {
        return false;
    }
 
    //Set the window caption
    SDL_WM_SetCaption( "Pacman", NULL );
 
    //If everything initialized fine
    return true;
}
 
SDL_Surface * load_image( std::string filename )
{
    //The image that's loaded
    SDL_Surface* loadedImage = NULL;
 
    //The optimized surface
    SDL_Surface* optimizedImage = NULL;
 
    //Load the image
    loadedImage = IMG_Load( filename.c_str() );
 
    //If the image loaded
    if( loadedImage != NULL )
    {
        //Create an optimized surface
        optimizedImage = SDL_DisplayFormat( loadedImage );
 
        //Free the old surface
        SDL_FreeSurface( loadedImage );
 
        //If the surface was optimized
        if( optimizedImage != NULL )
        {
            SDL_SetColorKey( optimizedImage, SDL_SRCCOLORKEY, SDL_MapRGB( optimizedImage->format, 0, 0, 0 ) );
        }
    }
    //Return the optimized surface
    return optimizedImage;
}
 
bool load_files()
{
    //Load the font
    font = TTF_OpenFont( "lazy.ttf", 38 );
 
    //Load the background
 
    //Load the tiles sheet
    tileSheet = load_image( "Pics/black_white_tiles.jpg");
 
    //Load the pacman images
    pacRight = load_image( "Pics/pac_right.png" );
    pacDown = load_image( "Pics/pac_down.png" );
    pacLeft = load_image( "Pics/pac_left.png" );
    pacUp = load_image( "Pics/pac_up.png" );
 
    //If there was a problem in loading the sprites
 
 
    if( pacRight == NULL || pacDown == NULL || pacLeft == NULL || pacUp == NULL )
    {
        return false;
    }
 
    if( tileSheet == NULL )
    {
        return false;
    }
 
    //If everything loaded fine
    return true;
}
 
bool check_collision( SDL_Rect A, SDL_Rect B )
{
    //The sides of the rectangles
    int leftA, leftB;
    int rightA, rightB;
    int topA, topB;
    int bottomA, bottomB;
 
    //Calculate the sides of rect A
    leftA = A.x;
    rightA = A.x + A.w;
    topA = A.y;
    bottomA = A.y + A.h;
 
    //Calculate the sides of rect B
    leftB = B.x;
    rightB = B.x + B.w;
    topB = B.y;
    bottomB = B.y + B.h;
 
    //If any of the sides from A are outside of B
    if( bottomA <= topB )
    {
        return false;
    }
 
    if( topA >= bottomB )
    {
        return false;
    }
 
    if( rightA <= leftB )
    {
        return false;
    }
 
    if( leftA >= rightB )
    {
        return false;
    }
 
    //If none of the sides from A are outside B
    return true;
}
 
void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip = NULL )
{
    //Holds offsets
    SDL_Rect offset;
 
    //Get offsets
    offset.x = x;
    offset.y = y;
 
    //Blit
    SDL_BlitSurface( source, clip, destination, &offset );
}
 
 
void close_all( Tile *tiles[] )
{
    //Free the pacman surfaces
    SDL_FreeSurface( pacRight );
    SDL_FreeSurface( pacDown );
    SDL_FreeSurface( pacLeft );
    SDL_FreeSurface( pacUp );
 
    //Free the background and tiles surfaces
    SDL_FreeSurface( tileSheet );
 
    //Free the tiles
    for( int t = 0; t < TOTAL_TILES; t++ )
    {
        delete tiles[ t ];
    }
    //Close Font
    TTF_CloseFont( font );
 
    //Quit SDL_ttf
    TTF_Quit();
 
    //Quit SDL
    SDL_Quit();
 
}
 
 
Tile::Tile( int x, int y, int tileType )
{
    //Get the offsets
    tilebox.x = x;
    tilebox.y = y;
 
    //Set the collision box
    tilebox.w = TILE_WIDTH;
    tilebox.h = TILE_HEIGHT;
 
    //Get the tile type
    type = tileType;
}
 
void Tile::show()
{
    //Show the tile
    apply_surface( tilebox.x, tilebox.y, tileSheet, screen, &clips[ type ] );
}
 
int main( int argc, char* args[] )
{
 
    bool quit = false;
 
 
    //The tiles that will be used
    Tile *tiles[ TOTAL_TILES ];
 
    //Initialize the SDL stuff
    if( init() == false )
    {
        return 1;
    }
 
    //Load the files
    if( load_files() == false )
    {
        return 1;
    }
 
    //Clip the tile sheet
    clip_tiles();
 
    //Set the tiles
    if( set_tiles( tiles ) == false )
    {
        return 1;
    }
 
    Timer fps;
 
    //The pacman
 
    //While the user hasn't quit
    while( quit == false )
    {
        //While there's events to handle
        while( SDL_PollEvent( &event ) )
        {
            //If the user has pressed Esc or X
            if( event.type == SDL_QUIT || event.key.keysym.sym == SDLK_ESCAPE )
            {
                //Quit the program
                quit = true;
            }
        }
 
        //Apply the background
 
        //Show the foos on the screen
 
        //Show the tiles
        for( int t = 0; t < TOTAL_TILES; t++ )
        {
            tiles[ t ]->show();
        }
 
        //Update the screen
        if( SDL_Flip( screen ) == -1 )
        {
            return 1;
        }
 
        //Cap the frame rate
        if( fps.get_ticks() < 1000 / FRAMES_PER_SECOND )
        {
            SDL_Delay( 1000 / FRAMES_PER_SECOND  - fps.get_ticks() - 5 );
        }
    }
 
    //Clean up
    close_all( tiles );
 
    return 0;
}
 

I just saw that the code is more than expected, so if you want a cleaner version of the program, I can delete some stuff and cut the program by half

This topic is closed to new replies.

Advertisement