Add sunrise Threads automation and improve capture and character interactions

This commit is contained in:
2026-11-02 03:28:58 +09:00
parent ff86bdb5b5
commit 850ac84ef7
34 changed files with 900 additions and 34 deletions
+40 -1
View File
@@ -414,6 +414,30 @@ export function createWorld(canvas: HTMLCanvasElement, terrainData: Awaited<Retu
});
const world = {
buildingCounts: buildings?.counts,
captureFrame(view?: PerspectiveCamera) {
const activeCamera = view ?? (overview ? overviewCamera : sheep ? followCamera : camera);
if (composer && !profile?.disablePost) {
renderPass.camera = activeCamera;
composer.render(0);
} else renderer.render(scene, activeCamera);
// Copy synchronously before WebGL clears the drawing buffer.
const frame = document.createElement('canvas');
frame.width = canvas.width;
frame.height = canvas.height;
frame.getContext('2d')!.drawImage(canvas, 0, 0);
return frame;
},
captureAngle(azimuth: number, pitch: number) {
// Orbit only the capture camera; keep the character facing the sunrise.
const view = camera.clone();
view.lookAt(view.position.clone().add(new Vector3(...directionFromAngles(azimuth, pitch))));
if (sheep) {
const orbit = view.clone();
updateThirdPersonCamera(orbit, view, (x, z) => harbour?.heightAt(x, z) ?? terrain.heightAt(x, z));
return world.captureFrame(orbit);
}
return world.captureFrame(view);
},
readPlayer(): PlayerUpdate {
const yaw = sheep?.group.rotation.y ?? camera.rotation.y;
return { x: camera.position.x, z: camera.position.z, yaw: Math.atan2(Math.sin(yaw), Math.cos(yaw)),
@@ -440,7 +464,7 @@ export function createWorld(canvas: HTMLCanvasElement, terrainData: Awaited<Retu
clearPlayers() { remotePlayers?.clear(); rendering.invalidate(); },
setWeather(weather: WeatherSample | null) {
weatherTarget = weatherAppearance(weather);
rainGear.updateWeather(weatherTarget.rain, weatherTarget.snowfall);
rainGear.updateWeather(weather?.rain ?? null, weather?.snowfall ?? null);
sheep?.setEquipment(rainGear.umbrella, rainGear.raincoat, rainGear.hood, flashlightOn);
refreshGear();
// Do not blend an old precipitation type into the newly selected weather.
@@ -475,6 +499,21 @@ export function createWorld(canvas: HTMLCanvasElement, terrainData: Awaited<Retu
if (target) camera.lookAt(target.position.clone().add(new Vector3(0, id.includes('mast') ? 14 : id === 'weather-radar' ? 10 : 1, 0)));
},
lookEast() { restoreView(); camera.lookAt(camera.position.clone().add(new Vector3(1, 0, 0))); },
lookAtSunrise(azimuth: number) {
restoreView();
forward.set(...directionFromAngles(azimuth, 0));
camera.lookAt(camera.position.clone().add(forward));
if (sheep) {
sheep.group.rotation.y = Math.atan2(forward.x, forward.z);
updateThirdPersonCamera(followCamera, camera, (x, z) => harbour?.heightAt(x, z) ?? terrain.heightAt(x, z));
}
},
lookAtSun() {
if (!solarState) return;
restoreView();
camera.lookAt(camera.position.clone().add(new Vector3(...directionFromAngles(solarState.azimuth, 0))));
if (sheep) updateThirdPersonCamera(followCamera, camera, (x, z) => harbour?.heightAt(x, z) ?? terrain.heightAt(x, z));
},
setEyeHeight(meters: number) {
eyeHeight = meters;
placeObserver();