AgroTech Rush
by StormGecko10642 lines21.2 KB
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>AgroTech Rush</title>
<style>
:root{
--bg1:#0b2e13;
--bg2:#12421c;
--panel:#1c5028;
--panel-dark:#0e3016;
--gold:#f4c542;
--gold-dark:#c98f1f;
--cream:#f4ecd8;
--danger:#e0503a;
--sky:#2ea7c9;
--text:#f4ecd8;
font-family: 'Courier New', 'Consolas', monospace;
}
*{box-sizing:border-box; -webkit-tap-highlight-color:transparent; user-select:none;}
html,body{
margin:0; padding:0; width:100%; height:100%;
background: radial-gradient(ellipse at top, var(--bg2), var(--bg1) 70%);
overflow:hidden; color:var(--text);
touch-action:none;
}
#game{
position:fixed; inset:0; display:flex; flex-direction:column;
}
#topbar{
display:flex; align-items:center; justify-content:space-between;
padding:8px 12px; background:var(--panel-dark);
border-bottom:4px solid var(--gold-dark);
font-weight:bold; font-size:clamp(12px,2.6vw,18px);
flex-wrap:wrap; gap:4px 10px; z-index:5;
}
#topbar .stat{display:flex; align-items:center; gap:4px;}
#hearts{letter-spacing:2px;}
#comboWrap{color:var(--gold); min-width:70px; text-align:center;}
#canvasWrap{position:relative; flex:1; min-height:0;}
canvas{display:block; width:100%; height:100%;}
#bins{
display:flex; background:var(--panel-dark);
border-top:4px solid var(--gold-dark);
padding:6px; gap:6px; z-index:5;
}
.bin{
flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center;
background:var(--panel); border:3px solid var(--gold-dark); border-radius:10px;
padding:8px 2px; cursor:pointer; color:var(--cream);
font-size:clamp(18px,5.5vw,30px); line-height:1.1;
transition:transform .06s, background .1s;
}
.bin small{font-size:clamp(8px,2vw,11px); letter-spacing:.5px;}
.bin:active, .bin.pressed{transform:scale(.9); background:var(--gold-dark);}
.bin.flash-good{background:#3f9142 !important;}
.bin.flash-bad{background:var(--danger) !important;}
.overlay{
position:absolute; inset:0; z-index:20;
display:flex; flex-direction:column; align-items:center; justify-content:center;
background:rgba(6,26,10,.92); text-align:center; padding:24px; gap:16px;
}
.hidden{display:none !important;}
h1{
color:var(--gold); font-size:clamp(28px,8vw,54px); margin:0;
text-shadow:3px 3px 0 var(--gold-dark), 0 0 20px rgba(244,197,66,.5);
letter-spacing:2px;
}
.subtitle{max-width:480px; font-size:clamp(13px,3.4vw,16px); line-height:1.5; color:var(--cream);}
.legend{display:flex; flex-wrap:wrap; gap:10px; justify-content:center; max-width:520px;}
.legend div{
background:var(--panel); border:2px solid var(--gold-dark); border-radius:8px;
padding:6px 10px; font-size:clamp(11px,2.8vw,14px);
}
button.big{
font-family:inherit; font-weight:bold; font-size:clamp(16px,4.5vw,22px);
padding:14px 34px; border-radius:12px; border:3px solid var(--gold-dark);
background:linear-gradient(180deg,var(--gold),var(--gold-dark)); color:#1c1300;
cursor:pointer; box-shadow:0 6px 0 #7a5a10; letter-spacing:1px;
}
button.big:active{transform:translateY(4px); box-shadow:0 2px 0 #7a5a10;}
button.ghost{
font-family:inherit; font-weight:bold; font-size:clamp(13px,3.4vw,16px);
padding:10px 22px; border-radius:10px; border:2px solid var(--gold);
background:transparent; color:var(--gold); cursor:pointer;
}
#factCard{
background:var(--panel); border:3px solid var(--gold);
border-radius:14px; padding:20px; max-width:480px;
}
#factCard .tag{color:var(--gold); font-weight:bold; letter-spacing:2px; font-size:13px;}
#factCard p{font-size:clamp(14px,3.6vw,18px); line-height:1.5; margin:10px 0 0;}
.score-big{font-size:clamp(30px,9vw,56px); color:var(--gold); font-weight:bold; text-shadow:2px 2px 0 var(--gold-dark);}
.best{font-size:clamp(12px,3.2vw,15px); color:var(--sky);}
#levelBadge{
position:absolute; top:10px; left:50%; transform:translateX(-50%);
background:var(--gold); color:#1c1300; font-weight:bold; padding:4px 14px;
border-radius:20px; font-size:clamp(11px,3vw,14px); z-index:8; opacity:.92;
}
</style>
</head>
<body>
<div id="game">
<div id="topbar">
<div class="stat">🏆 <span id="scoreVal">0</span></div>
<div id="comboWrap">✨ x<span id="comboVal">1.0</span></div>
<div class="stat" id="hearts">❤️❤️❤️</div>
</div>
<div id="canvasWrap">
<div id="levelBadge">NÍVEL 1</div>
<canvas id="c"></canvas>
<div id="menuScreen" class="overlay">
<h1>🌾 AGROTECH<br>RUSH</h1>
<div class="subtitle">
Itens caem representando problemas da lavoura. Toque na ação certa antes que caiam no chão! Combine ciência, agronomia e tecnologia pra salvar a colheita.
</div>
<div class="legend">
<div>🥀→💧 Água</div>
<div>🐛→🧪 Defensivo</div>
<div>🍂→🌿 Adubo</div>
<div>🔥→⛅ Sombra</div>
<div>🌽→🌾 Colher</div>
<div>🛰️ Drone = bônus!</div>
</div>
<button class="big" id="startBtn">🚀 COMEÇAR</button>
<div class="best" id="menuBest">Recorde: 0</div>
</div>
<div id="factScreen" class="overlay hidden">
<div id="factCard">
<div class="tag">🔬 VOCÊ SABIA?</div>
<p id="factText"></p>
</div>
</div>
<div id="overScreen" class="overlay hidden">
<h1 style="font-size:clamp(22px,7vw,40px)">🌾 FIM DE JOGO</h1>
<div class="score-big" id="finalScore">0</div>
<div class="best" id="overBest">Recorde: 0</div>
<button class="big" id="retryBtn">🔁 JOGAR DE NOVO</button>
<button class="ghost" id="shareBtn">📤 Copiar resultado</button>
</div>
</div>
<div id="bins">
<div class="bin" data-action="water"><div>💧</div><small>ÁGUA</small></div>
<div class="bin" data-action="pest"><div>🧪</div><small>PRAGA</small></div>
<div class="bin" data-action="fertilizer"><div>🌿</div><small>ADUBO</small></div>
<div class="bin" data-action="shade"><div>⛅</div><small>SOMBRA</small></div>
<div class="bin" data-action="harvest"><div>🌾</div><small>COLHER</small></div>
</div>
</div>
<script>
(function(){
"use strict";
// ---------- Setup ----------
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
var wrap = document.getElementById('canvasWrap');
var DPR = Math.min(window.devicePixelRatio || 1, 2);
function resize(){
var w = wrap.clientWidth, h = wrap.clientHeight;
canvas.width = w * DPR; canvas.height = h * DPR;
canvas.style.width = w+'px'; canvas.style.height = h+'px';
ctx.setTransform(DPR,0,0,DPR,0,0);
W = w; H = h;
}
var W=0,H=0;
window.addEventListener('resize', resize);
resize();
// ---------- Audio (WebAudio, no external files) ----------
var actx = null;
function ensureAudio(){
if(!actx){
try{ actx = new (window.AudioContext || window.webkitAudioContext)(); }catch(e){ actx = null; }
}
}
function beep(freq, dur, type, vol){
if(!actx) return;
try{
var o = actx.createOscillator();
var g = actx.createGain();
o.type = type || 'sine';
o.frequency.value = freq;
g.gain.value = 0;
o.connect(g); g.connect(actx.destination);
var t = actx.currentTime;
g.gain.linearRampToValueAtTime(vol!==undefined?vol:0.18, t+0.01);
g.gain.exponentialRampToValueAtTime(0.001, t + (dur||0.15));
o.start(t);
o.stop(t + (dur||0.15) + 0.02);
}catch(e){}
}
function playGood(comboLevel){
var base = 440 + Math.min(comboLevel,20)*18;
beep(base, 0.12, 'square', 0.15);
setTimeout(function(){ beep(base*1.5, 0.1, 'sine', 0.12); }, 60);
}
function playBad(){ beep(140, 0.28, 'sawtooth', 0.2); }
function playWhiff(){ beep(220, 0.08, 'triangle', 0.08); }
function playDrone(){
beep(300,0.15,'sine',0.15);
setTimeout(function(){beep(500,0.15,'sine',0.15);},90);
setTimeout(function(){beep(760,0.2,'sine',0.18);},180);
}
function playLevelUp(){
[520,660,880].forEach(function(f,i){ setTimeout(function(){beep(f,0.18,'square',0.16);}, i*100); });
}
// ---------- Game data ----------
var TYPES = {
water: {emoji:'🥀', action:'water', unlockLvl:1},
pest: {emoji:'🐛', action:'pest', unlockLvl:2},
fertilizer: {emoji:'🍂', action:'fertilizer', unlockLvl:3},
shade: {emoji:'🔥', action:'shade', unlockLvl:4},
harvest: {emoji:'🌽', action:'harvest', unlockLvl:1}
};
var FACTS = [
"Sensores de umidade no solo podem reduzir o uso de água na lavoura em até 30%.",
"Drones agrícolas mapeiam plantações inteiras e identificam pragas antes que se espalhem.",
"A rotação de culturas ajuda a manter os nutrientes do solo de forma natural.",
"A agricultura de precisão usa GPS para aplicar água e adubo só onde é necessário.",
"Minhocas melhoram a aeração do solo e aumentam a fertilidade da terra.",
"O Brasil é um dos maiores produtores agrícolas do planeta.",
"Compostagem transforma restos de comida em adubo rico em nutrientes.",
"Estufas inteligentes ajustam temperatura e umidade automaticamente com sensores.",
"Abelhas polinizam cerca de um terço de todos os alimentos que comemos.",
"Biossensores conseguem detectar doenças em plantas antes de aparecerem sintomas visíveis.",
"Satélites ajudam agricultores a prever safras e monitorar a saúde das plantas.",
"Irrigação por gotejamento pode economizar até 60% de água comparado à irrigação tradicional."
];
var usedFacts = [];
function nextFact(){
if(usedFacts.length >= FACTS.length) usedFacts = [];
var pool = FACTS.filter(function(f){return usedFacts.indexOf(f)===-1;});
var f = pool[Math.floor(Math.random()*pool.length)];
usedFacts.push(f);
return f;
}
var STORAGE_KEY = 'agrotech_rush_best';
function getBest(){
try{ return parseInt(localStorage.getItem(STORAGE_KEY)||'0',10) || 0; }catch(e){ return 0; }
}
function setBest(v){
try{ localStorage.setItem(STORAGE_KEY, String(v)); }catch(e){}
}
// ---------- Game state ----------
var state = 'menu'; // menu, playing, factpause, gameover
var score = 0, combo = 0, comboMult = 1.0, lives = 3, level = 1;
var correctSinceLevel = 0;
var items = [];
var particles = [];
var shake = 0;
var flashColor = null, flashAlpha = 0;
var spawnTimer = 0, spawnInterval = 1400;
var fallSpeedBase = 55; // px/sec
var lastTime = 0;
var droneCooldown = 0;
var binEls = Array.prototype.slice.call(document.querySelectorAll('.bin'));
function availableTypes(){
var keys = Object.keys(TYPES).filter(function(k){ return TYPES[k].unlockLvl <= level; });
return keys;
}
function resetGame(){
score=0; combo=0; comboMult=1.0; lives=3; level=1; correctSinceLevel=0;
items=[]; particles=[]; shake=0; flashAlpha=0;
spawnTimer=0; spawnInterval=1400; fallSpeedBase=55; droneCooldown=3000;
updateHUD();
}
function updateHUD(){
document.getElementById('scoreVal').textContent = Math.floor(score);
document.getElementById('comboVal').textContent = comboMult.toFixed(1);
document.getElementById('hearts').textContent = '❤️'.repeat(Math.max(lives,0)) + '🖤'.repeat(Math.max(3-lives,0));
document.getElementById('levelBadge').textContent = 'NÍVEL ' + level;
}
// ---------- Spawning ----------
function spawnItem(){
var avail = availableTypes();
var isDrone = droneCooldown<=0 && Math.random() < 0.10;
var key, typeInfo;
if(isDrone){
key = 'drone';
typeInfo = {emoji:'🛰️', action:'drone'};
droneCooldown = 9000 + Math.random()*4000;
} else {
key = avail[Math.floor(Math.random()*avail.length)];
typeInfo = TYPES[key];
}
var r = Math.max(24, Math.min(W,H)*0.055);
items.push({
key:key,
emoji: typeInfo.emoji,
action: typeInfo.action,
x: r + Math.random()*(W-2*r),
y: -r,
r: r,
speed: fallSpeedBase + level*7 + Math.random()*20,
wobble: Math.random()*Math.PI*2,
resolved:false
});
}
// ---------- Particles ----------
function burst(x,y,color,n){
for(var i=0;i<(n||14);i++){
var a = Math.random()*Math.PI*2;
var sp = 60+Math.random()*160;
particles.push({
x:x,y:y, vx:Math.cos(a)*sp, vy:Math.sin(a)*sp,
life:0.5+Math.random()*0.4, age:0, color:color, r:2+Math.random()*3
});
}
}
function triggerFlash(color){ flashColor=color; flashAlpha=0.35; }
function triggerShake(amount){ shake = Math.max(shake, amount); }
// ---------- Input handling ----------
function pressBin(el){
el.classList.add('pressed');
setTimeout(function(){ el.classList.remove('pressed'); }, 90);
}
function flashBin(el, good){
el.classList.add(good?'flash-good':'flash-bad');
setTimeout(function(){ el.classList.remove(good?'flash-good':'flash-bad'); }, 180);
}
function handleBinTap(action, el){
ensureAudio();
if(state==='menu'){ return; }
if(state!=='playing') return;
pressBin(el);
if(action==='drone'){
// shouldn't happen, bins don't have drone action
}
// find best matching item: any drone on screen resolves on ANY bin tap
var droneIdx = -1, matchIdx = -1, matchBestY = -1;
for(var i=0;i<items.length;i++){
var it = items[i];
if(it.resolved) continue;
if(it.action==='drone'){ droneIdx = i; }
else if(it.action===action){
if(it.y > matchBestY){ matchBestY = it.y; matchIdx = i; }
}
}
if(droneIdx!==-1){
resolveDrone(items[droneIdx]);
flashBin(el,true);
return;
}
if(matchIdx!==-1){
resolveCorrect(items[matchIdx], el);
} else {
// whiff - no matching item currently falling
flashBin(el,false);
playWhiff();
comboMult = Math.max(1.0, comboMult - 0.2);
combo = 0;
updateHUD();
}
}
function resolveCorrect(it, el){
it.resolved = true;
combo++;
comboMult = Math.min(3.0, 1.0 + combo*0.06);
var heightFrac = 1 - (it.y / H); // 1 = caught near top, 0 = near bottom
var basePts = 100 * (0.5 + heightFrac*1.0);
var pts = basePts * comboMult;
score += pts;
correctSinceLevel++;
burst(it.x, it.y, '#f4c542', 16);
if(el) flashBin(el,true);
playGood(combo);
updateHUD();
checkLevelUp();
}
function resolveDrone(it){
it.resolved = true;
var cleared = 0;
items.forEach(function(o){
if(!o.resolved && o.action!=='drone'){
o.resolved = true; cleared++;
burst(o.x,o.y,'#2ea7c9',10);
}
});
var pts = 150 + cleared*40;
score += pts * comboMult;
combo += 2;
comboMult = Math.min(3.0, 1.0 + combo*0.06);
burst(it.x, it.y, '#2ea7c9', 26);
triggerFlash('rgba(46,167,201,0.35)');
playDrone();
updateHUD();
}
function missItem(it){
it.resolved = true;
lives--;
combo = 0; comboMult = 1.0;
triggerShake(10);
triggerFlash('rgba(224,80,58,0.35)');
playBad();
updateHUD();
if(lives<=0){
endGame();
}
}
function checkLevelUp(){
var need = 8 + level*2;
if(correctSinceLevel >= need){
correctSinceLevel = 0;
level++;
fallSpeedBase += 9;
spawnInterval = Math.max(650, spawnInterval - 90);
playLevelUp();
showFact();
}
}
binEls.forEach(function(el){
var action = el.getAttribute('data-action');
el.addEventListener('pointerdown', function(e){
e.preventDefault();
handleBinTap(action, el);
});
});
// Keyboard support (1-5)
window.addEventListener('keydown', function(e){
var map = {'1':'water','2':'pest','3':'fertilizer','4':'shade','5':'harvest'};
if(map[e.key] && state==='playing'){
var idx = ['water','pest','fertilizer','shade','harvest'].indexOf(map[e.key]);
handleBinTap(map[e.key], binEls[idx]);
}
});
// ---------- Fact overlay ----------
var factTimer = null;
function showFact(){
state = 'factpause';
document.getElementById('factText').textContent = nextFact();
document.getElementById('factScreen').classList.remove('hidden');
clearTimeout(factTimer);
factTimer = setTimeout(function(){
document.getElementById('factScreen').classList.add('hidden');
state = 'playing';
}, 2200);
}
// ---------- Start / End ----------
function startGame(){
ensureAudio();
resetGame();
document.getElementById('menuScreen').classList.add('hidden');
document.getElementById('overScreen').classList.add('hidden');
document.getElementById('factScreen').classList.add('hidden');
state = 'playing';
lastTime = performance.now();
requestAnimationFrame(loop);
}
function endGame(){
state = 'gameover';
var best = getBest();
if(score > best){ best = Math.floor(score); setBest(best); }
document.getElementById('finalScore').textContent = Math.floor(score);
document.getElementById('overBest').textContent = 'Recorde: ' + best;
document.getElementById('overScreen').classList.remove('hidden');
}
document.getElementById('startBtn').addEventListener('pointerdown', function(e){
e.preventDefault(); startGame();
});
document.getElementById('retryBtn').addEventListener('pointerdown', function(e){
e.preventDefault(); startGame();
});
document.getElementById('shareBtn').addEventListener('pointerdown', function(e){
e.preventDefault();
var txt = '🌾 Fiz ' + Math.floor(score) + ' pontos no AgroTech Rush! Consegue superar? 🚀 (jogo feito no ArcadeLab)';
var done = function(){
var b = document.getElementById('shareBtn');
var old = b.textContent; b.textContent = '✅ Copiado!';
setTimeout(function(){ b.textContent = old; }, 1400);
};
try{
if(navigator.clipboard && navigator.clipboard.writeText){
navigator.clipboard.writeText(txt).then(done).catch(function(){ fallbackCopy(txt, done); });
} else {
fallbackCopy(txt, done);
}
}catch(err){ fallbackCopy(txt, done); }
});
function fallbackCopy(txt, done){
try{
var ta = document.createElement('textarea');
ta.value = txt; ta.style.position='fixed'; ta.style.opacity='0';
document.body.appendChild(ta); ta.select();
document.execCommand('copy');
document.body.removeChild(ta);
done();
}catch(e){}
}
document.getElementById('menuBest').textContent = 'Recorde: ' + getBest();
// ---------- Main loop ----------
function loop(now){
var dt = Math.min(0.05, (now - lastTime)/1000);
lastTime = now;
if(state==='playing'){
spawnTimer += dt*1000;
if(spawnTimer >= spawnInterval){
spawnTimer = 0;
spawnItem();
}
droneCooldown -= dt*1000;
for(var i=items.length-1;i>=0;i--){
var it = items[i];
if(it.resolved) continue;
it.y += it.speed * dt;
it.wobble += dt*2;
if(it.y - it.r > H){
if(it.action==='drone'){
it.resolved = true; // drone just leaves harmlessly
} else {
missItem(it);
}
}
}
items = items.filter(function(it){ return !(it.resolved && it.y > H+50) && it.y < H+80; });
items = items.filter(function(it){ return it.y < H + 60 || !it.resolved; });
}
for(var p=particles.length-1;p>=0;p--){
var pt = particles[p];
pt.age += dt;
if(pt.age >= pt.life){ particles.splice(p,1); continue; }
pt.x += pt.vx*dt; pt.y += pt.vy*dt;
pt.vy += 220*dt;
}
if(shake>0){ shake = Math.max(0, shake - dt*30); }
if(flashAlpha>0){ flashAlpha = Math.max(0, flashAlpha - dt*0.8); }
render();
requestAnimationFrame(loop);
}
function render(){
ctx.clearRect(0,0,W,H);
ctx.save();
if(shake>0){
var sx = (Math.random()-0.5)*shake, sy=(Math.random()-0.5)*shake;
ctx.translate(sx,sy);
}
// background field stripes
ctx.fillStyle = '#0e3719';
ctx.fillRect(0,0,W,H);
ctx.globalAlpha = 0.5;
for(var s=0;s<6;s++){
ctx.fillStyle = s%2===0 ? '#124020' : '#0e3719';
ctx.fillRect(0, H*(s/6), W, H/6);
}
ctx.globalAlpha = 1;
// danger line
ctx.strokeStyle = 'rgba(224,80,58,0.35)';
ctx.lineWidth = 2;
ctx.setLineDash([8,6]);
ctx.beginPath();
ctx.moveTo(0, H-6); ctx.lineTo(W, H-6);
ctx.stroke();
ctx.setLineDash([]);
// items
items.forEach(function(it){
if(it.resolved) return;
var wob = Math.sin(it.wobble)*4;
ctx.save();
ctx.translate(it.x + wob, it.y);
ctx.font = (it.r*1.7)+'px serif';
ctx.textAlign='center'; ctx.textBaseline='middle';
// glow circle
ctx.beginPath();
ctx.fillStyle = it.action==='drone' ? 'rgba(46,167,201,0.25)' : 'rgba(244,197,66,0.18)';
ctx.arc(0,0,it.r*1.15,0,Math.PI*2);
ctx.fill();
ctx.fillText(it.emoji, 0, 2);
ctx.restore();
});
// particles
particles.forEach(function(pt){
var alpha = 1 - pt.age/pt.life;
ctx.globalAlpha = Math.max(0,alpha);
ctx.fillStyle = pt.color;
ctx.beginPath();
ctx.arc(pt.x, pt.y, pt.r, 0, Math.PI*2);
ctx.fill();
ctx.globalAlpha = 1;
});
ctx.restore();
if(flashAlpha>0 && flashColor){
ctx.fillStyle = flashColor.replace(/[\d.]+\)$/, flashAlpha+')');
ctx.fillRect(0,0,W,H);
}
}
render();
})();
</script>
</body>
</html>Game Source: AgroTech Rush
Creator: StormGecko10
Libraries: none
Complexity: complex (642 lines, 21.2 KB)
The full source code is displayed above on this page.
Remix Instructions
To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: agrotech-rush-stormgecko10" to link back to the original. Then publish at arcadelab.ai/publish.