Coppercube API Documentation
All tutorials
CopperLicht Tutorial: Collision detection and response
This tutorial demonstrates how to do collision detection in CopperLicht.
The final result of this tutorial will look about like this:
A room where the user cannot move trough walls, and he can walk up stairs.
- Show live demo of this tutorial
- Download this tutorial as zip archive.
Creating a room
In order to collide against walls, we need a room. Start up the 3d editor CopperCube and create a simple room, like in this example:In the zip archive of this tutorial, you'll find a .ccb file named room.ccb which contains exactly this example, you can also use this one.
Use CopperCube to save the scene into a directory of your choice and publish the scene as WebGL/JavaScript (Choose Tools -> Test as JavaScript/WebGL). This will create a .ccbjs file with this scene which we can load using CopperLicht.
Writing CopperLicht code
Now create a .html file in that directory and paste the following code into it. What it does will be explained in detail below.<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <script type="text/javascript" src="copperlichtdata/copperlicht.js"></script> </head> <body> <b>Tutorial 06: Collision detection.</b><br/> Demonstrates how to do various ways of collision detection: Walking around in a room and picking the wall<br/><br/> <div style="width:640px; margin:auto; position:relative; font-size: 9pt; color: #777777;"> <canvas id="3darea" width="640" height="480" style="background-color:#000000"> </canvas> <div style="display:block; color:#ffffff; padding:5px; position:absolute; left:20px; top:420px; background-color:#000000; height:37px; width:300px; border-radius:5px; border:1px solid #777777; opacity:0.5;" id="helptext"> Look with the mouse, move with the cursor keys or WASD. Press space to 'shoot' a cube at the next wall. </div> </div> <script type="text/javascript"> <!-- var engine = startCopperLichtFromFile('3darea', 'copperlichtdata/room.ccbjs'); var cubeCollisionPosition = null; // this is called when loading the 3d scene has finished engine.OnLoadingComplete = function() { var scene = engine.getScene(); if (!scene) return; // in the CopperCube 3d editor, we already created a camera which collides against the wall in this scene. // But to demonstrate how this would work manually, we create a new camera here which does this as well: // add a user controlled camera var cam = new CameraSceneNode(); // ensure to place the camera inside the room, or it will fall out, into the endless void cam.Pos.X = -50; cam.Pos.Y = 180; cam.Pos.Z = -20; // add an animator which makes the camera move by keyboard and mouse input var animator = new AnimatorCameraFPS(cam, engine); animator.MoveSpeed = 0.2; animator.RotateSpeed = 100; cam.addAnimator(animator); animator.lookAt(new Vect3d(-200,90,200)); scene.getRootSceneNode().addChild(cam); scene.setActiveCamera(cam); // add the collision response animator to collide against walls var colanimator = new AnimatorCollisionResponse( new Vect3d(20,40,20), // size of the player ellipsoid new Vect3d(0,-10,0), // gravity direction new Vect3d(0,30,0), // position of the eye in the ellipsoid scene.getCollisionGeometry()); cam.addAnimator(colanimator); } // every time the user presses space, we want to do a collision test with the wall // and create a cube where we hit the wall document.onkeyup = function(event) { var scene = engine.getScene(); if (!scene) return; if (event.keyCode == 32) // space has been pressed { var cam = scene.getActiveCamera(); // calculate the start and end 3d point of the line, the beinning being // the camera position and the end about 2000 units away in the direction of the // camera target var startLine = cam.getAbsolutePosition(); var endLine = startLine.add(cam.getTarget().substract(startLine).multiplyWithScal(2000)); // test our line for a collision with the world var collisionPoint = scene.getCollisionGeometry().getCollisionPointWithLine(startLine, endLine, true, null); if (collisionPoint) { // a collision has been found. // create a cube at the point where the collision happened if (!cubeCollisionPosition) { cubeCollisionPosition = new CubeSceneNode(); scene.getRootSceneNode().addChild(cubeCollisionPosition); cubeCollisionPosition.getMaterial(0).Tex1 = engine.getTextureManager().getTexture('ground_stone.jpg', true); } cubeCollisionPosition.Pos = collisionPoint; } } // we need to call the key handler of the 3d engine as well, so that the user is // able to move the camera using the keys engine.handleKeyUp(event); }; --> </script> </body> </body> </html>Also, put a .jpg file named 'ground_stone.jpg' into that directory, so that the cube will have a texture.
What the code does
As always, the first few lines of the html code are creating a canvas element inside a container. Inside this container, there is a <div>, used for the 2d overlay. The style of these divs with its absolute positioning is making it possible to move them over the canvas:<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <script type="text/javascript" src="copperlichtdata/copperlicht.js"></script> </head> <body> <b>Tutorial 06: Collision detection.</b><br/> Demonstrates how to do various ways of collision detection: Walking around in a room and picking the wall<br/><br/> <div style="width:640px; margin:auto; position:relative; font-size: 9pt; color: #777777;"> <canvas id="3darea" width="640" height="480" style="background-color:#000000"> </canvas> <div style="display:block; color:#ffffff; padding:5px; position:absolute; left:20px; top:420px; background-color:#000000; height:37px; width:300px; border-radius:5px; border:1px solid #777777; opacity:0.5;" id="helptext"> Look with the mouse, move with the cursor keys or WASD. Press space to 'shoot' a cube at the next wall. </div> </div>So let's start with the javascript code. First, we simply initialize the 3d engine and tell it to load the scene file we created in the editor. You might have to adjust the file name of the .ccbjs file to fit the name you picked when saving the scene. We also store a variable named cubeCollisionPosition where we later save a scene node used to mark the position where we hit the wall when 'shooting':
<script type="text/javascript"> <!-- var engine = startCopperLichtFromFile('3darea', 'copperlichtdata/room.ccbjs'); var cubeCollisionPosition = null;Next, we add a camera to the scene when the .ccbjs file has finished loading. But this time, the camera should not only move when the user presses the cursor keys which is achieved using a AnimatorCameraFPS, we also want the camera to collide against walls. For this, we also add another animator which is named AnimatorCollisionResponse. The AnimatorCollisionResponse gets several parameters like gravity and the size of the player, and also the collision geometry as a triangle selector. Luckly, we don't have to create this triangle selector ourselves, we can simply use the one of the scene by calling scene.getCollisionGeometry(). This is done here:
engine.OnLoadingComplete = function() { var scene = engine.getScene(); if (!scene) return; // in the CopperCube 3d editor, we already created a camera which collides against the wall in this scene. // But to demonstrate how this would work manually, we create a new camera here which does this as well: // add a user controlled camera var cam = new CameraSceneNode(); // ensure to place the camera inside the room, or it will fall out, into the endless void cam.Pos.X = -50; cam.Pos.Y = 180; cam.Pos.Z = -20; // add an animator which makes the camera move by keyboard and mouse input var animator = new AnimatorCameraFPS(cam, engine); animator.MoveSpeed = 0.2; animator.RotateSpeed = 100; cam.addAnimator(animator); animator.lookAt(new Vect3d(-200,90,200)); scene.getRootSceneNode().addChild(cam); scene.setActiveCamera(cam); // add the collision response animator to collide against walls var colanimator = new AnimatorCollisionResponse( new Vect3d(20,40,20), // size of the player ellipsoid new Vect3d(0,-10,0), // gravity direction new Vect3d(0,30,0), // position of the eye in the ellipsoid scene.getCollisionGeometry()); cam.addAnimator(colanimator); }Instead of scene.getCollisionGeometry(), we could have also supplied some other collision geometry represented as TriangleSelector. Triangle selectors in CopperLicht simply provide a way to access geometry. If you have a Mesh for example, you can create a new triangle selector using new MeshTriangleSelector(yourMesh, yourSceneNode);. If the mesh is big, you could use new OctTreeTriangleSelector(yourMesh, yourSceneNode) instead to speed up the collision queries a bit.
CopperLicht automaticly provides a triangle selector for all geometry where the 'Collision' attribute was checked in the editor via scene.getCollisionGeometry(), so you won't have to build it yourself.
You could try out the program already now, it should work and you can walk around in the room without being able to walk through walls. But to demonstrate another collision detection feature, we'll add this final code part:
// every time the user presses space, we want to do a collision test with the wall // and create a cube where we hit the wall document.onkeyup = function(event) { var scene = engine.getScene(); if (!scene) return; if (event.keyCode == 32) // space has been pressed { var cam = scene.getActiveCamera(); // calculate the start and end 3d point of the line, the beinning being // the camera position and the end about 2000 units away in the direction of the // camera target var startLine = cam.getAbsolutePosition(); var endLine = startLine.add(cam.getTarget().substract(startLine).multiplyWithScal(2000)); // test our line for a collision with the world var collisionPoint = scene.getCollisionGeometry().getCollisionPointWithLine(startLine, endLine, true, null); if (collisionPoint) { // a collision has been found. // create a cube at the point where the collision happened if (!cubeCollisionPosition) { cubeCollisionPosition = new CubeSceneNode(); scene.getRootSceneNode().addChild(cubeCollisionPosition); cubeCollisionPosition.getMaterial(0).Tex1 = engine.getTextureManager().getTexture('ground_stone.jpg', true); } cubeCollisionPosition.Pos = collisionPoint; } } // we need to call the key handler of the 3d engine as well, so that the user is // able to move the camera using the keys engine.handleKeyUp(event); }; --> </script> </body> </body> </html>Basically, we just added a function which causes a cube to be created at the point of the wall we are looking at when pressing SPACE. To find this collision point, we used the getCollisionPointWithLine() function of the TriangleSelector class. It returns the collision point as Vect3d or null if there was no collision.
And that's it, now you know how to do basic collision detection in CopperLicht.
More Tutorials
© 2010 N.Gebhardt, Ambiera
Documentation generated by JsDoc Toolkit
Documentation generated by JsDoc Toolkit