Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (499)
Games in Android Showcase (118)
games submitted by our members
Games in WIP (567)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  How can I implement camera rotation into my collision detection?  (Read 423 times)
0 Members and 1 Guest are viewing this topic.
Offline tinfoilboy
« Posted 2014-08-20 22:34:54 »

I've started to add collision with AABBs, I did this without camera rotation and it worked fine, but now when I added rotation, It broke. I've tried to add the x axis to the detection, but it either teleported me to the end of the level, or crashed the game. I have no idea how to add this and would like some help.

Here is my detection code for the forward direction (left, right, and backward is basically the same)

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
float dWithRotX = distance * (float) Math.sin(Math.toRadians(rotationX));
float dWithRotZ = distance * (float) Math.cos(Math.toRadians(rotationX));
for (int z = (int) (this.position.getZ()); z < (int) (this.position.getZ() + dWithRotZ + boundingDepth); z++)
{
   // The maximum Z for this (poor) raycast.
  int maxZ = (int) (this.position.getZ() + distance + boundingDepth) - 1;
   // Get a bounding box at the current Z, could be null.
  AxisAlignedBoundingBox potentialCollider = Planetary.getPlanetary().currentPlanet.getAABBAt(new Vector3f(Math.abs(this.position.getX()), this.position.getY(), z));
   // Create a new bounding box for the camera at this position.
  AxisAlignedBoundingBox potentialCameraCollider = new AxisAlignedBoundingBox(this, new Vector3f(this.position.getX(), this.position.getY(), z), boundingWidth, boundingHeight, boundingDepth);
   // If the potential collider is not null.
  if (potentialCollider != null)
   {
      // If the potential camera collider collides with the potential collider
     if (potentialCameraCollider.intersects(potentialCollider))
      {
         // Break out of this raycast and don't move.
        break;
      }
      // If we don't collide and we are at the last part of the raycast move the camera and break out of the raycast.
     else if (z == maxZ)
      {
         position.x -= dWithRotX;

         position.z += dWithRotZ;

         break;
      }
   }
   // If there is no collider at the raycast position, and we are at the last part of the raycast, move the camera and break out of the raycast.
  else if (z == maxZ)
   {
      position.x -= dWithRotX;

      position.z += dWithRotZ;

      break;
   }
}


And here is my AABB class

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
public class AxisAlignedBoundingBox
{
   /**
    * The parent of this AABB.
    * */

   public Object parent = null;

    /**
    * The minimum X of this collider.
    * */

   public float minX = 0.0f;

   /**
    * The minimum Y of this collider.
    * */

   public float minY = 0.0f;

   /**
    * The minimum Z of this collider.
    * */

   public float minZ = 0.0f;

   /**
    * The maximum X of this collider.
    * */

   public float maxX = 0.0f;

   /**
    * The maximum Y of this collider.
    * */

   public float maxY = 0.0f;

   /**
    * The maximum Z of this collider.
    * */

   public float maxZ = 0.0f;

   /**
    * The width of this collider.
    * Stored for reference.
    * */

   private float width = 0.0f;

   /**
    * The height of this collider.
    * Stored for reference.
    * */

   private float height = 0.0f;

   /**
    * The depth of this collider.
    * Stored for reference.
    * */

   private float depth = 0.0f;

   public AxisAlignedBoundingBox(Object parent, Vector3f position, float width, float height, float depth)
   {
      this.parent = parent;
      this.minX = position.getX() - width;
      this.minY = position.getY() - height;
      this.minZ = position.getZ() - depth;
      this.maxX = position.getX() + width;
      this.maxY = position.getY() + height;
      this.maxZ = position.getZ() + depth;
      this.width = width;
      this.height = height;
      this.depth = depth;
   }

   /**
    * Update this bounding box.
    * */

   public void update()
   {
      if (parent instanceof Camera)
      {
         Camera pCamera = (Camera) parent;
         this.minX = pCamera.getPosition().getX() - width;
         this.minY = pCamera.getPosition().getY() - height;
         this.minZ = pCamera.getPosition().getZ() - depth;
         this.maxX = pCamera.getPosition().getX() + width;
         this.maxY = pCamera.getPosition().getY() + height;
         this.maxZ = pCamera.getPosition().getZ() + depth;
      }
   }

   /**
    * Check if this Bounding Box intersects with the other bounding box.
    * */

