• 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
Irlan

About the Game Logic Class

23 posts in this topic

So, I've just figure out that my Actor Component Model is flawed by reading L. Spiro posts saying that the game logic handles all the logic of a Character/Player/Node (that actually make a lot of sense).

In my simple implementation I have a IBehaviour class that goes in the Actor class, but AI and Game Logic is supposed to be in a AI class (the Game class in that case). Do you think the following approach is +- correct?
 

class Character : public Behaviour
{
public:
enum StateMask
{
CHARACTER_CAN_JUMP,
CHARACTER_CAN_FLY
};

Character() : mask(0) { }

virtual void Update(Actor* _pActor)
{
if ( mask & CHARACTER_CAN_JUMP ) //just an example
{
//Do something with jump code
}
}
private:
bool mask;
};

class Game
{
public:

void Update()
{

for ( size_t i = 0; i < characters.size(); ++i )
{

if ( SOME_CONDITION )
{
characters[i]->SetMask( characters[i]->GetMask() | CHARACTER_CAN_JUMP ); //just an example
}

}

}
private:

std::vector characters;

};

class Actor
{
public:
void Update( const Time& _time )
{
pBehaviour->Update( this );
}
private:

IBehaviour* pBehaviour;
};

In this case, I'm removing all the Behaviour stuff and putting into the AI class (the Game class in this case).
Then, I'll pass all data related to the Game in a game_config.xml file. When detects a Character, it's added to be managed by it, and adds a new Actor to the Scene.

Whenever my Actor gets created/destroyed, I need to notify to the Game class to remove the pBehaviour, but by doing this, I'm going in the wrong side of the Single Responsability Principle. Now my Scene knows about the Game class (the AI class (the Game class in this case) ).

Any good advice will be instantaneously voted up.

Edited by Irlan
0

Share this post


Link to post
Share on other sites

Not a comment on your organization, but on the implementation of your state mask. It appears you're trying to implement a bitmask for character attributes with binary ORs ("|") not logical ORs ("||"). A more common implementation:

enum {CAN_JUMP = 1, CAN_FLY = 2, CAN_OTHER = 4, ...=8 }; // actual bit positions within the mask
...
unsigned int mask;

Remember, if you add enums beyond 2, without specifying the value, they will continue with 3, 4,... Those masks will be binary 0011, 0100, etc. What you appear to be doing would be better implemented by actual bitmasks for each bit position: 0001, 0010, 0100, 1000, etc.

2

Share this post


Link to post
Share on other sites

Not a comment on your organization, but on the implementation of your state mask. It appears you're trying to implement a bitmask for character attributes with binary ORs ("|") not logical ORs ("||"). A more common implementation:

enum {CAN_JUMP = 1, CAN_FLY = 2, CAN_OTHER = 4, ...=8 }; // actual bit positions within the mask
...
unsigned int mask;

Remember, if you add enums beyond 2, without specifying the value, they will continue with 3, 4,... Those masks will be binary 0011, 0100, etc. What you appear to be doing would be better implemented by actual bitmasks for each bit position: 0001, 0010, 0100, 1000, etc.

I know this. I posted without the binary format just to keep it simple.

Edited by Irlan
0

Share this post


Link to post
Share on other sites

Veering off topic, but...
 

I know this. I posted without the binary format just to keep it simple.

If you're using recent-ish versions ofGCC or Clang or using Visual Studio 2013 + November CTP, note that a simple trick is to use constexpr function as a shorthand to make spelling out these enums easier:
 
constexpr unsigned bit(unsigned index) { return 1 << index; }

enum class foo { None, A = bit(0), B = bit(1), C = bit(2), D = bit(0)|bit(3), E };
// None = 0x0000, A = 0b0000, B = 0b0001, C = 0b0010, D = 0b0101, E = 0b0110
I also recommend a macro to turn enum classes (strong enums) into flag-like objects:
 
