Passing an object by reference to function doesnt change this object - c++

so basically, I'm trying to pass an object to my function Attack():
void Character::Attack(Character &another, short int range)
{
if (EnemyInRange(range) && another.health > 0)
{
if (allowed_to_attack)
{
attacked = true;
cout << name << " attacked " << another.name << " taking " << attack << " damage" << endl;
if (another.defensive > 0) // less important things down there
{
another.defensive--;
if (attack > another.defensive)
{
another.health -= (attack - another.defensive);
}
}
else if (another.defensive == 0)
{
another.health -= attack;
}
if (another.defensive <= 0)
another.defensive = 0;
if (another.health <= 0)
{
another.health = 0;
another.draw = false;
another.~Character();
}
}
else
{
attacked = false;
cout << "Blocked" << endl;
}
}
else
cout << name << " wanted to attack " << another.name << " ,but he's out of the range" << endl;
As you see, I'm using reference to pass an object. BUT, when I call this function:
void onClick(Vector2f mouse_position, Character current, Character *& target, Position &positionx)
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 5; j++)
{
if ((mouse_position.x >= 245 + i * 164 && mouse_position.x <= 370 + i * 164) &&
(mouse_position.y >= 56 + j * 201 && mouse_position.y <= 221 + j * 201))
{ // there's a 2d map with cards on those positions
target = &positionx.positioning[i][j];
current.Attack(*target);
}
}
}
}
positioning is an array filled with characters
It's behaving like I passed a copy of an object target (it writes out name, but it doesn't change its health)
in main() it looks like this:
Character *current = new Character();
Character *target = NULL;
if ((event.type == Event::MouseButtonPressed) && (event.mouseButton.button == Mouse::Left))//SFML lib
{
Vector2i pos = Mouse::getPosition(window);
Vector2f position = (Vector2f)pos;
onClick(position, *current, target, positionx);
} // target is selected after clicking on it

In the function onClick, the variable current is passed by value not reference. I assume that is supposed to be passed by reference:
void onClick(Vector2f mouse_position, Character &current, Character *target, Position &positionx)
Notice the argument current has been updated to a reference.
Edit:
Looking at the body of the Attack function, if the line printing out the name is met, are you sure the if-conditional statements if(another.defensive > 0) and if(attack > another.defensive) are met?

Do you think that Position &positionx might be a problem here? The most important part of onClick() function is target = &positionx.positioning[i][j]. But its passed by reference, so it shouldnt make a problem.

Related

Parameter passed by a reference behaves like a copy

