Sign in to follow this  
Heelp

How to check for all possible collisions (architecture)?

Recommended Posts

Guys, I realize that I ask about too much stuff these days, but internship deadlines are coming and I need to send some games. It's a decent excuse.

 

My problem is that I can't come up with a good way to code my shoot() function in my Player class.( 3d fpshooter )

 

What I need is to somehow say: if the player has clicked on the left mouse button, check if the ray that goes out straight from his crosshair has intersected with an enemy object, and if it is, inform the monster who was hit that he needs to die in hell (or to decrease hp).

 

And the actual problem is that if I do it this way, I need access to all objects in every character that shoots, this means if I have 20 characters, every character needs to keep a pointer to all other characters so it can check if collision with any of the objects will return true... and it gets messed up because I have 20 pointers pointing to the same stuff.

What to do, bros? :huh:

 

( shoot() function can't take arguments, because it's called in a virtual void update() function )

#include "player.h"


Player::Player( glm::vec3 pos, Input *inputManager, std::vector<Model*> anims, std::vector<Shader*> shaders, std::vector<GameObject*> *gameObjects )
       :Character( anims, shaders )
{
    this->inputManager = inputManager;
    objects = gameObjects;
    mainCam.setCurrentPosition( pos );
}

void Player::update()
{
    rememberPreviousState();
    handleInput();
    lookAround();
    Move();
    shoot();
}

void Player::shoot()
{

}

void Player::handleInput()
{
    //Player movement
    abilities[ int( Ability::MOVE_LEFT      ) ] =  inputManager->getKeyState( SDLK_a );
    abilities[ int( Ability::MOVE_RIGHT     ) ] =  inputManager->getKeyState( SDLK_d );
    abilities[ int( Ability::MOVE_FORWARD   ) ] =  inputManager->getKeyState( SDLK_w );
    abilities[ int( Ability::MOVE_BACKWARDS ) ] =  inputManager->getKeyState( SDLK_s );

    if( inputManager->verticalAngle >  F_PI/2.0f ) { inputManager->verticalAngle =  F_PI/2.0f; }
    if( inputManager->verticalAngle < -F_PI/2.0f ) { inputManager->verticalAngle = -F_PI/2.0f; }

    mainCam.yawAngle   = inputManager->horizontalAngle;
    mainCam.pitchAngle = inputManager->verticalAngle;

}

void Player::lookAround()
{
    mainCam.setDirectionRight( glm::vec3( cos( mainCam.yawAngle ), 0.0f, sin( mainCam.yawAngle ) ) );
    mainCam.setDirection( glm::normalize( glm::vec3(
                                    cos( mainCam.yawAngle - F_PI/2.0f )*cos( mainCam.pitchAngle ),
                                    sin( -mainCam.pitchAngle ),
                                    sin( mainCam.yawAngle - F_PI/2.0f )*cos( mainCam.pitchAngle ) ) ) );

    moveHelperCam.setDirection( glm::vec3( cos( mainCam.yawAngle - F_PI/2.0f ), 0.0f, sin( mainCam.yawAngle - F_PI/2.0f ) ) );
    mainCam.setDirectionUp( glm::cross( mainCam.getDirectionRight(), mainCam.getDirection() ) );
    mainCam.setCurrentPitch( glm::angleAxis( mainCam.pitchAngle, glm::vec3( 1, 0, 0 ) ) );
    mainCam.setCurrentYaw( glm::angleAxis( mainCam.yawAngle, glm::vec3( 0, 1, 0 ) ) );

}

 

 

Edited by codeBoggs

Share this post


Link to post
Share on other sites

frob, thanks very much for answering , there is stuff that is quite complicated( like the store, proxy, cache, loader stuff ), but I think I understood what you suggested, basically you want me to implement some messaging system that just sends messages to other objects (for example, the observer pattern) and you don't like the idea of every object knowing about everybody else, because it's not effective.

 

But the thing is that you have programmed too much and you know what is good in which situations, for me it's not clear at all and I don't understand why to even use such patterns, seems like an overkill to me. That's why I want to start with something simple that sounds logical to me and then if a problem happens, I will rewrite it, it's not the end of the world.

 

But I like your idea of one class that checks for collisions and just notifies. I will create a Collisions class, because it just checks for collisions. One thing per class, right?

 

And then I will try to optimize it as much as I can, by that I mean that I don't want to check for all collisions every frame, I will check if there is a chance to collide, and only if there is, check for that collision.(will figure out how to do that later, for now I have enough cpu cycles. )

 

And when collision between 2 guys happens (normally a bullet and a guy), use their pointers and call their onCollision functions, right?

 

Looks like this:

class Collisions
{
  std::vector<GameObject*> gameObjects;//Holds pointers to all game objects.

  public void detectCollision()
  {
    for( auto& object : gameObjects )
    {
      //some optimizations so I don't check too much collisions, I will come up with it later.
      if( hasCollided(bullet, badguy ) == true )
      {
        badguy->OnCollision( bullet );
        //and maybe some other info later on.
      }
    }
  }
} 

Is it ok? ( you don't have to go into details, just as overall, I know that there are probably hundreds of better ways, but I need to try something in order to learn that it doesn't work, right? Does this look like a good/mediocre start?   :wacko:  )

Edited by codeBoggs

Share this post


Link to post
Share on other sites

You can break the problem down into steps if that helps.

 

