Novaciano commited on
Commit
f014153
verified
1 Parent(s): 046ea31

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +72 -89
index.html CHANGED
@@ -2,27 +2,13 @@
2
  <html lang="es">
3
  <head>
4
  <meta charset="UTF-8">
5
- <title>OutRun Engine + HUD + Rivales</title>
6
  <style>
7
- body { margin:0; overflow:hidden; background:#6dd5fa; font-family:sans-serif; touch-action:none; }
8
- canvas { display:block; width:100vw; height:80vh; background:skyblue; }
9
- #controls {
10
- position:fixed; bottom:0; width:100%;
11
- display:flex; justify-content:space-around;
12
- padding:10px; background:rgba(0,0,0,0.3);
13
- }
14
- .btn {
15
- width:70px; height:70px; border-radius:50%; border:none;
16
- background:rgba(255,255,255,0.7);
17
- font-size:24px; font-weight:bold; user-select:none;
18
- }
19
- #hud {
20
- position:fixed; top:5px; left:0; right:0;
21
- display:flex; justify-content:space-around;
22
- font-size:20px; font-weight:bold;
23
- color:white; text-shadow:2px 2px 3px black;
24
- }
25
- @media(max-width:600px){ .btn{ width:60px; height:60px; font-size:20px; } }
26
  </style>
27
  </head>
28
  <body>
@@ -40,65 +26,61 @@
40
  </div>
41
 
42
  <script>
43
- // ===================== SETUP =====================
44
- const canvas = document.getElementById("game");
45
- const ctx = canvas.getContext("2d");
46
- function resize(){ canvas.width = window.innerWidth; canvas.height = window.innerHeight*0.8; }
47
- resize(); window.addEventListener("resize", resize);
48
 
49
- let roadWidth = 2000, segL = 200, camD = 0.84;
50
- let playerX = 0, pos = 0, speed = 200;
51
- let score=0, timeLeft=60;
52
- let keys = {left:false,right:false,up:false,down:false};
53
- let segments = [];
54
 
55
- // road segments with curves
56
- for(let i=0;i<500;i++){ segments.push({i,curve:Math.sin(i/30)*2,y:i*segL}); }
57
 
58
  // sprites
59
- let palmImg = new Image(); palmImg.src="https://i.ibb.co/6Hw6yHr/palm.png";
60
- let carImg = new Image(); carImg.src="https://i.ibb.co/VVvTqYm/car.png";
61
 
62
  // rivales
63
- let rivals = [];
64
  function spawnRival(){
65
- let lane = (Math.random()*2-1)*0.8; // -0.8, 0, 0.8
66
- let z = pos + 2000 + Math.random()*3000;
67
- let spd = 400+Math.random()*400;
68
  rivals.push({x:lane,z,spd});
69
  }
70
- setInterval(spawnRival,4000); // cada 4 segundos aparece uno nuevo
71
 
72
- // ===================== INPUT =====================
73
  window.addEventListener("keydown",e=>{
74
- if(e.key==="ArrowLeft") keys.left=true;
75
- if(e.key==="ArrowRight") keys.right=true;
76
- if(e.key==="ArrowUp") keys.up=true;
77
- if(e.key==="ArrowDown") keys.down=true;
78
  });
79
  window.addEventListener("keyup",e=>{
80
- if(e.key==="ArrowLeft") keys.left=false;
81
- if(e.key==="ArrowRight") keys.right=false;
82
- if(e.key==="ArrowUp") keys.up=false;
83
- if(e.key==="ArrowDown") keys.down=false;
84
  });
85
  function bindTouch(id,key){
86
  let el=document.getElementById(id);
87
  el.addEventListener("touchstart",()=>keys[key]=true);
88
  el.addEventListener("touchend",()=>keys[key]=false);
89
  }
90
- bindTouch("left","left");
91
- bindTouch("right","right");
92
- bindTouch("up","up");
93
- bindTouch("down","down");
94
 
