Jump to content

Collision Detection


Recommended Posts

I'm in the midst of fine-tuning a simple blockbreaker game in C++ using the allegro library for graphics. Everything that I've done so far works as expected, except for the collision. Collision is probably about 85% accurate as of now. The ball hits most blocks just fine, but sometimes- for example- it will go through a block and hit the top side of the block from the inside of the block. Haha.. it's quite unpredictable sometimes.

 

I'll post my source code at the end of this post if anyone wants to check it out. But what I'm asking is for your preferred method of collision detection- how you do it for primitive 2D objects. I'm checking to see if any of the x,y coordinates on the outside of the bounding box of the ball are within the bounding box of the block it's hitting.

 

block.h

[hide]

#ifndef BLOCK_H
#define BLOCK_H
#include <allegro.h>


typedef enum direction {left, right, up, down, control};

//bX and bY must be declared here so certain functions
//can access them. bX and bY refer to the x and y coords
//of the ball.
extern int bX, bY;

extern const int RES_X, RES_Y;
extern const int BALL_H, BALL_W;
extern direction horiz_dir, vert_dir;
extern void ball_hit(direction where);
//These are constants pertaining to the
//standard parameters of a block, used in
//certain constructors where not all the
//parameters have been specified.
const int BLOCK_STD_W = 60;
const int BLOCK_STD_H = 30;
const int BLOCK_STD_HEALTH = 1;
const int WALL_STD_THICKNESS = 10;

const int MAX_BLOCK_ARRAY_SIZE = 40;
const int BLOCK_STD_AUTOPLACEMENT_GAP_SIZE = 1;
const int BLOCK_STD_AUTOPLACEMENT_START_X = 100;
const int BLOCK_STD_AUTOPLACEMENT_START_Y = 100;
//block is the struct that contains all the
//relevant information pertaining to a block.
//a block object can be either destroyable or
//or non-destroyable, meaning the struct can
//be used for the walls as well.
struct sBlock
{
BITMAP* me;
bool canDestroy;
int size_h,
	size_w,
	pos_x,
	pos_y,
	color,
	health;
void init_block(int x, int y);
void init_block(int x, int y, char* filename);
void init_block(int x, int y, int w, int h);
void init_block(int x, int y, int w, int h, int hlth);
void init_block(int x, int y, int w, int h, int hlth, int clr);
void init_block(int x, int y, int w, int h, int clr, bool d);

direction hit_me();
	sBlock()
	{
	canDestroy = true;
	size_w = BLOCK_STD_W;
	size_h = BLOCK_STD_H;
	pos_x = 50;
	pos_y = 50;
	color = 0;
	health = BLOCK_STD_HEALTH;
	me = NULL;
	}
};

struct sBlockArray
{
sBlock* blocks[MAX_BLOCK_ARRAY_SIZE];

BITMAP* l_buffer;
int block_autoplacement_x;
int block_autoplacement_y;
int block_gap;
int num_blocks;

void read_from_file(char* filename);
void init_buffer(int x, int y);
void add_block();
void add_block(int x, int y);
void add_block(int x, int y, int w, int h);
void add_block(int x, int y, int w, int h, int hlth);
void add_block(int x, int y, int w, int h, int hlth, int clr);
void add_block(int x, int y, int w, int h, int clr, bool d);
void draw_blocks();
void update_autoplacement();
void make_walls(int color);
void check_collision();
int get_max_blocks();

sBlockArray(int num)
{
	num_blocks = num;
	for (int i = 0; i < MAX_BLOCK_ARRAY_SIZE; ++i)
	{
	blocks[i] = new sBlock();
	}
	block_autoplacement_x = BLOCK_STD_AUTOPLACEMENT_START_X;
	block_autoplacement_y = BLOCK_STD_AUTOPLACEMENT_START_Y;
	block_gap = BLOCK_STD_AUTOPLACEMENT_GAP_SIZE;
}

sBlockArray()
{
	for (int i = 0; i < MAX_BLOCK_ARRAY_SIZE; ++i)
	{
	blocks[i] = new sBlock();
	}
	l_buffer = NULL;
	block_autoplacement_x = BLOCK_STD_AUTOPLACEMENT_START_X;
	block_autoplacement_y = BLOCK_STD_AUTOPLACEMENT_START_Y;
	block_gap = BLOCK_STD_AUTOPLACEMENT_GAP_SIZE;
}

};
#endif