   public boolean intersects(AxisAlignedBoundingBox boundingBox)
   {
      return (this.maxX >= boundingBox.minX) && (this.maxY >= boundingBox.minY) && (this.maxZ >= boundingBox.minZ) &&
            (this.minX <= boundingBox.maxX) && (this.minY <= boundingBox.maxY) && (this.minZ <= boundingBox.maxZ);
   }
}

Offline thedanisaur

Senior Member


Medals: 10
Exp: 1 year



« Reply #1 - Posted 2014-08-21 01:06:36 »

Is there any reason you need the camera's bounding box to rotate?

Anyway, imo you should not rotate your simple bounding boxes at all. You should make sure that anyway your object rotates it sits inside its bounding box.

Then you should have another layer of bounding volume to do more complex collision detection (rotated, more accurate, etc.). As for your question I have never bothered rotating my bounding volumes, after the simple test I just see if the triangles on the mesh intersect, not the fastest method.

check this out, it may help:
http://www.gamasutra.com/view/feature/131833/when_two_hearts_collide_.php


Every village needs an idiot Cool
Offline tinfoilboy
« Reply #2 - Posted 2014-08-21 01:18:31 »

No, I'm not trying to rotate the bounding box, I'm trying to rotate the camera so you can look around and move, but my guess is that when you turn, the poor man's raycast I do gets messed up. Meaning that I can walk through the bounding boxes when looking from a different direction than the one you start with.

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline tinfoilboy
« Reply #3 - Posted 2014-08-21 01:37:34 »

I wonder if I should make the player's bounding box a sphere, and keep the terrain to AABBs...

Offline SHC
« Reply #4 - Posted 2014-08-21 02:53:45 »

Camera is only for controlling what is viewed on the screen and from where you look. Collisions should not use the camera, they should be done as they are, camera rotation should not affect collision detection.

Offline tinfoilboy
« Reply #5 - Posted 2014-08-21 03:01:12 »

Camera is only for controlling what is viewed on the screen and from where you look. Collisions should not use the camera, they should be done as they are, camera rotation should not affect collision detection.

Then how would you implement collision? Most games just use an FPS camera and move it, I know I could create a player class, but that would still require the camera to move it, from what I know.

Offline SHC
« Reply #6 - Posted 2014-08-21 03:31:47 »

You didn't get the basic idea. Think the scene as empty space. Y is up, X is towards right and Z is coming out towards you (out of monitor, of-course). This space is called as the world space. Now, for the case of objects, every object is composed of vertices. Here the vertices are in the object space, they have position inside relative to the object, and as a whole, they are transformed by scaling, translating, or rotating into the world space.

