Spaces:
Sleeping
Sleeping
Trae Assistant commited on
Commit ·
aa989e4
1
Parent(s): c868c0f
优化
Browse files- static/js/main.js +63 -46
- templates/index.html +1 -1
static/js/main.js
CHANGED
|
@@ -157,8 +157,8 @@ createApp({
|
|
| 157 |
this.x = window.innerWidth / 2;
|
| 158 |
this.y = window.innerHeight + 200;
|
| 159 |
this.angle = -Math.PI / 2;
|
| 160 |
-
this.scale = 1.5;
|
| 161 |
-
this.state = 'IDLE';
|
| 162 |
|
| 163 |
// Spirit Particles
|
| 164 |
this.spirits = [];
|
|
@@ -183,7 +183,7 @@ createApp({
|
|
| 183 |
}
|
| 184 |
|
| 185 |
// Position
|
| 186 |
-
const ease = 0.
|
| 187 |
this.x += dx * ease;
|
| 188 |
this.y += dy * ease;
|
| 189 |
|
|
@@ -343,8 +343,11 @@ createApp({
|
|
| 343 |
loading.value = false;
|
| 344 |
if (!canvasElement.value) return;
|
| 345 |
|
| 346 |
-
|
| 347 |
-
canvasElement.value.height = window.innerHeight
|
|
|
|
|
|
|
|
|
|
| 348 |
|
| 349 |
// Screen Shake
|
| 350 |
let shakeX = 0;
|
|
@@ -374,11 +377,14 @@ createApp({
|
|
| 374 |
canvasCtx.globalAlpha = 1.0;
|
| 375 |
|
| 376 |
// Hand & Gesture Logic
|
| 377 |
-
|
| 378 |
-
|
|
|
|
|
|
|
|
|
|
| 379 |
let detectedGesture = 'NONE';
|
| 380 |
|
| 381 |
-
if (
|
| 382 |
const lm = results.multiHandLandmarks[0];
|
| 383 |
const isFingerExtended = (tipIdx, pipIdx) => lm[tipIdx].y < lm[pipIdx].y;
|
| 384 |
|
|
@@ -411,56 +417,65 @@ createApp({
|
|
| 411 |
lastGesture = detectedGesture;
|
| 412 |
}
|
| 413 |
|
| 414 |
-
// Init Sword
|
| 415 |
-
if (!sword) {
|
| 416 |
sword = new Sword();
|
| 417 |
-
|
| 418 |
-
|
| 419 |
-
|
| 420 |
-
|
| 421 |
-
|
| 422 |
-
|
| 423 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 424 |
}
|
| 425 |
}
|
| 426 |
|
| 427 |
// State Machine
|
| 428 |
const STABLE = 5;
|
| 429 |
|
| 430 |
-
if (
|
| 431 |
-
if (
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
chargeLevel
|
| 436 |
-
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
|
| 440 |
-
|
| 441 |
-
if (
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
|
| 445 |
-
|
| 446 |
-
|
| 447 |
-
|
|
|
|
|
|
|
|
|
|
| 448 |
}
|
| 449 |
-
|
|
|
|
|
|
|
|
|
|
| 450 |
}
|
| 451 |
} else {
|
| 452 |
-
|
| 453 |
-
sword.state = 'FOLLOW';
|
| 454 |
chargeLevel = Math.max(0, chargeLevel - 0.05);
|
| 455 |
}
|
| 456 |
-
} else {
|
| 457 |
-
sword.state = 'IDLE';
|
| 458 |
-
chargeLevel = Math.max(0, chargeLevel - 0.05);
|
| 459 |
}
|
| 460 |
-
}
|
| 461 |
|
| 462 |
-
|
| 463 |
-
|
|
|
|
| 464 |
|
| 465 |
// Draw Rift (Behind Sword or Front? Front is better for "Split Sky")
|
| 466 |
if (riftEffect) {
|
|
@@ -471,13 +486,15 @@ createApp({
|
|
| 471 |
|
| 472 |
// Particles
|
| 473 |
particles.forEach((p, i) => {
|
| 474 |
-
p.update(sword.x, sword.y);
|
| 475 |
p.draw(canvasCtx);
|
| 476 |
if (p.life <= 0 && p.type !== 'SPIRIT') particles.splice(i, 1);
|
| 477 |
});
|
| 478 |
|
| 479 |
// Draw Sword
|
| 480 |
-
|
|
|
|
|
|
|
| 481 |
|
| 482 |
canvasCtx.restore();
|
| 483 |
};
|
|
|
|
| 157 |
this.x = window.innerWidth / 2;
|
| 158 |
this.y = window.innerHeight + 200;
|
| 159 |
this.angle = -Math.PI / 2;
|
| 160 |
+
this.scale = 1.5;
|
| 161 |
+
this.state = 'IDLE';
|
| 162 |
|
| 163 |
// Spirit Particles
|
| 164 |
this.spirits = [];
|
|
|
|
| 183 |
}
|
| 184 |
|
| 185 |
// Position
|
| 186 |
+
const ease = 0.2; // Slightly faster for better responsiveness
|
| 187 |
this.x += dx * ease;
|
| 188 |
this.y += dy * ease;
|
| 189 |
|
|
|
|
| 343 |
loading.value = false;
|
| 344 |
if (!canvasElement.value) return;
|
| 345 |
|
| 346 |
+
// Optimize: Only resize if dimensions changed
|
| 347 |
+
if (canvasElement.value.width !== window.innerWidth || canvasElement.value.height !== window.innerHeight) {
|
| 348 |
+
canvasElement.value.width = window.innerWidth;
|
| 349 |
+
canvasElement.value.height = window.innerHeight;
|
| 350 |
+
}
|
| 351 |
|
| 352 |
// Screen Shake
|
| 353 |
let shakeX = 0;
|
|
|
|
| 377 |
canvasCtx.globalAlpha = 1.0;
|
| 378 |
|
| 379 |
// Hand & Gesture Logic
|
| 380 |
+
const hasHand = results.multiHandLandmarks && results.multiHandLandmarks.length > 0;
|
| 381 |
+
|
| 382 |
+
// Default target (when no hand): Center of screen
|
| 383 |
+
let targetX = window.innerWidth / 2;
|
| 384 |
+
let targetY = window.innerHeight / 2;
|
| 385 |
let detectedGesture = 'NONE';
|
| 386 |
|
| 387 |
+
if (hasHand) {
|
| 388 |
const lm = results.multiHandLandmarks[0];
|
| 389 |
const isFingerExtended = (tipIdx, pipIdx) => lm[tipIdx].y < lm[pipIdx].y;
|
| 390 |
|
|
|
|
| 417 |
lastGesture = detectedGesture;
|
| 418 |
}
|
| 419 |
|
| 420 |
+
// Init Sword Logic: Only create if hand is detected
|
| 421 |
+
if (hasHand && !sword) {
|
| 422 |
sword = new Sword();
|
| 423 |
+
// Spawn at the bottom (off-screen) to animate "Sword Coming"
|
| 424 |
+
sword.x = window.innerWidth / 2;
|
| 425 |
+
sword.y = window.innerHeight + 200;
|
| 426 |
+
|
| 427 |
+
// Initialize stars if not already done
|
| 428 |
+
if (stars.length === 0) {
|
| 429 |
+
for(let i=0; i<80; i++) {
|
| 430 |
+
stars.push({
|
| 431 |
+
x: Math.random() * window.innerWidth,
|
| 432 |
+
y: Math.random() * window.innerHeight,
|
| 433 |
+
size: Math.random() * 2,
|
| 434 |
+
opacity: Math.random() * 0.5
|
| 435 |
+
});
|
| 436 |
+
}
|
| 437 |
}
|
| 438 |
}
|
| 439 |
|
| 440 |
// State Machine
|
| 441 |
const STABLE = 5;
|
| 442 |
|
| 443 |
+
if (sword) {
|
| 444 |
+
if (gestureTimer > STABLE) {
|
| 445 |
+
if (detectedGesture === 'SWORD_FINGER') {
|
| 446 |
+
// Charging State
|
| 447 |
+
sword.state = 'CHARGING';
|
| 448 |
+
if (chargeLevel < 1.0) {
|
| 449 |
+
chargeLevel += 0.02;
|
| 450 |
+
if (Math.random() < 0.2) playSound('CHARGE');
|
| 451 |
+
}
|
| 452 |
+
} else if (detectedGesture === 'OPEN_PALM') {
|
| 453 |
+
// If Charged, Trigger SPLIT
|
| 454 |
+
if (chargeLevel > 0.8) {
|
| 455 |
+
if (!riftEffect) {
|
| 456 |
+
riftEffect = new RiftEffect();
|
| 457 |
+
shockwave = 1.0;
|
| 458 |
+
playSound('SLASH');
|
| 459 |
+
// Sparks
|
| 460 |
+
for(let i=0; i<100; i++) {
|
| 461 |
+
particles.push(new Particle(targetX, targetY, 'SPARK'));
|
| 462 |
+
}
|
| 463 |
+
chargeLevel = 0; // Reset
|
| 464 |
}
|
| 465 |
+
} else {
|
| 466 |
+
// Just Follow
|
| 467 |
+
sword.state = 'FOLLOW';
|
| 468 |
+
chargeLevel = Math.max(0, chargeLevel - 0.05);
|
| 469 |
}
|
| 470 |
} else {
|
| 471 |
+
sword.state = 'IDLE';
|
|
|
|
| 472 |
chargeLevel = Math.max(0, chargeLevel - 0.05);
|
| 473 |
}
|
|
|
|
|
|
|
|
|
|
| 474 |
}
|
|
|
|
| 475 |
|
| 476 |
+
// Update Sword
|
| 477 |
+
sword.update(targetX, targetY);
|
| 478 |
+
}
|
| 479 |
|
| 480 |
// Draw Rift (Behind Sword or Front? Front is better for "Split Sky")
|
| 481 |
if (riftEffect) {
|
|
|
|
| 486 |
|
| 487 |
// Particles
|
| 488 |
particles.forEach((p, i) => {
|
| 489 |
+
p.update(sword ? sword.x : 0, sword ? sword.y : 0);
|
| 490 |
p.draw(canvasCtx);
|
| 491 |
if (p.life <= 0 && p.type !== 'SPIRIT') particles.splice(i, 1);
|
| 492 |
});
|
| 493 |
|
| 494 |
// Draw Sword
|
| 495 |
+
if (sword) {
|
| 496 |
+
sword.draw(canvasCtx);
|
| 497 |
+
}
|
| 498 |
|
| 499 |
canvasCtx.restore();
|
| 500 |
};
|
templates/index.html
CHANGED
|
@@ -37,7 +37,7 @@
|
|
| 37 |
|
| 38 |
<!-- UI Layer -->
|
| 39 |
<div class="ui-layer flex flex-col justify-between p-4">
|
| 40 |
-
<div class="text-center mt-
|
| 41 |
<h1 class="text-3xl md:text-5xl font-bold text-white tracking-widest title-text opacity-80">剑 来 · 开 天</h1>
|
| 42 |
<p class="text-gray-300 text-xs md:text-sm mt-2 opacity-60">剑指聚气,挥掌开天</p>
|
| 43 |
</div>
|
|
|
|
| 37 |
|
| 38 |
<!-- UI Layer -->
|
| 39 |
<div class="ui-layer flex flex-col justify-between p-4">
|
| 40 |
+
<div class="text-center mt-10">
|
| 41 |
<h1 class="text-3xl md:text-5xl font-bold text-white tracking-widest title-text opacity-80">剑 来 · 开 天</h1>
|
| 42 |
<p class="text-gray-300 text-xs md:text-sm mt-2 opacity-60">剑指聚气,挥掌开天</p>
|
| 43 |
</div>
|