So, I'm writing a roguelike game in C++. But, its complaining about a class I made called "Player" in the file "player.h" in the file "monster". When I input into monster this function:

void attackplayer(Player& hero, bool checkup, bool checkdown, bool checkleft, bool checkright)
	{
		if (checkup == true || checkdown == true || checkleft == true || checkright == true)
		{
			hero.damage(damage);
		}
	}

with player.h included, it complains hero is of an error type, even though it is initialized as a player. How do I fix this? It used to complain it couldn't find the Player Identifier, but it seemed to fix itself on that.

Here is the build message:

1>  Simple Rogue
1>c:\users\gio\desktop\documents\c++ programs\2d & 3d games\roguelike game\roguelike game\monster.h(56): error C2061: syntax error : identifier 'Player'
1>c:\users\gio\desktop\documents\c++ programs\2d & 3d games\roguelike game\roguelike game\monster.h(58): error C2065: 'checkup' : undeclared identifier
1>c:\users\gio\desktop\documents\c++ programs\2d & 3d games\roguelike game\roguelike game\monster.h(58): warning C4805: '==' : unsafe mix of type ''unknown-type'' and type 'bool' in operation
1>c:\users\gio\desktop\documents\c++ programs\2d & 3d games\roguelike game\roguelike game\monster.h(58): error C2065: 'checkdown' : undeclared identifier
1>c:\users\gio\desktop\documents\c++ programs\2d & 3d games\roguelike game\roguelike game\monster.h(58): warning C4805: '==' : unsafe mix of type ''unknown-type'' and type 'bool' in operation
1>c:\users\gio\desktop\documents\c++ programs\2d & 3d games\roguelike game\roguelike game\monster.h(58): error C2065: 'checkleft' : undeclared identifier
1>c:\users\gio\desktop\documents\c++ programs\2d & 3d games\roguelike game\roguelike game\monster.h(58): warning C4805: '==' : unsafe mix of type ''unknown-type'' and type 'bool' in operation
1>c:\users\gio\desktop\documents\c++ programs\2d & 3d games\roguelike game\roguelike game\monster.h(58): error C2065: 'checkright' : undeclared identifier
1>c:\users\gio\desktop\documents\c++ programs\2d & 3d games\roguelike game\roguelike game\monster.h(58): warning C4805: '==' : unsafe mix of type ''unknown-type'' and type 'bool' in operation
1>c:\users\gio\desktop\documents\c++ programs\2d & 3d games\roguelike game\roguelike game\monster.h(60): error C2065: 'hero' : undeclared identifier
1>c:\users\gio\desktop\documents\c++ programs\2d & 3d games\roguelike game\roguelike game\monster.h(60): error C2228: left of '.damage' must have class/struct/union
1>          type is ''unknown-type''
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Recommended Answers

All 8 Replies

Please post the smallest compilable code that will produce this error. "undeclared identifier" in this case probably means that you didn't include the header file?

Dave

Full Monster.h Source:

#ifndef MONSTER_H
#define MONSTER_H

#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <string>
#include "Player.h"

class Monster
{
private:
	int xpgiven;
	int damage;
	int maxhp;
	int curhp;
	int defense;
	sf::Font MonsterFont;
	sf::String MonsterSprite;
	float height;
	float width;
	float ypos;
	float xpos;
	bool alive;
public:
	Monster(sf::Unicode::Text sprite, int damage, int maxhp, int xpgiven, int defense, float xpos, float ypos, bool running)
	{
		xpgiven = xpgiven;
		damage = damage;
		maxhp = maxhp;
		curhp = maxhp;
		defense = defense;
		if (!MonsterFont.LoadFromFile("Lucida Console.ttf", 12))
		{
			running = false;
		}
		MonsterSprite.SetFont(MonsterFont);
		MonsterSprite.SetSize(12);
		MonsterSprite.SetText(sprite);
		MonsterSprite.SetColor(sf::Color(192, 192, 192));
		MonsterSprite.SetPosition(xpos, ypos);
		height = 20.0;
		width = 13.0;
		xpos = xpos;
		ypos = ypos;
		alive = true;
	}
	int getxpgiven() {return xpgiven;}
	int getdamage() {return damage;}
	int getmaxhp() {return maxhp;}
	int getcurhp() {return curhp;}
	float getxpos() {return xpos;}
	float getypos() {return ypos;}
	float getheight() {return height;}
	float getwidth() {return width;}
	bool checklife() {return alive;}
	void attackplayer(Player& hero, bool checkup, bool checkdown, bool checkleft, bool checkright)
	{
		if (checkup == true || checkdown == true || checkleft == true || checkright == true)
		{
			hero.damage(damage);
		}
	}
	void statcheck()
	{
		if (curhp > maxhp)
		{
			curhp = maxhp;
		}
	}
	bool death()
	{
		if (curhp <= 0)
		{
			MonsterSprite.SetText(" ");
			alive = false;
			return true;
		}
	}
	void takedamage(int nValue)
	{
		curhp -= nValue - defense;
		death();
		statcheck();
	}
	void heal(int nValue)
	{
		curhp += nValue;
		death();
		statcheck();
	}
	void damagereduction(int nValue)
	{
		damage -= nValue;
	}
};

#endif

Please post the smallest compilable code that will produce this error.

:)

This is not just for fun - the idea is that it gets you to isolate the problem and hopefully solve it on your own!

So you are indeed including Player.h, so now we need to see the contents of Player.h

Dave

#ifndef PLAYER_H
#define PLAYER_H

#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <string>
#include "Monster.h"

