I am working on a 2D game using SDL. Recently I implemented various functions that put objects (and their rectangles) into motion, but encountered performance issues that are most likely caused by inefficient mapping of rectangle coordinates. Please see below:
2D coordinates of the rectangle are stored in an integer array whenever move() is called. For example, coordinate[0] is the first point on the x axis and coordinate[1] is the last point on the x axis. Coordinates [2] and [3] work for points on the y axis.
The map() function takes the coordinates of a rectangle and stores them in static std::map (Status class). Each x and y pair is either 0 or 1, depending on whether a rectangle is present or not. Player's coordinates are not mapped.
When the player moves, the bool function collide() checks whether the player's rectangle is adjacent to another recantgle in a particular direction. If there is no rectangle blocking the way, the player is allowed to move.
Everything works well, but it seems like all these for loops in the map() function are very CPU-heavy. When rectangles are being moved on the screen, the program lags horribly. How can I map rectangle coordinates more efficiently?
void move(int x, int y) {
dstRect.x = x;
dstRect.y = y;
coordinate[0] = dstRect.x;
coordinate[1] = dstRect.x + dstRect.w;
coordinate[2] = dstRect.y;
coordinate[3] = dstRect.y + dstRect.h;
}
void map() {
for (int x = coordinate[0]; x != coordinate[1]; x++) {
for (int y = coordinate[2]; y != coordinate[3]; y++) {
Status::map().insert(std::pair<std::vector<int>, int>({ x, y }, 1));
}
}
}
bool collide(DIRECTION direction) {
if (direction == UP || direction == DOWN) {
for (int x = texture.coordinate[0]; x != texture.coordinate[1]; x++) {
if (direction == UP) {
if (Status::map().find({ x, texture.coordinate[2] - 1 })->second == 1) { return true; }
}
if (direction == DOWN) {
if (Status::map().find({ x, texture.coordinate[3] + 1 })->second == 1) { return true; }
}
}
}
if (direction == RIGHT || direction == LEFT) {
for (int y = texture.coordinate[2]; y != texture.coordinate[3]; y++) {
if (direction == RIGHT) {
if (Status::map().find({ texture.coordinate[1] + 1, y })->second == 1) { return true; }
}
if (direction == LEFT) {
if (Status::map().find({ texture.coordinate[0] - 1, y })->second == 1) { return true; }
}
}
}
return false;
}
void moveRight() {
for (int i = 0; i < speed; i ++) {
if (!collide(RIGHT)) {
int x = texture.dstRect.x + 1;
int y = texture.dstRect.y;
texture.move(x, y);
}
}
}
Followed #FrançoisAndrieux advice and created multidimensional vector for storing the coordinates.
Related
I'm trying to make objects move on a chessboard (a coordinate grid). I've defined these object as Vehicles. They have a position (x,y) on the plane and a direction. Being forced to move only North-South-East-West possible directions could be
North: (0, 1)
South: (0, -1)
East: (1, 0)
West: (-1, 0)
Vehicles can proceed only step by step (x+1, y), (x, y+1), where x, y are integers. Two vehicles cannot stand in the same position. A vehicle maintains its direction while it is possible, that is while it encounters an occupied position.
So I have to create a void move function which has as arguments the positions of the nearby vehicles (North South East West). Such a function should:
Check if the vehicle can maintain its direction and, if it can, refresh the vehicle position with the new position;
If the cell is occupied, go for another direction, check if the cell in that direction is free...
If every cell surrounding the vehicle is occupied, stay still.
I wrote a code that accomplish point 1 but I have difficulties with point 2. In particular, I can't think about an effective way to change the Vehicle's direction. Here's my code so far:
class Vehicle {
private:
int x, y;
int vx, vy;
public:
int getx() { return x;}
int gety() { return y;}
int getvx() { return vx;}
int getvy() { return vy;}
void sety(int a) { y = a;}
void setx(int a) { x = a;}
void setvx(int a) {
if (a != 0) {
vx = a / abs(a);
}else { vx = a;}
}
void setvy(int a) {
if (a != 0) {
vy = a / abs(a);
}else { vy = a;}
}
void move(Vehicle * v) {
int big = 0;
while(big<4) {
int cont=0;
for(int i=0; i<4; i++) {
if (x+vx != v[i].getx() or y+vy != v[i].gety()) {
cont ++;
}
}
if(cont==4) {
x = x + vx;
y = y + vy;
break;
} else {
big ++;
// CHANGE DIRECTION in PROPER WAY
}
}
}
void print() {
// prints the private members
}
};
How could I improve the while?
The game board is stored as a 2D char array. The Player moves his cursor around the board using the numpad, and chooses with the enter key- current position of the cursor is stored in two ints.
After each move, the board is evaluated for a win using the below method.
void checkwin()
{
//look along lines from current position
int x = cursorPosX;
int y = cursorPosY;
int c = playerTurn ? 1 : 2; //which mark to look for
for (int xAxis = 0; xAxis <= 2; xAxis++) //look along x axis
{
x = WrapValue(0, sizeof(squares[0]), x + 1);
if (CheckPos(x, y) != c) //if we don't find the same mark, must not be a horizontal line, otherwise, break out.
{
x = cursorPosX; //reset x
for (int yAxis = 0; yAxis <= 2; yAxis++) //look along y axis
{
y = WrapValue(0, sizeof(squares[0]), y + 1);
if (CheckPos(x, y) != c)
{
y = cursorPosY;
//look for diagonal
for (int i = 0; i <= 2; i++ )
{
x = WrapValue(0, sizeof(squares[0]), x + 1);
y = WrapValue(0, sizeof(squares[0]), y + 1);
if (CheckPos(x, y) != c)
{
//failed everything, return
winConditions = -1;
return;
}
}
break;
}
}
break;
}
}
//if we make it out of the loops, we have a winner.
winConditions = playerTurn ? 0 : 1;
}
I get wrong results- returning a draw or win when not appropriate. I'm almost certain x and y get wrong values at some point and start checking the wrong spots.
Visual Studio stops updating a watch on x and y after going into the yAxis loop- I'm not sure why, but it prevents me from keeping track of those values. Am I breaking a rule about scoping somewhere? This is the only place I use x and y as variable names.
Relevant wrap method below. My aim was to always be able to check the other 2 spaces by adding, no matter where I was on the board
int WrapValue(int min, int max, int value)
{
auto range = max - min;
while (value >= max)
{
value -= range;
}
while (value < min)
{
value += range;
}
return value;
}
I'd appreciate a trained eye to tell me what I did wrong here. Thanks so much for your time.
Nesting for loops was a terrible idea. I solved the problem by refactoring the code into multiple separate loops that each do 1 thing, rather than fall through each other into deeper levels of hell.
for (int xAxis = 0; xAxis <= 2; xAxis++) //look along x axis
{
x = WrapValue(0, sizeof(squares[0]), x + 1);
if (CheckPos(x, y) != c) //if we don't find the same mark, must not be a horizontal line, otherwise, break out.
{
x = cursorPosX; //reset x
break;
}
else if (xAxis == 2)
{
winConditions = playerTurn ? 0 : 1;
return;
}
}
for (int yAxis = 0; yAxis <= 2; yAxis++) //look along y axis
{
y = WrapValue(0, sizeof(squares[0]), y + 1);
if (CheckPos(x, y) != c)
{
y = cursorPosY;
break;
}
else if (yAxis == 2)
{
winConditions = playerTurn ? 0 : 1;
return;
}
}
...ect
This violates DRY, but it does work the way it's supposed to, I'm sure I can simplify it later.
While I'm not entirely sure why the previous way didn't work, I do realize that it was just bad design to start with.
I don't work with tiles but cubes drawn with sf::Vertex. Each cubes have 6 sides with 4 points each.
So i just have to cubes[numCube].sides()[numSide].... to select a side.
I create cubes layer.cpp :
for(int J = 0; J < mapSize; J++)
{
for(int I = 0; I < mapSize; I++)
{
x = (J - I) * (cubeSize/2);
y = (J + I) * (cubeSize/4);
c = new cube(cubeSize, x, y, z, I, J);
cs.push_back(*c);
}
}
In cube.cpp i create sides, then, in sides.cpp, i calcul each points' coordinates like this :
switch(typeSide)
{
case 0://DOWN_SIDE
light = 1;
tmp_x = x + (size/2);
tmp_y = y + (size/2);
p0 = new point(tmp_x, tmp_y, tmp_z);
tmp_x = x + size;
tmp_y = y + (3 * (size/4));
p1 = new point(tmp_x, tmp_y, tmp_z);
tmp_x = x + (size/2);
tmp_y = y + size;
p2 = new point(tmp_x, tmp_y, tmp_z);
tmp_x = x;
tmp_y = y + (3 * (size/4));
p3 = new point(tmp_x, tmp_y, tmp_z);
break;
case 1://BACK_LEFT_SIDE
//ETC. ....
Point.cpp :
/*
* point.cpp
*
* Created on: 21 nov. 2015
* Author: user
*/
#include "point.h"
point::point(float tx, float ty, float tz)
{
coords* dummyVar = new coords(tx, ty, tz);
coordinates = dummyVar;
}
std::vector<float> point::position()//Use : myPoint.getPosition[0] //get the x
{
std::vector<float> dummyVar;
dummyVar.push_back(coordinates->getX());
dummyVar.push_back(coordinates->getY() - coordinates->getZ());
return dummyVar;
}
void point::move(float tx, float ty, float tz)
{
coordinates->setX(tx);
coordinates->setY(ty);
coordinates->setZ(tz);
}
My problem come from the function i use to detect click :
if (event.type == sf::Event::MouseMoved)
{
currentSelectedCube = maps[currentMapID].getCubeIDAt(event.mouseMove.x, event.mouseMove.y, offsetLeft, offsetTop, enableOffset);
}
The function(don't bother with the comments) :
I try to get a cube's entry in my cube vector without 'for loop'.
Why ? to use less CPU when i click.
int map::getCubeIDAt(float x, float y, int offsetLeft, int offsetTop, bool enableOffset)//WIP ! //USED FOR CLICK DETECTION ON CUBES
{
//----------------------------------------------------------------//
int unsigned entry = -1;
int I = 0;
int J = 0;
//----------------------------------------------------------------//
if(currentLayerId() > -1)//If there is any layers
{
//IF CHECK IN MAP BOUDING BOX + ROTATION TO GOT DIAMOND SHAPE AREA(LAYER + OFFSETS)----------------------------------
//{
if(!enableOffset)//With offsets disabled
{
I = (y * 2 - x) / cubeSize;
J = (y * 2 + x) / cubeSize;
}
else //With offsets enabled
{
I = (((y-offsetTop)+(currentLayerId()*(cubeSize/2))) * 2 - (x-offsetLeft)) / cubeSize;
J = (((y-offsetTop)+(currentLayerId()*(cubeSize/2))) * 2 + (x-offsetLeft)) / cubeSize;
}
entry = I + J * size;
if (entry < 0 || entry >= layers()[currentLayerId()].cubes().size())
{
entry = -1;
}
else//DEBUG - DISPLAYING VALUES FOR TEST
{
std::cout << "Entry n°" << entry << " - ";
std::cout << "[" << I << "; " << J << "]" << std::endl;
}
//}
//END IF CHECK IN MAP BOUDING BOX + ROTATION TO GOT DIAMOND SHAPE AREA(LAYER + OFFSETS)----------------------------------
}
return entry;
}
The I-J and entryNumber are OK. i mean, for example, for the cube 0, i have I = 0; J = 0; etc ... This is working.
I don't understand why the coordinate range is like the red part(not accurate at 100%, i'm not a paint genius ha ha) in this picture :
But i should get that(2nd picture - the red part is where i click) :
But after few checks, the I-J and the entry i got are corresponding. This is so weird.
EDIT2:
Offsets and layer number implemented.
Problem left: wrong coordinates range.
Just in case, this is the 'function' handling events :
void GRAPHICS_HANDLER::listenEvents()
{
while (window->pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
window->close();
}
if(event.type == sf::Event::KeyPressed)
{
//DISPLAY/UNDISPLAY GRID -- DEBUG FUNCTION
if(event.key.code == sf::Keyboard::Escape)
{
if(grid)
grid = false;
else
grid = true;
}
//-----------------------------------------------------------------------------------DEBUG---------------------------------------------------------------//
if(event.key.code == sf::Keyboard::B)//ACTIVE BRUSHMODE -- NEED TO BLOCK IT WHEN ACCESS VIOLATION OF CUBES ARRAY(CRASH)
{
if(!brushMode)
{
brushMode = true;
std::cout << "Brush mode enabled" << std::endl;
}
else
{
brushMode = false;
std::cout << "Brush mode disabled" << std::endl;
}
}
if(event.key.code == sf::Keyboard::L)//ADD_LAYER
{
addLayer(getCurrentMapID());
}
if(event.key.code == sf::Keyboard::M)//DELETE_LAYER
{
deleteLayer(currentMapID, maps[currentMapID].currentLayerId());
}
if(event.key.code == sf::Keyboard::S)//ADD_LAYER
{
std::cout << "Select a texture: ";
std::cin >> currentSelectedTexture; std::cout << std::endl;
}
if(event.key.code == sf::Keyboard::Left)//Move in Layer
{
if(maps[currentMapID].currentLayerId() > 0)
{
maps[currentMapID].setCurrentLayerID(maps[currentMapID].currentLayerId()-1);
}
}
if(event.key.code == sf::Keyboard::Right)//Move in Layer
{
if(maps[currentMapID].currentLayerId() < maps[currentMapID].layers().size()-1)
{
maps[currentMapID].setCurrentLayerID(maps[currentMapID].currentLayerId()+1);
}
}
//-----------------------------------------------------------------------------------DEBUG---------------------------------------------------------------//
}
if (event.type == sf::Event::MouseMoved)
{
//--------------------------------------------------------------------------CURSOR-----------------------------------------------------------------------//
currentSelectedCube = maps[currentMapID].getCubeIDAt(event.mouseMove.x, event.mouseMove.y, offsetLeft, offsetTop, enableOffset);
//--------------------------------------------------------------------------CURSOR-----------------------------------------------------------------------//
}
if (event.type == sf::Event::MouseButtonPressed)
{
//--------------------------------------------------------------------------CURSOR-----------------------------------------------------------------------//
currentSelectedCube = maps[currentMapID].getCubeIDAt(event.mouseButton.x, event.mouseButton.y, offsetLeft, offsetTop, enableOffset);
//--------------------------------------------------------------------------CURSOR-----------------------------------------------------------------------//
if (event.mouseButton.button == sf::Mouse::Left)
{
//--------------------------------------------------------------------------CUBE CLICK DETECTION--------------------------------------------------//
if(maps.size() > 0 && maps[currentMapID].layers().size() > 0 && currentSelectedCube > -1)
{
cubeClicked = true;
}
}
if (event.mouseButton.button == sf::Mouse::Right)
{
if(maps.size() > 0 && maps[currentMapID].layers().size() > 0 && currentSelectedCube > -1)
{
maps[currentMapID].layers()[maps[currentMapID].currentLayerId()].cubes()[currentSelectedCube].setTexture(1);
}
}
//--------------------------------------------------------------------------CUBE CLICK DETECTION--------------------------------------------------//
}
}
}
EDIT3: I updated my code to allow me to draw only the down side of the cube, so i can do this(the grass) :
The coordinate range(the red isometric square shown before in the screenshots) change a little when i put flat square(green).
I don't know why, i prefer to precise it, just in case.
You need to store the "heigth" of each element from the tiles plane in order to distinguish which cube are you actually selecting (the closer to the observer):
Same screen coordinates, but different tiles.
It's not clear to me how you modeled your world, so I'll give you a partial algorithm to check what face of what cube is the one clicked. Please, adapt it to your actual code and to the classes you have written to make it work.
// I'll let you to add the offsets for the screen coordinates
I = (y * 2 - x) / cubeSize;
J = (y * 2 + x) / cubeSize;
// find out if it is a left or right triangle
if ( x < (J - I) * (cubeSize/2) ) {
// left triangle
for ( k = max_n_layer; k > -1; --k ) {
// you create the cubes nesting the I loop in the J loop, so to get the index of a cube,
// assuming that you have created all the cubes (even the invisible ones, like it seems from your code)
index = (J+1+k)*mapsize + I+1+k;
// I don't really get how you define the existence or not of a face, but I guess something like this:
if ( index < map.layer[k].cubes.size()
&& map.layer[k].cubes[index].sides[top_side] != 0 ) {
// the face selected is the top side of cube[index] of layer k
// you have to return index and k to select the right face, or simply a pointer to that face
// if this makes any sense with how you have designed your model
return &map.layer[k].cubes[index].sides[top_side];
}
// now check for the side
index = (J+k)*mapsize + I+1+k;
if ( index < map.layer[k].cubes.size()
&& map.layer[k].cubes[index].sides[right_side] != 0 ) {
return &map.layer[k].cubes[index].sides[right_side];
}
index = (J+k)*mapsize + I+k;
if ( index < map.layer[k].cubes.size()
&& map.layer[k].cubes[index].sides[left_side] != 0 ) {
return &map.layer[k].cubes[index].sides[left_side];
}
}
} else {
// right triangle
for ( k = max_n_layer; k > -1; --k ) {
index = (J+1+k)*mapsize + I+1+k;
if ( index < map.layer[k].cubes.size()
&& map.layer[k].cubes[index].sides[top_side] != 0 ) {
return &map.layer[k].cubes[index].sides[top_side];
}
index = (J+1+k)*mapsize + I+k;
if ( index < map.layer[k].cubes.size()
&& map.layer[k].cubes[index].sides[left_side] != 0 ) {
return &map.layer[k].cubes[index].sides[left_side];
}
index = (J+k)*mapsize + I+k;
if ( index < map.layer[k].cubes.size()
&& map.layer[k].cubes[index].sides[right_side] != 0 ) {
return &map.layer[k].cubes[index].sides[right_side];
}
}
}
// well, no match found. As I said is up to you to decide how to do in this case
return nullptr;
Edit
I suggest you to try another way.
Consider the screen as divided not by quadrangular tiles but by the triangles you already depicted. Every 2D tile of your model will be formed by two of those triangles and so all the sides of the cubes you want to draw. For every cube don't draw nor even create the back sides, those will never be drawn.
You can try to implement a sort of specialized z-buffer algorithm by storing for each one of the triangles you have to draw on the screen the index of the side which is closer to the observer.
The coordinates of the vertex of all the triangles are calculated (once) with the code you already have.
(I,J) //For every node (I,J) you have a left and a right triangle
. * .
(I+1,J) * . | . * (I,J+1)
*
(I+1,J+1)
You are creating your cubes layer by layer, I guess, each layer having a different heigth over the base plane. Create every side of the cube using the coordinates calculated earlier. For every face (only the 3 pointing to the observer) consider each one of its 2 triangles. You can easily determine if it is visible or not if you proceed in order, then you only have to update the ID stored in the corresponding triangle.
Once finished this fase, you'll have to draw each triangle once as you already have dropped the hidden ones.
To determine the inverse transformation from screen coordinates to cell indexes, you only have to calculate which triangle is hitted and then look up which ID correspond to that. So transform back x,y to I,J (you already have those equations) and choose the left triangle if x < (J-I)/cubesize the right one otherwise.
Ok so what I'm trying to do is create an array of pointers that point to vectors that change in size. Also the array of pointers is nestled inside a class that's inside a vector. For some reason I seem to be having problems with memory becoming corrupt. Also if I use vectors I run into the problems with the stack overflowing caused by stuff resizing and calling constructors. Here is an essential layout of what I'm gunning for.
Maybe a little sloppy. But I end up with the problem of memory being currupted in the babyclasses pointers, basically I want to access "linked" babyclasses via the babyclasses vector of babyclasses it's connected to.
Any clever ideas here?
And before anyone tells me this is a silly way to do things, isn't this type of functionality the basis of OO Programming?
class Baby
{
public:
deque<shared_ptr<Baby>> vInputs;
int X;
int Y;
int Z;
Baby()
{
numInputs = 0;
isNull = false;
wasTickled = false;
X,Y,Z = 0;
}
void addInput(shared_ptr<Baby> baby)
{
if(numInputs == 0)
vInputs = deque<shared_ptr<Baby>>(0);
vInputs.push_back(baby);
numInputs++;
}
void setXYZ(int x, int y, int z)
{
X = x;
Y = y;
Z = z;
}
void Tickle()
{
if(!wasTickled)
wasTickled = true;
else
return;
for(int i=0;i<numInputs;i++)
{
vInputs[i]->Tickle();
}
}
void setNull(bool isnull)
{
isNull = isnull;
}
private:
int numInputs;
bool isNull;
bool wasTickled;
};
class BabyLayer
{
public:
int Width;
int Height;
BabyLayer()
{
Width = 0;
Height = 0;
}
BabyLayer(int width, int height)
{
Width = width;
Height = height;
vecBabies = std::deque<deque<Baby>>(0);
for(int i=0;i<height;i++)
{
deque<Baby> row = deque<Baby>(0);
for(int i=0;i<width;i++)
{
row.push_back(Baby());
};
vecBabies.push_back(row);
}
MakeConnections();
}
Baby * getBaby(int x, int y)
{
Baby n = Baby();
n.setNull(true);
if(x >= Width || x <0)
return &n;
if(y >= Height || y < 0)
return &n;
n.setNull(false);
return &vecBabies[y][x];
}
~BabyLayer(void)
{
}
private:
std::deque<deque<Baby>> vecBabies;
void MakeConnections()
{
for(int y=0;y<Height;y++)
{
for(int x=0;x<Width;x++)
{
//Top Right
if(y > 0 && x < Width-1)
vecBabies[y][x].addInput(shared_ptr<Baby>(&vecBabies[y-1][x+1]));
//Middle Right
if(x < Width -1)
vecBabies[y][x].addInput(shared_ptr<Baby>(&vecBabies[y][x+1]));
//Bottom Right
if(x < Width -1 && y < Height-1)
vecBabies[y][x].addInput(shared_ptr<Baby>(&vecBabies[y+1][x+1]));
//Bottom Middle
if(y < Height-1)
vecBabies[y][x].addInput(shared_ptr<Baby>(&vecBabies[y+1][x]));
}
}
}
};
class BabyCube
{
public:
int X;
int Y;
int Z;
BabyCube(int x, int y, int z)
{
X = x;
Y = y;
Z = z;
Layers = deque<BabyLayer>();
for(int i=0;i<z;i++)
{
BabyLayer lay = BabyLayer(x,y);
Layers.push_back(lay);
}
NullBaby = Baby();
NullBaby.setNull(true);
MakeConnections();
}
void MakeConnections()
{
int l = Layers.size();
if(l == 0 || l == 1)
return;
for(int layer=0;layer<l;layer++)
{
BabyLayer * lay = &Layers[layer];
if(layer< l-1)
{
for(int y=0;y<lay->Height;y++)
{
for(int x=0;x<lay->Width;x++)
{
//Top Left
if(x > 0 && y > 0)
Layers[layer].getBaby(x,y)->addInput(shared_ptr<Baby>(Layers[layer+1].getBaby(x-1,y-1)));
//Top Middle
if(y > 0)
Layers[layer].getBaby(x,y)->addInput(shared_ptr<Baby>(Layers[layer+1].getBaby(x,y-1)));
//Top Right
if(y > 0 && x+1 < lay->Width-1)
Layers[layer].getBaby(x,y)->addInput(shared_ptr<Baby>(Layers[layer+1].getBaby(x+1,y-1)));
//Middle Right
if(x+1 < lay->Width -1)
Layers[layer].getBaby(x,y)->addInput(shared_ptr<Baby>(Layers[layer+1].getBaby(x+1,y)));
//Bottom Right
if(x+1 < lay->Width -1 && y+1 < lay->Height-1)
Layers[layer].getBaby(x,y)->addInput(shared_ptr<Baby>(Layers[layer+1].getBaby(x+1,y+1)));
//Bottom Middle
if(y+1 < lay->Height-1)
Layers[layer].getBaby(x,y)->addInput(shared_ptr<Baby>(Layers[layer+1].getBaby(x,y+1)));
//Bottom Left
if(x > 0 && y+1 < lay->Height-1)
Layers[layer].getBaby(x,y)->addInput(shared_ptr<Baby>(Layers[layer+1].getBaby(x-1,y+1)));
//Middle Left
if(x > 0)
Layers[layer].getBaby(x,y)->addInput(shared_ptr<Baby>(Layers[layer+1].getBaby(x-1,y)));
//Middle Middle
Layers[layer].getBaby(x,y)->addInput(shared_ptr<Baby>(Layers[layer+1].getBaby(x,y)));
}
}
}
}
}
Baby * getBaby(int x, int y, int z)
{
if(z >= Layers.size() || z < 0)
return &NullBaby;
if(y >= Layers[z].Height || y < 0)
return &NullBaby;
if(x >= Layers[z].Width || x < 0)
return &NullBaby;
return Layers[z].getBaby(x,y);
}
void Update()
{
}
~BabyCube(void)
{
}
private:
deque<BabyLayer> Layers;
Baby NullBaby;
};
Out of morbid curiosity, I revisited this question to see if anyone had deciphered it.
The only obvious issue I see with the source code is in BabyLayer::GetBaby():
Baby n = Baby();
n.setNull(true);
if(x >= Width || x <0)
return &n; // Bad.
if(y >= Height || y < 0)
return &n; // Bad.
You're declaring a new Baby instance on the stack, then returning a pointer to it. The Baby instance named 'n' gets destructed when GetBaby() returns, and the returned pointer is now invalid.
I don't know what compiler you're using, but Visual Studio 2010 emits, "warning C4172: returning address of local variable or temporary" on these lines. Note that your code sample is incomplete and doesn't actually do anything, I had to declare a BabyCube instance to receive this warning.
Since I can't decipher what your code is supposed to do, and can make no sense of its operation, I can't explain why the memory access exceptions are thrown.
I am new to c++ and I have been practicing collision in a small game program that does nothing and I just can't get the collision right
So I use images loaded into variables
background = oslLoadImageFile("background.png", OSL_IN_RAM, OSL_PF_5551);
sprite = oslLoadImageFile("sprite.png", OSL_IN_RAM, OSL_PF_5551);
bush = oslLoadImageFile("bush.png", OSL_IN_RAM, OSL_PF_5551);
While there are variables stored like
sprite->x = 3;
if ( (sprite->x + spritewidth > bush->x) && (sprite->x < bush->x + bushwidth) && (sprite->y + spriteheight > bush->y) && (sprite->y < bush->y + bushheight) )
{
bushcol = 1;
}
else
{
bushcol = 0;
}
So when i press a button
if (osl_keys->held.down)
{
if (bushcol == 1)
{
sprite->y = bush->y + 38;
}
else
{
sprite->y += 3;
}
}
if (osl_keys->held.up)
{
if (bushcol == 1)
{
sprite->y = bush->y - 23;
}
else
{
sprite->y -= 3;
}
}
if (osl_keys->held.right)
{
if (bushcol == 1)
{
sprite->x = bush->x - 28;
}
else
{
sprite->x += 3;
}
}
if (osl_keys->held.left)
{
if (bushcol == 1)
{
sprite->x = bush->x + 28;
}
else
{
sprite->x -= 3;
}
}
i was thinking of things like
sprite->y = bushheight - 24;
but it doesnt work
Any suggestions?
I'd suggest making a function solely for the purpose of bounding box colision detection.
It could look like
IsColiding(oslImage item1, oslImage item2)
{
/* Perform check */
}
in which you perform the check if there is a collision between image 1 and image 2.
As for the algorithm you're trying to use check out this wikipedia for example AABB bounding box
Especially this part:
In the case of an AABB, this tests
becomes a simple set of overlap tests
in terms of the unit axes. For an AABB
defined by M,N against one defined by
O,P they do not intersect if (Mx>Px)
or (Ox>Nx) or (My>Py) or (Oy>Ny) or
(Mz>Pz) or (Oz>Nz).
I think you have the basic idea. Just check your work. Here is a simple version which compiles:
#import <stdlib.h>
typedef struct {
// I'm going to say x, y, is in the center
int x;
int y;
int width;
int height;
} Rect;
Rect newRect(int x, int y, int w, int h) {
Rect r = {x, y, w, h};
return r;
}
int rectsCollide(Rect *r1, Rect *r2) {
if (r1->x + r1->width/2 < r2->x - r2->width/2) return 0;
if (r1->x - r1->width/2 > r2->x + r2->width/2) return 0;
if (r1->y + r1->height/2 < r2->y - r2->height/2) return 0;
if (r1->y - r1->height/2 > r2->y + r2->height/2) return 0;
return 1;
}
int main() {
Rect r1 = newRect(100,200,40,40);
Rect r2 = newRect(110,210,40,40);
Rect r3 = newRect(150,250,40,40);
if (rectsCollide(&r1, &r2))
printf("r1 collides with r2\n");
else
printf("r1 doesnt collide with r2\n");
if (rectsCollide(&r1, &r3))
printf("r1 collides with r3\n");
else
printf("r1 doesnt collide with r3\n");
}
First of all i suppose you mean
sprite->y = bush->**y** - 3;
second i dont know what platform you are using, but often times the y-coordinates are inverted. i.e., y=0 corresponds to top of the screen. In that case your comparisons might not work.
third collision checking can quickly become complicated when you add rotation and non-rectangular objects to it. You should consider using CGAL or some other computational geometry algorithms library, which can handle polygon intersection.