Sign in to follow this  

Trying to design for a game

This topic is 3296 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

Hi. I'm using DarkGDK to make Pong. I have created an Object class that I want to be abstract. It will inherit every object I create. Dark GDK works with IDs, eg.
void dbLoadImage ( char* szFilename, int iImage )
iImage becomes a unique ID. So I made Object to help me create objects without worrying about the IDs. (the class will take care)
#ifndef DARK_OBJECT_H
#define DARK_OBJECT_H

#include "DarkGDK.h"

namespace DarkObject
{
	class Object // abstract
	{
	public:
		
	protected:
		static int imageID, spriteID;
	};

	class Rect2D : public Object
	{
	public:
		Rect2D(int x, int y, int width, int height);
		
		int GetX() const {return x;}
		int GetY() const {return y;}
		int GetWidth() const {return width;}
		int GetHeight() const {return height;}

		static int GetNumberOfRects() {return number_of_rects_created;}

	protected: // might be needed for inheritance, e.g. to create a square
		int x, y, width, height;

	private:
		static int number_of_rects_created;
	};
}

#endif // DARK_OBJECT_H

I think the Rect class is ok. But I need to work on the base class. 1. Rect doesn't use IDs because it doesn't need to. Other objects will use it. The problem is that spriteID for example is protected, so Rect can alter it and I don't like this. Is there a way to choose which classes will inherit the ID variables? If not, is it better to keep the ID variables private and have a function return a unique ID to each object? 2.
class Object // abstract
	{
	public:
		virtual void x() = 0;

	protected:
		static int imageID, spriteID;
	};
I also put it Rect (virtual void x(){}) If I change Object to this, I get: 'DarkObject::Rect2D' : cannot instantiate abstract class due to following members: 1> 'void DarkObject::Object::x(void)' : is abstract c:\users\user\documents\visual studio 2008\projects\pong\pong\darkobject.h(11) : see declaration of 'DarkObject::Object::x' I wrote a constructor for Object that does nothing but the errors I get are the same. I would like advice on how to fix the errors and on the design method I chose, thanks in advance.

Share this post


Link to post
Share on other sites
0)
	class Object // abstract
{
public:

protected:
static int imageID, spriteID;
};

Why are imageID and spriteID static? Each instance an object should have its own imageID and spriteID?

1) If it doesn't need the attributes of Object, why does it inherit from it?

2)
	class Object // abstract

{

public:

virtual void x() = 0;



protected:

static int imageID, spriteID;

};

Any class that you want to instantiate (create instances of) that inherits from another class which contains a pure virtual function, you have to implement the function in the derived class. Read C++ FAQ Lite: Pure Virtual Functions.

Share this post


Link to post
Share on other sites
Don't derive Rect2D from Object if it isn't an Object (e.g. it doesn't or shouldn't have the characteristics of Object). Any Object that needs to have a rectangle can simply contain one as a member variable. Also, you probably don't need rectangles to have unique image ID's...

Currently, your Object design is mostly useless, as it provides no interface, in fact, it provides nothing (if this is all the code, then it does not provide a unique ID either). The most common use for an abstract base class is so you can use a common interface for a group of objects, regardless of their exact type. If that's not what you're going for, then think twice if inheritance is really what you need here, and if you really need an empty Object class.


Also, the static integer 'number_of_rects_created' is not going to work very well, because besides a constructor, there is also a copy constructor that can be called when creating objects (in this case, 'Rect2D(const Rect2D& other)').

As for creating unique ID's, what about the following free function? Every object that needs an unique ID could ask for one:
int GetUniqueID()
{
static int uniqueID = 0;
uniqueID++;
return uniqueID;
}

Share this post


Link to post
Share on other sites
Your design method is dangerously close to overuse of object-oriented features.

Object-oriented programming is first and foremost used to reduce the amount of work required to perform a refactoring (for extensibility or reuse) later on, at the cost of slightly increased work right now. It becomes counter-productive to use object-oriented programming techniques once a certain threshold is reached: if the work you do right now takes longer than the work it would take to refactor from scratch later on, you're just wasting time for no reason.