class Player
{
private:
	int gold;
	int level;
	int curxp;
	int nextxp;
	int maxhp;
	int curhp;
	int maxstr;
	int curstr;
	sf::Font HeroFont;
	sf::String HeroSprite;
	float height;
	float width;
	float ypos;
	float xpos;
public:
	Player(float xpos, float ypos, bool running)
	{
		gold = 0;
		level = 1;
		curxp = 0;
		nextxp = 10;
		maxhp = 12;
		curhp = maxhp;
		maxstr = 16;
		curstr = maxstr;
		if (!HeroFont.LoadFromFile("Lucida Console.ttf", 12))
		{
			running = false;
		}
		HeroSprite.SetFont(HeroFont);
		HeroSprite.SetSize(12);
		HeroSprite.SetText("&");
		HeroSprite.SetColor(sf::Color(192, 192, 192));
		HeroSprite.SetPosition(xpos, ypos);
		height = 20.0;
		width = 13.0;
		xpos = xpos;
		ypos = ypos;
	}
	int getgold(){ return gold;}
	int getlevel(){ return level;}
	int getcurxp(){ return curxp;}
	int getmaxhp(){ return maxhp;}
	int getcurhp(){ return curhp;}
	int getmaxstr(){ return maxstr;}
	int getcurstr(){ return curstr;}
	float getxpos() { return xpos;}
	float getypos() { return ypos;}
	float getheight() { return height;}
	float getwidth() { return width;}
	void levelup()
	{
		if (curxp >= nextxp)
		{
			level++;
			nextxp = static_cast<int>(nextxp+nextxp/3);
			maxhp += sf::Randomizer::Random(1, 4);
			maxstr += sf::Randomizer::Random(1, 4);
		}
	}
	void moveleft(bool checkleft)
	{
		if (checkleft == false)
		{
			HeroSprite.Move(-13, 0);
			xpos -= 13;
		}
	}
	void moveright(bool checkright)
	{
		if (checkright == false)
		{
			HeroSprite.Move(13, 0);
			xpos += 13;
		}
	}
	void moveup(bool checkup)
	{
		if (checkup == false)
		{
			HeroSprite.Move(0, 20);
			ypos += 20;
		}
	}
	void movedown(bool checkdown)
	{
		if (checkdown = false)
		{
			HeroSprite.Move(0, -20);
			ypos -= 20;
		}
	}
	void statcheck()
	{
		if (curstr > maxstr)
		{
			curstr = maxstr;
		}
		if (curhp > maxhp)
		{
			curhp = maxhp;
		}
	}
	bool death()
	{
		if (curhp <= 0)
		{
			return false;
		}
	}
	void addgold(int nValue)
	{
		gold += nValue;
	}
	void addxp(int nValue)
	{
		curxp += nValue;
		levelup();
	}
	void addstr(int nValue)
	{
		maxstr += nValue;
		statcheck();
	}
	void addhp(int nValue)
	{
		maxhp += nValue;
		death();
		statcheck();
	}
	void damage(int nValue)
	{
		curhp -= nValue;
		death();
		statcheck();
	}
	void heal(int nValue)
	{
		curhp += nValue;
		death();
		statcheck();
	}
	void attackenemy(Monster enemy, bool checkup, bool checkdown, bool checkleft, bool checkright)
	{
		if (checkup == true || checkdown == true || checkleft == true || checkright == true)
		{
			enemy.takedamage(curstr);
		}
	}
};

#endif

First some design problem. This function is pretty bad :

void attackplayer(Player& hero, bool checkup, bool checkdown, bool checkleft, bool checkright){
 if (checkup == true || checkdown == true || checkleft == true || checkright == true){
	hero.damage(damage);
 }
}

First an obvious way to make this better is to use the boolean as boolean, no need
for conversions, thus you should just do this

void attackplayer(Player& hero, bool checkup, bool checkdown, bool checkleft, bool checkright)
{
	if (checkup || checkdown  || checkleft || checkright ){
		hero.damage(damage);
	}
}

But its still bad. Specifically, you have a variable for each direction. What you
should do is abstract the direction. So the param is just 1 Direction and in that
Direction it has left,right,up,and down states. So do Something like this :

struct Directions{
public:
	enum Dir{EAST,WEST,NORTH,SOUTH,SIZE};
private:
	bool dir[SIZE];
	Directions(){
		std::fill(dir,dir+SIZE,false);
	}
public:
	void east(bool r){ dir[EAST] = r; }
	void west(bool l){ dir[WEST] = l; }	
	void south(bool s){ dir[SOUTH] = s; }
	void north(bool n){ dir[NORTH] = n; }

	bool get(const Dir direction)const{
		return dir[direction];
	}
};

class Player{
private:
	Directions playerDirection;
public:
	void attackplayer(Player& hero,const Directions& dir){
		if(dir.get(dir.EAST) || dir.get(dir.WEST) || dir.get(dir.NORTH) || dir.get(dir.SOUTH)){
			/* Do stuff */
		}
	}
};

No that might look like a little more work, but end the end it will save you more trouble.

I agree with first person on that part.

As for the undefined symbol, I don't see anything obviously wrong. Again, you have posted 160 lines where probably 10 would do - I really suggest stripping everything down in a separate folder/project (just empty constructors basically) to try to isolate where the problem is coming from.

Here is an example of your problem :

//Player .h
#include "Monsters.h"
//...
//Monster.h
#include "Player.h"
//...

Your problem is called Circular Dependency
See if you can solve it on your own.

Thanks to all of you. I have updated my code with forward declaration and it worked fine. I also used FirstPerson's Suggestion for directions, which seems to be working well with my classes so far. I will also remember in the future to use smaller samples of code.;)

commented: I'm glad you learned something from this. Keep up the good work. +5
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.