|
Cedric Moonen wrote: add a variable in the base_class that specify which kind of object it is
This is what I was referring to in my comment.
This article[^] can expliain why I think its probably a bad idea better then I can here. The section on The Open Closed Principle is about such designs and why they're a bad idea.
Steve
|
|
|
|
|
Hi Stephen, thanks for the article, it was interesting.
I totally agree with you on that point but here, a part of the problem is solved by using a virtual ResolveCollision function. Still, there is a need to know with which entity the current entity is colliding with. So, typically what you suggest is the use of RTTI (getting the typeid of the class) ? This will 'separate' the base class from the implementations (a enum in the base class is not required anymore). Is that what you were thinking about ?
Thanks for your answer
PS: if I'm so interested, it's because I also develop a game in this style and I implemented in the way I described above. But I'm open to better suggestions
Cédric Moonen
Software developer
Charting control
|
|
|
|
|
I would not use any type of RTTI. First I'd think about the game. For example with collision detection in asteroids the following should be noted:
- Asteroids don't collide with each other.
- Bullets don't collide with each other.
These facts mean we don't have to check every pair of objects for collisions: we only need to test for the following collisions:
- Bullets with asteroids.
- Bullets with the enemy ships.
- Asteroids with asteroids.
- Your ship with asteroids.
- Your ship with bullets.
- Your ship with enemy ship.
These distinctions should be reflected in our design to minimize the amount of work we need to do to detect collisions.
I haven't thought it through, but I'd probably use multiple lists instead on one super list.
Steve
|
|
|
|
|
Stephen Hewitt wrote: I haven't thought it through, but I'd probably use multiple lists instead on one super list.
Mmmhh, I see a big restriction in that way of thinking: what happens if you want to add a new entity type, say 'bonus' (that gives you lives or new weapon) ? Then, you got a problem in your design because you have to manage a new list which can result in a lot of changes in the existing code...
Right now, what we are doing is that we have a factory that can create specific entities. The different entities register themselves in the factory at the program startup (in fact they register their name and a function that create one instance of the entity, so no need to modify the factoty when new entities are added, it's just map names to a creation function). So, if you want to create a new entity type, you just have to create the new class (and the creation function) and register it in the factory at startup and that's done ! No modifications in the rest of the code.
You will tel me: 'Ok, but to be used, these new entites needs to be created so you need to know if they exist or not'. In fact this step is not 'directly' required because the creation of the levels of the game is made through an editor. The editor retrieves the available entities from the factory and allow the end user to place them in the level (so, there also, there is no need to know these entities).
With your design, I see a flaw when you want to add new entity types that were not planned.
Stephen Hewitt wrote: These distinctions should be reflected in our design to minimize the amount of work we need to do to detect collisions.
It's perfectly doable with the method I exposed you: in the ResolveCollision of each entity type, it's up to you to take action on one or several 'collisions type'
PS: I don't want to prove you're wrong, but this is an interesting debate and I'm interested in your opinion.
Cédric Moonen
Software developer
Charting control
|
|
|
|
|
We'll stick with asteroids as that's the original topic. My original comment was against switching on object type, be it by using typeid , dynamic_cast or an enum in a base class. I don't think I need to go over this further given that the article I posted a link to explains it better than I could.
Now let’s get to the collision detection. As I pointed out you need not check for collisions between every pair of object as; for example, bullets can't collide with each other. If you've got n objects there are (n*(n-1))/2 = (n^2-n)/2 pairs to test: so it's probably a good idea to limit the size on n since the growth is quadratic. I admit in a game of asteroids, with today’s computers, you probably need not worry. I would probably use multiple lists as not every aspect of an objects behavior need be determined by it: some aspects can be controlled by its environment. For example, which container it's listed in. This need not be a limitation as you control which objects are added to which lists.
I don't want to get into too much of a debate however, as a lot of this is all theoretical. To really get into it we would need a concrete example to work with and spend some time analyzing it and then contrast different implementation strategies; that's a lot of work to win an argument.
Steve
|
|
|
|
|
Stephen Hewitt wrote: I don't think I need to go over this further given that the article I posted a link to explains it better than I could.
Yes sure,I agree. Thanks for article though.
Stephen Hewitt wrote: If you've got n objects there are (n*(n-1))/2 = (n^2-n)/2 pairs to test: so it's probably a good idea to limit the size on n since the growth is quadratic.
I solved this in another way: there are only three "teams": players (ship and bullets), ennemies (ships and bullets) and neutral (bonus, and other things that doesn't have any impact on the game). So, basically this reduce a lot the pairs of collisions. And anyway these 'Resolving collisions' are done in the derived classes themselves (so, you can neglected certain pairs).
Stephen Hewitt wrote: I don't want to get into too much of a debate however, as a lot of this is all theoretical
Yes sure. But anyway thanks for exposing your point of vue . I find this always interesting to see how other programmers solve design 'problems' (that's what I'm doing here also, just showing you how I do that, absolutely not saying that it's the best solution ). But I agree with you, we won't dig into more details as it requires a concrete example and some time to spend on it.
Cédric Moonen
Software developer
Charting control
|
|
|
|
|
Cedric Moonen wrote: I solved this in another way: there are only three "teams": players (ship and bullets), ennemies (ships and bullets) and neutral (bonus, and other things that doesn't have any impact on the game).
If you make a list of objects in each "team" you’re left with a similar architecture to what I was suggesting. Having a list for the members of each of the team means you can visit the members of a team without visiting every object in the "world".
Steve
|
|
|
|
|
HI,
u can use typeid operator for checking
for this u have to enable the Run Time Type Identification from Project options.
the following code snippet explain the operation
using dynamic_cast operator also u can accomplish this.
// expre_typeid_Operator.cpp
// compile with: /GR /EHsc
#include <iostream>
#include <typeinfo.h>
class Base {
public:
virtual void vvfunc() {}
};
class Derived : public Base {};
using namespace std;
int main()
{
Derived* pd = new Derived;
Base* pb = pd;
cout << typeid( pb ).name() << endl; //prints "class Base *"
cout << typeid( *pb ).name() << endl; //prints "class Derived"
cout << typeid( pd ).name() << endl; //prints "class Derived *"
cout << typeid( *pd ).name() << endl; //prints "class Derived"
delete pd;
}
-Sarath
|
|
|
|
|
I took a look at the doc. Ok that's fine but some actions need to be performed depending on the type of object. So, you need to compare the result from typeid to something. What will be this something ? Probably getting the class name from the clas info and compare it to a string:
if (strcmp(typeid(MyClass).name(),"CPlayerShip"))
{
}
I don't see really a major advantage on using a technique in which you manage the type of your class yourself (see my previous post). And honnestly, I found that ugly (but that's personal).
Any comment ? (I just explain my point of vue, I would like to have your ).
Cédric Moonen
Software developer
Charting control
|
|
|
|
|
You should compare the type_info objects returned by typeid , not the class names.
if ( typeid(myObj) == typeid(CPlayerShip)) {
}
The major advantage over managing the type of class by yourself is that you don't have to manage the class information by yourself
|
|
|
|
|
Ok, I didn't read carefully enough the doc . I didn't saw that you could pass the class to the typeid (typeid(CPlayerShip) ).
In that case that make sense. But I suppose there is also a drawback in enabling RTTI. Do you have any idea about that ?
Cédric Moonen
Software developer
Charting control
|
|
|
|
|
check whether this serve for ur purpose. enable RTTI.
class Base;
class Der: public Base;
class Der1: public Base;
Der * d1 = dynamic_cast<der*>(d); // ok
Base * b1 = dynamic_cast<base*>(d); // OK
Base * b2 = dynamic_cast<der1*>(d); // error
-Sarath
|
|
|
|
|
G_urr_A wrote: I was wondering if there is a way to determine what type of object the pointer is pointing at.
Is the typeid operator of any help?
"The largest fire starts but with the smallest spark." - David Crow
|
|
|
|
|
Well, as earlier posters have pointed out, dynamic_cast and typeid can be used to extract the information you want.
However, to me at least, when you need to do this (and presumably frequently for an astroids game) you might start asking if you have the best possible design.
I kind of liked the suggestion of the eariler poster about adding a function like "virtual bool ResolveColision (baseClass *)". Otherwise you could have a huge ugly mess of collision resolution between any 2 possible object types.
If you happen to just need to be able to get set of all asteroids in the game, why not keep around an extra container just for astroids (and one for ships, missles, etc). Then you can iterate through any specific object without messing with all the other object types you are not interested in.
|
|
|
|
|
I've ended up using typeid now.
And of course I'm using the best possible design. Not.
It's grown slightly too messy for my tastes by now, and it'll probably get worse.
The whole thing is a school project in which I have to cooperate with another guy. We've implemented support in some places for features that haven't been implemented, we did not think everything through before we started writing, and we don't really share a common concept of what OO is, so the code is quite messy. I'd love to rewrite the whole thing, but we're expected to present the stuff to our teacher this friday, and we're expected to understand all the code (he needs to understand "my parts"), and he's out of town, coming back thursday evening. So, a rewrite isn't an option right now.
But, thanks a lot to everyone for the input! We got my problem solved, and I got some other good info on what not to do next time. Now I just need to finnish this stuff...
|
|
|
|
|
Hmm.... Since I've already started a thread, I guess I might as well put it to good use...
I've implemented an ugly hack now.
In the code where I give bullets their position and speed, I first find the ship that fired them in ObjectList (which is the vector of *base_class that I've mentioned), then get some data from the ship object. The thing is, I need to access methods that are specific to the CShip class, but I've only got a pointer to base_class to handle it. What I do now is the following:
CShip *temp;
temp = (CShip*)(void*)ObjectList.at(i);
I cast to void* and then to the data type I need. Anything but this explicit casting produces errors, since the compiler doesn't realize that I've checked (using typeid) that what I'm handling is really a CShip object.
This solution is really ugly, IMO. There should be a good way to do this, but I can't figure it out (I'm kind of new to OO).
|
|
|
|
|
If you must use this technique use dynamic_cast instead. This design is poor: using a downcast is rarely needed and you should use virtual function instead.
Steve
|
|
|
|
|
Hi ppl,
The problem is error #10061 (WSAGetLastError()) with connect() when I am trying to connect to a host that behind a router. I have already port-forwarded it and shut the firewall off, still the host refuses the connection activly. Please help.
|
|
|
|
|
Well, the error says it all...;)
WSAECONNREFUSED
10061 No connection could be made because the target machine actively refused it.
Don't think you are, know you are...
custom hardware & software - olloc.be
|
|
|
|
|
Hi All,
I have a problem in timers....Actually I am using the OnTimer() function for one purpose (say keeping track of the list box added item ...only when some item is added) ....I want to use the same ontimer() for updating the "Current System Time" in the static text control also (where the timer will be always used not like the previous case ).... So is there any way to define two timers for the same dialog ....or anyother alternative..... or can anyone tell me how to use CALLBACK fuction in the setTimer() function for the solution of the same...
Thanks in Advance
With regards
Raja Bose
-- modified at 7:09 Wednesday 17th May, 2006
|
|
|
|
|
Create two timers with different ID. In the OnTimer function, the parameter supplied to the function is the ID of the timer which has 'finished'.
Cédric Moonen
Software developer
Charting control
|
|
|
|
|
Dear Raja,
u will get the value passing to nIDEvent (first parameter) of SetTimer function will receive at OnTimer Function as nIDEvent
so u can differentiate ur functionality through setting diferent event for timer
e.g:
#define UPDATE_LIST 1
#define UPDATE_STATIC 2
#define ELAPSE_TIME 200
// set timer to update list
SetTimer( UPDATE_LIST, ELAPSE_TIME, 0 );
// set timer to update static
SetTimer( STATIC, ELAPSE_TIME, 0 );
At OnTimer function
void OnTimer(UINT nIDEvent)
{
if(UPDATE_LIST == nIDEvent)
//update list
else if(UPDATE_STATIC == nIDEvent)
//update static
}
Hope it is clear
-Sarath
|
|
|
|
|
thank u Sarath ... it was working great ... Thank u for ur king help
With regards
Raja Bose
|
|
|
|
|
Hi out there !
I am currently writing a tab control view that allows for the dynamic appending of other CWnd* based widgets on each tab. On appending, a small header bar is assigned to each widget, which makes the widget collapsible, basically turning the widget into a rollout-like control.
The structure then is as follows :
CTabView (derived from CCtrlView)
|
|- CTab (derived from CScrollView)
|
|- CTabElement (derived from CWnd*)
| |
| |- CWnd* widget
|
|- CTabElement
| |
| |- CWnd* widget
|
The two things I am most concerned about are :
- Though I create the CTabElements with CTab as its parent, I need to manually call their OnPaint-methods in the OnDraw-Method of my CTab, shouldn't MFC do this automatically ?
- When scrolling sets in I am only able to properly update the original view content, i.e. the part of the screen that shows when the scroll position is (0,0).
Possibly those problems are closely related, but because I am pretty new to MFC, i have not yet managed to find the particalur point where I made the misstake.
Maybe someone can give me a hint,
thanks in advance,
Christian
|
|
|
|
|