Skip to content

Commit

Permalink
Improved raycasting for better ground detection
Browse files Browse the repository at this point in the history
  • Loading branch information
tracygardner committed Jul 25, 2024
1 parent 9f1de71 commit 7a0ed77
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 90 deletions.
2 changes: 1 addition & 1 deletion dev-dist/sw.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ define(['./workbox-07658ed7'], (function (workbox) { 'use strict';
"revision": "3ca0b8505b4bec776b69afdba2768812"
}, {
"url": "index.html",
"revision": "0.l30l2oi1398"
"revision": "0.3l98b1qdp6o"
}], {});
workbox.cleanupOutdatedCaches();
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
Expand Down
121 changes: 110 additions & 11 deletions flock.js
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ function createCapsuleFromBoundingBox(mesh, scene) {
boundingInfo.boundingBox.minimumWorld.z;

// Calculate the radius as the min of the width and depth
const radius = Math.max(width, depth) / 2;
const radius = Math.min(width, depth) / 2;

// Calculate the effective height of the capsule's cylindrical part
const cylinderHeight = Math.max(0, height - 2 * radius);
Expand Down Expand Up @@ -749,31 +749,32 @@ export function isTouchingSurface(modelName) {
}

function checkIfOnSurface(mesh) {
// Get the bounding box of the mesh
// Compute the world matrix to ensure updated positions
mesh.computeWorldMatrix(true);
const boundingInfo = mesh.getBoundingInfo();

// Setting the ray origin slightly above the mesh's lowest point
const minY = boundingInfo.boundingBox.minimumWorld.y;
//console.log("Min Y", minY);
// Cast the ray from a point slightly below the bottom of the mesh
const rayOrigin = new BABYLON.Vector3(
boundingInfo.boundingBox.centerWorld.x,
minY,
minY + 0.01, // Slightly above to avoid hitting the mesh itself
boundingInfo.boundingBox.centerWorld.z,
);
rayOrigin.y -= 0.01;
// Adjust the ray origin slightly below the mesh's bottom

// Raycast downwards
const ray = new BABYLON.Ray(rayOrigin, new BABYLON.Vector3(0, -1, 0), 0.02);
// Cast the ray downwards with sufficient length to cover expected distances
const ray = new BABYLON.Ray(rayOrigin, new BABYLON.Vector3(0, -1, 0), 2);
//const rayHelper = new BABYLON.RayHelper(ray);
//rayHelper.show(window.scene);

// Perform the raycast
mesh.isPickable = false;
const hit = window.scene.pickWithRay(ray);
mesh.isPickable = true;

//console.log(`Raycasting from: ${rayOrigin.toString()}`);
//console.log(`Ray hit: ${hit.hit}, Distance: ${hit.distance}, Picked Mesh: ${hit.pickedMesh ? hit.pickedMesh.name : "None"}`,);

return hit.hit && hit.pickedMesh !== null && hit.distance <= 0.1;
// Check if the mesh is directly on top of the surface
return hit.hit && hit.pickedMesh !== null && hit.distance <= 0.02; // Adjust the threshold as needed
}

export function keyPressed(key) {
Expand Down Expand Up @@ -842,3 +843,101 @@ export async function changeColour(modelName, color) {
}
});
}

// Helper function to move the model forward
export function moveForward(modelName, speed) {
const model = window.scene.getMeshByName(modelName);
if (!model || speed === 0) return;

const forwardSpeed = speed;
const cameraForward = window.scene.activeCamera
.getForwardRay()
.direction.normalize();
const moveDirection = cameraForward.scale(forwardSpeed);
const currentVelocity = model.physics.getLinearVelocity();

// Set linear velocity
model.physics.setLinearVelocity(
new BABYLON.Vector3(
moveDirection.x,
currentVelocity.y,
moveDirection.z,
),
);

// Set rotation
const facingDirection =
speed >= 0
? new BABYLON.Vector3(
-cameraForward.x,
0,
-cameraForward.z,
).normalize()
: new BABYLON.Vector3(
cameraForward.x,
0,
cameraForward.z,
).normalize();
const targetRotation = BABYLON.Quaternion.FromLookDirectionLH(
facingDirection,
BABYLON.Vector3.Up(),
);
const currentRotation = model.rotationQuaternion;
const deltaRotation = targetRotation.multiply(currentRotation.conjugate());
const deltaEuler = deltaRotation.toEulerAngles();
model.physics.setAngularVelocity(
new BABYLON.Vector3(0, deltaEuler.y * 5, 0),
); // Adjust scalar as needed
model.rotationQuaternion.x = 0;
model.rotationQuaternion.z = 0;
model.rotationQuaternion.normalize(); // Re-normalize the quaternion
}