#define MAKE_FLAGS(E) \
using E##_t = typename std::underlying_type<E>::type; \
constexpr E operator|(E lhs, E rhs) { return (E)((E_t)lhs | (E_t)rhs); } \
constexpr E operator&(E lhs, E rhs) { return (E)((E_t)lhs & (E_t)rhs); } \
constexpr E operator^(E lhs, E rhs) { return (E)((E_t)lhs ^ (E_t)rhs); } \
constexpr E operator|=(E& lhs, E rhs) { return lhs = lhs | rhs; } \
constexpr E operator&=(E& lhs, E rhs) { return lhs = lhs & rhs; } \
constexpr E operator^=(E& lhs, E rhs) { return lhs = lhs ^ rhs; } \
constexpr E operator~(E v) { return (E)(~(E_t)lhs); } \
constexpr bool isset(E bits, E mask) { return ((E_t)bits & (E_t)mask) != E_t{}; } \
constexpr void set(E& bits, E mask) { return bits |= mask; } \
constexpr void clear(E& bits, E mask) { return bits &= ~mask; }

MAKE_FLAGS(foo); // defines operators for foo and also a foo_t you can ignore

foo flags = foo::A | foo::C;
flags &= foo::A | foo::B;
if (isset(flags, foo::B))
  clear(flags, foo::B)
You can also accomplish the above with a template wrapper class instead of a macro, though then you end up with two different names: the wrapper name and the enum namespace name.

I have a bits.h that defines the macro, the helper functions like bit(), and so on. Lots of convenience and you can take advantage of the added safety of C++11 strong enums while still using them as convenient flag types.

 

 

Why don't you guys donate $5 bucks to get a up vote?

Just kidding...

Edited by Irlan
0

Share this post


Link to post
Share on other sites


Whenever my Actor gets created/destroyed, I need to notify to the Game class to remove the pBehaviour, but by doing this, I'm going in the wrong side of the Single Responsability Principle. Now my Scene knows about the Game class (the AI class (the Game class in this case) ).

 

Why is your scene destroying Actors?

0

Share this post


Link to post
Share on other sites

Not a comment on your organization, but on the implementation of your state mask. It appears you're trying to implement a bitmask for character attributes with binary ORs ("|") not logical ORs ("||"). A more common implementation:

enum {CAN_JUMP = 1, CAN_FLY = 2, CAN_OTHER = 4, ...=8 }; // actual bit positions within the mask
...
unsigned int mask;

See reply by SeanMiddleditch. Always prefer (1 << x), either hand-coded or via a macro or constant expression over raw numbers for bit-based enumerations. One of the things I would propose to the new C++ standard is to add bitenum { A, B, C }; to do this for us as it is very common.
 
 

In my simple implementation I have a IBehaviour class that goes in the Actor class, but AI and Game Logic is supposed to be in a AI class (the Game class in that case). Do you think the following approach is +- correct?

Although I said the game knows about the game logic, I suppose I was technically talking about each game states, not the Game class itself.
CMainMenuState and CCreditsState will have entirely different logic from CMainGameState, and indeed game logic could change between parts of the main game (see Sonic the Hedgehog 2 which mixed primitive 3D gameplay between its side-scrolling gameplay).
The game state is what decides the logic for each part of the game.


Other than that, what you are implementing is a state machine. You can swap behavior classes in and out of an actor and change how it behaves, so a single actor can have one of many “behaviors” at any given time. This is mostly useful for AI, not a player-controlled character (the human’s mind is the state machine that decides what behaviors to inflict upon his or her in-game persona). While it provides a fairly nice way to encapsulate various enemy behaviors, be warned that it can get tedious and possibly become spaghetti trying to code them all one-by-one as you figure out what code needs to moved around to avoid duplication etc.


The biggest problem with your implementation (I won’t get into the circular dependency, which I would solve by making IBehavior know about ActorBase rather than Actor, or make IBehavior know about Actor but only AIActor has an IBehavior, etc.) is that you are setting flags to indicate potentially valid states.
The only time you need to know if the player can jump is when the player tries to jump. In order to figure out “just in case” a player can jump you are doing some kind of ground test etc. every frame when 99% of the time that information isn’t needed on that frame.
Somewhere in the game logic (the state class that handles the main gameplay) there simply needs to be a boolean indicating, “Yes, the player can jump now,” or, “No, the player cannot jump now,” which is tested only when the player tries to jump, and immediately handled appropriately (not saved as a flag to be deferred for later processing).
Most (if not all) “can I perform this action” tests are done similarly, otherwise you will get a ridiculous explosion of state-setting tests which will invariably lead to bugs. While making Dolphin Trainer DS, my coworker tried to do this, and as a result there are out-lying cases where the dolphin would land back in the water after a jump but fail to correct its alignment and start swimming with its nose pointing down.

