一、使用yuka实现路径跟随
yuka官方文档:https://mugen87.github.io/yuka/
<script setup>
import * as THREE from "three";
import * as YUKA from "yuka";
// 导入控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
// 创建场景
const scene = new THREE.Scene();
// 创建相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.set(0, 10, 20);
camera.lookAt(0, 0, 0);
// 创建渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.shadowMap.enabled = true;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建地面
const planeGeometry = new THREE.PlaneGeometry(50, 50);
const planeMaterial = new THREE.MeshStandardMaterial({ color: 0x999999 });
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.receiveShadow = true;
plane.rotation.x = -Math.PI / 2;
plane.position.y = -0.5;
scene.add(plane);
// 创建灯光
const light = new THREE.SpotLight(0xffffff, 3, 100, Math.PI / 6, 0.5);
light.position.set(10, 40, 10);
light.castShadow = true;
scene.add(light);
// 创建控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
const time = new YUKA.Time();
requestAnimationFrame(function animate() {
const delta = time.update().getDelta();
controls.update();
entityManager.update(delta);
renderer.render(scene, camera);
requestAnimationFrame(animate);
});
// 创建椎体
// const coneGeometry = new THREE.ConeGeometry(0.2, 1, 32);
// coneGeometry.rotateX(Math.PI / 2);
// const coneMaterial = new THREE.MeshStandardMaterial({ color: 0xff0000 });
// const cone = new THREE.Mesh(coneGeometry, coneMaterial);
// // cone.matrixAutoUpdate = false;
// cone.receiveShadow = true;
// cone.castShadow = true;
// scene.add(cone);
// 加载模型
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("./draco/");
loader.setDRACOLoader(dracoLoader);
loader.load("./model/car.gltf", function (gltf) {
console.log(gltf);
const car = gltf.scene;
car.children[0].rotation.y = Math.PI / 2;
car.children[0].scale.set(0.2, 0.2, 0.2);
scene.add(car);
vehicle.setRenderComponent(car, callback);
});
// 创建yuka的车辆
const vehicle = new YUKA.Vehicle();
vehicle.maxSpeed = 5;
// 设置车辆的渲染对象
// vehicle.setRenderComponent(cone, callback);
function callback(entity, renderComponent) {
// console.log(entity, renderComponent);
renderComponent.position.copy(entity.position);
renderComponent.quaternion.copy(entity.rotation);
// renderComponent.matrix.copy(entity.worldMatrix);
}
// 创建yuka的路径
const path = new YUKA.Path();
path.add(new YUKA.Vector3(0, 0, 0));
path.add(new YUKA.Vector3(0, 0, 10));
path.add(new YUKA.Vector3(10, 0, 10));
path.add(new YUKA.Vector3(10, 0, 0));
path.add(new YUKA.Vector3(0, 0, 0));
// 设置路径的循环模式
path.loop = true;
// 将路径当前的位置设置为车辆的位置
vehicle.position.copy(path.current());
// 跟随路径的行为
const followPathBehavior = new YUKA.FollowPathBehavior(path);
vehicle.steering.add(followPathBehavior);
// 保持在路径中行为
const onPathBehavior = new YUKA.OnPathBehavior(path, 0.1);
onPathBehavior.weight = 10;
vehicle.steering.add(onPathBehavior);
// 创建对实体管理对象
const entityManager = new YUKA.EntityManager();
entityManager.add(vehicle);
showPathLine(path);
function showPathLine(path) {
console.log(path);
const positions = [];
for (let i = 0; i < path._waypoints.length; i++) {
positions.push(
path._waypoints[i].x,
path._waypoints[i].y,
path._waypoints[i].z
);
}
const geometry = new THREE.BufferGeometry();
geometry.setAttribute(
"position",
new THREE.Float32BufferAttribute(positions, 3)
);
const material = new THREE.LineBasicMaterial({ color: 0x0000ff });
const line = new THREE.Line(geometry, material);
scene.add(line);
}
</script>
<template>
<div></div>
</template>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
canvas {
width: 100vw;
height: 100vh;
position: fixed;
left: 0;
top: 0;
}
</style>
二、搜索目标前进与抵达 并避开障碍
<script setup>
import * as THREE from "three";
import * as YUKA from "yuka";
// 导入控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
// 创建场景
const scene = new THREE.Scene();
// 创建相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.set(0, 10, 20);
camera.lookAt(0, 0, 0);
// 创建渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.shadowMap.enabled = true;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建地面
const planeGeometry = new THREE.PlaneGeometry(50, 50);
const planeMaterial = new THREE.MeshStandardMaterial({ color: 0x999999 });
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.receiveShadow = true;
plane.rotation.x = -Math.PI / 2;
plane.position.y = -0.5;
scene.add(plane);
// 创建灯光
const light = new THREE.SpotLight(0xffffff, 3, 100, Math.PI / 6, 0.5);
light.position.set(10, 40, 10);
light.castShadow = true;
scene.add(light);
// 创建控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
const time = new YUKA.Time();
requestAnimationFrame(function animate() {
const delta = time.update().getDelta();
controls.update();
entityManager.update(delta);
renderer.render(scene, camera);
requestAnimationFrame(animate);
});
// 创建椎体
// const coneGeometry = new THREE.ConeGeometry(0.2, 1, 32);
// coneGeometry.rotateX(Math.PI / 2);
// const coneMaterial = new THREE.MeshStandardMaterial({ color: 0xff0000 });
// const cone = new THREE.Mesh(coneGeometry, coneMaterial);
// // cone.matrixAutoUpdate = false;
// cone.receiveShadow = true;
// cone.castShadow = true;
// scene.add(cone);
// 加载模型
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("./draco/");
loader.setDRACOLoader(dracoLoader);
loader.load("./model/car.gltf", function (gltf) {
console.log(gltf);
const car = gltf.scene;
car.children[0].rotation.y = Math.PI / 2;
car.children[0].scale.set(0.2, 0.2, 0.2);
scene.add(car);
vehicle.setRenderComponent(car, callback);
});
// 创建yuka的车辆
const vehicle = new YUKA.Vehicle();
vehicle.maxSpeed = 5;
// 设置车辆的渲染对象
// vehicle.setRenderComponent(cone, callback);
function callback(entity, renderComponent) {
// console.log(entity, renderComponent);
renderComponent.position.copy(entity.position);
renderComponent.quaternion.copy(entity.rotation);
// renderComponent.matrix.copy(entity.worldMatrix);
}
// 创建目标小球
const sphereGeometry = new THREE.SphereGeometry(0.1, 32, 32);
const sphereMaterial = new THREE.MeshStandardMaterial({ color: 0xff00ff });
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
sphere.receiveShadow = true;
sphere.castShadow = true;
scene.add(sphere);
// 创建目标
const target = new YUKA.GameEntity();
target.setRenderComponent(sphere, callback);
target.position.set(Math.random() * 20 - 10, 0, Math.random() * 20 - 10);
const entityManager = new YUKA.EntityManager();
entityManager.add(vehicle);
entityManager.add(target);
// 到达行为
const arriveBehavior = new YUKA.ArriveBehavior(target.position);
vehicle.steering.add(arriveBehavior);
// 搜索目标行为
// const seekBehavior = new YUKA.SeekBehavior(target.position);
// vehicle.steering.add(seekBehavior);
// setInterval(() => {
// target.position.set(Math.random() * 20 - 10, 0, Math.random() * 20 - 10);
// }, 2000);
function showPathLine(path) {
console.log(path);
const positions = [];
for (let i = 0; i < path._waypoints.length; i++) {
positions.push(
path._waypoints[i].x,
path._waypoints[i].y,
path._waypoints[i].z
);
}
const geometry = new THREE.BufferGeometry();
geometry.setAttribute(
"position",
new THREE.Float32BufferAttribute(positions, 3)
);
const material = new THREE.LineBasicMaterial({ color: 0x0000ff });
const line = new THREE.Line(geometry, material);
scene.add(line);
}
// 点击将目标移动到点击的位置
const ndc = new THREE.Vector2();
const raycaster = new THREE.Raycaster();
window.addEventListener("pointerdown", (event) => {
ndc.x = (event.clientX / window.innerWidth) * 2 - 1;
ndc.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(ndc, camera);
const intersects = raycaster.intersectObject(plane);
if (intersects.length > 0) {
const point = intersects[0].point;
target.position.set(point.x, 0, point.z);
}
});
// 创建障碍物
const obstacles = [];
for (let i = 0; i < 5; i++) {
const boxGeometry = new THREE.BoxGeometry(3, 3, 3);
const boxMaterial = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const box = new THREE.Mesh(boxGeometry, boxMaterial);
box.position.set(Math.random() * 30 - 15, 0, Math.random() * 30 - 5);
box.receiveShadow = true;
box.castShadow = true;
scene.add(box);
// 创建障碍物
const obstacle = new YUKA.GameEntity();
obstacle.position.copy(box.position);
// 设置障碍物半径
boxGeometry.computeBoundingSphere();
obstacle.boundingRadius = boxGeometry.boundingSphere.radius;
obstacles.push(obstacle);
entityManager.add(obstacle);
}
// 避障行为
const obstacleAvoidanceBehavior = new YUKA.ObstacleAvoidanceBehavior(obstacles);
vehicle.steering.add(obstacleAvoidanceBehavior);
vehicle.smoother = new YUKA.Smoother(30);
</script>
<template>
<div></div>
</template>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
canvas {
width: 100vw;
height: 100vh;
position: fixed;
left: 0;
top: 0;
}
</style>
三、逃避行为
<script setup>
import * as THREE from "three";
import * as YUKA from "yuka";
// 导入控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
// 创建场景
const scene = new THREE.Scene();
// 创建相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.set(0, 10, 20);
camera.lookAt(0, 0, 0);
// 创建渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.shadowMap.enabled = true;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建地面
const planeGeometry = new THREE.PlaneGeometry(50, 50);
const planeMaterial = new THREE.MeshStandardMaterial({ color: 0x999999 });
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.receiveShadow = true;
plane.rotation.x = -Math.PI / 2;
plane.position.y = -0.5;
scene.add(plane);
// 创建灯光
const light = new THREE.SpotLight(0xffffff, 3, 100, Math.PI / 6, 0.5);
light.position.set(10, 40, 10);
light.castShadow = true;
scene.add(light);
// 创建控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
const time = new YUKA.Time();
requestAnimationFrame(function animate() {
const delta = time.update().getDelta();
controls.update();
entityManager.update(delta);
renderer.render(scene, camera);
requestAnimationFrame(animate);
});
// 创建椎体
// const coneGeometry = new THREE.ConeGeometry(0.2, 1, 32);
// coneGeometry.rotateX(Math.PI / 2);
// const coneMaterial = new THREE.MeshStandardMaterial({ color: 0xff0000 });
// const cone = new THREE.Mesh(coneGeometry, coneMaterial);
// // cone.matrixAutoUpdate = false;
// cone.receiveShadow = true;
// cone.castShadow = true;
// scene.add(cone);
// 加载模型
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("./draco/");
loader.setDRACOLoader(dracoLoader);
loader.load("./model/car.gltf", function (gltf) {
console.log(gltf);
const car = gltf.scene;
car.children[0].rotation.y = Math.PI / 2;
car.children[0].scale.set(0.2, 0.2, 0.2);
scene.add(car);
vehicle.setRenderComponent(car, callback);
});
// 创建yuka的车辆
const vehicle = new YUKA.Vehicle();
vehicle.maxSpeed = 5;
// 设置车辆的渲染对象
// vehicle.setRenderComponent(cone, callback);
function callback(entity, renderComponent) {
// console.log(entity, renderComponent);
renderComponent.position.copy(entity.position);
renderComponent.quaternion.copy(entity.rotation);
// renderComponent.matrix.copy(entity.worldMatrix);
}
// 创建目标小球
const sphereGeometry = new THREE.SphereGeometry(0.1, 32, 32);
const sphereMaterial = new THREE.MeshStandardMaterial({ color: 0xff00ff });
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
sphere.receiveShadow = true;
sphere.castShadow = true;
scene.add(sphere);
// 创建目标
const target = new YUKA.GameEntity();
target.setRenderComponent(sphere, callback);
target.position.set(Math.random() * 20 - 10, 0, Math.random() * 20 - 10);
const entityManager = new YUKA.EntityManager();
entityManager.add(vehicle);
entityManager.add(target);
// 到达行为
// const arriveBehavior = new YUKA.ArriveBehavior(target.position);
// vehicle.steering.add(arriveBehavior);
// 搜索目标行为
// const seekBehavior = new YUKA.SeekBehavior(target.position);
// vehicle.steering.add(seekBehavior);
// setInterval(() => {
// target.position.set(Math.random() * 20 - 10, 0, Math.random() * 20 - 10);
// }, 2000);
function showPathLine(path) {
console.log(path);
const positions = [];
for (let i = 0; i < path._waypoints.length; i++) {
positions.push(
path._waypoints[i].x,
path._waypoints[i].y,
path._waypoints[i].z
);
}
const geometry = new THREE.BufferGeometry();
geometry.setAttribute(
"position",
new THREE.Float32BufferAttribute(positions, 3)
);
const material = new THREE.LineBasicMaterial({ color: 0x0000ff });
const line = new THREE.Line(geometry, material);
scene.add(line);
}
// 点击将目标移动到点击的位置
const ndc = new THREE.Vector2();
const raycaster = new THREE.Raycaster();
window.addEventListener("pointerdown", (event) => {
ndc.x = (event.clientX / window.innerWidth) * 2 - 1;
ndc.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(ndc, camera);
const intersects = raycaster.intersectObject(plane);
if (intersects.length > 0) {
const point = intersects[0].point;
target.position.set(point.x, 0, point.z);
}
});
// 创建障碍物
const obstacles = [];
for (let i = 0; i < 5; i++) {
const boxGeometry = new THREE.BoxGeometry(3, 3, 3);
const boxMaterial = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const box = new THREE.Mesh(boxGeometry, boxMaterial);
box.position.set(Math.random() * 30 - 15, 0, Math.random() * 30 - 5);
box.receiveShadow = true;
box.castShadow = true;
scene.add(box);
// 创建障碍物
const obstacle = new YUKA.GameEntity();
obstacle.position.copy(box.position);
// 设置障碍物半径
boxGeometry.computeBoundingSphere();
obstacle.boundingRadius = boxGeometry.boundingSphere.radius;
obstacles.push(obstacle);
entityManager.add(obstacle);
}
// 避障行为
const obstacleAvoidanceBehavior = new YUKA.ObstacleAvoidanceBehavior(obstacles);
vehicle.steering.add(obstacleAvoidanceBehavior);
vehicle.smoother = new YUKA.Smoother(30);
// 逃离行为
const fleeBehavior = new YUKA.FleeBehavior(target.position, 3);
vehicle.steering.add(fleeBehavior);
</script>
<template>
<div></div>
</template>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
canvas {
width: 100vw;
height: 100vh;
position: fixed;
left: 0;
top: 0;
}
</style>
四、追击行为
<script setup>
import * as THREE from "three";
import * as YUKA from "yuka";
// 导入控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
// 创建场景
const scene = new THREE.Scene();
// 创建相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.set(0, 10, 20);
camera.lookAt(0, 0, 0);
// 创建渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.shadowMap.enabled = true;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建地面
const planeGeometry = new THREE.PlaneGeometry(50, 50);
const planeMaterial = new THREE.MeshStandardMaterial({ color: 0x999999 });
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.receiveShadow = true;
plane.rotation.x = -Math.PI / 2;
plane.position.y = -0.5;
scene.add(plane);
// 创建灯光
const light = new THREE.SpotLight(0xffffff, 3, 100, Math.PI / 6, 0.5);
light.position.set(10, 40, 10);
light.castShadow = true;
scene.add(light);
// 创建控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
const time = new YUKA.Time();
requestAnimationFrame(function animate() {
const delta = time.update().getDelta();
controls.update();
entityManager.update(delta);
renderer.render(scene, camera);
requestAnimationFrame(animate);
});
// 创建椎体
// const coneGeometry = new THREE.ConeGeometry(0.2, 1, 32);
// coneGeometry.rotateX(Math.PI / 2);
// const coneMaterial = new THREE.MeshStandardMaterial({ color: 0xff0000 });
// const cone = new THREE.Mesh(coneGeometry, coneMaterial);
// // cone.matrixAutoUpdate = false;
// cone.receiveShadow = true;
// cone.castShadow = true;
// scene.add(cone);
// 加载模型
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("./draco/");
loader.setDRACOLoader(dracoLoader);
let c1, c2;
c1 = loader.loadAsync("./model/car.gltf");
c2 = loader.loadAsync("./model/truck.gltf");
Promise.all([c1, c2]).then((res) => {
const car = res[0].scene;
const truck = res[1].scene;
car.children[0].rotation.y = Math.PI / 2;
car.children[0].scale.set(0.2, 0.2, 0.2);
const vehicle = new YUKA.Vehicle();
vehicle.maxSpeed = 3;
vehicle.position.set(Math.random() * 20 - 10, 0, Math.random() * 20 - 10);
vehicle.setRenderComponent(car, callback);
entityManager.add(vehicle);
truck.children[0].rotation.y = Math.PI / 2;
truck.children[0].scale.set(0.2, 0.2, 0.2);
const vehicle2 = new YUKA.Vehicle();
vehicle2.maxSpeed = 6;
vehicle2.position.set(Math.random() * 20 - 10, 0, Math.random() * 20 - 10);
vehicle2.setRenderComponent(truck, callback);
entityManager.add(vehicle2);
scene.add(car);
scene.add(truck);
// 设置追击行为
const pursuitBehavior = new YUKA.PursuitBehavior(vehicle2, 5);
vehicle.steering.add(pursuitBehavior);
// 设置卡车到达目标行为
const arriveBehavior = new YUKA.ArriveBehavior(target.position);
vehicle2.steering.add(arriveBehavior);
setInterval(() => {
target.position.set(Math.random() * 50 - 25, 0, Math.random() * 50 - 25);
}, 3000);
});
function callback(entity, renderComponent) {
// console.log(entity, renderComponent);
renderComponent.position.copy(entity.position);
renderComponent.quaternion.copy(entity.rotation);
// renderComponent.matrix.copy(entity.worldMatrix);
}
// 创建目标小球
const sphereGeometry = new THREE.SphereGeometry(0.1, 32, 32);
const sphereMaterial = new THREE.MeshStandardMaterial({ color: 0xff00ff });
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
sphere.receiveShadow = true;
sphere.castShadow = true;
scene.add(sphere);
// 创建目标
const target = new YUKA.GameEntity();
target.setRenderComponent(sphere, callback);
target.position.set(Math.random() * 20 - 10, 0, Math.random() * 20 - 10);
const entityManager = new YUKA.EntityManager();
entityManager.add(target);
</script>
<template>
<div></div>
</template>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
canvas {
width: 100vw;
height: 100vh;
position: fixed;
left: 0;
top: 0;
}
</style>
五、候鸟群集聚散效果
<script setup>
import * as THREE from "three";
import * as YUKA from "yuka";
// 导入控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
// 创建场景
const scene = new THREE.Scene();
// 创建相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.set(0, 10, 20);
camera.lookAt(0, 0, 0);
// 创建渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.shadowMap.enabled = true;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建地面
const planeGeometry = new THREE.PlaneGeometry(50, 50);
const planeMaterial = new THREE.MeshStandardMaterial({ color: 0x999999 });
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.receiveShadow = true;
plane.rotation.x = -Math.PI / 2;
plane.position.y = -0.5;
scene.add(plane);
// 创建灯光
const light = new THREE.SpotLight(0xffffff, 3, 100, Math.PI / 6, 0.5);
light.position.set(10, 40, 10);
light.castShadow = true;
scene.add(light);
// 创建控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
const time = new YUKA.Time();
requestAnimationFrame(function animate() {
const delta = time.update().getDelta();
controls.update();
entityManager.update(delta);
renderer.render(scene, camera);
requestAnimationFrame(animate);
});
// 创建椎体
// const coneGeometry = new THREE.ConeGeometry(0.2, 1, 32);
// coneGeometry.rotateX(Math.PI / 2);
// const coneMaterial = new THREE.MeshStandardMaterial({ color: 0xff0000 });
// const cone = new THREE.Mesh(coneGeometry, coneMaterial);
// // cone.matrixAutoUpdate = false;
// cone.receiveShadow = true;
// cone.castShadow = true;
// scene.add(cone);
// 加载模型
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("./draco/");
loader.setDRACOLoader(dracoLoader);
loader.load("./model/car.gltf", function (gltf) {
// console.log(gltf);
// 创建群体随机行走行为
const wanderBehavior = new YUKA.WanderBehavior(3);
// 设置整齐群体转向
const alignmentBehavior = new YUKA.AlignmentBehavior();
alignmentBehavior.weight = 5;
// 设置聚集行为
const cohesionBehavior = new YUKA.CohesionBehavior();
cohesionBehavior.weight = 5;
// 设置分离行为
const separationBehavior = new YUKA.SeparationBehavior();
separationBehavior.weight = 0.5;
for (let i = 0; i < 40; i++) {
// 创建yuka的车辆
const vehicle = new YUKA.Vehicle();
vehicle.position.set(Math.random() * 20 - 10, 0, Math.random() * 20 - 10);
vehicle.rotation.fromEuler(0, Math.random() * Math.PI, 0);
vehicle.maxSpeed = 3;
const car = gltf.scene.clone();
car.children[0].rotation.y = Math.PI / 2;
car.children[0].scale.set(0.2, 0.2, 0.2);
scene.add(car);
vehicle.setRenderComponent(car, callback);
entityManager.add(vehicle);
vehicle.steering.add(wanderBehavior);
vehicle.steering.add(alignmentBehavior);
vehicle.steering.add(cohesionBehavior);
vehicle.steering.add(separationBehavior);
}
});
// 设置车辆的渲染对象
// vehicle.setRenderComponent(cone, callback);
function callback(entity, renderComponent) {
// console.log(entity, renderComponent);
renderComponent.position.copy(entity.position);
renderComponent.quaternion.copy(entity.rotation);
// renderComponent.matrix.copy(entity.worldMatrix);
}
// 创建对实体管理对象
const entityManager = new YUKA.EntityManager();
</script>
<template>
<div></div>
</template>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
canvas {
width: 100vw;
height: 100vh;
position: fixed;
left: 0;
top: 0;
}
</style>