[/hide]

 

block.cpp

[hide]

#include <allegro.h>
#include <iostream>
#include "block.h"

//#define DEBUG
//###########
//TODO::
//
//::sBlockArray::add_block needs to have equal headers
//::for each sBlock::init_block function. This way, a
//::block may be added and intialized in as many ways as
//::there are sBlock::init_block headers, and a block
//::can still (re)initialized individually using a call
//::to sBlock::init_block. Yay for flexibility.
//
//::Add functions for:
// ::damage_block() ... decrements a destroyable block's
// ::health by the current damage factor.
//
// ::hit_block() ... a call that changes the direction
// ::of the ball if it hits that block
//
// ::draw_blocks() ... function to draw all blocks to
// ::the buffer.
//###########

extern BITMAP* buffer;
void sBlock::init_block(int x, int y)
{
canDestroy = true;
size_w = BLOCK_STD_W;
size_h = BLOCK_STD_H;
pos_x = x;
pos_y = y;
color = makecol(150,100,100);
health = BLOCK_STD_HEALTH;
me = create_bitmap(size_w, size_h);
rectfill(me, 0, 0, size_w, size_h, color);
rect(me, 0, 0, size_w, size_h, color);
#ifdef DEBUG
	std::cout << "Adding block to array.\n";
	std::cout << "canDestroy = " << canDestroy << std::endl
	<< "size_w = " << size_w << std::endl << "size_h = " << size_h
	<< std::endl << "pos_x = " << pos_x << std::endl << "pos_y = " << pos_y
	<< std::endl << "color = " << color << std::endl << "health = "
	<< health << std::endl;

	if ( me == NULL )
	std::cout << "me is NULL for some reason..\n";
	else
	std::cout << "me is not NULL.\n";
#endif
}

void sBlock::init_block(int x, int y, char* filename)
{
pos_x = x;
pos_y = y;
health = BLOCK_STD_HEALTH;
canDestroy = false;
me = load_bitmap(filename, NULL);
}

void sBlock::init_block(int x, int y, int w, int h)
{
canDestroy = true;
pos_x = x;
pos_y = y;
size_w = w;
size_h = h;
color = makecol(255,255,255);
health = BLOCK_STD_HEALTH;
me = create_bitmap(size_w, size_h);
rectfill(me, 0, 0, size_w, size_h, color);
rect(me, 0, 0, size_w, size_h, color);
#ifdef DEBUG
	std::cout << "Adding block to array.\n";
	std::cout << "canDestroy = " << canDestroy << std::endl
	<< "size_w = " << size_w << std::endl << "size_h = " << size_h
	<< std::endl << "pos_x = " << pos_x << std::endl << "pos_y = " << pos_y
	<< std::endl << "color = " << color << std::endl << "health = "
	<< health << std::endl;

	if ( me == NULL )
	std::cout << "me is NULL for some reason..\n";
	else
	std::cout << "me is not NULL.\n";
#endif
}

void sBlock::init_block(int x, int y, int w, int h, int hlth)
{
canDestroy = true;
pos_x = x;
pos_y = y;
size_w = w;
size_h = h;
color = makecol(255,255,255);
health = hlth;
me = create_bitmap(size_w, size_h);
rectfill(me, 0, 0, size_w, size_h, color);
rect(me, 0, 0, size_w, size_h, color);
#ifdef DEBUG
	std::cout << "Adding block to array.\n";
	std::cout << "canDestroy = " << canDestroy << std::endl
	<< "size_w = " << size_w << std::endl << "size_h = " << size_h
	<< std::endl << "pos_x = " << pos_x << std::endl << "pos_y = " << pos_y
	<< std::endl << "color = " << color << std::endl << "health = "
	<< health << std::endl;

	if ( me == NULL )
	std::cout << "me is NULL for some reason..\n";
	else
	std::cout << "me is not NULL.\n";
#endif
}