For this reason, while it was important to note that your enumerations were not actually bit masks, actually you can just get rid of it entirely.
Bit masks are more suitable for keeping track of character statuses. I don’t mean potential statuses such as “can jump” but currently active statuses such as “power jump is active”.


L. Spiro
1

Share this post


Link to post
Share on other sites

One of the things I would propose to the new C++ standard is to add bitenum { A, B, C }; to do this for us as it is very common.


I already tried floating that on the ISOCPP lists and it got shot down pretty quickly. Whether or not it would be favorably received by the committee proper is another story; someone would have to muster the energy and force of will to write a paper on it, submit it, and then defend it at the next official committee meeting (or find a champion if you can't travel there).

C++ is far more likely to get a std::bit constexpr function and maybe the template wrapper alternative to the MAKE_FLAGS macro.
0

Share this post


Link to post
Share on other sites

 

Not a comment on your organization, but on the implementation of your state mask. It appears you're trying to implement a bitmask for character attributes with binary ORs ("|") not logical ORs ("||"). A more common implementation:

enum {CAN_JUMP = 1, CAN_FLY = 2, CAN_OTHER = 4, ...=8 }; // actual bit positions within the mask
...
unsigned int mask;
See reply by SeanMiddleditch. Always prefer (1 << x), either hand-coded or via a macro or constant expression over raw numbers for bit-based enumerations. One of the things I would propose to the new C++ standard is to add bitenum { A, B, C }; to do this for us as it is very common.
 
 

In my simple implementation I have a IBehaviour class that goes in the Actor class, but AI and Game Logic is supposed to be in a AI class (the Game class in that case). Do you think the following approach is +- correct?

Although I said the game knows about the game logic, I suppose I was technically talking about each game states, not the Game class itself.
CMainMenuState and CCreditsState will have entirely different logic from CMainGameState, and indeed game logic could change between parts of the main game (see Sonic the Hedgehog 2 which mixed primitive 3D gameplay between its side-scrolling gameplay).
The game state is what decides the logic for each part of the game.


Other than that, what you are implementing is a state machine. You can swap behavior classes in and out of an actor and change how it behaves, so a single actor can have one of many “behaviors” at any given time. This is mostly useful for AI, not a player-controlled character (the human’s mind is the state machine that decides what behaviors to inflict upon his or her in-game persona). While it provides a fairly nice way to encapsulate various enemy behaviors, be warned that it can get tedious and possibly become spaghetti trying to code them all one-by-one as you figure out what code needs to moved around to avoid duplication etc.


The biggest problem with your implementation (I won’t get into the circular dependency, which I would solve by making IBehavior know about ActorBase rather than Actor, or make IBehavior know about Actor but only AIActor has an IBehavior, etc.) is that you are setting flags to indicate potentially valid states.
The only time you need to know if the player can jump is when the player tries to jump. In order to figure out “just in case” a player can jump you are doing some kind of ground test etc. every frame when 99% of the time that information isn’t needed on that frame.
Somewhere in the game logic (the state class that handles the main gameplay) there simply needs to be a boolean indicating, “Yes, the player can jump now,” or, “No, the player cannot jump now,” which is tested only when the player tries to jump, and immediately handled appropriately (not saved as a flag to be deferred for later processing).
Most (if not all) “can I perform this action” tests are done similarly, otherwise you will get a ridiculous explosion of state-setting tests which will invariably lead to bugs. While making Dolphin Trainer DS, my coworker tried to do this, and as a result there are out-lying cases where the dolphin would land back in the water after a jump but fail to correct its alignment and start swimming with its nose pointing down.

For this reason, while it was important to note that your enumerations were not actually bit masks, actually you can just get rid of it entirely.
Bit masks are more suitable for keeping track of character statuses. I don’t mean potential statuses such as “can jump” but currently active statuses such as “power jump is active”.


L. Spiro

 

Understood. Makes more sense. What have fucked everything is that an Interface (Behaviour) knows about a concrete type (Actor) that doesn't have nothing to do with.

 

class AIActor is a bag of behaviours. Actor can have a AIActor.

AIActor updates an Actor.

class AIActor
{
public:
    void Update(Actor* _pActor)
    {
         if ( !behaviours.empty() )
         {
            behaviours.top()->Update( _pActor );
         }
    }
private:
     std::stack<Behaviour*> behaviours;
};

Edited by Irlan
0

Share this post


Link to post
Share on other sites

 


Whenever my Actor gets created/destroyed, I need to notify to the Game class to remove the pBehaviour, but by doing this, I'm going in the wrong side of the Single Responsability Principle. Now my Scene knows about the Game class (the AI class (the Game class in this case) ).

 

Why is your scene destroying Actors?

 

Because manages them.

0

Share this post


Link to post
Share on other sites

class AIActor is a bag of behaviours.

I disagree. An AI can have at one time only one state/behavior.
There does not need to be a notification to the game state class that an actor has been deleted and so its behavior must be deleted.
Firstly, this can be achieved more easily via the simple use of smart pointers, but secondly it shouldn’t be done at all. The pool of behaviors doesn’t need to be released until the game state is over.


L. Spiro
2

Share this post


Link to post
Share on other sites

 

class AIActor is a bag of behaviours.

I disagree. An AI can have at one time only one state/behavior.
There does not need to be a notification to the game state class that an actor has been deleted and so its behavior must be deleted.
Firstly, this can be achieved more easily via the simple use of smart pointers, but secondly it shouldn’t be done at all. The pool of behaviors doesn’t need to be released until the game state is over.


L. Spiro

 

That's what I do.

The Scene (for instance) is initialized inside the Gameplay (A GameState) class.

 

Gameplay::Init()->Scene->Load()

Gameplay::Destroy()->Scene->ClearActors()

 

I'm not using a actor/behaviour pool yet. sad.png

Edited by Irlan
0

Share this post


Link to post
Share on other sites
Actors should be created and deleted on-the-fly as they are to come to exist in the game scene and when they are removed from it respectively.
Keeping around dead actors is nothing but overhead, if not in CPU usage then in memory, but typically both.


L. Spiro
1

Share this post


Link to post
Share on other sites

Actors should be created and deleted on-the-fly as they are to come to exist in the game scene and when they are removed from it respectively.
Keeping around dead actors is nothing but overhead, if not in CPU usage then in memory, but typically both.


L. Spiro

I know, I always use new/delete and I'm not talking about memory allocation because I have a lot of experience with it.

What I'm saying is the Scene create and delete (manages) all actors.

0

Share this post


Link to post
Share on other sites
Your game state doesn’t have pointers to actors. It accesses them through the scene manager(s).

(Do not make scene managers static, singletons, or otherwise “only one”. The game state class can make as many scene managers as it wants (even if most of the time there will be only one). Very useful for multi-perspective games. It was a pain in the ass when I had to make a golfing game with only one scene manager where the 3D golf world was overlayed by a 3D silhouette of a golfer in a totally different perspective and environment—a totally different setup from split-screen where there would still be only one scene but 2 cameras.)


L. Spiro
1

Share this post


Link to post
Share on other sites

Your game state doesn’t have pointers to actors. It accesses them through the scene manager(s).

(Do not make scene managers static, singletons, or otherwise “only one”. The game state class can make as many scene managers as it wants (even if most of the time there will be only one). Very useful for multi-perspective games. It was a pain in the ass when I had to make a golfing game with only one scene manager where the 3D golf world was overlayed by a 3D silhouette of a golfer in a totally different perspective and environment—a totally different setup from split-screen where there would still be only one scene but 2 cameras.)


L. Spiro

 

So, my Scene has a pointer to a main Actor?

If so when updating my Scene, I'll calculate the Camera (worldMatrix) values based on that Actor?

Why do you mean?

 

The only global that have is the main function, but I don't think I can make a Object. laugh.png

Edited by Irlan
0

Share this post


Link to post
Share on other sites

So, my Scene has a pointer to a main Actor?

No.
Currently your Game class has std::vector characters. This belongs in the scene manager.


L. Spiro

1

Share this post


Link to post
Share on other sites

 

So, my Scene has a pointer to a main Actor?

No.
Currently your Game class has std::vector characters. This belongs in the scene manager.


L. Spiro

 

My scene has actors and characters or by character you mean an actor?

My scene just need  to know about an actor isn't?

0

Share this post


Link to post
Share on other sites

Every actor in the game, be it a character or otherwise, is managed by the scene manager.
I mean what I said in the last post: Your Game class example has a member called “std::vector characters”.  It’s pseudocode so I don’t know what the vector actually contains, but I would assume it is an array of Actor * (why would Character inherit from Behavior instead of Actor? A Character is an Actor).

 

To be clear: a Character is a form of actor and should inherit from Actor.

SceneManager should have std::vector<Actor *> m_vActors, which is an array of all characters/actors in the scene.

 

 

L. Spiro

1

Share this post


Link to post
Share on other sites

Every actor in the game, be it a character or otherwise, is managed by the scene manager.
I mean what I said in the last post: Your Game class example has a member called “std::vector characters”.  It’s pseudocode so I don’t know what the vector actually contains, but I would assume it is an array of Actor * (why would Character inherit from Behavior instead of Actor? A Character is an Actor).

 

To be clear: a Character is a form of actor and should inherit from Actor.

SceneManager should have std::vector<Actor *> m_vActors, which is an array of all characters/actors in the scene.

 

 

L. Spiro

That's what I do. The single responsability of my scene is to manage actors. It manages a array of actor. I was thinking that inheriting from an Actor was a bad idea (using composition over inhertance), but if my Character is an Actor, it'll make the scene a lot more easier to manage.

0

Share this post


Link to post
Share on other sites

Every actor in the game, be it a character or otherwise, is managed by the scene manager.
I mean what I said in the last post: Your Game class example has a member called “std::vector characters”.  It’s pseudocode so I don’t know what the vector actually contains, but I would assume it is an array of Actor * (why would Character inherit from Behavior instead of Actor? A Character is an Actor).

 

To be clear: a Character is a form of actor and should inherit from Actor.

SceneManager should have std::vector<Actor *> m_vActors, which is an array of all characters/actors in the scene.

 

 

L. Spiro

class Character : public Actor
{
public:     virtual void Update(const Time& _time)
     {
          isActive = maxLives < 0;
     }private:     int maxLives;};

class Scene
{
public:
     void Update(const Time& _time)
     {
          for each actor, update him!
          update camera!
     }
private:
     Camera *m_pActiveCamera;
     std::vector<Actor *> m_vActors;};

class Game
{
public:

private:
     Character *pCharacter; // main character
     //(...)
};

There is a bunch of things that I won't post, but I think you got it.

Now I need a way of handling the pCharacter pointer in the game class when gets removed of the scene without using smart pointers.

Edited by Irlan
0

Share this post


Link to post
Share on other sites

You could simply use a message / notification system to alert subscribers that their state is now invalid. This could be something as simple as o

MessageSystem->NotifySubscribers<CharacterDestroyedMessage>();

However, it does seem to me that the AI behaviour should be a component of an entity, rather than a standalone system from the entity system. If this is the case, then removing any behaviour components should remove the entity from the system. It doesn't seem sensible to store a pointer to the "Main" character, as that is subjective to the point of development, and will force you to produce code that is inflexible to future design change.

Edited by Angus Hollands
0

Share this post


Link to post
Share on other sites

You could simply use a message / notification system to alert subscribers that their state is now invalid. This could be something as simple as o

MessageSystem->NotifySubscribers<CharacterDestroyedMessage>();

However, it does seem to me that the AI behaviour should be a component of an entity, rather than a standalone system from the entity system. If this is the case, then removing any behaviour components should remove the entity from the system. It doesn't seem sensible to store a pointer to the "Main" character, as that is subjective to the point of development, and will force you to produce code that is inflexible to future design change.

 

I'm not using any kind of Event/Message/Notification/Signal System in my in-house game engine. This should be avoided as much as possible in this type of applications.

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