new 加入动画开关门
建房子
for (let i = 0; i < 30; i++) {
const w = Math.random() * 10 + 3;
const h = House(w, w * 2, w > 7);
h.position.set(
Math.random() * 200 - 100,
0.001,
Math.random() * 200 - 100
);
h.rotateY(Math.random());
h.rotateX(Math.random());
h.rotateZ(Math.random());
scene.add(h);
}
function House(width: number = 5, length: number = 10, openDoor?: boolean) {
const house: any = {
};
const elements = [];
const group = new THREE.Group();
const material = new THREE.MeshLambertMaterial({
map: texture1,
side: THREE.DoubleSide,
});
texture2.repeat.set(2, 2);
const material2 = new THREE.MeshLambertMaterial({
map: texture2,
side: THREE.DoubleSide,
});
const door1Mesh = new THREE.MeshLambertMaterial({
map: door1Texture,
side: THREE.DoubleSide,
});
const floorProps = [width, length];
const floor = new THREE.Mesh(
new THREE.PlaneGeometry(...floorProps),
material
);
floor.rotateX(halfPI);
floor.rotateZ(halfPI);
elements.push({
element: floor, type: "floor" });
const sideProps = [floorProps[0], 4];
const leftSide = new THREE.Mesh(
new THREE.PlaneGeometry(...sideProps),
material
);
leftSide.position.set(-floorProps[1] / 2, sideProps[1] / 2, 0);
leftSide.rotateY(halfPI);
const rightSide = new THREE.Mesh(
new THREE.PlaneGeometry(...sideProps),
material
);
rightSide.position.set(floorProps[1] / 2, sideProps[1] / 2, 0);
rightSide.rotateY(halfPI);
elements.push(
{
element: leftSide, type: "leftSide" },
{
element: rightSide, type: "rightSide" }
);
const back = new THREE.Mesh(
new THREE.PlaneGeometry(floorProps[1], sideProps[1]),
material
);
back.position.set(0, sideProps[1] / 2, -floorProps[0] / 2);
elements.push({
element: back, type: "back" });
const heartShape = new THREE.Shape();
const pointX = floorProps[1] / 2;
const pointY = sideProps[1] / 2;
heartShape.moveTo(-pointX, -pointY);
heartShape.lineTo(-pointX, pointY);
heartShape.lineTo(pointX, pointY);
heartShape.lineTo(pointX, -pointY);
heartShape.lineTo(-pointX, -pointY);
const holeX = pointX / 3;
const holeY = pointY / 3;
const windowHole = new THREE.Path();
windowHole.moveTo(-holeX, holeY);
windowHole.lineTo(0, holeY);
windowHole.lineTo(0, -pointY);
windowHole.lineTo(-holeX, -pointY);
windowHole.lineTo(-holeX, holeY);
heartShape.holes.push(windowHole);
const frontGeometry = new THREE.ShapeGeometry(heartShape);
const front = new THREE.Mesh(frontGeometry, material2);
front.position.set(0, sideProps[1] / 2, floorProps[0] / 2);
elements.push({
element: front, type: "front" });
const box = new THREE.BoxGeometry(holeX, pointY + pointY / 3, 0.1);
const door = new THREE.Mesh(box, door1Mesh);
door.position.set(-holeX / 2, (pointY / 3) * 2, floorProps[0] / 2);
const doorWrap = new THREE.Object3D();
doorWrap.position.set(0, (pointY / 3) * 2, floorProps[0] / 2);
door.position.set(-holeX / 2, 0, 0);
doorWrap.add(door);
if (openDoor) {
doorWrap.userData.open = true;
doorWrap.rotateY(Math.PI);
}
elements.push({
element: door, type: "door", filter: true });
elements.push({
element: doorWrap, type: "door" });
const coverHeight = 2;
const cover = new THREE.Mesh(
new THREE.CylinderBufferGeometry(
coverHeight,
coverHeight,
floorProps[1] + coverHeight,
3
),
material
);
cover.position.y = sideProps[1] + coverHeight / 2;
cover.scale.x = floorProps[0] / 3;
cover.rotateX(-halfPI);
cover.rotateZ(halfPI);
elements.push({
element: cover, type: "cover" });
for (const {
element, type } of elements) {
house[type] = element.id;
}
for (const {
element, filter } of elements) {
element.userData.type = "house";
element.userData.house = house;
element.castShadow = true;
if (!filter) group.add(element);
}
return group;
}
点击监听
canvas.addEventListener("click", event => {
event.preventDefault();
const intersects = getIntersects(event);
if (intersects.length && intersects[0].object instanceof THREE.Mesh) {
const selectObject = intersects[0].object;
if (selectObject.userData.type === "house") {
handleHouseClick(selectObject.userData.house);
}
}
});
function getIntersects(event: MouseEvent) {
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(scene.children);
return intersects;
}
function handleHouseClick(house: any) {
const mash = scene.getObjectByProperty("id", house.door);
if (mash) {
console.log("door:", mash);
let c = 0;
const speed = 7;
let angle = Math.PI / speed;
if (mash.userData.open) {
angle *= -1;
}
const animate = () => {
requestAnimationFrame(() => {
if (c !== speed) {
mash.rotateY(angle);
c++;
requestAnimationFrame(animate);
}
});
};
animate();
mash.userData.open = angle > 0;
}
}
old
建房子
for (let i = 0; i < 5; i++) {
const w = Math.random() * 10 + 4;
const h = House(w, w * 2);
h.position.set(Math.random() * 100 - 50, 0, Math.random() * 100 - 50);
h.rotateY(Math.random());
scene.add(h);
}
function House(width: number = 5, length: number = 10) {
const house: any = {
};
const elements = [];
const group = new THREE.Group();
const material = new THREE.MeshLambertMaterial({
map: texture1,
side: THREE.DoubleSide,
});
texture2.repeat.set(2, 2);
const material2 = new THREE.MeshLambertMaterial({
map: texture2,
side: THREE.DoubleSide,
});
const door1Mesh = new THREE.MeshLambertMaterial({
map: door1Texture,
side: THREE.DoubleSide,
});
const floorProps = [width, length];
const floor = new THREE.Mesh(
new THREE.PlaneGeometry(...floorProps),
material
);
floor.rotateX(halfPI);
floor.rotateZ(halfPI);
elements.push({
element: floor, type: "floor" });
const sideProps = [floorProps[0], 4];
const leftSide = new THREE.Mesh(
new THREE.PlaneGeometry(...sideProps),
material
);
leftSide.position.set(-floorProps[1] / 2, sideProps[1] / 2, 0);
leftSide.rotateY(halfPI);
const rightSide = new THREE.Mesh(
new THREE.PlaneGeometry(...sideProps),
material
);
rightSide.position.set(floorProps[1] / 2, sideProps[1] / 2, 0);
rightSide.rotateY(halfPI);
elements.push(
{
element: leftSide, type: "leftSide" },
{
element: rightSide, type: "rightSide" }
);
const back = new THREE.Mesh(
new THREE.PlaneGeometry(floorProps[1], sideProps[1]),
material
);
back.position.set(0, sideProps[1] / 2, -floorProps[0] / 2);
elements.push({
element: back, type: "back" });
const heartShape = new THREE.Shape();
const pointX = floorProps[1] / 2;
const pointY = sideProps[1] / 2;
heartShape.moveTo(-pointX, -pointY);
heartShape.lineTo(-pointX, pointY);
heartShape.lineTo(pointX, pointY);
heartShape.lineTo(pointX, -pointY);
heartShape.lineTo(-pointX, -pointY);
const holeX = pointX / 3;
const holeY = pointY / 3;
const windowHole = new THREE.Path();
windowHole.moveTo(-holeX, holeY);
windowHole.lineTo(0, holeY);
windowHole.lineTo(0, -pointY);
windowHole.lineTo(-holeX, -pointY);
windowHole.lineTo(-holeX, holeY);
heartShape.holes.push(windowHole);
const frontGeometry = new THREE.ShapeGeometry(heartShape);
const front = new THREE.Mesh(frontGeometry, material2);
front.position.set(0, sideProps[1] / 2, floorProps[0] / 2);
elements.push({
element: front, type: "front" });
const box = new THREE.BoxGeometry(holeX, pointY + pointY / 3, 0.1);
const door = new THREE.Mesh(box, door1Mesh);
door.position.set(-holeX / 2, (pointY / 3) * 2, floorProps[0] / 2);
elements.push({
element: door, type: "door" });
const coverHeight = 2;
const cover = new THREE.Mesh(
new THREE.CylinderBufferGeometry(
coverHeight,
coverHeight,
floorProps[1] + coverHeight,
3
),
material
);
cover.position.y = sideProps[1] + coverHeight / 2;
cover.scale.x = floorProps[0] / 3;
cover.rotateX(-halfPI);
cover.rotateZ(halfPI);
elements.push({
element: cover, type: "cover" });
for (const {
element, type } of elements) {
house[type] = element.id;
}
for (const {
element } of elements) {
element.userData = {
type: "house", house };
group.add(element);
}
return group;
}
点击监听
canvas.addEventListener("click", event => {
event.preventDefault();
const intersects = getIntersects(event);
if (intersects.length && intersects[0].object instanceof THREE.Mesh) {
const selectObject = intersects[0].object;
if (selectObject.userData.type === "house") {
handleHouseClick(selectObject.userData.house);
}
}
});
function getIntersects(event: MouseEvent) {
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(scene.children);
return intersects;
}
function handleHouseClick(house: any) {
const mash = scene.getObjectByProperty("id", house.door);
if (mash) {
console.log("door:", mash);
mash.position.x *= -1;
}
}