void sBlock::init_block(int x, int y, int w, int h, int hlth, int clr)
{
canDestroy = true;
pos_x = x;
pos_y = y;
size_w = w;
size_h = h;
color = clr;
health = hlth;
me = create_bitmap(size_w, size_h);
rectfill(me, 0, 0, size_w, size_h, color);
rect(me, 0, 0, size_w, size_h, color);
#ifdef DEBUG
	std::cout << "Adding block to array.\n";
	std::cout << "canDestroy = " << canDestroy << std::endl
	<< "size_w = " << size_w << std::endl << "size_h = " << size_h
	<< std::endl << "pos_x = " << pos_x << std::endl << "pos_y = " << pos_y
	<< std::endl << "color = " << color << std::endl << "health = "
	<< health << std::endl;

	if ( me == NULL )
	std::cout << "me is NULL for some reason..\n";
	else
	std::cout << "me is not NULL.\n";
#endif
}

void sBlock::init_block(int x, int y, int w,int h, int clr, bool d)
{
canDestroy = d;
pos_x = x;
pos_y = y;
size_w = w;
size_h = h;
color = clr;
health = BLOCK_STD_HEALTH;
me = create_bitmap(size_w, size_h);
rectfill(me, 0, 0, size_w, size_h, color);
rect(me, 0, 0, size_w, size_h, color);
#ifdef DEBUG
	std::cout << "Adding block to array.\n";
	std::cout << "canDestroy = " << canDestroy << std::endl
	<< "size_w = " << size_w << std::endl << "size_h = " << size_h
	<< std::endl << "pos_x = " << pos_x << std::endl << "pos_y = " << pos_y
	<< std::endl << "color = " << color << std::endl << "health = "
	<< health << std::endl;

	if ( me == NULL )
	std::cout << "me is NULL for some reason..\n";
	else
	std::cout << "me is not NULL.\n";
#endif
}

direction sBlock::hit_me()
{
for (int curX = bX; curX >= bX && curX <= bX + BALL_W; curX++)
{
	if ( curX >= pos_x && curX <= pos_x + size_w )
	{
	if ( bY <= pos_y + size_h && bY >= pos_y + size_h - 2 )
	{
	if ( vert_dir == up )
	{
	std::cout << "hit bottom of block\n";
	health--;
	return up;
	}
	else break;
	}
	else if ( bY + BALL_H >= pos_y && bY + BALL_H <= pos_y + 2 )
	{
	if ( vert_dir == down )
	{
	std::cout << "hit top of block\n";
	health--;
	return down;
	}
	else break;
	}
	}
}

for (int curY = bY; curY >= bY && curY <= bY + BALL_H; curY++)
{
	if ( curY >= pos_y && curY <= pos_y + size_h )
	{
	if ( bX + BALL_W >= pos_x && bX + BALL_W <= pos_x + 2 )
	{
	if ( horiz_dir == right )
	{
	health--;
	std::cout << "hit left of block\n";
	return right;
	}
	else break;
	}
	else if ( bX <= pos_x + size_w && bX >= pos_x + size_w - 2 )
	{
	if ( horiz_dir == left )
	{
	std::cout << "hit right of block\n";
	health--;
	return left;
	}
	else break;
	}
	}
}
return control;
}

void sBlockArray::read_from_file(char* filename)
{

}

void sBlockArray::init_buffer(int x, int y)
{
l_buffer = create_bitmap(x, y);
}

void sBlockArray::draw_blocks()
{
if ( l_buffer == NULL )
{
	std::cerr << "l_buffer is NULL!\n";
	return;
}

clear_to_color(l_buffer, makecol(255,0,255));
for (int i = 0; i < MAX_BLOCK_ARRAY_SIZE; i++)
{
	if ( blocks[i]->health <= 0 && blocks[i]->canDestroy == true )
	blocks[i]->me = NULL;
	if ( blocks[i]->me != NULL )
	{
	blit(blocks[i]->me, l_buffer, 0, 0, blocks[i]->pos_x, blocks[i]->pos_y, blocks[i]->size_w, blocks[i]->size_h);
	}
}
}

void sBlockArray::update_autoplacement()
{
if ( (block_autoplacement_x + BLOCK_STD_W) < (RES_X - BLOCK_STD_AUTOPLACEMENT_START_X) )
	block_autoplacement_x += BLOCK_STD_W + block_gap;
else
{
	block_autoplacement_x = BLOCK_STD_AUTOPLACEMENT_START_X;
	block_autoplacement_y += block_gap + BLOCK_STD_H;
}
}

void sBlockArray::add_block()
{
for (int i = 0; i < MAX_BLOCK_ARRAY_SIZE; i++)
{
	if ( blocks[i]->me == NULL )
	{
	blocks[i]->init_block(block_autoplacement_x, block_autoplacement_y);
	update_autoplacement();
	break;
	}
}
}

void sBlockArray::add_block(int x, int y)
{
for (int i = 0; i < MAX_BLOCK_ARRAY_SIZE; i++)
{
	if ( blocks[i]->me == NULL )
	{
	blocks[i]->init_block(x, y);
	update_autoplacement();
	break;
	}
}
}
void sBlockArray::add_block(int x, int y, int w, int h)
{
for (int i = 0; i < MAX_BLOCK_ARRAY_SIZE; i++)
{
	if ( blocks[i]->me == NULL )
	{
	blocks[i]->init_block(x, y, w, h);
	update_autoplacement();
	break;
	}
}
}
void sBlockArray::add_block(int x, int y, int w, int h, int hlth)
{
for (int i = 0; i < MAX_BLOCK_ARRAY_SIZE; i++)
{
	if ( blocks[i]->me == NULL )
	{
	blocks[i]->init_block(x, y, w, h, hlth);
	update_autoplacement();
	break;
	}
}
}
void sBlockArray::add_block(int x, int y, int w, int h, int hlth, int clr)
{
for (int i = 0; i < MAX_BLOCK_ARRAY_SIZE; i++)
{
	if ( blocks[i]->me == NULL )
	{
	blocks[i]->init_block(x, y, w, h, hlth, clr);
	update_autoplacement();
	break;
	}
}
}
void sBlockArray::add_block(int x, int y, int w, int h, int clr, bool d)
{
for (int i = 0; i < MAX_BLOCK_ARRAY_SIZE; i++)
{
	if ( blocks[i]->me == NULL )
	{
	blocks[i]->init_block(x, y, w, h, clr, d);
	update_autoplacement();
	break;
	}
}
}

void sBlockArray::make_walls(int color)
{
add_block(0, 0, WALL_STD_THICKNESS, RES_Y, color, false);
add_block((RES_X-WALL_STD_THICKNESS), 0, WALL_STD_THICKNESS, RES_Y, color, false);
add_block(0, 0, RES_X, WALL_STD_THICKNESS, color, false);
}


void sBlockArray::check_collision()
{
for (int i = 0; i < MAX_BLOCK_ARRAY_SIZE; i++)
{
	if ( blocks[i]-> me != NULL )
	ball_hit(blocks[i]->hit_me());

}
}

int sBlockArray::get_max_blocks()
{
return MAX_BLOCK_ARRAY_SIZE;
}

[/hide]

 

main.cpp

[hide]

#include <allegro.h>
#include <iostream>

#include "block.h"
/*########
//TODO::
//::Figure out a new way to detect collision with stuff.
//
//::Separate the logic of the game into its own function
//::that will call helper functions to move the game along
//::a step.
//
//::Implement a ball damage factor so the ball could do
//::more or less damage according to different multipliers.
//########
*/


//RES_X and RES_Y control the resolution of the screen.
//They are set as global variables so that positions can
//be calculated according to the screen size and not
//to a fixed position.
const int RES_X = 640;
const int RES_Y = 480;