I'm having two pointers called Character *current = nullptr; and Character *target = nullptr;.
I'm changing them by a function:
void Position::Current(const Vector2f & mouse_position, Character *& current)
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 5; j++)
{
if ((mouse_position.x >= 245 + i * 164 && mouse_position.x <= 370 + i * 164) &&
(mouse_position.y >= 56 + j * 201 && mouse_position.y <= 221 + j * 201))
{
current = &positioning[i][j];
cout << "Selected: " << current->name << endl;
cout << endl;
current->health -= 5; //it doesn't change anything
break;
}
}
}
}
Target() function is implemented by the same way.
Both functions select the right character, but it looks like those are copies of original objects (I cant change character's statistics) .
Character positioning[4][5] is array filled with characters. I can add them on specific positions by function:
void Position::Add(Character & character, int x, int y)
{
if ((x >= 0 && x < 4) && (y >= 0 && y < 5))
{
positioning[x][y] = character; //is this a problem ?
Character::position[x][y] = true;
character.x = x;
character.y = y;
}
}
Position class has only one object.
In main() it looks like this:
positionx.Add(knight, 3, 4);
positionx.Add(demon, 2, 4);
and then:
if ((event.type == Event::MouseButtonPressed) && (event.mouseButton.button == Mouse::Right))
{
Vector2i pos = Mouse::getPosition(window);
Vector2f position = (Vector2f)pos;
positionx.Current(position, current);
}
Current function should take 5 health from selected character, but nothing like that happens.
Where have I made a mistake?
Thanks for any answer.
Problem solved!
I just had to make Character positioning[4][5] -> Character *positioning[4][5]
Then after clicking on a certain character, it finally started to behave like an original object.

Vector subscript out of range in SFML game

Im working on a game as a project for my game development course. It is using vectors to spawn enemies at the top of the screen and run down as well as creating "bullets" that are fired by both the player and the boss. After adding the boss and code for his bullets the previously working code is now throwing a vector subscript out of range error. This error is always thrown right after hitting an enemy and didn't happen before the boss was introduced.
bullets[i].shape.move(bullets[i].currVelocity);
//Bullet Removal
if (bullets[i].shape.getPosition().x < 0 || bullets[i].shape.getPosition().x > window.getSize().x
|| bullets[i].shape.getPosition().y < 0 || bullets[i].shape.getPosition().y > window.getSize().y) {
bullets.erase(bullets.begin() + i);
}
else {
//Collision Code
for (size_t k = 0; k < enemies.size(); k++) {
if (bullets[i].shape.getGlobalBounds().intersects(enemies[k].getGlobalBounds())) {
bullets.erase(bullets.begin() + i);
enemies.erase(enemies.begin() + k);
score = score + 1;
fiveScore = fiveScore + 1;
std::cout << "Score: " << score << std::endl;
hitSound.play();
if (fiveScore == 5) {
fiveScore = 0;
//scoreUpSound.play();
}
if (score >= 100 && bossSpawned == false) {
bossSpawned = true;
boss.setPosition(250.0f, 50.0f);
}
break;
}
}
if (bullets[i].shape.getGlobalBounds().intersects(boss.getGlobalBounds())) {
bullets.erase(bullets.begin() + i);
hitSound.play();
bossHP = bossHP - 1;
if (bossHP <= 0) {
bossSpawned = false;
boss.setPosition(3214.0f, 4322.0f);
text.setString("You have completed your quest." "\n" "The warlock is slain and the realm is" "\n" "safe, yet as life returns to the kingdom" "\n" "you are dissatisfied. Your brother and" "\n" "lover are both deceased and" "\n" "you feel only death will heal your pain.");
text.setPosition(25.0f, 150.0f);
window.clear();
window.draw(text);
window.display();
Sleep(9000);
return 0;
}
break;
}
}
}
This is the code for the player's bullet collisions.
b2.shape.setPosition(bossCenter);
b2.currVelocity = bossAimDirNorm * b2.maxSpeed;
bossbullets.push_back(BossBullet(b2));
}
for (size_t z = 0; z < bossbullets.size(); z++) {
bossbullets[z].shape.move(bossbullets[z].currVelocity);
//BossBullet Removal
if (bossbullets[z].shape.getPosition().x < 0 || bossbullets[z].shape.getPosition().x > window.getSize().x
|| bossbullets[z].shape.getPosition().y < 0 || bossbullets[z].shape.getPosition().y > window.getSize().y) {
bossbullets.erase(bossbullets.begin() + z);
}
else {
//Collision Code
if (bossbullets[z].shape.getGlobalBounds().intersects(player.getGlobalBounds())) {
bossbullets.erase(bossbullets.begin() + z);
playerDead = true;
text.setString("You have failed your quest.");
text.setPosition(150.0f, 150.0f);
window.clear();
window.draw(text);
window.display();
Sleep(5000);
return 0;
}
}
}
This is the code for the boss' bullet collisions. Any help or even ideas of what could be wrong would be helpful. Reverting to before I added the boss is the only solution I've found for now.
You are erasing from your vector while looping over it. This changes the size of your vector which can often be a source of errors.
Take a look at Remove elements of a vector inside the loop for a way to do it instead.

Why this Interpolation search algorithm correctly works for only 1 digit values? ( does not work with key greater than 10)