export function attachCamera(modelName) {
window.whenModelReady(modelName, function (mesh) {
if (mesh) {
// After physics calculations, adjust velocities and rotations
window.scene.onAfterPhysicsObservable.add(() => {
const currentVelocity = mesh.physics.getLinearVelocity();
const newVelocity = new BABYLON.Vector3(
0,
currentVelocity.y,
0,
); // Maintain vertical velocity, reset horizontal
mesh.physics.setLinearVelocity(newVelocity);
mesh.physics.setAngularVelocity(BABYLON.Vector3.Zero());

const currentRotationQuaternion = mesh.rotationQuaternion;
const currentEulerRotation =
currentRotationQuaternion.toEulerAngles();
const newRotationQuaternion =
BABYLON.Quaternion.RotationYawPitchRoll(
currentEulerRotation.y,
0,
0,
);
mesh.rotationQuaternion.copyFrom(newRotationQuaternion);
});

// Set up camera
const camera = new BABYLON.ArcRotateCamera(
"camera",
Math.PI / 2,
Math.PI / 4,
10,
mesh.position,
window.scene,
);
camera.checkCollisions = true;
camera.lowerBetaLimit = Math.PI / 2.5; // Lower angle limit
camera.upperBetaLimit = Math.PI / 2; // Upper angle limit
camera.lowerRadiusLimit = 2;
camera.upperRadiusLimit = 7;
camera.setTarget(mesh.position);
camera.attachControl(canvas, true);
window.scene.activeCamera = camera;
} else {
console.log("Model not loaded:", modelName);
}
});
}
97 changes: 19 additions & 78 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ import {
randomColour,
scaleMesh,
changeColour,
moveForward,
attachCamera,
} from "./flock.js";
import { toolbox } from "./toolbox.js";
import { FlowGraphLog10Block } from "babylonjs";
Expand Down Expand Up @@ -70,6 +72,8 @@ window.randomColour = randomColour;
window.scaleMesh = scaleMesh;
window.changeColour = changeColour;
window.newCharacter = newCharacter;
window.moveForward = moveForward;
window.attachCamera = attachCamera;

registerFieldColour();

Expand Down Expand Up @@ -196,28 +200,6 @@ const modelNames = [
//"bear_anim.glb",
];

/*
#e49085
#ab8b64
#cc9863
#d1a17f
#eac083
#e6bd91
#db9d9e
#d7977a
#ffb5a2
#e6b7ae
#d97c57
#eeb4a8
#fdc8b8
#efa19a
#ffdbd9
#c8734c
#f8d4ce
#eda898
#ee959b
*/

console.log("Welcome to Flock 🐑🐑🐑");

workspace.addChangeListener(function (event) {
Expand Down Expand Up @@ -2666,62 +2648,15 @@ javascriptGenerator.forBlock["switch_animation"] = function (block) {
javascriptGenerator.forBlock["move_forward"] = function (block) {
const modelName = javascriptGenerator.nameDB_.getName(
block.getFieldValue("MODEL"),
Blockly.Names.NameType.VARIABLE,
Blockly.Names.NameType.VARIABLE
);
const speed =
javascriptGenerator.valueToCode(
block,
"SPEED",
javascriptGenerator.ORDER_ATOMIC,
) || "0";
return `
const model = window.scene.getMeshByName(${modelName});
if (model) {
if (${speed} === 0){ return; }
const forwardSpeed = -${speed};
const cameraForward = window.scene.activeCamera.getForwardRay().direction.normalize();
// Forward direction adjusted to move away from the camera
const moveDirection = cameraForward.scale(-forwardSpeed);
const currentVelocity = model.physics.getLinearVelocity();
model.physics.setLinearVelocity(
new BABYLON.Vector3(
moveDirection.x,
currentVelocity.y,
moveDirection.z
)
);
// Decide the facing direction based on whether steps is positive or negative
let facingDirection;
if (${speed} >= 0) {
// Face away from the camera when moving forward
facingDirection = new BABYLON.Vector3(-cameraForward.x, 0, -cameraForward.z).normalize();
} else {
// Face towards the camera when moving backward
facingDirection = new BABYLON.Vector3(cameraForward.x, 0, cameraForward.z).normalize();
}
// Calculate the target rotation from the facing direction
const targetRotation = BABYLON.Quaternion.FromLookDirectionLH(facingDirection, BABYLON.Vector3.Up());
const currentRotation = model.rotationQuaternion;
const deltaRotation = targetRotation.multiply(currentRotation.conjugate());
const deltaEuler = deltaRotation.toEulerAngles();
const scaledAngularVelocityY = new BABYLON.Vector3(0, deltaEuler.y * 5, 0); // Adjust the scalar as needed
// Update angular velocity for rotation
model.physics.setAngularVelocity(scaledAngularVelocityY);
model.rotationQuaternion.x = 0;
model.rotationQuaternion.z = 0;
model.rotationQuaternion.normalize(); // Re-normalize the quaternion to maintain a valid rotation
const speed = javascriptGenerator.valueToCode(
block,
"SPEED",
javascriptGenerator.ORDER_ATOMIC
) || "0";

}
`;
return `moveForward(${modelName}, ${speed});\n`;
};

javascriptGenerator.forBlock["up"] = function (block) {
Expand All @@ -2743,6 +2678,14 @@ javascriptGenerator.forBlock["touching_surface"] = function (block) {
return [`isTouchingSurface(${modelName})`, javascriptGenerator.ORDER_NONE];
};

javascriptGenerator.forBlock["camera_follow2"] = function (block) {
const modelName = javascriptGenerator.nameDB_.getName(
block.getFieldValue("MESH_VAR"),
Blockly.Names.NameType.VARIABLE
);
return `attachCamera(${modelName});\n`;
};

javascriptGenerator.forBlock["camera_follow"] = function (block) {
const modelName = javascriptGenerator.nameDB_.getName(
block.getFieldValue("MESH_VAR"),
Expand Down Expand Up @@ -2778,8 +2721,6 @@ window.scene.onAfterPhysicsObservable.add(() => {
mesh.rotationQuaternion.copyFrom(newRotationQuaternion);
});
const camera = new BABYLON.ArcRotateCamera("camera", Math.PI / 2, Math.PI / 4, -20, mesh.position, window.scene);
camera.checkCollisions = true;
Expand Down

0 comments on commit 7a0ed77

Please sign in to comment.