Think of the camera, as just another object in the world. you can position it anywhere you want, and rotate to change the scene what is viewed when seen through it. Therefore, the camera should not affect the collisions in the world. Usually, you wrap up your objects in a sphere or an aabb and test them for collisions. The shapes you use should also move along with the object, that is, whatever transformation you use, will also apply to the colliding shape (We should only apply transformations like translation and rotation, and not of the camera's of-course).

There, in the world space, you will test your objects for collisions and apply transforms according to your collision response. Only then, you apply the camera to the entire scene and then project it to the screen. Usually, these are only applied in the shader level.

Hope you got it now.

Offline lcass
« Reply #7 - Posted 2014-08-21 10:59:15 »

So , rotation is a bit iffy with this. The question is what are you rotating are you rotating a sprite that is smaller than a sprite normal size for instance a person texture (someone who is inside the tile whose rotation would not go outside its bounds) or with walls and floor or large square like objects where the length of its diameter is either greater than its width or height. Any object whose diagonal is less than the width of the bounding box is a bit unnecesary , if you wanted to you can using a similar method.
The way I would go about tackling this is firstly translate the bounding box coordinates and rotate , note that I will do this outside of shaders with trigonometry just so its a bit easier to see.
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
double nxa ,nya ,nxb,nyb,nxc,nyc,nxd,nyd = 0;//generate the doubles for the trig
     nxa = x * Math.cos(angle) - y * Math.sin(angle);//implement rotation of x returning the new x coordinate assuming that this is the top left of your square.
     nya = y * Math.cos(angle) + x * Math.sin(angle);
        //calculate the different x positions in a clockwise motion.
     nxb = (x + width) * Math.cos(angle) - y * Math.sin(angle);//top right corner
     nyb = y * Math.cos(angle) + (x + width) * Math.sin(angle);
      //bottom right corner corner
     nxc = (x + width) * Math.cos(angle) - (y + height) * Math.sin(angle);
      nyc = (y + height) * Math.cos(angle) + (x + width) * Math.sin(angle);
      //bottom left corner
     nxd = x * Math.cos(angle) - (y + height) * Math.sin(angle);
      nyd = (y + height) * Math.cos(angle) + x * Math.sin(angle);

Thats the rotation done , we now have all the coordinates for each of our corners , this is where the difficult is it sort of turns into pixel perfect collision , this is because you are having to generate an array of all the coordinates on the line , you can check if it has crossed the border between the two with some painful checking code using a mixture of pythag gradients and a lot of calculations per tick. So lets stick with this see where we go, now that we have our new coordinates we can use the information to figure out the gradient and with this we can create a list of points that are on that where we are able to check if its crossed the border.
So to calculate our gradients:
1  
2  
3  
4  
   ab =(Math.max(nya,nyb) - Math.min(nya, nyb))/ (Math.max(nxa, nxb) - Math.min(nxa, nxb));//basic gradient calculation , using min and max so that our gradient is always positive
     bc = (Math.max(nyb,nyc) - Math.min(nyb, nyc))/ (Math.max(nxb, nxc) - Math.min(nxb, nxc));
      cd = (Math.max(nyc,nyd) - Math.min(nyc, nyd))/ (Math.max(nxc, nxd) - Math.min(nxc, nxd));
      da = (Math.max(nya,nyd) - Math.min(nya, nyd))/ (Math.max(nxa, nxd) - Math.min(nxa, nxd));

Now we can use my overused friend the for loop to generate our array of points . Because we have used the Math.min and Math.max the function of this is made so much easier because we dont need to bother with all the silly is it a negative gradient.
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
       vertex[] boundries  = new vertex[(int)((Math.max(nya,nyb) - Math.min(nya, nyb)) + (Math.max(nyb,nyc) - Math.min(nyb, nyc)) +(Math.max(nyc,nyd) 
           - Math.min(nyc, nyd)) +(Math.max(nya,nyd) - Math.min(nya, nyd))) + 1];//make it the length of the entire set of coordinates we will recieve I am sorry for this spaghetti just here
               int counter = 0; //store a counter for our position in the boundries array so that we dont have to deal with annoying maths
     for(double fx = nxa;fx < nxb;fx++){//For further info on this bit you can add an accuracyfactor variable that means you read through the x values in a double so that you prevent holes
        boundries[counter] = new vertex(fx,fx * ab,-1);//im using a 3d vertex here , ill ignore the last value and just put -1
        counter++;
      }
      //simples
     for(double fx = nxb;fx < nxc;fx++){
         boundries[counter] = new vertex(fx,fx * bc,-1);
         counter++;
      }
      for(double fx = nxc;fx < nxd;fx++){
         boundries[counter] = new vertex(fx,fx * cd,-1);
         counter++;
      }
      for(double fx = nxd;fx < nxa;fx++){
         boundries[counter] = new vertex(fx,fx * da,-1);
         counter++;
      }

Ok so we have filled our array with all the coordinates , fairly simple . But wait , int casting is always dodgy at the best of times , what if there are extra slots in the array? that would require checks in the other class which are just a tad tedious , especially if you are doing it with a thousand objects , so here is the check for those. Note how I added 1 extra slot to the array just in case the casting went wrong in the other direction.
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
//ok so lets say the cast went wrong and we have some null spaces in our array , lets just clean those up quickly and transfer them to a clean array
     boolean slotsfree = false;
      int actuallength = 0;
      for(int i = 0; i < boundries.length;i++){
         actuallength++;
         if(boundries[i] == null){
            slotsfree = true;
            break;
         }
      }
      vertex[] newboundries;
      if(slotsfree){
         newboundries = new vertex[actuallength];
         for(int i = 0; i < actuallength;i++){
            newboundries[i] = boundries[i];
         }
         return newboundries;
      }
      else{
         return boundries;
      }

So there it is , the way to do it. I am not sure if it will work as expected it was written as I was writing this so there may be some errors.
Here is the function it is contained in.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
       public vertex[] checkAABB(float x , float y , float width , float height,float angle){
      //create a method that has four verticies
     
      //( each corner of your AABB) each respectively named a b c d
     double nxa ,nya ,nxb,nyb,nxc,nyc,nxd,nyd = 0;//generate the doubles for the trig
     nxa = x * Math.cos(angle) - y * Math.sin(angle);//implement rotation of x returning the new x coordinate assuming that this is the top left of your square.
     nya = y * Math.cos(angle) + x * Math.sin(angle);
        //calculate the different x positions in a clockwise motion.
     nxb = (x + width) * Math.cos(angle) - y * Math.sin(angle);//top right corner
     nyb = y * Math.cos(angle) + (x + width) * Math.sin(angle);
      //bottom right corner corner
     nxc = (x + width) * Math.cos(angle) - (y + height) * Math.sin(angle);
      nyc = (y + height) * Math.cos(angle) + (x + width) * Math.sin(angle);
      //bottom left corner
     nxd = x * Math.cos(angle) - (y + height) * Math.sin(angle);
      nyd = (y + height) * Math.cos(angle) + x * Math.sin(angle);
      double ab,bc,cd,da = 0;// these are the gradients where ab = A to B
     ab =(Math.max(nya,nyb) - Math.min(nya, nyb))/ (Math.max(nxa, nxb) - Math.min(nxa, nxb));//basic gradient calculation , using min and max so that our gradient is always positive
     bc = (Math.max(nyb,nyc) - Math.min(nyb, nyc))/ (Math.max(nxb, nxc) - Math.min(nxb, nxc));
      cd = (Math.max(nyc,nyd) - Math.min(nyc, nyd))/ (Math.max(nxc, nxd) - Math.min(nxc, nxd));
      da = (Math.max(nya,nyd) - Math.min(nya, nyd))/ (Math.max(nxa, nxd) - Math.min(nxa, nxd));
      vertex[] boundries  = new vertex[(int)((Math.max(nya,nyb) - Math.min(nya, nyb)) + (Math.max(nyb,nyc) - Math.min(nyb, nyc)) +(Math.max(nyc,nyd)
       - Math.min(nyc, nyd)) +(Math.max(nya,nyd) - Math.min(nya, nyd))) + 1];//make it the length of the entire set of coordinates we will recieve I am sorry for this spaghetti just here
     int counter = 0; //store a counter for our position in the boundries array so that we dont have to deal with annoying maths
     for(double fx = nxa;fx < nxb;fx++){//For further info on this bit you can add an accuracyfactor variable that means you read through the x values in a double so that you prevent holes
        boundries[counter] = new vertex(fx,fx * ab,-1);//im using a 3d vertex here , ill ignore the last value and just put -1
        counter++;
      }
      //simples
     for(double fx = nxb;fx < nxc;fx++){
         boundries[counter] = new vertex(fx,fx * bc,-1);
         counter++;
      }
      for(double fx = nxc;fx < nxd;fx++){
         boundries[counter] = new vertex(fx,fx * cd,-1);
         counter++;
      }
      for(double fx = nxd;fx < nxa;fx++){
         boundries[counter] = new vertex(fx,fx * da,-1);
         counter++;
      }
      //ok so lets say the cast went wrong and we have some null spaces in our array , lets just clean those up quickly and transfer them to a clean array
     boolean slotsfree = false;
      int actuallength = 0;
      for(int i = 0; i < boundries.length;i++){
         actuallength++;
         if(boundries[i] == null){
            slotsfree = true;
            break;
         }
      }
      vertex[] newboundries;
      if(slotsfree){
         newboundries = new vertex[actuallength];
         for(int i = 0; i < actuallength;i++){
            newboundries[i] = boundries[i];
         }
         return newboundries;
      }
      else{
         return boundries;
      }
     
   }



I hope this helps , its a difficult topic and a bit mind boggling when trying to visulaise Smiley
Pages: [1]
  ignore  |  Print  
 
 

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Pippogeek (39 views)
2014-09-24 16:13:29

Pippogeek (30 views)
2014-09-24 16:12:22

Pippogeek (19 views)
2014-09-24 16:12:06

Grunnt (45 views)
2014-09-23 14:38:19

radar3301 (27 views)
2014-09-21 23:33:17

BurntPizza (63 views)
2014-09-21 02:42:18

BurntPizza (33 views)
2014-09-21 01:30:30

moogie (41 views)
2014-09-21 00:26:15

UprightPath (50 views)
2014-09-20 20:14:06

BurntPizza (54 views)
2014-09-19 03:14:18
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!