Hey hey!
I’m working on this project that has a ArcRotate camera following a player, with the ability to look around and move with WASD keys and jump with space. Just like in a third person shooter. Physics and everything seem to work perfectly.
However as you can see the sphere starts spinning after collision. I have been trying to stop it with no success. Is there some simple way of doing this? ChatGPT is suggesting to use a Quartion but it doesn’t seem to work. Here is how I handle the playerphysics:
import { Ray, Mesh, Scene, Vector3, PhysicsImpostor, ArcRotateCamera } from "@babylonjs/core";
export class PlayerPhysics {
private mesh: Mesh;
private scene: Scene;
private camera: ArcRotateCamera;
private lastInputVector: Vector3 | null = null; // Add this line
private mass: number;
constructor(mesh: Mesh, scene: Scene, camera: ArcRotateCamera) {
this.mesh = mesh;
this.scene = scene;
this.camera = camera;
this.mass = mesh.physicsImpostor.mass; // Cache the mass if it doesn't change
}
public move(inputVector: Vector3) {
if (!this.camera) {
console.warn("Camera not set for PlayerPhysics instance.");
return;
}
let forward = this.camera.getForwardRay().direction;
forward.y = 0; // Maintain horizontal movement
forward.normalize();
const right = Vector3.Cross(Vector3.Up(), forward).normalize();
const mass = this.mesh.physicsImpostor.mass; // Assuming the mass is set correctly on the physics impostor
const additionalGravity = new Vector3(0, -9.81, 0); // This value represents the extra gravity force you want to apply
let moveDirection = forward.scale(inputVector.z).add(right.scale(inputVector.x));
let currentVelocity = this.mesh.physicsImpostor.getLinearVelocity();
let verticalVelocity = currentVelocity ? currentVelocity.y : 0;
if (this.lastInputVector && !inputVector.equalsWithEpsilon(this.lastInputVector, 0.1)) {
this.mesh.physicsImpostor.setLinearVelocity(new Vector3(0, verticalVelocity, 0));
} else {
moveDirection = moveDirection.normalize().scale(15); // Adjust speed as needed
this.mesh.physicsImpostor.setLinearVelocity(new Vector3(moveDirection.x, verticalVelocity, moveDirection.z));
}
this.lastInputVector = inputVector.clone();
}
public update() {
// Calculate additional gravity force
const additionalGravity = new Vector3(0, -15.81, 0); // This value represents the extra gravity force you want to apply
const mass = this.mesh.physicsImpostor.mass; // Assuming the mass is set correctly on the physics impostor
// Apply the additional gravity force to the player
// Note: This force is applied in addition to the scene's global gravity
this.mesh.physicsImpostor.applyForce(additionalGravity.scale(mass), this.mesh.getAbsolutePosition());
}
public jump() {
// Simple ground check before jumping
if (this.isOnGround()) {
const jumpForce = new Vector3(0, 30, 0); // Adjust the Y value as needed for jump height
this.mesh.physicsImpostor.applyImpulse(jumpForce, this.mesh.getAbsolutePosition());
}
}
private isOnGround(): boolean {
// Define the start and end points of the ray
const rayStart = this.mesh.position;
const rayEnd = new Vector3(rayStart.x, rayStart.y - 1.1, rayStart.z); // 1.1 units below the player, adjust as needed
// Create the ray
const ray = new Ray(rayStart, rayEnd.subtract(rayStart), 1.1); // The third parameter is the length of the ray
// Cast the ray and check for intersections
const pickInfo = this.scene.pickWithRay(ray, (mesh) => {
return mesh !== this.mesh && mesh.isPickable && mesh.isVisible; // Ignore the player's own mesh
});
// If the ray intersects a mesh, the player is considered to be on the ground
return !!pickInfo.hit;
}
}
And this is how I create the player:
// Import necessary Babylon.js classes and custom modules for player setup
import { ArcRotateCamera, Scene, MeshBuilder, Vector3, PhysicsImpostor, Mesh, Color3, StandardMaterial, Texture, Quaternion } from "@babylonjs/core";
import { InputControls } from "./inputControls"; // Manages player input
import { createCamera } from "./cameraSetup"; // Configures the player's camera
import { PlayerPhysics } from "./playerPhysics"; // Handles physics interactions for the player
// Defines the Player class
export class Player {
private scene: Scene; // Reference to the Babylon.js scene
private inputControls: InputControls; // Input controller for managing player actions
private mesh: Mesh; // The player's mesh in the scene
private playerPhysics: PlayerPhysics; // Physics logic specific to the player
public camera: ArcRotateCamera; // The camera attached to the player, made public for external access
// Constructor initializes the player within the provided scene and attaches a camera
constructor(scene: Scene, canvas: HTMLCanvasElement) {
this.scene = scene; // Store reference to the scene
this.mesh = this.createPlayerMesh(); // Create the player's mesh
this.camera = createCamera(scene, canvas, this.mesh); // Initialize the camera and attach it to the player
this.inputControls = new InputControls(scene); // Setup input controls for the player
this.playerPhysics = new PlayerPhysics(this.mesh, this.scene, this.camera); // Initialize player-specific physics handling
}
// Creates the player's mesh, setting up its appearance and physics properties
private createPlayerMesh(): Mesh {
// Create a sphere to represent the player
const sphere = MeshBuilder.CreateSphere("player", {diameter: 2, segments: 32}, this.scene);
sphere.position = new Vector3(0, 1, 0); // Adjust position as needed
const material = new StandardMaterial("playerMaterial", this.scene);
material.diffuseColor = new Color3(1, 1, 1); // Set to white to not affect the texture's colors
// Apply the striped texture
const texture = new Texture("path/to/your/stripedTexture.png", this.scene);
material.diffuseTexture = texture;
sphere.material = material;
// Add physics to the sphere
sphere.physicsImpostor = new PhysicsImpostor(sphere, PhysicsImpostor.SphereImpostor, { mass: 2, restitution: 0.5 }, this.scene);
return sphere;
}
// Returns the player's mesh. Useful for external classes that need to interact with the player
public getMesh(): Mesh {
return this.mesh;
}
// The main update loop for the player, called every frame to handle input and physics updates
public update() {
const inputVector = this.inputControls.getInputVector(); // Get the current input vector
this.playerPhysics.move(inputVector); // Move the player based on input
if (this.inputControls.isJumping()) { // Check if the jump action was triggered
this.playerPhysics.jump(); // Make the player jump
}
this.playerPhysics.update(); // Perform any additional physics updates, such as applying custom gravity
}
}
Any help on this would super appreciated