• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
zdlr

Game Entity Organization

6 posts in this topic

I am returning to a bit of game development after about five years away. Back then, I was lucky enough to get a job without having a portfolio of samples. However, I always started something and never really saw it through. Now that I am an experienced developer (albeit, with the bulk of my career spent in C#) I decided I would try to complete something fairly simple. The first thing I am creating is Pong, probably the simplest thing that I could think of. I am using C++ and DirectX and trying to write much of it myself - while I am relying heavily on STL and Boost, I'm not using middleware for physics, etc.

Enough setup- the question I have is around organizing two types of entities: drawable entities and collidable entities. I have a renderer interface: IRenderer and then an implementation called DXRenderer which is for DirectX 10.1. This isn't for runtime late binding purposes (the projects in which they reside are static libs, not dlls) but for separation of concerns purposes. My Game class (from which I have a Pong subclass) accepts an IRenderer* and registers with it IDrawable*s. Per frame, IRenderer iterates through all of its IDrawables and - if they are not hidden - the renderer calls IDrawable::Draw(IRenderer* pRenderer), passing itself it.

Now, this achieves a fairly pleasant separation of concerns, but I'm now a bit worried about the amount of work I've just created for myself. So far, I have only two IDrawable implementations: StringDrawable and RectangleDrawable. IRenderer thus has two methods corresponding to these: IRenderer::DrawFIlledRectangle(...) and IRenderer::DrawString(...). The two issues here are: having to add another method almost per IDrawable interface, and having to open up each method sufficiently to support a plethora of rendering options (so far, you can't even choose what color you want to render the rectangle or string - it's just a black brush from d2d).

The second issue is pretty similar, in that it's about me painting myself into a bit of a designerly corner. The Game class has a CollisionDetector, into which games can register ICollidable objects. Per frame, the CollisionDetector iterates through all of the moving objects and checks if they have collided with something (ie: it iterates through everything else per object, this feels a wee bit heavy-handed, but is in no way slowing things down so far- still takes <1ms per frame). ICollidables only support bounding Rectangles at the moment, so one issue is how I would be able to support multiple types of bounding shape (well, for Pong I only really need rectangles and circles, but still...) The next issue is about how I go about responding to a collision. CollisionDetector retrieves the bounding rectangle of two ICollidables and finds their intersecting Rectangle, if one exists. I then pass the primary object the intersecting rectangle and a pointer to the ICollidable that it hit.

If we take the example of the player's paddle moving vertically in the playing area, I have created two Wall objects: _floor and _ceiling. These are ICollidables. Currently, Paddle::Collided(...) is called and the top of intersecting rectangle is the same as the top of the Paddle, then I "know" we're in the _ceiling and need to move down the same distance as the intersecting rectangle's height. Conversely, if Paddle::Collided(...) is called and the bottom of the intersection is equal to the bottom of the Paddle, the I "know" we're in the _floor and need to move the Paddle up the same distance as the intersecting rectangle's height. Clearly, this is not going to apply to many more scenarios. Eventually, I'm going to have to pass more context into the Collided(...) method, or request it from ICollidables.

Also, I'm not too happy about doing Euler integration on the velocity to get the position of the paddle, but something like RK4 is going to be massive overkill until I can justify it. I'm doing this on evenings and at weekends in between the myriad responsibilities I have, so each change I make can't really take more than an hour without seeing some tangible results. However, is this kind of 'corrective' collision detection still the norm? Ie: after the Game's Update method is called, objects have already intersected so enact some kind of restorative hack to make things look right. I far prefer the idea of predictively detecting collisions, but I guess that's also overkill for now. I do (eventually) wish to make more than just Pong with this framework, though, which is why I'm going to so many pains as to make things extensible and `neat`.

Thanks, and apologies for the rambling wall of text.

-Edit: Here's some code to illuminate what I'm talking about-

[CODE]
// Update loop in my Game base class
void Game::Loop(double time)
{
Update(time);
_collisionDetector.TestForCollisions();
_pRenderer->RenderFrame(time);
}

// Renderer iterates through IDrawable*s and asks them to draw themselves...
void IRenderer::RenderFrame(double time)
{
std::for_each(this->_vpDrawables.cbegin(), this->_vpDrawables.cend(), boost::bind(&DrawDrawable, _1, this, time));
}

void DrawDrawable(const IDrawable* pDrawable, IRenderer* pRenderer, double time)
{
pDrawable->Draw(pRenderer, time);
}

// I need an implementation of IDrawable for everything that can be drawn. At the moment, all I can do is render black filled rectangles...
void RectangleDrawable::Draw(IRenderer* pRenderer, double time) const
{
if(!Hidden)
pRenderer->FilledRectangle(_position.Left, _position.Top, _position.Right - _position.Left, _position.Bottom - _position.Top);
}

//...and black strings:
void StringDrawable::Draw(IRenderer* pRenderer, double time) const
{
if(!Hidden)
pRenderer->String(_position.X, _position.Y, _text);
}

//To use this in a game, I need to register something as drawable:
Pong::Pong(float width, float height, IRenderer* pRenderer) :
Game(pRenderer),
_screenExtents(width, height),
_playArea(width*.05f, height*.05f, width*.95f, height*.95f),
_floor(Math::Rectangle<float>(.0f, height*.95f, width, height)),
_ceiling(Math::Rectangle<float>(.0f, .0f, width, height*.05f)),
_playerLeft(width*.05f, height*.05f),
_playerRight(width*.95f, height*.05f)
{
AddDrawable(&_playerLeft);
AddDrawable(&_playerRight);
AddCollidable(&_playerLeft);
AddCollidable(&_playerRight);
AddCollidable(&_floor);
AddCollidable(&_ceiling);
}

//This does mean that Player is IDrawable, but it just delegates to its components, which will (in turn) delegate to either RectangleDrawable or StringDrawable, of which they are composed:
void Player::Draw(IRenderer* pRenderer, double time) const
{
_paddle.Draw(pRenderer, time);
_score.Draw(pRenderer, time);
}
[/CODE]

Collision detection is much the same story:

[CODE]
// I'm sure this is going to be hugely inefficient at some point:
void CollisionDetector::TestForCollisions()
{
for(CollidableCollection::iterator i(_vpCollidables.begin()); i!=_vpCollidables.end(); ++i)
{
if((*i)->IsMoving())
{
for(CollidableCollection::iterator j(_vpCollidables.begin()); j!=_vpCollidables.end(); ++j)
{
if((*i) != (*j)) // don't test for collisions between ourselves
{
Rectangle<float> intersection;
if((*i)->GetBounds().GetIntersect((*j)->GetBounds(), intersection))
{
(*i)->Collided((*j), intersection);
}
}
}
}
}
}

// As we saw before, Player implements ICollidable, but again it delegates to components:
void Player::Collided(ICollidable* pCollidable, const Math::Rectangle<float>& intersection)
{
_paddle.Collided(pCollidable, intersection);
}

// Paddle handles the collision, but this also feels like I'm doing only what will work for this specific case - I've tried to design a general solution but there is still too much knowledge that is apropos of nothing:
void Paddle::Collided(ICollidable* pCollidable, const Math::Rectangle<float>& intersection)
{
const Rectangle<float>& position(_position.GetBounds());
if(intersection.Top == position.Top)
{
// we have intersected with the ceiling, move down...
_position.Move(.0f, intersection.Bottom - intersection.Top);
}
else if (intersection.Bottom == position.Bottom)
{
// we have intersected with the ceiling, move up...
_position.Move(.0f, intersection.Top - intersection.Bottom);
}
}
[/CODE]
0

Share this post


Link to post
Share on other sites
You should investigate component-based entities. The idea is to split up the responsibilities of an object into separate components that can be handled by different 'manager' objects. It's very powerful and flexible.

For your collision detection question, I advise against moving objects THEN detecting collisions. I would calculate the next-frame positions for all objects then look for collisions and adjust those positions accordingly.

You should also consider (re)writing your renderer for DX11, because this is backwards compatible with DX10 and 10.1 (being a superset of their functionality). When you create the device you can command it to only support DX10.1 functionality, so the game runs on DX10.1 hardware.
0

Share this post


Link to post
Share on other sites
The reason for not targeting DX11 is that interoping DX11 with D2D looks like a bit of a nightmare. There was a couple hoops to jump through with 10.1, and I understand it is even worse with 11. However, I guess that once the initialization is done, I don't really need to think about it again.

Is the next-frame position of an object just assuming that the frame delta is going to be exactly the same as the current frame? That sounds... imprecise?

I have split up my entities into components - the Player is composed of a Paddle (as well as a score and other such stuff) and the Paddle is IColllidable and IDrawable. The IDrawable delegates to a RectangleDrawable, which basically adapts my Math::Rectangle to also implement IDrawable. I don't have too much problem with how they are separated, I just wonder if I've perhaps gone an indirection too far? Maybe RectangleDrawable doesn't need to be given an IRenderer to which it `describes` itself. Perhaps, instead, I could just pass in to the RectangleDrawable an ID2DRenderTarget. My obvious grip with this being that, while my game entities are unaware of DX, their components are now wedded to it. Might prevent me having to effective facade DX, though...
0

Share this post


Link to post
Share on other sites
Ahhh, to me - that's a criticism sandwich! Still, tasty. Really appreciate that response, uglybdavis. I will read and digest that post. It seemed like a smell to have to implement those interfaces, so I'm glad my intuition was correct.
0

Share this post


Link to post
Share on other sites
I read bad things about the performance of D2D. To be honest, I never recognised the niche it occupies - want fast 2D graphics? Use D3D. I bet you could easily render an entire pong game in a single DrawIndexed with D3D11.

P.s. Pickles and mustard in the same sandwich? Madness
0

Share this post


Link to post
Share on other sites

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  
Followers 0