• Advertisement
Sign in to follow this  

Conscious Classes

This topic is 4352 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

So I've been wittling away at some errors I've been getting and have to come to a conclusion finally, but I'm not completely sure how to solve it. Let me explain my predicament. I am creating my first 2d scroller. I have a header file I've completed with two classes in it. The base class of the two is the primitive class, which basically just holds the vertices and controls the texture placement. Then I have a character class which holds the more specific information like the type of player (player, enemy, allie), health, etc etc. My problem stems from the fact that the primitive class constructor takes a pointer to the character class. While this is all fine and dandy, the character class must create an instance of the primitive class to work with. This means that the primitive class must know of the character class and vice versa. Since they are in the same file this obviously can't happen. Initially I had them in seperate header files but I had to include the other for each to work and that made c++ throw errors stating that the class had already been defined. Is there a way to make the classes "aware" of each other? Here is the code of the two classes (Very messy and primordial at this point)
class CCharacter {

	public:

		CCharacter::CCharacter(LPDIRECT3DDEVICE8 paramD3DDevice) {
				
				CPolygon = new CPrimitive(paramD3DDevice, this);

				Sprite_Frames = new CFrames;

				CPolygon->Set_Size(100.0f, 100.0f);
				CPolygon->Set_Position(100.0f, 100.0f, 1.0f);
				CPolygon->Set_Color(100, 100, 100);

				CPolygon->CreateVertexBuf();

		}


		void CCharacter::SetDimensions(float DimensionValue, int Dimension) {

			switch(Dimension) {
				case WIDTH:

					width = DimensionValue;

				break;
				case HEIGHT:

					height = DimensionValue;

				break;
			}

		}

		float CCharacter::GetDimension(int Dimension) {

			switch(Dimension) {
				case WIDTH:

					return width;

				break;
				case HEIGHT:

					return height;

				break;
			}

			return 0.0f;

		}

		void CCharacter::SetPosition(float SentPosition, int Axis) {

			switch(Axis) {
				case X_AXIS:

					x_position = SentPosition;

				break;
				case Y_AXIS:

					y_position = SentPosition;

				break;
				case Z_AXIS:

					z_position = SentPosition;

				break;
			}

		}

		float CCharacter::GetPosition(int Axis) {

			switch(Axis) {
				case X_AXIS:

					return x_position;

				break;
				case Y_AXIS:

					return y_position;

				break;
				case Z_AXIS:

					return z_position;

				break;
			}

			return 0.0f;

		}

		void CCharacter::SetCharacterType(char* IAm) {

			CharacterType = IAm;

		}

		char* CCharacter::GetCharacterType(void) {

			return CharacterType;

		}


		void CCharacter::SetHealth(int SentHealth) {

			Health = SentHealth;

		}

		int CCharacter::GetHealth(void) {

			return Health;

		}

		void CCharacter::SetDamagePoints(int SentDamage) {

			Damage = SentDamage;

		}

		int CCharacter::GetDamagePoints() {

			return Damage;

		}

		void CCharacter::HurtCharacter(int Force) {

			Health = Health - Force;

		}

		void CCharacter::SetTexture(char* TexturePath, int Columns, int Rows, int TotalSprites, int SpriteFPS) {

			CPolygon->SetTexture(TexturePath);
			this->SpritesTotal = TotalSprites;
			this->TextureColumns = Columns;
			this->TextureRows = Rows;
			this->FPS = SpriteFPS;

		}

		void CCharacter::SetTextureCoordinates(char* ActionName, float StartX, float StartY, float EndX, float EndY) {

			Sprite_Frames->Add(ActionName, StartX, StartY, EndX, EndY);
			
		}

		void CCharacter::DrawSprite() {

			CPolygon->SetVertexAndRender();

		}

	private:

		CPrimitive* CPolygon;
		CFrames* Sprite_Frames;

		char* CharacterType, CharacterName;
		int CurrentFrame, FPS;
		int Health, Damage;
		float x_position, y_position, z_position;
		float width, height;

		int SpritesTotal, TextureRows, TextureColumns;


};