Your Rect2D class, for instance, certainly seems like too much work, especially considering the simpler alternative:
struct rect2d {
float x, y, w, h;
rect2d(float x, float y, float w, float h) : x(x), y(y), w(w), h(h)
{ assert (w > 0); assert (h > 0); }
};


Or using an ad hoc readonly-assignable pattern:
struct rect2d_data {
float x, y, w, h;
rect2d_data(float x, float y, float w, float h) : x(x), y(y), w(w), h(h)
{ assert (w > 0); assert (h > 0); }
};

class rect2d {
rect2d_data impl;
public:
rect2d(float x, float y, float w, float h) : impl(x,y,w,h) {}
operator const rect2d_data&() const { return impl; }
};
None of the other features you have added to your class provide any interesting functionality to a Pong game. In particular, a rectangle doesn't have any relevant supertypes in the case of a Pong game, because there are no situations where you would want to treat a rectangle like a non-rectangle object. If such a situation appears, you will either use an adapter or implement an interface at that time.

Also, you don't really have to use generic "objects" from which you inherit: all things that are used to draw behave the same (they're an image and they are made to appear at a certain position) so no subclasses are needed, and all things which are drawn behave completely differently aside from the fact that they can be drawn, so you can use composition instead of inheritance.

Share this post


Link to post
Share on other sites
First, thanks for the replies. You are right, I complicate things.

Maybe something this simple?


class Block : public object
{
public:
Block(char *filename, int x, int y, int w, int h):x(x), y(y), w(w), h(h)
{

dbLoadImage(filename, ++imageID);
dbSprite(imageID, x, y, ++spriteID);
}

private:
int x, y, w, h;
static imageID, spriteID;
};



Do I have to increment imageID and spriteID in the copy constructor as well?

Share this post


Link to post
Share on other sites
Why did you throw out your 2D rectangle class? It makes perfect sense to write a class (or struct) for it, especially if you're frequently using rectangles. If every Object has it's own dimension, then you can simply give Object a Rect2D as a member variable.

Also, you still haven't fixed your Object class. Because imageID and spriteID are still static, there's only one of them total, not one per class instance. I understand that you want to use these to keep track of the next unique ID, but if you want each Object instance to have it's own unique ID, then you need to give them an ID of their own.


As for copy constructors, take a look at the following:
Object a;     // Default constructor is invoked here: Object()
Object b = a; // This is the same as Object b(a);,
// which invokes the copy constructor, Object(const Object& other)
So, yeah, if you only take care of making ID's unique in your constructor, then things will go wrong in the above case.


On a side-note, if you're using C++, it's better to use std::string instead of char*. If you need a char pointer, for example when calling library functions, you can use std::string's c_str() function. std::strings manage a strings memory for you and are generally safer and easier to use than char*'s. Just pass them by const reference (const std::string& filename) to avoid making a copy and you'll be fine.

Share this post


Link to post
Share on other sites

class Object
{
public:
Object(int x, int y): x(x), y(y){}

void move(int move_x, int move_y) {x += move_x; y += move_y;}
//virtual Object& operator() (int x, int y) = 0;

protected:
int x, y, w, h;

// return a unique ID to derived objects
int get_imageID() {return static_imageID++;}
int get_spriteID() {return static_spriteID++;}

private:
static int static_imageID, static_spriteID;
};



Constructor: I pass x and y<b/> as parameters. Derived classes will explicity assign w and h.
void move(int move_x, int move_y): moves the object on the x and y axis. It is the same for all classes.
operator(): Can I make it virtual? Or override it?

x, y, w, h: protected so all classes have them.
get_spriteID(), get_imageID(): return unique IDs to derived objects.

How can I make this class abstract? Can I set the () operator as virtual? Is there a way to make a class abstract without this: e.g. virtual void x() = 0; ?
abstract is a keyword in my compiler, how can I use it? Thanks in advance.

Share this post


Link to post
Share on other sites

This topic is 3296 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this