//PADDLE_W and PADDLE_H refer to the height and width
//of the paddle. These constants are used in calculations
//regarding the paddle.
//BALL_W and BALL_H refer to the height and width of the ball,
//available here for universal calculations regarding the ball.
//MOVESPEED controls how fast the paddle will move. It should
//stay an even number so as to keep calculations precise.
const int PADDLE_W = 75;
const int PADDLE_H = 20;
const int BALL_W = 20;
const int BALL_H = 20;
const int MOVESPEED = 8;
const int BALL_SPEED_X_MAX = 5;
const int BALL_SPEED_Y_MAX = 5;
const int BALL_SPEED_X_MIN = -4;
const int BALL_SPEED_Y_MIN = 2;

//pX and pY make up the current x and y position of the paddle
//in relation to the screen. By default, the coordinates are
//set to have the paddle appear in the bottom middle of the screen.
//pLB and pRB are the left and right bounds of the paddle respectively.
//bX and bY form the x and y coordinates of the ball.
int pX = (RES_X/2) - (PADDLE_W/2);
int pY = RES_Y - (RES_Y/12);
int pLB = pX;
int pRB = pLB + PADDLE_W;
int bX = (RES_X/2) - (BALL_W/2);
int bY= pY - 20;
int ball_speed_x = 4;
int ball_speed_y = 4;
int ball_speed_multiplier = 1;
direction horiz_dir = right;
direction vert_dir = up;

//BITMAP pointers are declared here so they can be used in any function
//without having to pass them by reference each time. This way, the
//BITMAP objects will be accessible by all functions inherently.
BITMAP* buffer;
BITMAP* paddle;
BITMAP* ball;

//sBlockArray level holds the array of blocks for each level.
sBlockArray level;
sBlockArray walls;

//these are essentially state flags that are set and reset when
//certain events occur.
bool gameStarted = false;
bool gamePaused = false;
bool lifeLost = false;

//testing function
void test_structs()
{
for ( int i = 0; i < MAX_BLOCK_ARRAY_SIZE; i++)
{
	level.add_block();
}

}

//gfx_init() initializes the graphics in one place so as to
//tidy up the code and not clutter main() with all the graphics.
void gfx_init()
{
PALETTE pal;
allegro_init();
install_keyboard();
set_color_depth(32);
set_gfx_mode(GFX_AUTODETECT_WINDOWED, RES_X, RES_Y, 0, 0);

paddle = load_bitmap("paddle.bmp", pal);
ball = load_bitmap("ball.bmp", pal);
buffer = create_bitmap(RES_X, RES_Y);

level.init_buffer(RES_X, RES_Y);
	test_structs();

level.draw_blocks();

walls.init_buffer(RES_X, RES_Y);
walls.make_walls(makecol(0,50,150));
walls.draw_blocks();

masked_blit(walls.l_buffer, buffer, 0, 0, 0, 0, RES_X, RES_Y);
masked_blit(level.l_buffer, buffer, 0, 0, 0, 0, RES_X, RES_Y);
masked_blit(paddle, buffer, 0, 0, pX, pY, PADDLE_W, PADDLE_H);
masked_blit(ball, buffer, 0, 0, bX, bY, BALL_W, BALL_H);
blit(buffer, screen, 0, 0, 0, 0, RES_X, RES_Y);

}

//redraw() clears the buffer and reconstructs it, then draws
//it to the screen.
void redraw()
{
clear_bitmap(buffer);

level.draw_blocks();
walls.draw_blocks();

masked_blit(walls.l_buffer, buffer, 0, 0, 0, 0, RES_X, RES_Y);
masked_blit(level.l_buffer, buffer, 0, 0, 0, 0, RES_X, RES_Y);

masked_blit(paddle, buffer, 0, 0, pX, pY, PADDLE_W, PADDLE_H);
rect(ball, 0, 0, BALL_W-1, BALL_H-1, makecol(0,255,0));
masked_blit(ball, buffer, 0, 0, bX, bY, BALL_W, BALL_H);
textprintf_ex(buffer, font, 2, 2, makecol(255,255,255), -1, "ball_speed_x: %d", ball_speed_x);
textprintf_ex(buffer, font, 2, 10, makecol(255,255,255), -1, "ball_speed_y: %d", ball_speed_y);
textprintf_ex(buffer, font, 2, 18, makecol(255,255,255), -1, "bX = %d bY = %d", bX, bY);
textprintf_ex(buffer, font, 2, 26, makecol(255,255,255), -1, "horiz_dir = %d vert_dir = %d", horiz_dir, vert_dir);
blit(buffer, screen, 0, 0, 0, 0, RES_X, RES_Y);
}