class CPrimitive {

	public:

		float myWidth, myHeight;
		float myX, myY, myZ;

		CPrimitive::CPrimitive(LPDIRECT3DDEVICE8 paramD3DDevice, CCharacter ChPtr) {
			
			myD3DDevice = paramD3DDevice;				//Retrieve D3D Device
			myTexture = NULL;

		}

		HRESULT CPrimitive::CreateVertexBuf() {

			if(FAILED(myD3DDevice->CreateVertexBuffer(4 * sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &myVertexBuf)))	{
				
				return E_FAIL;

			} else {

				return S_OK;

			}

		}

		HRESULT CPrimitive::SetVertexAndRender() {

			VOID* pVertices;

			CUSTOMVERTEX cvVertices[] =	{

				{myX, myY + myHeight, myZ, 1.0f, D3DCOLOR_XRGB(myRed, myGreen, myBlue), 0.0f, 1.0f},
				{myX, myY, myZ, 1.0f, D3DCOLOR_XRGB(myRed, myGreen, myBlue), 0.0f, 0.0f},
				{myX + myWidth, myY + myHeight, myZ, 1.0f, D3DCOLOR_XRGB(myRed, myGreen, myBlue), 1.0f, 1.0f},
				{myX + myWidth, myY, myZ, 1.0f, D3DCOLOR_XRGB(myRed, myGreen, myBlue), 1.0f, 0.0f},

			};
			
			//Get a pointer to the vertex buffer vertices and lock the vertex buffer
			if(FAILED(myVertexBuf->Lock(0, sizeof(cvVertices), (BYTE**)&pVertices, 0))) {
			
				return E_FAIL;

			}

			//Copy our stored vertices values into the vertex buffer
			memcpy(pVertices, cvVertices, sizeof(cvVertices));
			
			//Unlock the vertex buffer
			myVertexBuf->Unlock();

			Render();

			return S_OK;

		}

		HRESULT CPrimitive::Render() {

			myD3DDevice->SetStreamSource(0, myVertexBuf, sizeof(CUSTOMVERTEX));
			myD3DDevice->SetVertexShader(D3DFVF_CUSTOMVERTEX);
			myD3DDevice->SetTexture(0, myTexture);
			myD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);

			return S_OK;

		}

		void CPrimitive::Set_Size(float width, float height) {

			myWidth = width;
			myHeight = height;

		}

		void CPrimitive::Set_Position(float nextX, float nextY, float nextZ) {

			myX = nextX;
			myY = nextY;
			myZ = nextZ;

		}

		void CPrimitive::Set_Color(int Red, int Green, int Blue) {

			myRed = Red;
			myGreen = Green;
			myBlue = Blue;

		}

		bool CPrimitive::SetTexture(const char *TexturePath) {
			
			//if(FAILED(D3DXCreateTextureFromFile(myD3DDevice, TexturePath, &myTexture))) { return false; }
			
			//D3DCOLOR colorkey = 0xFFFF00FF;

			if (FAILED(D3DXCreateTextureFromFileEx (myD3DDevice, TexturePath, 0, 0, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_FILTER_NONE, D3DX_DEFAULT, NULL, NULL, NULL, &myTexture))) {

				return false;

			}

			return true;

		}

		struct CUSTOMVERTEX
		{
			FLOAT x, y, z, rhw;
			DWORD colour;
			FLOAT u, v;
		};

	private:

		int myRed, myGreen, myBlue;
		//int winWidth, winHeight;

		LPDIRECT3DVERTEXBUFFER8 myVertexBuf;
		LPDIRECT3DDEVICE8 myD3DDevice;
		LPDIRECT3DTEXTURE8 myTexture;
		
};