Step one: cast a ray from the player to wherever he is aiming(assuming you're using hitscan-style weapons.)

 

-Some class needs to handle this, as frob pointed out it probably makes sense for the World class or maybe a Scene class or a GameLogic class or something to know how to exhibit that functionality(depends on your design.) If the player had to know how to cast a ray then you have the issue of the player having to know all about the scene and all the other characters in it.

 

Step two: resolve the collision.

 

-Collisions are all about spatial partitioning, if you can't guarantee an object isn't in the same space(trees or similar) you'll have to use a code check to compare them. That said the simplest answer to a problem is often the easiest one, for every raycast you'll be checking(n) characters for collisions(or n-1 if your function excludes the player.) If your game doesn't have that many characters it may be fine to just do all those checks. If you want to use something like octrees then worry about it when it becomes an issue.

 

Step three: do something with the results.

 

-When you fire the weapon certain systems will need to know about who was hit. An enemy will either have to be directly told it was hit, and then the enemy decides how much damage it takes based on information about the hit, or some third party class will do that decision making and affect the enemy class, either way you get the same result.

 

But other systems might be interested as well, you might want a hit marker to show up(cod style) that's a UI change. You might play a sound when the bullet impacts something(a wall or an enemy,) you might have blood or dust particles show. So who tells them? The simplest approach would probably be to have a mediator class(game logic) the logic knows when you fire it needs to cast a ray(it asks the world to cast a ray) it then receives results on who/what was hit and acts accordingly, informing them. It can also talk to the other major subsystems to cause the effects I mentioned prior to happen. That's one way to do it.

 

Another way is like how frob suggested, if we think of the gamelogic as a telling system then we can think of an event bus as a listening system. When you set up the game you hook up different systems to begin listening for messages they may be interested in(observer pattern or variants of it.) The nice part about this is everything is basically automatic once the game starts and new things can be added easily. Someone fired a gun? That could create a message saying someone fired a gun, that message could be picked up by an achievement system, the sound system to play the gunfire sound, an ai system to alert nearby creatures to the noise. The point is the system is flexible. That said it is also more complex in many ways and it is just a generic system, you still have to decide where you want the code to actually live. You could just as easily create an event system where the game logic still does all the processing, it just gets informed by event messages instead of direct function calls.

Share this post


Link to post
Share on other sites

frob, thanks very much for answering , there is stuff that is quite complicated( like the store, proxy, cache, loader stuff ), but I think I understood what you suggested, basically you want me to implement some messaging system that just sends messages to other objects (for example, the observer pattern) and you don't like the idea of every object knowing about everybody else, because it's not effective.
 
But the thing is that you have programmed too much and you know what is good in which situations, for me it's not clear at all and I don't understand why to even use such patterns, seems like an overkill to me. That's why I want to start with something simple that sounds logical to me and then if a problem happens, I will rewrite it, it's not the end of the world.


The most important thing to take away from Frob's post is simply this: the player doesn't need to know about all other characters in order to resolve the 'shoot' functionality. It just needs access to one object that knows about all the characters, and that object can resolve the shooting functionality.

That is one of the fundamental solutions in all of programming - whenever you find yourself thinking, "aahhh, all my X potentially need to know about all of Y", you need to introduce a new object B that is responsible for that process. (It doesn't necessarily have to be a completely new object, if an existing one can sensibly hold the functionality - but the key point is that you centralise the logic.)
 
The short answer: characters don't examine all the other characters and objects to see what they shot. The world (or some other central, shared class) does that, and tells the shooter what they need to know about the outcome. (It can also implement the outcome, too. No reason why the original shooter should have to work out how much damage was done or remove the victim from the world, etc.)

 

And when collision between 2 guys happens (normally a bullet and a guy), use their pointers and call their onCollision functions, right?


Normally there are 2 types of weapon projectile:

  • those that are resolved instantly, with a raycast - they don't need adding to any sort of list. Just check what they hit, and then they're done.
  • those that travel through the world, with a physical object - they can be added to some sort of collision list.

Make sure you know what type you're dealing with.
 
Also, if your collision resolving class iterates over all the game objects, it probably doesn't need its own copy of that list. It can probably access it from whatever the central source of game objects is. (The world? The map? The game? Usually there is a central object responsible for that.)

Share this post


Link to post
Share on other sites

Guys, thanks again for the answers. I kind of fixed it, so I think the problem is solved. ^_^

 

That is one of the fundamental solutions in all of programming - whenever you find yourself thinking, "aahhh, all my X potentially need to know about all of Y", you need to introduce a new object B that is responsible for that process. (It doesn't necessarily have to be a completely new object, if an existing one can sensibly hold the functionality - but the key point is that you centralise the logic.)

Okay, I'll try to remember that for next time.

 

 

There are countless excellent messaging systems freely available online, so there isn't even a need to write one from scratch.

Where? I see only some JMS program that seems to establish communication between different applications, not objects/classes.

Edited by codeBoggs

Share this post


Link to post
Share on other sites
What I need is to somehow say: if the player has clicked on the left mouse button, check if the ray that goes out straight from his crosshair has intersected with an enemy object, and if it is, inform the monster who was hit that he needs to die in hell (or to decrease hp).

 

// get the mouse button

getmouse(&x,&y,&b)

// if left mouse button pressed

if b==1 

   {

   // cast ray from camera, return ID of entity hit, or -1 for none.

   tgt=raycast()

   // return if they didn't hit anything

   if tgt==-1 return

   // apply damage

   damage_tgt(tgt)

   }

 

complications can arise depending on how the code is organized.

 

here, the cast uses the camera as the start location and direction, and the list of entities as the 'scene" into which the ray is cast. so the list of entities is the basic data structure,and raycast is type of search that can be performed on the entities list.  damage_tgt is likewise a method that works on the entities list.    if you use ECS, these methods would then call the location or damage component systems to do their jobs.    damage_tgt would in turn call kill_tgt  if the target took sufficient damage.   note that this does not use any messaging, its all immediate processing.

Edited by Norman Barrows

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