I'm making a 2d game and I'm trying to stop enemy sprites moving over each other. I've implemented the following method that is supposed to check that enemies are not overlapping, then move one of them back in the direction they came. However this method seems to crash my game as only one enemy is ever rendered.
This is my check method:
size = enemys.size();
for (int i = 0; i<size; i++){
double x = enemys[i].getEnemyX();
double y = enemys[i].getEnemyY();
for (int s = 1; s<size; s++){
double enemyX = enemys[s].getEnemyX();
double enemyY = enemys[s].getEnemyY();
if (x >= enemyX-5.0 && x <= enemyX+5.0 && y >= enemyY-5.0 && y <= enemyY + 5.0){
double xDir = x - enemyX;
double yDir = y - enemyY;
double hyp = sqrt(xDir*xDir + yDir*yDir);
xDir /= hyp;
yDir /= hyp;
x -= xDir * 5;
y -= yDir * 5;
enemys[s].setEnemyCoord(x,y);
}
}
}*
Your code will end up checking each enemy against itself.
Make your inner loop start from s=i+1
Related
I am trying to program a simplified version of the Mandelbrot-set algorithm. But calculating Z_n+1 by storing every single Z for one pixel in an array and using Z[n] to calculate Z[n+1] seems to be faster than just storing Z_n to claculate Z_n+1. Which does not make much sense to me.
I am programming this in C++ with Qt, running in release mode.
Version one (fast):
// inside QWidget-class
int numberIterations = 500;
double dw = width();
double dh = height();
int iw = width();
int ih = height();
int colors[iw][ih] = {};
double cr = 0.0;
double cc = 0.0;
double zr[numberIterations] = {0.0};
double zc[numberIterations] = {0.0};
for (int x = 0; x < iw; x++) {
for (int y = 0; y < ih; y++) {
cr = ((double)x/dw)*3.0-2.0;
cc = ((double)y/dh)*2.0-1.0;
colors[x][y]=0;
QTime time;
time.start();
for(int n=1; n<numberIterations; n++){
zr[n] = zr[n-1]*zr[n-1] -(zc[n-1]*zc[n-1]) + cr;
zc[n] = zr[n-1]*zc[n-1] + cc;
if(qAbs(zr[n])>2.0 || qAbs(zc[n])>2.0){ // to simplify it
colors[x][y]=1;
break;
}
}
qDebug() << time.elapsed(); // prints almost always 0 (ms)
}
}
As you can see, i seperate the real part of the complex number Z and the i part. By solving the binomial, it is really easy to claculate it that way, but it actually is not important in this case, since the actual calculation is the same.
Version 2 (slow):
// ...
double zr = 0.0;
double zc = 0.0;
double zr_old = 0.0;
for (int x = 0; x < iw; x++) {
for (int y = 0; y < ih; y++) {
cr = ((double)x/dw)*3.0-2.0;
cc = ((double)y/dh)*2.0-1.0;
colors[x][y]=0;
QTime time;
time.start();
for(int n=1; n<numberIterations; n++){
zr_old = zr;
zr = zr*zr -(zc*zc) + cr;
zc = zr_old*zc + cc;
if(qAbs(zr)>2.0 || qAbs(zc)>2.0){
colors[x][y]=1;
break;
}
}
qDebug() << time.elapsed(); // prints about 2 on average (0-6)
}
}
It's sounds really strange to me that accessing an element in a double array at an index is faster than just using a double variable... is this actually the case or am I missing something that makes the inner for loop (with n) much slower when using the variables (and one extra assignment of course)?
Probably I am just blind right now but I just don't get it sorry...
EDIT 1
My second version is wrong as Dmytro Dadyka pointed out. In the arrays the first element is always zero (convention) but I didn't zero the variables insinde the pixel loops when switching to the next pixel which gave me wrong times for a senseful computation since the number of iteration of the inner for loop is greater then. It needs to be:
// ...
double zr = 0.0;
double zc = 0.0;
for (int x = 0; x < iw; x++) {
for (int y = 0; y < ih; y++) {
zr = 0.0;
zc = 0.0;
for(int n=1; n<numberIterations; n++){
// ...
}
}
}
But the time it takes to compute all values for the pixels is still about 10% longer with this version than with the array version. Which is strange since it should take more instructions as pointed Garf365 out.
The examples you give are not equivalent. Initial zr and zc value in first case is zr[0] = 0, zc[0] = 0 and is the same for each (x, y) pixel. In second case initial zr and zc values is final values of previous pixel. I think it breaks the computing logic and you get wrong iteration count in second case. Fix your code by zr and zc initializing in the loop:
for (int x = 0; x < iw; x++) {
for (int y = 0; y < ih; y++) {
cr = ((double)x/dw)*3.0-2.0;
cc = ((double)y/dh)*2.0-1.0;
double zr = 0.0;
double zc = 0.0;
So I'm relatively new to coding in SFML, so apologies if I made some newbie mistake. My project is Space Invaders in SFML. When I was working on the shooting, a problem arose. How do I do collision? I was familiar with shape.getGlobalBounds().intersect(), and it worked on previous projects. It didn't work. So I tried simplifying it. I used RectangleShape for both the enemy shape, and the bullet shape.
Here is the actual for loop, for the collision:
for (int y = 0; y <= 2; ++y) {
for (int x = 0; x <= 6; ++x) {
if (shootShape.getPosition().x < e.aliensX[x] && shootShape.getPosition().x > e.aliensX[x] + 15 ||
shootShape.getPosition().y < e.aliensY[y] && shootShape.getPosition().y > e.aliensY[y] + 15) {
e.aliensX[x] = -10;
e.aliensY[y] = -10;
shooting = false;
reload = false;
}
}
}
This is the shooting function:
void Player::shoot() {
if (reload) {
shootX = posX + 5;
shootY = posY - 50;
shootShape.setPosition(shootX, shootY);
shooting = true;
reload = false;
}
if (shooting) {
shootY -= 150 * 2 * deltaTime;
shootShape.setPosition(shootX, shootY);
}
}
And this is how I draw the enemies (I don't know how to create multiple enemies):
void Enemy::drawAliens() {
for (int j = 0; j <= arraySizeY; ++j) {
for (int i = 0; i <= arraySizeX; ++i) {
actualShape.setPosition(aliensX[i], aliensY[j]);
if (aliensY[i] <= p.shootY && aliensY[i] >= p.shootY) {
aliensX[i] = -10;
aliensY[i] = -10;
}
else {
win.draw(actualShape);
}
}
}
}
Explanation behind some of the variables:
aliensX is an array which contains the different x positions for the enemies.
aliensY is an array which contains the different y positions for the enemies.
shooting is a bool variable, which is true when the bullet is travelling.
reload is whether you can shoot.
EDIT:
Intersect will not work because of the way I created my enemies. They are all in ONE shape. I need it to work with specific coordinates, because I don't know a better way to create multiple enemies all at once. If there is a way to do that, advice would be appreciated!
It's rather easy, if you rely on SFML's templated sf::Rect class. Just retrieve the rectangle for both objects as global boundaries and try to intersect them:
const bool collides = firstDrawable.getGlobalBounds().intersect(secondDrawable.getGlobalBounds());`
Same can be done with a small temporary rectangle you can fill with dynamic values not directly associated with a sf::Drawable:
const sf::FloatRect bullet(x - width / 2, y - height / 2, width, height);
const bool collides = firstDrawable.getGlobalBounds().intersect(bullet);`
Your if statement is never true. You have
shootShape.getPosition().x < e.aliensX[x] && shootShape.getPosition().x > e.aliensX[x] + 15.
Your shootShape.getPosition().x can never be smaller than e.aliensX[x] and bigger than e.aliensX[x] + 15 at the same time. That's impossible. The same for y position. Change your if statement to
for (int y = 0; y <= 2; ++y) {
for (int x = 0; x <= 6; ++x) {
if (shootShape.getPosition().x > e.aliensX[x] && shootShape.getPosition().x < e.aliensX[x] + 15 ||
shootShape.getPosition().y > e.aliensY[y] && shootShape.getPosition().y < e.aliensY[y] + 15) {
e.aliensX[x] = -10;
e.aliensY[y] = -10;
shooting = false;
reload = false;
}
}
}
void Draw() {
int c1;
int x = 59;
int y = 500;
int temp = x;
for (int i = 0; i < 13; ++i){
for (int j = 0; j < 10; ++j){
x_coordinates[i][j] = x;
y_coordinates[i][j] = y;
c1 = temp_color[i][j];
DrawRectangle(x, y, 65, 25, colors[c1]);
x += 67;
}
x = temp;
y -= 28;
}
DrawRectangle(tempx, 0, 85, 12, colors[5]);
DrawCircle(templx, temply, 10, colors[7]);
}
// This function will be called automatically by this frequency 1000.0 / FPS
void Animate() {
//if (temply < - 10)
//exit(1);
Brick_collision( );
glutPostRedisplay(); // Once again call the Draw member function
}
int Brick_collision(){
for (int i=0; i<13; ++i){
for (int j=0; j<10; ++j){
if (((templx >= x_coordinates[i][j]) && (templx <= x_coordinates[i][j] + 65)) && ((temply + 5 >= y_coordinates[i][j]) && (temply + 5 <= y_coordinates[i][j] + 35 ))){
vy = -vy;
temp_color[i][j] = 2;
// x_coordinates[i][j] -= 300;
// y_coordinates[i][j] -= 300;
// I HAVE USED THESE VALUES BECAUSE NOW THE BRICK WOULD BE OUTSIDE THE SCREEN AND THE BALL WILL NOT COLLIDE WITH IT AGAIN BUT THIS DOESN'T WORK.
return 1;
}
}
}
}
I am trying to make a BrickSlayer game using OpenGL. In the Draw() function I am drawing the structure of the game i.e the bricks, pedal and the ball. Now I am storing the x and y co-ordinates of the bricks in a 2-D Array. And In the Animate() function I am calling the function Brick_collision() In which I have applied the condition for the detection of the bricks. As the ball collides with brick I make it invinssible i.e I change its colour to White and also I have to remove its co-ordinates from the 2-D array so the ball does not detect it again. How can I achive this? All the methods that I have used for the removal of co-ordinates have not worked.
I think your "Magic Number" solution could work. Just add some logic to your collision detection to look for that magic number specifically and ignore it if it is a match. I.E.:
int Brick_collision(){
for (int i=0; i<13; ++i){
for (int j=0; j<10; ++j){
if (((x_coordinates[i][j] != -300) &&
(y_coordinates[i][j] != -300) &&
(templx >= x_coordinates[i][j]) &&
(templx <= x_coordinates[i][j] + 65)) &&
((temply + 5 >= y_coordinates[i][j]) &&
(temply + 5 <= y_coordinates[i][j] + 35))){
vy = -vy;
temp_color[i][j] = 2;
// x_coordinates[i][j] -= 300;
// y_coordinates[i][j] -= 300;
// I HAVE USED THESE VALUES BECAUSE NOW THE BRICK
// WOULD BE OUTSIDE THE SCREEN AND THE BALL WILL NOT
// COLLIDE WITH IT AGAIN BUT THIS DOESN'T WORK.
Good luck!
I'm trying to calculate the angles of two points in 2D space. It works with the following:
double angle;
x = player->x - x;
z = player->z - y;
angle = atan2 (x, y);
angle *= (180.0 / M_PI);
if(angle < 0) angle += 360;
if(angle >= 360) angle -= 360;
return angle;
However I want to use a table for better results:
x = player->x - x;
z = player->y - y;
return atanTable[x+32][y+32];
With init:
int xp = -32;
int yp = -32;
for (int x = 0; x < 64; x++, xp++)
for (int y = 0; y < 64; y++, yp++){
double angle;
angle = atan2 (xp, yp);
angle *= (180.0 / M_PI);
if(angle < 0) angle += 360;
if(angle >= 360) angle -= 360;
atanTable[x][y] = angle;
}
The angle is only calculated for values -32 to 32 for x and y.
The table is not properly produced however. I get values of only around 359 and 0, while I should get a range of 0 to 360 degrees.
Am I misusing atan2 somehow?
You need to reset yp within the first loop, not before it.
int xp = -32;
for (int x = 0; x < 64; x++, xp++)
{
int yp = -32; // Note, needs to be reset each time x changes.
for (int y = 0; y < 64; y++, yp++)
{
Nit: atan2() returns an angle in [-pi,pi] always. Your second if statement is redundant. It's also likely a bad design: very often you want to test later on for angles in [pi,2pi], which can be done with a simple <0 for the default range. Basically, atan2() is your friend, the reason the function exists is to save you from the hassle of doing modular math on angles.
I am working on a college compsci project and I would like some help with a field of view algorithm. I works mostly, but in some situations the algorithm sees through walls and hilights walls the player should not be able to see.
void cMap::los(int x0, int y0, int radius)
{ //Does line of sight from any particular tile
for(int x = 0; x < m_Height; x++) {
for(int y = 0; y < m_Width; y++) {
getTile(x,y)->setVisible(false);
}
}
double xdif = 0;
double ydif = 0;
bool visible = false;
float dist = 0;
for (int x = MAX(x0 - radius,0); x < MIN(x0 + radius, m_Height); x++) { //Loops through x values within view radius
for (int y = MAX(y0 - radius,0); y < MIN(y0 + radius, m_Width); y++) { //Loops through y values within view radius
xdif = pow( (double) x - x0, 2);
ydif = pow( (double) y - y0, 2);
dist = (float) sqrt(xdif + ydif); //Gets the distance between the two points
if (dist <= radius) { //If the tile is within view distance,
visible = line(x0, y0, x, y); //check if it can be seen.
if (visible) { //If it can be seen,
getTile(x,y)->setVisible(true); //Mark that tile as viewable
}
}
}
}
}
bool cMap::line(int x0,int y0,int x1,int y1)
{
bool steep = abs(y1-y0) > abs(x1-x0);
if (steep) {
swap(x0, y0);
swap(x1, y1);
}
if (x0 > x1) {
swap(x0,x1);
swap(y0,y1);
}
int deltax = x1-x0;
int deltay = abs(y1-y0);
int error = deltax/2;
int ystep;
int y = y0;
if (y0 < y1)
ystep = 1;
else
ystep = -1;
for (int x = x0; x < x1; x++) {
if ( steep && getTile(y,x)->isBlocked()) {
getTile(y,x)->setVisible(true);
getTile(y,x)->setDiscovered(true);
return false;
} else if (!steep && getTile(x,y)->isBlocked()) {
getTile(x,y)->setVisible(true);
getTile(x,y)->setDiscovered(true);
return false;
}
error -= deltay;
if (error < 0) {
y = y + ystep;
error = error + deltax;
}
}
return true;
}
If anyone could help me make the first blocked tiles visible but stops the rest, I would appreciate it.
thanks,
Manderin87
You seem to be attempting to create a raycasting algorithm. I assume you have knowledge of how Bresenham's lines work, so I'll cut to the chase.
Instead of checking the visibility of each cell in the potential field of view, you only need to launch Bresenham lines from the FOV centre towards each cell at the very perimetre of the potential FOV area (the square you loop through). At each step of the Bresenham line, you check the cell status. The pseudocode for each ray would go like this:
while (current_cell != destination) {
current_cell.visible = true;
if (current_cell.opaque) break;
else current_cell = current_cell.next();
}
Please remember that raycasting produces tons of artifacts and you might also need postprocessing after you have calculated your field of view.
Some useful resources:
ray casting on Roguebasin
ray casting FOV implementation in libtcod (in C, you can dig through the repository for a C++ wrapper to it)
a FOV study