#include <iostream>
#include <string>
using namespace std;
int main()
{
int arr[] = {1,3,5,7,9,11,13,15,17,19,21};
int first, last, pos, key;
first = 0;
last = (sizeof(arr)/ sizeof(arr[0])) - 1;
cout << "Enter the key value:\t" << endl;
cin >> key;
//The search code starts from here
while(first <= last && key >= first && key <= last) {
pos = first + (((last - first)/(arr[last] - arr[first])) * (key - arr[first]));
if(key < arr[pos]) {
last = pos - 1;
}
else if(key > arr[pos]) {
first = pos + 1;
}
else {
cout << "Found the value at index:\t" << pos << endl;
break;
}
}
//if the value is not found
if(first > last) {
cout << "The value is not found." << endl;
}
return 0;
}
This algorithm works from zero to 10. However, whenever I am inputting 11 or more, the code is somehow leaking which I am not able to figure out. I am new to programming, thus, I am facing some difficulty.
Thank you for your time.
The problem is that when you divide two integer values then if the first value (numerator) less then the second one (denominator) you'l get zero. Then you need to increase the value of numerator by doing multiplication first. Try to use this code:
pos = first + (last - first) * (key - arr[first]) / (arr[last] - arr[first]);
Or honestly use floating point calculations:
//The search code starts from here
while(first <= last && key >= first && key <= last) {
pos = (int)((double)first + (double)(last - first) * (double)(key - arr[first]) / (double)(arr[last] - arr[first]));
if(key < arr[pos]) {
last = pos - 1;
}
else if(key > arr[pos]) {
first = pos + 1;
}
else {
cout << "Found the value at index:\t" << pos << endl;
break;
}
}

2d vector incrementation error