//ball_hit() is called when the ball comes into contact
//with the something, resulting in the ball changing directions
//according to the ball's position relative to the position
//of the object.
void ball_hit(direction where)
{
if ( where == up )
{
	ball_speed_y = ball_speed_y * (-1);
	vert_dir = down;
	return;
}
else if ( where == down )
{
	ball_speed_y = ball_speed_y * (-1);
	vert_dir = up;
	return;
}
else if ( where == left )
{
	ball_speed_x *= -1;
	horiz_dir = right;
	return;
}
else if ( where == right )
{
	ball_speed_x *= -1;
	horiz_dir = left;
	return;
}
else
	return;
}

//used when pausing the game, shows the menu and stops the ball
//from moving.
void game_pause()
{

}

void check_hit_paddle()
{
if ( bX + (BALL_W/2) >= pX && bX + (BALL_W/2) <= pX + PADDLE_W
	&& bY + BALL_H >= pY && bY + BALL_H <= pY + 2 )
	//if ( bY >= pY )
	{
	if ( bX + (1/2)*BALL_W <= pLB + (1/3)*PADDLE_W )
	{
	std::cout << ":::: hit left of paddle\n";
	//ball_speed_x = std::max(BALL_SPEED_X_MIN, ball_speed_x - 1);
	ball_hit(down);
	return;
	}
	else if ( bX + (1/2)*BALL_W >= pRB - (1/3)*PADDLE_W )
	{
	std::cout << ":::: hit right of paddle\n";
	//ball_speed_x = std::min(BALL_SPEED_X_MAX, ball_speed_x + 1);
	ball_hit(down);
	return;
	}

	std::cout << ":::: hit middle of paddle\n";

	ball_hit(down);
	}
}

//ball_move() controls the movement of the ball.
void ball_move()
{
if ( gameStarted && !gamePaused )
{
	bX += ball_speed_x;
	bY -= ball_speed_y;
}
}

//game_init() is called at the beginning of the game to set up
//the state flags and do the initial "hit" on the ball.
void game_init()
{
if ( gameStarted == true )
	return;
else
{
	gameStarted = true;
	gamePaused = false;
	lifeLost = false;
	ball_move();
}
}
int main()
{
gfx_init();

while ( !key[KEY_ESC] )
{
	vsync();
	if ( key[KEY_LEFT] )
	{
	if ( pLB - 4 > 0 )
	{
	pX -= MOVESPEED;
	pLB -= MOVESPEED;
	pRB -= MOVESPEED;
	}
	}
	else if ( key[KEY_RIGHT] )
	{
	if ( pRB + 4 < RES_X )
	{
	pX += MOVESPEED;
	pRB += MOVESPEED;
	pLB += MOVESPEED;
	}
	}

	if ( key[KEY_SPACE] )
	{
	if ( gameStarted == false )
	game_init();
	else
	game_pause();
	}

	if ( gameStarted && !gamePaused )
	{

	redraw();
	check_hit_paddle();
	walls.check_collision();
	level.check_collision();
	ball_move();
	}

}

return 0;
}
END_OF_MAIN();

[/hide]

demonslayer2.png

Retired Tip.It Mod || Admin and Founder of Caesar 3 Mod Squad! All are welcome!

Link to comment
Share on other sites

First

bX + (BALL_W/2)

=

bX + (1/2)*BALL_W

4/2=2

0.5*4=2

 

