this is my code
import * as THREE from '../js/three/build/three.module.js';
import * as CANNON from '../js/cannon_es/dist/cannon-es.js';
import { OBJLoader } from "../js/three/examples/jsm/loaders/OBJLoaderLocal.js";
import { Joystick } from './joystick.js';
const fiveTone = new THREE.TextureLoader().load('../assest/gradientMaps/fiveTone.jpg')
fiveTone.minFilter = THREE.NearestFilter;
fiveTone.magFilter = THREE.NearestFilter;
export class Player {
constructor(main) {
this.main = main;
// Player and chassis
this.vehicle;
this.playerMesh;
// Wheels
this.playerWheelMash;
this.wheelMeshes = [ ];
this.wheelMaterial = new THREE.MeshToonMaterial();
this.wheelRadius = 0.6;
this.wheelBodies = [];
this.chassisSize = new CANNON.Vec3(8, 4, 4);
this.maxSteerVal = 0.5; // Maximum steering force
this.maxForce = 1000; // Maximum engine force
this.brakeForce = 1000000; // Magnitude of the brake force
this.loader = new OBJLoader();
this.textureLoader = new THREE.TextureLoader();
this.Texturenum = 0;
this.Usejoystick = new Joystick(this);
this.localVelocity = new CANNON.Vec3();
this.moveDistance = 60;
this.canJump = false;
this.jumpVelocity = 15;
this.rotationQuaternion = new CANNON.Quaternion();
}
init() {
/* Physics */
this.set_VehicleBody();
// 01. Set up the physics for the vehicle and create a RaycastVehicle object.
// 02. Add the wheel configuration to the RaycastVehicle and attach the wheels to the chassis. Then add the chassis to the physics world.
// 03. Add cylindrical physics for the wheels to the world.
/* Entities */
this.loadPlayerTexture();
// 04. The addmesh() function will add the player mesh and wheel meshes.
// 05. Once all entities are added, update_WheelBodyEvListener() will be called to listen for position changes and update the meshes.
/* Others */
this.jump(this);
}
/* Physics */
set_VehicleBody() {
const chassisBody = new CANNON.Body({
mass: 150,
shape: new CANNON.Box(new CANNON.Vec3(this.chassisSize.x / 2, this.chassisSize.y / 2, this.chassisSize.z / 2)),
material: new CANNON.Material({
friction: 0,
restitution: 0
})
})
chassisBody.position.set(0, 10, 0);
// Set an initial angular velocity
chassisBody.angularVelocity.set(0, 0.5, 0);
// Set up the vehicle using the RaycastVehicle from the CANNON library
this.vehicle = new CANNON.RaycastVehicle({
chassisBody,
/* xx */
indexForwardAxis: 0,
indexRightAxis: 1,
indexUpAxis: 2
});
this.set_WheelBody();
}
set_WheelBody() {
// Set up wheel options
const wheelOptions = {
radius: 0.5, // Wheel radius
directionLocal: new CANNON.Vec3(0, -1, 0), // Wheel's local direction vector
suspensionStiffness: 30, // Affects the elasticity response of the wheel to the ground.
suspensionRestLength: 0.3, // Initial length of the wheel suspension
frictionSlip: 1.4, // Friction force of the wheel
dampingRelaxation: 2.3, // Wheel's damping settings
dampingCompression: 4.4, // Also affects elasticity
maxSuspensionForce: 100000, // Maximum suspension force the wheel can handle
rollInfluence: 0.01, // Influence of the wheel's rolling during steering
axleLocal: new CANNON.Vec3(0, 0, 1), // Set the axis of rotation for the wheel
chassisConnectionPointLocal: new CANNON.Vec3(1, 0, -1),
maxSuspensionTravel: 0.3,
customSlidingRotationalSpeed: -30, // Speed of wheel sliding
useCustomSlidingRotationalSpeed: true // Whether to use custom sliding rotational speed
};
// Add wheels and set their connection points relative to the chassis
wheelOptions.chassisConnectionPointLocal.set(-1.5, -2.5, 2.1);
this.vehicle.addWheel(wheelOptions);
wheelOptions.chassisConnectionPointLocal.set(-1.5, -2.5, -2.1);
this.vehicle.addWheel(wheelOptions);
wheelOptions.chassisConnectionPointLocal.set(1.5, -2.5, 2.1);
this.vehicle.addWheel(wheelOptions);
wheelOptions.chassisConnectionPointLocal.set(1.5, -2.5, -2.1);
this.vehicle.addWheel(wheelOptions);
// The physics setup is done, the vehicle can now be added to the physics world.
this.vehicle.addToWorld(this.main.world);
this.set_WheelGeometry();
}
set_WheelGeometry() {
// Add the cylindrical physics for the wheels
const that = this;
const wheelMaterial = new CANNON.Material('wheel');
this.vehicle.wheelInfos.forEach((wheel) => { // .wheelInfos is a built-in attribute of Cannon.js that holds information about the wheels
/* Add the cylinder shape and then add the rigid body */
const cylinderShape = new CANNON.Cylinder(wheel.radius, wheel.radius, wheel.radius, 16);
const wheelBody = new CANNON.Body({
mass: 0,
material: wheelMaterial,
});
wheelBody.type = CANNON.Body.KINEMATIC; // KINEMATIC body is not affected by forces from the physics engine
wheelBody.collisionFilterGroup = 0; // Disable collision
const quaternion = new CANNON.Quaternion().setFromEuler(-Math.PI / 2, 0, 0); // Set a quaternion to rotate around the X-axis by -90 degrees
wheelBody.addShape(cylinderShape, new CANNON.Vec3(), quaternion); /* Set the cylinder shape and change its direction */
/* The above code sets the rotation direction for the wheel physics */
that.wheelBodies.push(wheelBody); // Finally, add the wheel physics to an array for use in postStep.
that.main.world.addBody(wheelBody);
});
}
update_WheelBodyEvListener() {
this.main.world.addEventListener('postStep', () => {
for (let i = 0; i < this.vehicle.wheelInfos.length; i++) {
this.vehicle.updateWheelTransform(i); // Update the wheel transformation information
const transform = this.vehicle.wheelInfos[i].worldTransform; // This includes the position and rotation information of the wheel
/* Sync the player mesh to the physical body */
this.playerMesh.position.copy(this.vehicle.chassisBody.position);
this.playerMesh.quaternion.copy(this.vehicle.chassisBody.quaternion);
/* Set the position and rotation of the wheel body to match the world transformation information of the wheel */
this.wheelBodies[i].position.copy(transform.position);
this.wheelBodies[i].quaternion.copy(transform.quaternion);
/* Synchronize to the mesh */
this.wheelMeshes[i].position.copy(this.wheelBodies[i].position);
this.wheelMeshes[i].quaternion.copy(this.wheelBodies[i].quaternion);
}
})
}
/* Entities */
loadPlayerTexture() {
let that = this;
// Material and texture for the wheels
this.mats = [
new THREE.MeshToonMaterial({
gradientMap: fiveTone,
bumpMap: that.textureLoader.load('../assest/textures/mazu/mazuHead_Height.png', TextureOnLoad),
map: that.textureLoader.load('../assest/textures/mazu/mazuHead_BaseColor.png', TextureOnLoad)
}),
new THREE.MeshToonMaterial({
gradientMap: fiveTone,
// side: THREE.DoubleSide,
bumpMap: that.textureLoader.load('../assest/textures/mazu/mazuCar_Height.png', TextureOnLoad),
map: that.textureLoader.load('../assest/textures/mazu/mazuCar_BaseColor.png', TextureOnLoad)
}),
new THREE.MeshToonMaterial({
gradientMap: fiveTone,
bumpMap: that.textureLoader.load('../assest/textures/mazu/mazuBody_Height.png', TextureOnLoad),
map: that.textureLoader.load('../assest/textures/mazu/mazuBody_BaseColor.png', TextureOnLoad)
}),
];
// Material and texture for the wheels
this.wheelMaterial = new THREE.MeshToonMaterial({
gradientMap: fiveTone,
bumpMap: that.textureLoader.load('../assest/textures/wheel/wheel_Normal.png', TextureOnLoad),
map: that.textureLoader.load('../assest/textures/wheel/wheel_BaseColor.png', TextureOnLoad)
})
function TextureOnLoad() {
that.main.Ui.loading();
that.Texturenum += 1;
if (that.Texturenum == that.mats.length * 2) {
that.addmesh();
}
}
}
addmesh() { // Executed in loadPlayerTexture
let that = this; // Change the context of 'this' first
this.add_VehicleMesh(this);
this.add_WheeleMesh(this);
}
add_VehicleMesh(that) {
let materialIndex = 0; // Index variable to track the current material to use
this.loader.load('../assest/models/mazu/mazuAll_L.obj', (object) => {
that.main.Ui.loading();
that.playerMesh = object;
that.playerMesh.scale.set(0.3, 0.3, 0.3);
that.playerMesh.traverse(function (child) {
if (child instanceof THREE.Mesh) {
child.material = that.mats[materialIndex];
child.castShadow = true;
child.receiveShadow = true;
materialIndex = (materialIndex + 1) % that.mats.length; // Increment the index to loop through the materials within the range
}
});
that.main.scene.add(that.playerMesh);
that.main.Camera.CameraSwitch("init"); // Create the camera
});
}
add_WheeleMesh(that) {
this.loader.load('../assest/models/mazu/wheel.obj', (object) => {
that.main.Ui.loading();
that.playerWheelMash = object;
that.playerWheelMash.scale.set(0.3, 0.3, 0.3);
that.playerWheelMash.traverse(function (child) {
if (child instanceof THREE.Mesh) {
child.material = that.wheelMaterial;
child.castShadow = true;
child.receiveShadow = true;
}
});
this.wheelBodies.forEach((wheelBody, index) => {
const wheelMesh = that.playerWheelMash.clone();
that.main.scene.add(wheelMesh);
that.wheelMeshes.push(wheelMesh); // Add the wheel meshes to the array
});
// Call update_WheelBodyEvListener() here as well
this.update_WheelBodyEvListener();
});
}
/* Other methods */
jump(that) {
/* This segment is used to detect whether it encounters a surface from which it can jump */
// let contactNormal = new CANNON.Vec3();
// let upAxis = new CANNON.Vec3(0, 1, 0);
// this.playerBody.addEventListener("collide", function (e) {
// let contact = e.contact;
// if (contact.bi.id == that.playerBody.id) {
// contact.ni.negate(contactNormal);
// }
// else {
// contactNormal.copy(contact.ni);
// }
// if (contactNormal.dot(upAxis) > 0) {
// that.canJump = true;
// }
// });
}
movement() {
// Handle movement based on input keys or joystick direction
if (
this.main.keys.includes("w") ||
this.main.keys.includes('arrowup') ||
this.main.direction.includes('top')
) {
this.vehicle.applyEngineForce(-this.maxForce, 2);
this.vehicle.applyEngineForce(-this.maxForce, 3);
}
if (
this.main.keys.includes("s") ||
this.main.keys.includes('arrowdown') ||
this.main.direction.includes('bottom')
) {
this.vehicle.applyEngineForce(this.maxForce, 2);
this.vehicle.applyEngineForce(this.maxForce, 3);
}
if (
this.main.keys.includes("a") ||
this.main.keys.includes('arrowleft') ||
this.main.direction.includes('left')
) {
this.vehicle.setSteeringValue(this.maxSteerVal, 0);
this.vehicle.setSteeringValue(this.maxSteerVal, 1);
}
if (
this.main.keys.includes("d") ||
this.main.keys.includes('arrowright') ||
this.main.direction.includes('right')
) {
this.vehicle.setSteeringValue(-this.maxSteerVal, 0);
this.vehicle.setSteeringValue(-this.maxSteerVal, 1);
}
}
setState() {
// Your code for setting state goes here
}
}