I'm trying to create a simple minesweeper game, and have some issues with creating the board. I am using a 2d vector in lieu of a 2d array and am having trouble incrementing the tiles value to see how many mines are adjacent to the tile.
int Boardsize::createBoard() const {
// vector < vector<Tile> > board;
impl->board.resize(getLength(), vector<Tile>(getWidth(), Tile()));
for (int i = 0; i < getMines(); i++) {
int v1 = rand() % getLength();
int v2 = rand() % getWidth();
if (impl->board[v1][v2].getMine() == true) i--;
else {impl->board[v1][v2].setMine(true);
if (v1 - 1 > -1) impl->board[v1-1][v2]++;
if (v1 + 1 < getLength()) impl->board[v1+1][v2]++;
if (v2 - 1 > -1) impl->board[v1][v2-1]++;
if (v2 + 1 < getWidth()) impl->board[v1][v2+1]++;
if ((v1 - 1 > -1) && (v2 - 1 > -1)) impl->board[v1-1][v2-1]++;
if ((v1 - 1 > -1) && (v2 + 1 < getWidth())) impl->board[v1-1][v2+1]++;
if ((v1 + 1 < getLength()) && (v2 - 1 > -1)) impl->board[v1+1][v2-1]++;
if ((v1 + 1 < getLength()) && (v2 + 1 < getWidth())) impl->board[v1+1][v2+1]++;
}
}
}
Values length, width and mines are set ahead of time. The way I intend it to work is "Check if getMine = true, if yes then game over. If no, isRevealed is set to true and the tile shows how many mines are adjacent to the tile. However, I'm getting the error:
error: no 'operator++(int)' declared for postfix '++' [-fpermissive]|
Do I need to set a seperate function to increment the content? I am assuming that the board.resize fills the vector full of 0's.
I appreciate the help.
Here is the "Tile" file's contents:
namespace Minesweeper {
using namespace std;
class Tile::Tilement {
int status;
bool mine;
int Adjmines;
friend class Tile;
public:
Tilement ()
: status(0), mine(false), Adjmines(0)
{
}
};
Tile::Tile() {
cout << "Tile is being created" << endl;
}
Tile::~Tile() {
cout << "Tile is being deleted" << endl;
}
void Tile::setMine(int a) {
tint->mine = true;
}
void Tile::setStatus(int a) {
if ((a == 0) || (a == 1) || (a == 2)) {
tint->status = a;
}
else {
#ifdef DEBUG
cout << "Tile status invalid" << endl;
#endif // DEBUG
throw invalid_argument("Invalid tile status");
}
}
//void Tile::setContent(char r) {
// tint->content = r;
//}
int Tile::getStatus() const {
return tint->status;
}
char Tile::getAdjcount() const {
return tint->Adjmines;
}
char Tile::getMine() const {
return tint->mine;
}
int Tile::setAdjmines(int a) {
a = a++;
}
char Tile::getContent() const {
if (Tile::getMine() == true) {
return tint->mine;
}
else return tint->Adjmines;
}
EDIT: I've changed the incrementations a bit so that they're now like this:
if (v1 - 1 > -1) impl->board[v1-1][v2].incAdjmines; (etc).
And the incAdjmines function looks like this:
int Tile::incAdjmines() {
Adjmines = Adjmines + 1;
}
And...well, the code compiled, if nothing else, but due to some errors in another fragment of code, I can't tell if it works correctly. Thank you all for your help so far.
You are calling ++ on Tile object which seems with no overload for this operator.
You can solve your problem by overloading this operator for Tile class. Or by directly telling which variable you want to increase for example:
impl->board[v1-1][v2].cout_of_things++

Backtracking maze

I'm trying to write a maze solver using backtracking. It should see whether it's possible to solve a given puzzle from the starting point S to the end point E. The pseudo code can be seen in this link here. My implementation looks like this:
const int N = 8; // global var
bool exploreMaze(char maze[][N], int x, int y)
{
if(y >= 8 || y < 0 || x >= 7 || x < 0) // null char at end of each 1d array
return false;
if(maze[x][y] == '*')
return false;
if(maze[x][y] == 'E')
return true;
maze[x][y] = '*'; // set grid to '*' as to not loop infinitely
if(exploreMaze(maze, x + 1, y))
{
cout << "up" << ", ";
return true;
}
if(exploreMaze(maze, x - 1, y))
{
cout << "down" << ", ";
return true;
}
if(exploreMaze(maze, x, y - 1))
{
cout << "left" << ", ";
return true;
}
if(exploreMaze(maze, x, y + 1))
{
cout << "right" << ", ";
return true;
}
return false;
}
bool isMazeSolvable(char maze[][N])
{
int startX = -1, startY = -1;
for(int i = 0; i < N; i++)
{
for(int j = 0; j < N; j++)
{
if(maze[i][j] == 'S')
startX = i;
startY = j;
}
}
if(startX == -1)
return false;
return exploreMaze(maze, startX, startY);
}
int main()
{
char maze[N][N] = {"*******", " S ", "*******", " E ", "*******",
"*******", "*******", "*******"};
cout << isMazeSolvable(maze);
return 0;
}
The array that I'm testing in main should definitely have no solution, but somehow I'm getting 1(true) as the output. Any ideas?
Your maze '*' is only initialized out in the Y direction by 7 characters, but your maze walker checks out to 8 character. This allows it to walk around the end of your walls.
I added a quick maze print function and changed the exploreMaze to put '.' where it walks. Giving the following output:
Initial maze:
*******
S
*******
E
*******
*******
*******
*******
left, left, left, left, left, up, up, right, right, right, right, right, right,
1
After explore:
*******
.......
*******.
E.....
*******
*******
*******
*******
Soluton: Either change the initializer to use 8 character walls, or change the exploreMaze function to only look 7 characters in the Y direction.
Also note: You are not doing the "backtracking" part of the maze solver, because you mark where you have been but don't clean off your path on your way out of the recursion. Add
maze[x][y] = ' '; // Clear the grid so we can try this spot again in another recursion
to the end of your exploreMaze function