[hide]

  if ( bX + (BALL_W/2) >= pX && bX + (BALL_W/2) <= pX + PADDLE_W
       && bY + BALL_H >= pY && bY + BALL_H <= pY + 2 )
       //if ( bY >= pY )
       {
       if ( bX + (1/2)*BALL_W <= pLB + (1/3)*PADDLE_W )
       {
       std::cout << ":::: hit left of paddle\n";
       //ball_speed_x = std::max(BALL_SPEED_X_MIN, ball_speed_x - 1);
       ball_hit(down);
       return;
       }
       else if ( bX + (1/2)*BALL_W >= pRB - (1/3)*PADDLE_W )
       {
       std::cout << ":::: hit right of paddle\n";
       //ball_speed_x = std::min(BALL_SPEED_X_MAX, ball_speed_x + 1);
       ball_hit(down);
       return;
       }

       std::cout << ":::: hit middle of paddle\n";

       ball_hit(down);
       }

[/hide]

That section is where the issue is.

You code says if the center of the ball hits the paddle.

You want this to be the side of the ball.

I can't envision the game, but it needs to either be

bX + BALL_W

or

bX - BALL_W

.

One of those will fix the issue, however I'm not 100% on the rest of the code as I just flicked through it to give you a fast answer.

[hide=Drops]

  • Dragon Axe x11
    Berserker Ring x9
    Warrior Ring x8
    Seercull
    Dragon Med
    Dragon Boots x4 - all less then 30 kc
    Godsword Shard (bandos)
    Granite Maul x 3

Solo only - doesn't include barrows[/hide][hide=Stats]

joe_da_studd.png[/hide]

Link to comment
Share on other sites

You're right on that, and that should 100% fix why the ball is going through the paddle sometimes. Easy fix, thanks.

 

But I'm looking for help on the collision with the ball hitting a block. The relevant code is in block.cpp.

demonslayer2.png

Retired Tip.It Mod || Admin and Founder of Caesar 3 Mod Squad! All are welcome!

Link to comment
Share on other sites

You're right on that, and that should 100% fix why the ball is going through the paddle sometimes. Easy fix, thanks.

 

But I'm looking for help on the collision with the ball hitting a block. The relevant code is in block.cpp.

When implementing collision detection, the easiest method is to just draw a rectangle around it. If its a block, that should be easy. If it's a ball, you can use the distance formula, but drawing a box is just as easy.

You can write a function to determine if two boxes overlap. If they do, they've collided. The other thing you can do to make sure it doesn't overlap on screen is to test for collision *before* drawing to the screen, and then taking appropriate steps from there.

 

Other, more precise yet complex methods include drawing polygons, and checking each point on the polygon to see if it is inside the other polygons.

The slowest method is to check every individual pixel.

 

If you can describe what you want on paper, there's probably some tutorial already out there in every computer language.

 

Hope this helps.

99 dungeoneering achieved, thanks to everyone that celebrated with me!

 

♪♪ Don't interrupt me as I struggle to complete this thought
Have some respect for someone more forgetful than yourself ♪♪

♪♪ And I'm not done
And I won't be till my head falls off ♪♪

Link to comment
Share on other sites

I've settled on restarting the project from scratch with actual planning this time. I just started on that one without planning anything out, so I was just throwing things in there when I needed it. It got confusing after a while though.

 

The way I'm going to do collision now is to test the four corners of each bounding box against each other. The ball and block have their own sets of x1,y1 (top left) and x2,y2 (bottom-right) coordinates. So, it's like:

 

Check if ball's x1 or x2 is somewhere between the block's x1 and x2. Then, check if the ball's y1 or y2 is within the block's y1 and y2. That checks for collision pretty quickly on the top and bottom. Then I just modify that check in a new if statement to check for left-right collision. I split it up like that so I know where exactly the ball is hitting so I can change it's direction accordingly. I think that's a simple enough solution for collision for a simple game!

 

:D

demonslayer2.png

Retired Tip.It Mod || Admin and Founder of Caesar 3 Mod Squad! All are welcome!

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.