95
- // ===================== CORE FUNCTIONS =====================
96
- function project(p, camX, camY, camZ){
97
- let dz = p.z - camZ;
98
- let dx = p.x - camX;
99
- let dy = p.y - camY;
100
- let scale = camD / dz;
101
- return { x:(1+scale*dx)*canvas.width/2, y:(1-scale*dy)*canvas.height/2, w:scale*roadWidth/2 };
102
  }
103
  function drawSegment(p1,p2,color){
104
  ctx.fillStyle=color.grass; ctx.fillRect(0,p2.y,canvas.width,p1.y-p2.y);
@@ -107,60 +89,61 @@ function drawSegment(p1,p2,color){
107
  ctx.moveTo(p1.x-p1.w,p1.y); ctx.lineTo(p1.x+p1.w,p1.y);
108
  ctx.lineTo(p2.x+p2.w,p2.y); ctx.lineTo(p2.x-p2.w,p2.y);
109
  ctx.fill();
110
- ctx.fillStyle=color.rumble;
111
- ctx.fillRect(p1.x-p1.w*1.2,p2.y,p1.w*0.2,(p1.y-p2.y));
112
- ctx.fillRect(p1.x+p1.w,p2.y,p1.w*0.2,(p1.y-p2.y));
113
  }
114
- function drawSprite(img,scale,x,y,w,h){ ctx.drawImage(img,x-w*scale/2,y-h*scale,w*scale,h*scale); }
115
 
116
- // ===================== UPDATE =====================
117
  function update(dt){
118
- pos += speed*dt; if(pos >= segments.length*segL) pos-=segments.length*segL;
119
- if(keys.left) playerX-=0.02;
120
- if(keys.right) playerX+=0.02;
121
- if(keys.up) speed+=5;
122
- if(keys.down) speed-=5;
123
- if(speed<0) speed=0; if(speed>2000) speed=2000;
124
- // rivals
125
- for(let r of rivals){ r.z -= (speed-r.spd)*dt; }
126
- rivals = rivals.filter(r=>r.z>pos && r.z<pos+8000);
127
- // tiempo y score
128
- timeLeft-=dt; if(timeLeft<=0){ timeLeft=0; speed=0; }
129
- score += Math.floor(speed*dt*0.1);
130
  document.getElementById("score").textContent="SCORE: "+score;
131
  document.getElementById("time").textContent="TIME: "+Math.floor(timeLeft);
132
  document.getElementById("speed").textContent="SPEED: "+Math.floor(speed/10)+" km/h";
133
  }
134
 
135
- // ===================== RENDER =====================
136
  function render(){
137
  ctx.clearRect(0,0,canvas.width,canvas.height);
138
- let base=Math.floor(pos/segL), camY=1000, camZ=pos+500;
139
  let x=0,dx=0;
140
  for(let n=0;n<300;n++){
141
  let seg=segments[(base+n)%segments.length];
142
  seg.z=seg.y-pos; x+=dx; dx+=seg.curve*0.001;
143
  let p1=project({x:x,y:0,z:seg.z},playerX*roadWidth,camY,camZ);
144
  let p2=project({x:x+dx,y:0,z:seg.z+segL},playerX*roadWidth,camY,camZ);
145
- let color={ road:n%2?"#707070":"#696969", grass:n%2?"#10aa10":"#009900", rumble:"#fff" };
146
- if(p1.y>=p2.y && p2.y<canvas.height) drawSegment(p1,p2,color);
147
- // palmeras
148
- if(n%20===0 && palmImg.complete){ let s=p1.w/250; drawSprite(palmImg,s,p1.x-p1.w*1.5,p1.y,200,200); drawSprite(palmImg,s,p1.x+p1.w*1.5,p1.y,200,200); }
 
 
 
149
  }
150
- // rivales
151
  for(let r of rivals){
152
- let dz=r.z-pos; if(dz<0) continue;
153
- let proj=project({x:r.x*roadWidth,y:0,z:dz},playerX*roadWidth,camY,camZ);
154
- if(carImg.complete){ let s=proj.w/350; drawSprite(carImg,s,proj.x,proj.y,120,60); }
 
 
 
155
  }
156
  // auto jugador
157
  ctx.fillStyle="red";
158
- ctx.fillRect(canvas.width/2-20+playerX*200, canvas.height-80,40,60);
159
  }
160
 
161
- // ===================== GAME LOOP =====================
162
  let last=0;
163
- function loop(ts){ let dt=(ts-last)/1000; if(dt>0.05) dt=0.05; last=ts; update(dt); render(); requestAnimationFrame(loop); }
164
  requestAnimationFrame(loop);
165
  </script>
166
  </body>
 
2
  <html lang="es">
3
  <head>
4
  <meta charset="UTF-8">
5
+ <title>OutRun con Rivales visibles</title>
6
  <style>
7
+ body{margin:0;overflow:hidden;background:#6dd5fa;font-family:sans-serif;touch-action:none;}
8
+ canvas{display:block;width:100vw;height:80vh;background:skyblue;}
9
+ #controls{position:fixed;bottom:0;width:100%;display:flex;justify-content:space-around;padding:10px;background:rgba(0,0,0,0.3);}
10
+ .btn{width:70px;height:70px;border-radius:50%;border:none;background:rgba(255,255,255,0.7);font-size:24px;font-weight:bold;user-select:none;}
11
+ #hud{position:fixed;top:5px;left:0;right:0;display:flex;justify-content:space-around;font-size:20px;font-weight:bold;color:white;text-shadow:2px 2px 3px black;}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  </style>
13
  </head>
14
  <body>
 
26
  </div>
27
 
28
  <script>
29
+ // ===== SETUP =====
30
+ const canvas=document.getElementById("game"),ctx=canvas.getContext("2d");
31
+ function resize(){canvas.width=window.innerWidth;canvas.height=window.innerHeight*0.8;}
32
+ resize();window.addEventListener("resize",resize);
 
33
 
34
+ let roadWidth=2000,segL=200,camD=0.84;
35
+ let playerX=0,pos=0,speed=200;
36
+ let score=0,timeLeft=60;
37
+ let keys={left:false,right:false,up:false,down:false};
38
+ let segments=[];
39
 
40
+ // carretera
41
+ for(let i=0;i<500;i++){segments.push({i,curve:Math.sin(i/30)*2,y:i*segL});}
42
 
43
  // sprites
44
+ let palmImg=new Image(); palmImg.src="https://i.ibb.co/6Hw6yHr/palm.png";
45
+ let carImg=new Image(); carImg.src="https://i.ibb.co/VVvTqYm/car.png";
46
 
47
  // rivales
48
+ let rivals=[];
49
  function spawnRival(){
50
+ let lane=(Math.random()*2-1)*0.8; // carriles
51
+ let z=pos+2000+Math.random()*3000;
52
+ let spd=400+Math.random()*400;
53
  rivals.push({x:lane,z,spd});
54
  }
55
+ setInterval(spawnRival,3000);
56
 
57
+ // ===== INPUT =====
58
  window.addEventListener("keydown",e=>{
59
+ if(e.key==="ArrowLeft")keys.left=true;
60
+ if(e.key==="ArrowRight")keys.right=true;
61
+ if(e.key==="ArrowUp")keys.up=true;
62
+ if(e.key==="ArrowDown")keys.down=true;
63
  });
64
  window.addEventListener("keyup",e=>{
65
+ if(e.key==="ArrowLeft")keys.left=false;
66
+ if(e.key==="ArrowRight")keys.right=false;
67
+ if(e.key==="ArrowUp")keys.up=false;
68
+ if(e.key==="ArrowDown")keys.down=false;
69
  });
70
  function bindTouch(id,key){
71
  let el=document.getElementById(id);
72
  el.addEventListener("touchstart",()=>keys[key]=true);
73
  el.addEventListener("touchend",()=>keys[key]=false);
74
  }
75
+ bindTouch("left","left"); bindTouch("right","right");
76
+ bindTouch("up","up"); bindTouch("down","down");
 
 
77
 
78
+ // ===== CORE =====
79
+ function project(p,camX,camY,camZ){
80
+ let dz=p.z-camZ; if(dz<=0.1)dz=0.1; // evita divisi贸n por cero
81
+ let dx=p.x-camX,dy=p.y-camY;
82
+ let scale=camD/dz;
83
+ return {x:(1+scale*dx)*canvas.width/2,y:(1-scale*dy)*canvas.height/2,w:scale*roadWidth/2};
 
84
  }
85
  function drawSegment(p1,p2,color){
86
  ctx.fillStyle=color.grass; ctx.fillRect(0,p2.y,canvas.width,p1.y-p2.y);
 
89
  ctx.moveTo(p1.x-p1.w,p1.y); ctx.lineTo(p1.x+p1.w,p1.y);
90
  ctx.lineTo(p2.x+p2.w,p2.y); ctx.lineTo(p2.x-p2.w,p2.y);
91
  ctx.fill();
 
 
 
92
  }
93
+ function drawSprite(img,scale,x,y,w,h){ctx.drawImage(img,x-w*scale/2,y-h*scale,w*scale,h*scale);}
94
 
95
+ // ===== UPDATE =====
96
  function update(dt){
97
+ pos+=speed*dt; if(pos>=segments.length*segL)pos-=segments.length*segL;
98
+ if(keys.left)playerX-=0.02;
99
+ if(keys.right)playerX+=0.02;
100
+ if(keys.up)speed+=5;
101
+ if(keys.down)speed-=5;
102
+ if(speed<0)speed=0;if(speed>2000)speed=2000;
103
+ for(let r of rivals){r.z-= (speed-r.spd)*dt;}
104
+ rivals=rivals.filter(r=>r.z>pos&&r.z<pos+8000);
105
+ timeLeft-=dt;if(timeLeft<=0){timeLeft=0;speed=0;}
106
+ score+=Math.floor(speed*dt*0.1);
 
 
107
  document.getElementById("score").textContent="SCORE: "+score;
108
  document.getElementById("time").textContent="TIME: "+Math.floor(timeLeft);
109
  document.getElementById("speed").textContent="SPEED: "+Math.floor(speed/10)+" km/h";
110
  }
111
 
112
+ // ===== RENDER =====
113
  function render(){
114
  ctx.clearRect(0,0,canvas.width,canvas.height);
115
+ let base=Math.floor(pos/segL),camY=1000,camZ=pos+500;
116
  let x=0,dx=0;
117
  for(let n=0;n<300;n++){
118
  let seg=segments[(base+n)%segments.length];
119
  seg.z=seg.y-pos; x+=dx; dx+=seg.curve*0.001;
120
  let p1=project({x:x,y:0,z:seg.z},playerX*roadWidth,camY,camZ);
121
  let p2=project({x:x+dx,y:0,z:seg.z+segL},playerX*roadWidth,camY,camZ);
122
+ let color={road:n%2?"#707070":"#696969",grass:n%2?"#10aa10":"#009900",rumble:"#fff"};
123
+ if(p1.y>=p2.y&&p2.y<canvas.height)drawSegment(p1,p2,color);
124
+ if(n%20===0&&palmImg.complete){
125
+ let s=p1.w/250;
126
+ drawSprite(palmImg,s,p1.x-p1.w*1.5,p1.y,200,200);
127
+ drawSprite(palmImg,s,p1.x+p1.w*1.5,p1.y,200,200);
128
+ }
129
  }
130
+ // rivales visibles
131
  for(let r of rivals){
132
+ let dz=r.z-pos; if(dz<=0)continue;
133
+ let proj=project({x:r.x*roadWidth,y:0,z:dz},playerX*roadWidth,1000,pos+500);
134
+ if(carImg.complete){
135
+ let s=proj.w/350;
136
+ drawSprite(carImg,s,proj.x,proj.y,120,60);
137
+ }
138
  }
139
  // auto jugador
140
  ctx.fillStyle="red";
141
+ ctx.fillRect(canvas.width/2-20+playerX*200,canvas.height-80,40,60);
142
  }
143
 
144
+ // ===== LOOP =====
145
  let last=0;
146
+ function loop(ts){let dt=(ts-last)/1000;if(dt>0.05)dt=0.05;last=ts;update(dt);render();requestAnimationFrame(loop);}
147
  requestAnimationFrame(loop);
148
  </script>
149
  </body>