AltitudeWeb/frontend/src/app/particles/services/intersection-plane.service.ts

157 lines
5.1 KiB
TypeScript

import {Injectable} from '@angular/core';
import * as THREE from 'three';
import {RendererService} from './renderer.service';
/**
* Service responsible for managing the intersection plane
*/
@Injectable({
providedIn: 'root'
})
export class IntersectionPlaneService {
private intersectionPlane!: THREE.Mesh;
private planePosition: number = 8; // Position in 1/16th of a block
constructor(private rendererService: RendererService) {
}
/**
* Creates the intersection plane and adds it to the scene
*/
createIntersectionPlane(): THREE.Mesh {
const planeGeometry = new THREE.PlaneGeometry(3, 3);
const planeMaterial = new THREE.MeshBasicMaterial({
color: 0x00AA00,
transparent: true,
opacity: 0.05,
side: THREE.DoubleSide
});
this.intersectionPlane = new THREE.Mesh(planeGeometry, planeMaterial);
this.intersectionPlane.position.z = 0;
// Center the plane vertically with the player (player is about 2 blocks tall)
this.intersectionPlane.position.y = 1;
this.rendererService.scene.add(this.intersectionPlane);
return this.intersectionPlane;
}
/**
* Updates the plane position based on slider value
*/
updatePlanePosition(value: number): void {
this.planePosition = value;
// Convert from 1/16th block to Three.js units
const position = (this.planePosition / 16) - 0.5; // Center at 0
// Check if the plane is rotated vertically (looking from above/below)
if (Math.abs(this.intersectionPlane.rotation.x) > 0.1) {
// For vertical orientation, adjust Y position
this.intersectionPlane.position.y = position * (this.intersectionPlane.rotation.x > 0 ? -1 : 1);
// Reset x and z positions
this.intersectionPlane.position.x = 0;
this.intersectionPlane.position.z = 0;
} else {
const rotation = this.intersectionPlane.rotation.y;
if (Math.abs(rotation) < 0.1 || Math.abs(rotation - Math.PI) < 0.1) {
// Camera in front (0) or behind (PI)
const direction = Math.abs(rotation) < 0.1 ? 1 : -1;
this.intersectionPlane.position.z = position * direction;
// Reset x position to avoid cumulative changes
this.intersectionPlane.position.x = 0;
} else {
// Camera on right (PI/2) or left (-PI/2)
const direction = rotation > 0 ? 1 : -1;
this.intersectionPlane.position.x = position * direction;
// Reset z position to avoid cumulative changes
this.intersectionPlane.position.z = 0;
}
}
}
/**
* Updates the plane orientation based on camera position
*/
updatePlaneOrientation(camera: THREE.Camera): void {
if (!this.intersectionPlane) return;
// Check if camera is looking from above or below first
const verticalAngle = Math.atan2(
camera.position.y,
Math.sqrt(camera.position.x * camera.position.x + camera.position.z * camera.position.z)
);
// Threshold angle for considering the camera to be above/below (about 45 degrees)
const verticalThreshold = Math.PI / 4;
if (verticalAngle > verticalThreshold) {
// Camera is above
this.intersectionPlane.rotation.x = -Math.PI / 2;
this.intersectionPlane.rotation.y = 0;
this.updatePlaneMaterial(0xAA0000);
} else if (verticalAngle < -verticalThreshold) {
// Camera is below
this.intersectionPlane.rotation.x = Math.PI / 2;
this.intersectionPlane.rotation.y = 0;
this.updatePlaneMaterial(0xAA0000);
} else {
// Reset rotation.x as we're now in the horizontal plane
this.intersectionPlane.rotation.x = 0;
// Calculate the angle between camera and player (in the XZ plane)
const cameraAngle = Math.atan2(
camera.position.x,
camera.position.z
);
// Determine which quadrant the camera is in with a 45-degree offset
const quadrant = Math.floor((cameraAngle + Math.PI + Math.PI / 4) / (Math.PI / 2)) % 4;
// Rotate the plane to face the camera
if (quadrant === 0) {
this.intersectionPlane.rotation.y = 0; // Camera in front
this.updatePlaneMaterial(0x00AA00);
} else if (quadrant === 1) {
this.intersectionPlane.rotation.y = Math.PI / 2; // Camera on right
this.updatePlaneMaterial(0x0000AA);
} else if (quadrant === 2) {
this.intersectionPlane.rotation.y = Math.PI; // Camera behind
this.updatePlaneMaterial(0x00AA00);
} else {
this.intersectionPlane.rotation.y = -Math.PI / 2; // Camera on left
this.updatePlaneMaterial(0x0000AA);
}
}
// Update position after rotation change
this.updatePlanePosition(this.planePosition);
}
/**
* Updates the plane material color
*/
private updatePlaneMaterial(color: number): void {
this.intersectionPlane.material = new THREE.MeshBasicMaterial({
color: color,
transparent: true,
opacity: 0.05,
side: THREE.DoubleSide
});
}
/**
* Gets the intersection plane
*/
getIntersectionPlane(): THREE.Mesh {
return this.intersectionPlane;
}
/**
* Gets the current plane position
*/
getPlanePosition(): number {
return this.planePosition;
}
}