Up-in-the-Air – commitdiff

You can use Git to clone the repository via the web URL. Download snapshot (zip)
Added basic ending cutscene
authorJulian Fietkau <git@fietkau.software>
Sun, 22 Sep 2024 20:05:42 +0000 (22:05 +0200)
committerJulian Fietkau <git@fietkau.software>
Sun, 22 Sep 2024 20:05:42 +0000 (22:05 +0200)
index.html
main.js
textures/windowsill2.png [new file with mode: 0644]

index 2fd3f817f9c3c853979d10a3d714954dd17774b8..0589ebe661b01c80e0f4bcb2b0f58c0f2c981314 100644 (file)
     align-items: end;
     gap: 2em;
   }
+  .ui-page.title.end {
+    align-items: start;
+  }
   .ui-page.title h1 {
     font-size: 1em;
     width: 24em;
     font-size: 1.4em;
     text-shadow: 0 0 .07em #fff;
   }
+  .ui-page.title.end .footer {
+    right: unset;
+    left: 0;
+    align-items: start;
+  }
   .ui-page.credits {
     padding: 1em;
     display: flex;
     line-height: 1em;
     font-family: Cookie;
   }
-  .ui-page.gameplay, .ui-page.openingcutscene {
+  .ui-page.outro {
+    padding: 1em;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    gap: 1em;
+  }
+  .ui-page.outro button {
+    width: 8em;
+    padding: .45em .6em;
+    font-size: 2.5em;
+    line-height: 1em;
+    font-family: Cookie;
+  }
+  .ui-page.gameplay, .ui-page.openingcutscene, .ui-page.endingcutscene {
     cursor: none;
   }
   canvas {
 <button class="goto title">Back</button>
 </div>
 <div class="ui-page openingcutscene"></div>
+<div class="ui-page endingcutscene"></div>
+<div class="ui-page outro">
+<button class="goto title">Return to Title Screen</button>
+</div>
 <div class="ui-page gameplay">
 <canvas width="800" height="800"></canvas>
 <div class="options" style="display: none">
diff --git a/main.js b/main.js
index 7905c46031584f3e3017fc2b31308e94c6fe75eb..430e36c4996769079da75496a638c980be031be3 100644 (file)
--- a/main.js
+++ b/main.js
@@ -64,6 +64,7 @@ function loadAllAssets(game, renderProgressCallback) {
       'textures/logo.png': 221524,
       'textures/pinwheel.png': 904,
       'textures/windowsill1.png': 483119,
+      'textures/windowsill2.png': 484665,
     };
     let total = Object.keys(todoList).map(k => todoList[k]).reduce((a, b) => a + b, 0);
     let progress = {};
@@ -122,7 +123,7 @@ function start(game) {
 function init(game, canvas) {
 
   game.timeProgress = 0;
-  game.timeTotal = 258;
+  game.timeTotal = 5;
   game.courseRadius = 50;
 
   game.objects = {};
@@ -341,6 +342,17 @@ function init(game, canvas) {
   game.objects.startingWindowsill = new THREE.Mesh(new THREE.PlaneGeometry(8, 12), startingWindowsillMaterial);
   game.objects.startingWindowsill.position.set(-10.3, -game.courseRadius - 4, -7);
   scene.add(game.objects.startingWindowsill);
+  const endingWindowsillMaterial = new THREE.MeshBasicMaterial({
+    map: game.assets.textures.windowsill2,
+    transparent: true,
+    alphaTest: 0.5,
+  });
+  game.objects.endingWindowsill = new THREE.Mesh(new THREE.PlaneGeometry(8, 12), endingWindowsillMaterial);
+  game.objects.endingWindowsill.position.set(
+    -game.objects.startingWindowsill.position.x,
+    game.objects.startingWindowsill.position.y,
+    game.objects.startingWindowsill.position.z
+  );
 
   game.view.camera.position.set(-5, -game.courseRadius, game.view.camera.position.z);
 
@@ -390,9 +402,28 @@ function animate(game, renderer, scene) {
     let cameraSwayFactor = 1;
     let cameraX = -5;
     if(game.ui.currentPage == 'title') {
-      game.objects.feather.position.set(cameraX - 6.45, -game.courseRadius - 4.2, -6.6);
-      game.objects.feather.rotation.set(Math.PI, 0, Math.PI / 2.1);
+      if(!game.ui.reachedEnd) {
+        game.objects.feather.position.set(cameraX - 6.45, -game.courseRadius - 4.2, -6.6);
+        game.objects.feather.rotation.set(Math.PI, 0, Math.PI / 2.1);
+      } else {
+        cameraX = 5;
+      }
     } else if(game.ui.currentPage == 'openingcutscene') {
+      if(game.ui.reachedEnd) {
+        game.ui.reachedEnd = false;
+        for(let i = 0; i < 6; i++) {
+          game.view.materials['cloud' + i].uniforms.lerp.value = 0.0;
+        }
+        scene.add(game.objects.startingWindowsill);
+        scene.remove(game.objects.endingWindowsill);
+        game.objects.feather.position.set(cameraX - 6.45, -game.courseRadius - 4.2, -6.6);
+        game.objects.feather.rotation.set(Math.PI, 0, Math.PI / 2.1);
+        game.objects.words.collectedCount = 0;
+        for(let word of game.objects.words) {
+          word.collected = null;
+        }
+        game.ui.root.querySelector('.ui-page.title').classList.remove('end');
+      }
       cameraSwayFactor = 1 - (game.timeProgress / 8);
       cameraX = -5 + Math.pow(Math.max(0, game.timeProgress - 3) / 5, 1.6) * 5;
 
@@ -404,22 +435,49 @@ function animate(game, renderer, scene) {
         game.ui.moveToPage('gameplay', true);
         start(game);
       }
+    } else if(game.ui.currentPage == 'endingcutscene') {
+      cameraSwayFactor = game.timeProgress / 8;
+      cameraX = 5 - Math.pow(Math.max(0, 5 - game.timeProgress) / 5, 1.6) * 5;
+      game.objects.feather.rotation.z = -0.2;
+      game.objects.feather.position.setX(10.5 * Math.min(1, easeInOut(1 - Math.max(0, 4 - game.timeProgress) / 4)));
+      game.objects.feather.position.setY(-game.courseRadius - 5.4 * Math.min(1, easeInOut(1 - Math.max(0, 4 - game.timeProgress) / 4)));
+      game.objects.feather.position.setZ(-6.6 * Math.min(1, easeInOut(1 - Math.max(0, 4 - game.timeProgress) / 4)));
+      game.objects.pinwheel.material[4].opacity = easeInOut(Math.max(0, (1 - game.timeProgress)));
+      if(game.timeProgress >= 8) {
+        game.ui.root.querySelector('.ui-page.title').classList.add('end');
+        game.ui.moveToPage('outro', true);
+      }
+    } else if(game.ui.reachedEnd) {
+      cameraX = 5;
     }
     game.view.camera.position.setY(-game.courseRadius + 0.07 * cameraSwayFactor * Math.sin(game.view.clock.getElapsedTime() * 0.5));
     game.view.camera.position.setX(cameraX + 0.05 * cameraSwayFactor * Math.sin(game.view.clock.getElapsedTime() * 0.7));
     renderer.render(scene, game.view.camera);
     return;
   }
+  if(game.timeProgress / game.timeTotal >= 1.0) {
+    game.ui.reachedEnd = true;
+    game.ui.moveToPage('endingcutscene', true);
+    start(game);
+  }
 
   const angle = 2 * Math.PI * (game.timeProgress / game.timeTotal);
   game.view.camera.position.x = game.courseRadius * Math.sin(angle);
   game.view.camera.position.y = - game.courseRadius * Math.cos(angle);
 
-  const sunsetValue = 2.0 * easeInOut(Math.min(1, Math.max(0, ((game.timeProgress / game.timeTotal) - 0.3) / 0.6)));
+  let sunsetValue = 2.0;
+  if(!game.ui.reachedEnd) {
+    sunsetValue = sunsetValue * easeInOut(Math.min(1, Math.max(0, ((game.timeProgress / game.timeTotal) - 0.3) / 0.6)));
+  }
   for(let i = 0; i < 6; i++) {
     game.view.materials['cloud' + i].uniforms.lerp.value = sunsetValue;
   }
 
+  if(game.timeProgress / game.timeTotal > 0.5 && game.objects.startingWindowsill.parent == scene) {
+    scene.remove(game.objects.startingWindowsill);
+    scene.add(game.objects.endingWindowsill);
+  }
+
   game.var.featherLocalPos.subVectors(game.objects.feather.position, game.view.camera.position).setZ(0);
   game.var.featherBorderForce.set(0, 0, 0);
   for(let coord of [0, 1]) {
diff --git a/textures/windowsill2.png b/textures/windowsill2.png
new file mode 100644 (file)
index 0000000..ac33f8b
Binary files /dev/null and b/textures/windowsill2.png differ