Spaces:
Running
Running
Update play.html
Browse files
play.html
CHANGED
|
@@ -585,39 +585,238 @@ function manageEntities(spd) {
|
|
| 585 |
let minGap = 500 - (spd * 8);
|
| 586 |
let last = entities[entities.length-1];
|
| 587 |
|
|
|
|
| 588 |
if (!last || (canvas.width - last.x > minGap)) {
|
| 589 |
-
if (Math.random() > 0.
|
| 590 |
|
| 591 |
let typeKey = 'OBSTACLE';
|
| 592 |
let rand = Math.random();
|
| 593 |
-
|
| 594 |
-
if (rand > 0.
|
|
|
|
| 595 |
|
| 596 |
let conf = GAME_CONFIG.ENTITIES[typeKey];
|
| 597 |
-
|
| 598 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 599 |
|
| 600 |
-
entities.push({
|
|
|
|
|
|
|
|
|
|
|
|
|
| 601 |
}
|
| 602 |
|
|
|
|
| 603 |
for (let i = entities.length - 1; i >= 0; i--) {
|
| 604 |
let e = entities[i];
|
| 605 |
e.x -= spd;
|
| 606 |
-
|
|
|
|
| 607 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 608 |
if (e.active) {
|
| 609 |
-
ctx.
|
| 610 |
-
|
| 611 |
-
ctx.
|
| 612 |
-
ctx.font = "
|
| 613 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 614 |
|
| 615 |
-
|
|
|
|
|
|
|
|
|
|
| 616 |
}
|
| 617 |
if (e.x + e.w < 0) entities.splice(i, 1);
|
| 618 |
}
|
| 619 |
}
|
| 620 |
-
|
| 621 |
function rectHit(x1, y1, w1, h1, x2, y2, w2, h2) { return x2 < x1 + w1 && x2 + w2 > x1 && y2 < y1 + h1 && y2 + h2 > y1; }
|
| 622 |
|
| 623 |
function handleHit(e) {
|
|
|
|
| 585 |
let minGap = 500 - (spd * 8);
|
| 586 |
let last = entities[entities.length-1];
|
| 587 |
|
| 588 |
+
// --- 1. SPAWNING LOGIC BILANCIATA ---
|
| 589 |
if (!last || (canvas.width - last.x > minGap)) {
|
| 590 |
+
if (Math.random() > 0.96) return;
|
| 591 |
|
| 592 |
let typeKey = 'OBSTACLE';
|
| 593 |
let rand = Math.random();
|
| 594 |
+
|
| 595 |
+
if (rand > 0.65) typeKey = 'LEGACY';
|
| 596 |
+
if (rand > 0.93) typeKey = 'AI';
|
| 597 |
|
| 598 |
let conf = GAME_CONFIG.ENTITIES[typeKey];
|
| 599 |
+
// Dimensioni base più grandi per visibilità
|
| 600 |
+
let h = 60, w = 60, y = state.groundY - 60;
|
| 601 |
+
let variant = 'normal';
|
| 602 |
+
|
| 603 |
+
if (typeKey === 'OBSTACLE') {
|
| 604 |
+
let obsType = Math.random();
|
| 605 |
+
|
| 606 |
+
// --- LOGICA VARIANTI ---
|
| 607 |
+
if (obsType < 0.3) {
|
| 608 |
+
// DRONE
|
| 609 |
+
w = 55; h = 55;
|
| 610 |
+
y = state.groundY - 120 - (Math.random() * 40);
|
| 611 |
+
variant = 'flying';
|
| 612 |
+
} else if (obsType < 0.65) {
|
| 613 |
+
// TOWER (Muro Alto)
|
| 614 |
+
w = 60;
|
| 615 |
+
h = 95 + (Math.random() * 50);
|
| 616 |
+
y = state.groundY - h;
|
| 617 |
+
variant = 'tower';
|
| 618 |
+
} else {
|
| 619 |
+
// GROUND (Standard)
|
| 620 |
+
y = state.groundY - h;
|
| 621 |
+
variant = 'ground';
|
| 622 |
+
}
|
| 623 |
+
|
| 624 |
+
// --- FIX: MAI DUE TORRI DI FILA ---
|
| 625 |
+
if (variant === 'tower' && last && last.variant === 'tower') {
|
| 626 |
+
// Se l'ultimo era una torre, questo diventa terra forzatamente
|
| 627 |
+
variant = 'ground';
|
| 628 |
+
h = 60; // Resetta altezza standard
|
| 629 |
+
y = state.groundY - h;
|
| 630 |
+
}
|
| 631 |
+
}
|
| 632 |
+
else if (typeKey === 'AI') {
|
| 633 |
+
w = 50; h = 50;
|
| 634 |
+
y = state.groundY - 90 - (Math.random() * 60);
|
| 635 |
+
}
|
| 636 |
+
else {
|
| 637 |
+
// LEGACY
|
| 638 |
+
y = state.groundY - 65;
|
| 639 |
+
}
|
| 640 |
|
| 641 |
+
entities.push({
|
| 642 |
+
type: typeKey, conf: conf, x: canvas.width, y: y, w: w, h: h,
|
| 643 |
+
active: true, variant: variant, pulse: Math.random() * 10,
|
| 644 |
+
rot: 0
|
| 645 |
+
});
|
| 646 |
}
|
| 647 |
|
| 648 |
+
// --- 2. RENDER LOOP "HIGH VISIBILITY" ---
|
| 649 |
for (let i = entities.length - 1; i >= 0; i--) {
|
| 650 |
let e = entities[i];
|
| 651 |
e.x -= spd;
|
| 652 |
+
e.pulse += 0.05;
|
| 653 |
+
e.rot += 0.02;
|
| 654 |
|
| 655 |
+
let floatY = 0;
|
| 656 |
+
if (e.variant === 'flying' || e.type !== 'OBSTACLE') {
|
| 657 |
+
floatY = Math.sin(state.frame * 0.08 + e.x * 0.01) * 5;
|
| 658 |
+
}
|
| 659 |
+
let drawY = e.y + floatY;
|
| 660 |
+
|
| 661 |
if (e.active) {
|
| 662 |
+
ctx.save();
|
| 663 |
+
ctx.textAlign = "center";
|
| 664 |
+
ctx.textBaseline = "middle";
|
| 665 |
+
ctx.font = "36px Arial"; // EMOJI PIÙ GRANDE
|
| 666 |
+
|
| 667 |
+
let cx = e.x + e.w/2;
|
| 668 |
+
let cy = drawY + e.h/2;
|
| 669 |
+
|
| 670 |
+
// BORDURA SPESSA PER TUTTI
|
| 671 |
+
ctx.lineWidth = 4;
|
| 672 |
+
|
| 673 |
+
// ==========================================
|
| 674 |
+
// A. AI - VERTEX NODE
|
| 675 |
+
// ==========================================
|
| 676 |
+
if (e.type === 'AI') {
|
| 677 |
+
ctx.shadowBlur = 30;
|
| 678 |
+
ctx.shadowColor = '#00D4FF';
|
| 679 |
+
|
| 680 |
+
// Anelli
|
| 681 |
+
ctx.translate(cx, cy);
|
| 682 |
+
ctx.rotate(e.rot * 2);
|
| 683 |
+
ctx.strokeStyle = '#00D4FF'; // Ciano puro
|
| 684 |
+
ctx.setLineDash([5, 5]);
|
| 685 |
+
ctx.beginPath();
|
| 686 |
+
ctx.arc(0, 0, (e.w/1.5), 0, Math.PI * 2);
|
| 687 |
+
ctx.stroke();
|
| 688 |
+
|
| 689 |
+
ctx.rotate(-e.rot * 4);
|
| 690 |
+
ctx.strokeStyle = '#fff';
|
| 691 |
+
ctx.lineWidth = 2;
|
| 692 |
+
ctx.setLineDash([]);
|
| 693 |
+
ctx.beginPath();
|
| 694 |
+
ctx.arc(0, 0, (e.w/2.2), 0, Math.PI * 2);
|
| 695 |
+
ctx.stroke();
|
| 696 |
+
|
| 697 |
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
| 698 |
+
ctx.shadowBlur = 0;
|
| 699 |
+
ctx.fillText(e.conf.CHAR, cx, cy);
|
| 700 |
+
}
|
| 701 |
+
|
| 702 |
+
// ==========================================
|
| 703 |
+
// B. LEGACY - CAFFÈ VISIBILE
|
| 704 |
+
// ==========================================
|
| 705 |
+
else if (e.type === 'LEGACY') {
|
| 706 |
+
let breathe = 1 + Math.sin(e.pulse * 2) * 0.1;
|
| 707 |
+
|
| 708 |
+
ctx.shadowBlur = 25;
|
| 709 |
+
ctx.shadowColor = '#FFC107';
|
| 710 |
+
ctx.strokeStyle = '#FFC107';
|
| 711 |
+
// SFONDO PIÙ OPACO per contrasto col caffè
|
| 712 |
+
ctx.fillStyle = 'rgba(255, 193, 7, 0.35)';
|
| 713 |
+
|
| 714 |
+
ctx.translate(cx, cy);
|
| 715 |
+
ctx.scale(breathe, breathe);
|
| 716 |
+
|
| 717 |
+
ctx.beginPath();
|
| 718 |
+
ctx.roundRect(-e.w/2, -e.h/2, e.w, e.h, 12);
|
| 719 |
+
ctx.fill();
|
| 720 |
+
ctx.stroke();
|
| 721 |
+
|
| 722 |
+
// Angoli Bianchi
|
| 723 |
+
ctx.strokeStyle = '#FFF';
|
| 724 |
+
ctx.lineWidth = 3; // Angoli più spessi
|
| 725 |
+
let corner = 10;
|
| 726 |
+
let hs = e.w/2 - 2;
|
| 727 |
+
ctx.beginPath();
|
| 728 |
+
ctx.moveTo(-hs, -hs + corner); ctx.lineTo(-hs, -hs); ctx.lineTo(-hs + corner, -hs);
|
| 729 |
+
ctx.moveTo(hs, -hs + corner); ctx.lineTo(hs, -hs); ctx.lineTo(hs - corner, -hs);
|
| 730 |
+
ctx.moveTo(-hs, hs - corner); ctx.lineTo(-hs, hs); ctx.lineTo(-hs + corner, hs);
|
| 731 |
+
ctx.moveTo(hs, hs - corner); ctx.lineTo(hs, hs); ctx.lineTo(hs - corner, hs);
|
| 732 |
+
ctx.stroke();
|
| 733 |
+
|
| 734 |
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
| 735 |
+
|
| 736 |
+
// --- FIX VISIBILITÀ CAFFÈ ---
|
| 737 |
+
// Disegniamo un alone BIANCO dietro l'emoji per staccarla dal fondo scuro/oro
|
| 738 |
+
ctx.shadowBlur = 20;
|
| 739 |
+
ctx.shadowColor = '#ffffff';
|
| 740 |
+
ctx.fillStyle = '#ffffff'; // Colore di riempimento per sicurezza (alcuni browser usano questo per emoji testuali)
|
| 741 |
+
ctx.fillText(e.conf.CHAR, cx, cy + 3);
|
| 742 |
+
// Ridisegniamo senza ombra per nitidezza
|
| 743 |
+
ctx.shadowBlur = 0;
|
| 744 |
+
ctx.fillText(e.conf.CHAR, cx, cy + 3);
|
| 745 |
+
}
|
| 746 |
+
|
| 747 |
+
// ==========================================
|
| 748 |
+
// C. OSTACOLO - GLITCH
|
| 749 |
+
// ==========================================
|
| 750 |
+
else {
|
| 751 |
+
let color = '#FF3D00';
|
| 752 |
+
let jitter = (Math.random() - 0.5) * 4;
|
| 753 |
+
let gx = e.x + jitter;
|
| 754 |
+
|
| 755 |
+
ctx.shadowBlur = 15;
|
| 756 |
+
ctx.shadowColor = color;
|
| 757 |
+
// Sfondo rosso più visibile
|
| 758 |
+
ctx.fillStyle = 'rgba(255, 61, 0, 0.3)';
|
| 759 |
+
ctx.strokeStyle = color;
|
| 760 |
+
|
| 761 |
+
// Bordo molto spesso
|
| 762 |
+
ctx.lineWidth = 4;
|
| 763 |
+
|
| 764 |
+
ctx.fillRect(gx, drawY, e.w, e.h);
|
| 765 |
+
ctx.strokeRect(gx, drawY, e.w, e.h);
|
| 766 |
+
|
| 767 |
+
// Dettagli interni
|
| 768 |
+
ctx.fillStyle = color;
|
| 769 |
+
ctx.globalAlpha = 0.8; // Dettagli più visibili
|
| 770 |
+
|
| 771 |
+
if (e.variant === 'tower') {
|
| 772 |
+
// SERVER RACK
|
| 773 |
+
for(let ly = drawY + 10; ly < drawY + e.h; ly += 20) {
|
| 774 |
+
ctx.fillRect(gx + 8, ly, e.w - 16, 4); // Linee più spesse
|
| 775 |
+
}
|
| 776 |
+
// Led lampeggiante
|
| 777 |
+
if (Math.floor(state.frame / 10) % 2 === 0) {
|
| 778 |
+
ctx.fillStyle = '#fff'; // Led bianco strobo
|
| 779 |
+
ctx.shadowColor = '#fff';
|
| 780 |
+
ctx.shadowBlur = 15;
|
| 781 |
+
ctx.beginPath(); ctx.arc(gx + e.w - 12, drawY + 12, 4, 0, Math.PI*2); ctx.fill();
|
| 782 |
+
}
|
| 783 |
+
}
|
| 784 |
+
else if (e.variant === 'flying') {
|
| 785 |
+
// DRONE
|
| 786 |
+
let wingY = Math.sin(state.frame * 0.5) * 5;
|
| 787 |
+
ctx.beginPath();
|
| 788 |
+
ctx.lineWidth = 3;
|
| 789 |
+
ctx.moveTo(gx, drawY + e.h/2);
|
| 790 |
+
ctx.lineTo(gx - 20, drawY + e.h/2 + wingY); // Ali più lunghe
|
| 791 |
+
ctx.moveTo(gx + e.w, drawY + e.h/2);
|
| 792 |
+
ctx.lineTo(gx + e.w + 20, drawY + e.h/2 + wingY);
|
| 793 |
+
ctx.stroke();
|
| 794 |
+
} else {
|
| 795 |
+
// GROUND X
|
| 796 |
+
ctx.lineWidth = 3;
|
| 797 |
+
ctx.beginPath();
|
| 798 |
+
ctx.moveTo(gx + 5, drawY + 5); ctx.lineTo(gx + e.w - 5, drawY + e.h - 5);
|
| 799 |
+
ctx.moveTo(gx + e.w - 5, drawY + 5); ctx.lineTo(gx + 5, drawY + e.h - 5);
|
| 800 |
+
ctx.stroke();
|
| 801 |
+
}
|
| 802 |
+
|
| 803 |
+
ctx.globalAlpha = 1;
|
| 804 |
+
ctx.shadowBlur = 0;
|
| 805 |
+
|
| 806 |
+
// EMOJI CON OMBRA NERA PER CONTRASTO SUL ROSSO
|
| 807 |
+
ctx.shadowColor = '#000';
|
| 808 |
+
ctx.shadowBlur = 5;
|
| 809 |
+
ctx.fillText(e.conf.CHAR, cx + jitter, cy);
|
| 810 |
+
}
|
| 811 |
|
| 812 |
+
ctx.restore();
|
| 813 |
+
|
| 814 |
+
// Collision Check
|
| 815 |
+
if (rectHit(player.x, player.y, player.w, player.h, e.x, drawY, e.w, e.h)) handleHit(e);
|
| 816 |
}
|
| 817 |
if (e.x + e.w < 0) entities.splice(i, 1);
|
| 818 |
}
|
| 819 |
}
|
|
|
|
| 820 |
function rectHit(x1, y1, w1, h1, x2, y2, w2, h2) { return x2 < x1 + w1 && x2 + w2 > x1 && y2 < y1 + h1 && y2 + h2 > y1; }
|
| 821 |
|
| 822 |
function handleHit(e) {
|