Here are the errors I receive that lead me to believe this:
c:\multimedia\programming\projects\pong 2\classes.h(22) : error C2143: syntax error : missing ';' before '*'
c:\multimedia\programming\projects\pong 2\classes.h(22) : error C2501: 'CPrimitive' : missing storage-class or type specifiers
c:\multimedia\programming\projects\pong 2\classes.h(22) : error C2501: 'CPolygon' : missing storage-class or type specifiers
c:\multimedia\programming\projects\pong 2\classes.h(23) : error C2143: syntax error : missing ';' before '*'
c:\multimedia\programming\projects\pong 2\classes.h(23) : error C2501: 'CFrames' : missing storage-class or type specifiers
c:\multimedia\programming\projects\pong 2\classes.h(23) : error C2501: 'Sprite_Frames' : missing storage-class or type specifiers


Another example of what I mean can be seen with the CFrames class above, which is defined further down the header file than these two classes, so they cant apparently reference it. Now I suppose the obvious solution to my problem would be to just let the character class control the primitive class directly, but I am trying to make this as elegant as possible(Although Im sure it doesnt look that way at this point). I hope this makes sense to everyone. Thanks for the help in advance! [Edited by - Run_The_Shadows on March 28, 2006 9:11:11 PM]

Share this post


Link to post
Share on other sites
Advertisement
I just fixed your post, the source tag should be used instead of the code tag.
Also, it's generally a good idea to declare a class and it's members in a header, then define them in an actual CPP file, makes navigating the two much much easier.

Now that things are clean, let me take a look at your code and see if I spot anything obvious.

Also, any time you have two headers mutually reliant upon each other, you're probably doing something wrong, or at least in a way that's not efficient.

Share this post


Link to post
Share on other sites
Yeah, thats how I originally had it, but it was getting really confusing with all of the includes in every file I had to do and it was causing me a lot of headache so I combined them and here I am, most likely I'll go back to that once I get these things sorted out

Share this post


Link to post
Share on other sites
Quote:
Original post by jrmiller84
Yeah, thats how I originally had it, but it was getting really confusing with all of the includes in every file I had to do and it was causing me a lot of headache so I combined them and here I am, most likely I'll go back to that once I get these things sorted out


To make this a lot easier to bugshoot, really quickly split them up more like this:
CCharacter.hpp

class CCharacter
{
public:
...
private:
...
};




CCharacter.cpp

#include "CCharacter.hpp"
CCharacter::funcname()
{

}
...
...




Then post the full HPP file. I can't tell whether you're including the other necessary headers/making declarations/etc from what you've posted. It looks like because CPrimitive is defined after CCharacter, in this case, when you try to use CPrimitive in CCharacter, the compiler doesn't know what's going on.

Share this post


Link to post
Share on other sites
Yeah, do as Shadow said and divide your classes into separate header and source files; will make things much easier.

To solve your problem with the headers linking each other, you can do a sort of prototyping with classes that's handy in these kinds of cases. For example:

class NeedThisClass;

class AnotherClass
{
...
};
That way, AnotherClass knows what NeedThisClass is without it being defined. However, in order for this to work NeedThisClass has to be defined at some point along the build of your program. And that should do what you need.

Share this post


Link to post
Share on other sites
You can use a forward declaration, as long as one class only ever needs pointers or references to objects of the second class:

// A.h
class StuffINeed; // Forward declaration

class ObjectA
{
public:
StuffINeed* GetSomeStuff();
};


// B.h

#include "A.h"

class StuffINeed
{
private:
ObjectA ThingIHaveForSomeReason;
};



However, as Run_The_Shadows has mentioned, circular references are usually a bad sign. In your case, you can probably fix things up by separating the graphics portion into a CCharacterGraphics class, and having each character hold an CCharacterGraphics object, which takes care of texture, polygons, etc. The graphics object itself should have no need to know about the CCharacter that holds it; it should just draw graphics on the screen.

Share this post


Link to post
Share on other sites
If I know what you're talking about, which I think I am, use prototypes.
class CPrimitive;
class CCharacter;

class CPrimitive
{
...
};

class CCharacter : public CPrimitive
{
...
};

Share this post


Link to post
Share on other sites
Ahh yes, that is what I meant. Now that I know that I can clean this up and split them into files. Reason I combined them was to troubleshoot this problem in the first place and thats what lead me to realizing they werent aware of each other no matter which orientation I had them. Thanks guys, you're always a help here!

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement