Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save kdrnic/e026873bd238a77d275a0fb4f46ea886 to your computer and use it in GitHub Desktop.
Save kdrnic/e026873bd238a77d275a0fb4f46ea886 to your computer and use it in GitHub Desktop.
test2.html
<html>
<head>
</head>
<body onload="Start()">
<!--
<input type="button" onclick="AddBox()" value="Spawn crate"><input type="button" onmousedown="mouseD=true" onmouseup="mouseD=false" value="Spawn crates continuously"><br>
-->
<div id="screenArea" style="position: relative; background-image: url(loading.gif); width: 640px; height: 480px;"></div>
<br>
<pre>
Controls
Left/right - rotate player
Up/down - accelerate player
Space - jump
Ctrl - Throw ball
T - Third person camera
P - First person camera
</pre>
<script src="three.js"></script>
<script src="ammo.js"></script>
<script src="TrackballControls.js"></script>
<!-- <script src="FirstPersonControls.js"></script> -->
<script src="keycodes.js"></script>
<script>
var frameTime = 1000 / 60;
var mouseD = false;
var physFrame = 0;
var gfxFrame = 0;
var oldPhysFrame = 0;
var oldGfxFrame = 0;
var physFPS = 60;
var gfxFPS = 60;
var pressed = [];
var BIT = (b => 1 << b);
var colNull = 0;
var colWall = BIT(3);
var colPlr = BIT(1);
var colBall = BIT(2);
var colRay = BIT(0);
function Timestamp(){
return window.performance && window.performance.now ? window.performance.now() : new Date().getTime();
}
function InitPhysics(){
var collisionConfiguration = new Ammo.btDefaultCollisionConfiguration();
var dispatcher = new Ammo.btCollisionDispatcher(collisionConfiguration);
var overlappingPairCache = new Ammo.btDbvtBroadphase();
var solver = new Ammo.btSequentialImpulseConstraintSolver();
dynamicsWorld = new Ammo.btDiscreteDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConfiguration);
force.setValue(0, -10, 0);
dynamicsWorld.setGravity(force);
}
function MakePlayerBody(){
var playerShape = new Ammo.btCapsuleShape(0.5, 1);
var playerMass = 1.0;
var playerInertia = new Ammo.btVector3(0, 0, 0);
playerShape.calculateLocalInertia(playerMass, playerInertia);
var playerInfo = new Ammo.btRigidBodyConstructionInfo(playerMass, 0, playerShape, playerInertia);
playerBody = new Ammo.btRigidBody(playerInfo);
dynamicsWorld.addRigidBody(playerBody, colPlr, colWall);
ResetPlayerBody();
var playerGeometry = new THREE.CylinderGeometry(0.5, 0.5, 1, 16);
var sphereGeometry = new THREE.SphereGeometry(0.5, 16, 8);
sphereGeometry.translate(0, 0.5, 0);
playerGeometry.merge(sphereGeometry);
sphereGeometry.translate(0, -1, 0);
playerGeometry.merge(sphereGeometry);
var playerMaterial = new THREE.MeshBasicMaterial({color: "red"});
playerBody.setAngularFactor(new Ammo.btVector3(0, 0.1, 0));
playerMesh = new THREE.Mesh(playerGeometry, playerMaterial);
scene.add(playerMesh);
playerMesh.add(povCamera);
}
function ResetPlayerBody(){
playerBody.getWorldTransform().setIdentity();
playerBody.getWorldTransform().getOrigin().setValue(0, 10, 0);
playerBody.getLinearVelocity().setValue(0, 0, 0);
playerBody.getAngularVelocity().setValue(0, 0, 0);
playerBody.activate(true);
}
function MakeBall(){
var pT = playerBody.getWorldTransform();
var pPos = pT.getOrigin();
var pRot = pT.getRotation();
var ball = {};
if(typeof ballInfo == "undefined"){
var ballShape = new Ammo.btSphereShape(0.25);
var ballMass = 0.5;
var ballInertia = new Ammo.btVector3(0, 0, 0);
ballShape.calculateLocalInertia(ballMass, ballInertia);
ballInfo = new Ammo.btRigidBodyConstructionInfo(ballMass, 0, ballShape, ballInertia);
}
ball.body = new Ammo.btRigidBody(ballInfo);
ball.body.getWorldTransform().setOrigin(new Ammo.btVector3(pPos.x(), pPos.y(), pPos.z()));
ball.body.getWorldTransform().setRotation(new Ammo.btQuaternion(pRot.x(), pRot.y(), pRot.z(), pRot.w()));
dynamicsWorld.addRigidBody(ball.body, colBall, colWall | colBall);
SetForceLocal(ball.body, 0, 100 / 60, -200 / 60);
ball.body.applyImpulse(force);
ball.mesh = new THREE.Mesh(ballGeometry, ballMaterial);
scene.add(ball.mesh);
balls.push(ball);
}
function MakeLevelBody(){
var _levelMesh = new Ammo.btTriangleMesh();
var geo = levelMesh.geometry;
var _vertices = geo.vertices.map(v => new Ammo.btVector3(v.x, v.y, v.z));
for(var faceI in geo.faces){
var face = geo.faces[faceI];
_levelMesh.addTriangle(_vertices[face.a], _vertices[face.b], _vertices[face.c]);
}
var levelShape = new Ammo.btBvhTriangleMeshShape(_levelMesh, true);
var levelInfo = new Ammo.btRigidBodyConstructionInfo(0, 0, levelShape, new Ammo.btVector3(0, 0, 0));
levelBody = new Ammo.btRigidBody(levelInfo);
dynamicsWorld.addRigidBody(levelBody, colWall, colPlr | colBall | colRay);
}
function Start(){
window.addEventListener("keyup", function (event){
pressed[event.keyCode] = false;
});
window.addEventListener("keydown", function (event){
pressed[event.keyCode] = true;
});
scene = new THREE.Scene();
trackCamera = new THREE.PerspectiveCamera(75, 640/480, 0.1, 1000);
povCamera = new THREE.PerspectiveCamera(75, 640/480, 0.1, 1000);
activeCamera = povCamera;
renderer = new THREE.WebGLRenderer();
renderer.setSize(640, 480);
document.getElementById("screenArea").appendChild(renderer.domElement);
trackCamera.position.set(0, 4, 8);
trackControls = new THREE.TrackballControls(trackCamera, renderer.domElement);
trackControls.rotateSpeed = 1.0;
trackControls.zoomSpeed = 1.2;
trackControls.panSpeed = 0.8;
trackControls.noZoom = false;
trackControls.noPan = false;
trackControls.staticMoving = true;
trackControls.dynamicDampingFactor = 0.3;
trackControls.keys = [65, 83, 68];
var loader = new THREE.JSONLoader();
loader.load('level.json', function (geometry, materials){
levelMesh = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load('checkers.png'), side: THREE.DoubleSide}));
scene.add(levelMesh);
});
InitPhysics();
renderer.domElement.style.position = "absolute";
fpsDiv = document.createElement("div");
fpsDiv.style.position = "absolute";
fpsDiv.style.color = "white";
fpsDiv.style.width = "120px";
fpsDiv.style.height = "32px";
document.getElementById("screenArea").appendChild(fpsDiv);
setInterval(function(){
physFPS = physFrame - oldPhysFrame;
gfxFPS = gfxFrame - oldGfxFrame;
oldPhysFrame = physFrame;
oldGfxFrame = gfxFrame;
fpsDiv.innerHTML = physFPS.toString() + " FPS logic <br>" + gfxFPS + " FPS graphics<br>" + balls.length + " balls";
}, 1000);
ballMaterial = new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load('ball.png')});
ballGeometry = new THREE.SphereGeometry(0.25, 10, 5);
balls = [];
lastFrameTime = Timestamp();
setTimeout(Update, 0.95 * frameTime);
requestAnimationFrame(Render);
}
var force = new Ammo.btVector3(0,0,0);
function ApplyLocalForce(body, x, y, z){
force.setValue(x, y, z);
body.activate(true);
body.applyCentralLocalForce(force);
}
function SetForceLocal(body, x, y, z){
force.setValue(x, y, z);
var t = body.getWorldTransform();
var b = t.getBasis();
force.setValue(force.dot(b.getRow(0)), force.dot(b.getRow(1)), force.dot(b.getRow(2)));
}
function BodyTransformToScene(body, object){
var t = body.getWorldTransform();
var pos = t.getOrigin();
var rot = t.getRotation();
object.position.set(pos.x(), pos.y(), pos.z());
object.quaternion.set(rot.x(), rot.y(), rot.z(), rot.w());
}
function Render(){
for(var i in balls){
BodyTransformToScene(balls[i].body, balls[i].mesh);
}
if(typeof playerBody != "undefined"){
BodyTransformToScene(playerBody, playerMesh);
}
gfxFrame++;
trackControls.update();
renderer.render(scene, activeCamera);
requestAnimationFrame(Render);
}
oldCtrl = false;
rayFromVector = new Ammo.btVector3();
rayToVector = new Ammo.btVector3();
function Update(){
var t = Timestamp();
while(t - lastFrameTime < frameTime){
t = Timestamp();
}
lastFrameTime = Timestamp();
if((typeof levelMesh != "undefined") && (typeof levelBody == "undefined")){
MakeLevelBody();
MakePlayerBody();
}
physFrame++;
if(typeof playerBody != "undefined"){
if(pressed[keyCodes.VK_LEFT]){
force.setValue(0, 10, 0);
playerBody.activate(true);
playerBody.applyTorque(force);
}
if(pressed[keyCodes.VK_RIGHT]){
force.setValue(0, -10, 0);
playerBody.activate(true);
playerBody.applyTorque(force);
}
if(pressed[keyCodes.VK_UP]){
ApplyLocalForce(playerBody, 0, 0, -10);
}
if(pressed[keyCodes.VK_DOWN]){
ApplyLocalForce(playerBody, 0, 0, 10);
}
if(pressed[keyCodes.VK_SPACE]){
var res = new Ammo.ClosestRayResultCallback();
var pPos = playerBody.getWorldTransform().getOrigin();
rayFromVector.setValue(pPos.x(), pPos.y(), pPos.z());
rayToVector.setValue(pPos.x(), pPos.y() - 1.001, pPos.z());
dynamicsWorld.rayTest(rayFromVector, rayToVector, res);
if(res.hasHit()){
jumpFrame = physFrame;
SetForceLocal(playerBody, 0, 5, 0);
playerBody.activate(true);
playerBody.applyImpulse(force);
}
Ammo.destroy(res);
}
if(pressed[keyCodes.VK_CONTROL] && (!oldCtrl)){
MakeBall();
}
if(pressed[keyCodes.VK_T]){
activeCamera = trackCamera;
}
if(pressed[keyCodes.VK_P]){
activeCamera = povCamera;
}
if(pressed[keyCodes.VK_R]){
ResetPlayerBody();
}
oldCtrl = pressed[keyCodes.VK_CONTROL];
playerBody.getAngularVelocity().setY(playerBody.getAngularVelocity().y() * 0.95);
}
dynamicsWorld.stepSimulation(frameTime / 1000, 10);
setTimeout(Update, Math.max((0.95 * frameTime) - (Timestamp() - lastFrameTime), 0));
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment