<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
<title>🚀 کارخانه موشک</title>
<style>
*{
box-sizing:border-box;
-webkit-tap-highlight-color:transparent;
}
html,body{
margin:0;
width:100%;
height:100%;
overflow:hidden;
background:#020617;
font-family:Tahoma,Arial,sans-serif;
color:white;
}
#game{
position:fixed;
inset:0;
}
canvas{
display:block;
width:100%;
height:100%;
}
#hud{
position:fixed;
top:12px;
right:12px;
width:285px;
max-width:calc(100vw - 24px);
z-index:10;
pointer-events:none;
}
.panel{
background:rgba(5,10,25,.78);
border:1px solid rgba(255,255,255,.13);
border-radius:16px;
padding:12px;
margin-bottom:9px;
backdrop-filter:blur(12px);
box-shadow:0 10px 35px rgba(0,0,0,.3);
}
.title{
font-size:20px;
font-weight:bold;
margin-bottom:8px;
}
.stat{
display:flex;
justify-content:space-between;
padding:5px 0;
font-size:13px;
}
.value{
color:#7dd3fc;
font-weight:bold;
}
.bar{
height:8px;
background:#172033;
border-radius:20px;
overflow:hidden;
margin-top:5px;
}
.bar i{
display:block;
height:100%;
width:0%;
background:#38bdf8;
transition:.15s;
}
#menu{
position:fixed;
left:12px;
bottom:12px;
width:320px;
max-width:calc(100vw - 24px);
max-height:calc(100vh - 24px);
overflow:auto;
z-index:20;
background:rgba(3,7,18,.9);
border:1px solid rgba(255,255,255,.15);
border-radius:18px;
padding:12px;
backdrop-filter:blur(16px);
}
button{
width:100%;
border:0;
border-radius:11px;
padding:10px;
margin:4px 0;
background:#172554;
color:white;
font-size:13px;
cursor:pointer;
}
button:hover{
background:#1e3a8a;
}
button:active{
transform:scale(.98);
}
button.launch{
background:#0369a1;
font-size:16px;
font-weight:bold;
padding:13px;
}
button.danger{
background:#7f1d1d;
}
.section{
border-top:1px solid rgba(255,255,255,.1);
padding-top:10px;
margin-top:10px;
}
.section h3{
margin:0 0 6px;
font-size:14px;
}
.small{
font-size:11px;
color:#94a3b8;
line-height:1.7;
}
.recipe{
background:rgba(255,255,255,.04);
border-radius:10px;
padding:8px;
margin:5px 0;
}
.recipe button{
margin-top:6px;
}
#message{
position:fixed;
top:50%;
left:50%;
transform:translate(-50%,-50%);
z-index:50;
background:rgba(2,6,23,.9);
border:1px solid rgba(255,255,255,.2);
border-radius:15px;
padding:15px 20px;
font-weight:bold;
text-align:center;
opacity:0;
pointer-events:none;
transition:.25s;
}
#message.show{
opacity:1;
}
#altitudeBig{
position:fixed;
left:50%;
top:17px;
transform:translateX(-50%);
z-index:12;
font-size:20px;
font-weight:bold;
padding:8px 15px;
border-radius:15px;
background:rgba(2,6,23,.62);
backdrop-filter:blur(8px);
pointer-events:none;
}
#controls{
position:fixed;
bottom:15px;
right:50%;
transform:translateX(50%);
z-index:30;
background:rgba(2,6,23,.65);
border-radius:13px;
padding:7px 13px;
font-size:12px;
pointer-events:none;
}
#flight{
display:none;
}
.hidden{
display:none!important;
}
@media(max-width:700px){
#hud{
width:220px;
}
.panel{
padding:9px;
}
.stat{
font-size:11px;
}
#menu{
width:245px;
font-size:12px;
}
#altitudeBig{
font-size:16px;
top:10px;
}
#controls{
font-size:10px;
}
}
</style>
</head>
<body>
<div id="game"></div>
<div id="altitudeBig">
ارتفاع: <span id="altitude">0</span> متر
</div>
<div id="hud">
<div class="panel">
<div class="title">🚀 کارخانه موشک</div>
<div class="stat">
<span>💰 پول</span>
<span class="value" id="money">10,000</span>
</div>
<div class="stat">
<span>🏆 رکورد</span>
<span class="value" id="record">0 متر</span>
</div>
<div class="stat">
<span>✈️ پروازها</span>
<span class="value" id="flights">0</span>
</div>
<div class="stat">
<span>⛽ سوخت</span>
<span class="value" id="fuel">0</span>
</div>
<div class="bar">
<i id="fuelBar"></i>
</div>
</div>
<div class="panel" id="flight">
<div class="stat">
<span>🚀 سرعت</span>
<span class="value" id="speed">0 km/h</span>
</div>
<div class="stat">
<span>📈 ارتفاع</span>
<span class="value" id="flightAltitude">0 m</span>
</div>
<div class="stat">
<span>🔥 موتور</span>
<span class="value" id="engineState">خاموش</span>
</div>
</div>
</div>
<div id="menu">
<button class="launch" onclick="launchRocket()">
🚀 پرتاب موشک
</button>
<div class="section">
<h3>🔧 ساخت و ارتقای موشک</h3>
<div class="small">
هرچه قطعات بهتر باشند، موشک ارتفاع بیشتری میگیرد.
</div>
<button onclick="upgrade('body')">
🧱 بدنه ← سطح <span id="bodyLevel">1</span>
</button>
<button onclick="upgrade('engine')">
🔥 موتور ← سطح <span id="engineLevel">1</span>
</button>
<button onclick="upgrade('tank')">
⛽ مخزن ← سطح <span id="tankLevel">1</span>
</button>
<button onclick="upgrade('fins')">
🪽 بالهها ← سطح <span id="finsLevel">1</span>
</button>
</div>
<div class="section">
<h3>🏭 کارخانه سوخت</h3>
<div class="recipe">
💧 5 مایع → ⛽ 4 سوخت
<button onclick="makeFuel(1)">تولید</button>
</div>
<div class="recipe">
💧 10 مایع + 🧱 2 آهن → ⛽ 10 سوخت
<button onclick="makeFuel(2)">تولید</button>
</div>
<div class="recipe">
💧 15 مایع + ⚙️ 2 فولاد → ⛽ 17 سوخت
<button onclick="makeFuel(3)">تولید</button>
</div>
<div class="recipe">
💧 25 مایع + 🪨 2 تیتانیوم → ⛽ 30 سوخت
<button onclick="makeFuel(4)">تولید</button>
</div>
</div>
<div class="section">
<h3>🛒 فروشگاه مواد</h3>
<button onclick="buy('iron')">
🧱 آهن ×1 | 35 تومان
</button>
<button onclick="buy('steel')">
⚙️ فولاد ×1 | 90 تومان
</button>
<button onclick="buy('aluminum')">
🔩 آلومینیوم ×1 | 70 تومان
</button>
<button onclick="buy('titanium')">
🪨 تیتانیوم ×1 | 250 تومان
</button>
<button onclick="buy('liquid5')">
💧 مایع ×5 | 80 تومان
</button>
<button onclick="buy('liquid20')">
💧 مایع ×20 | 290 تومان
</button>
</div>
<div class="section">
<h3>📦 مواد اولیه</h3>
<div class="stat">
<span>🧱 آهن</span>
<span class="value" id="iron">0</span>
</div>
<div class="stat">
<span>⚙️ فولاد</span>
<span class="value" id="steel">0</span>
</div>
<div class="stat">
<span>🔩 آلومینیوم</span>
<span class="value" id="aluminum">0</span>
</div>
<div class="stat">
<span>🪨 تیتانیوم</span>
<span class="value" id="titanium">0</span>
</div>
<div class="stat">
<span>💧 مایع</span>
<span class="value" id="liquid">0</span>
</div>
</div>
<div class="section">
<div class="small">
🎮 کنترل کامپیوتر:<br>
Space = پرتاب<br>
← → یا A / D = هدایت<br>
Esc = توقف پرواز
</div>
</div>
</div>
<div id="controls">
← → یا A / D = هدایت │ Space = پرتاب
</div>
<div id="message"></div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script>
<script>
/* =========================================================
ذخیره بازی
========================================================= */
const SAVE_KEY = "rocket_factory_high_quality_v1";
let data = {
money:10000,
fuel:0,
flights:0,
record:0,
iron:20,
steel:5,
aluminum:10,
titanium:0,
liquid:20,
body:1,
engine:1,
tank:1,
fins:1
};
try{
const old = localStorage.getItem(SAVE_KEY);
if(old){
data = {...data,...JSON.parse(old)};
}
}catch(e){}
function save(){
try{
localStorage.setItem(SAVE_KEY,JSON.stringify(data));
}catch(e){}
}
/* =========================================================
UI
========================================================= */
function format(n){
return Math.floor(n).toLocaleString("fa-IR");
}
function updateUI(){
document.getElementById("money").textContent =
format(data.money);
document.getElementById("record").textContent =
format(data.record) + " متر";
document.getElementById("flights").textContent =
format(data.flights);
document.getElementById("fuel").textContent =
format(data.fuel);
document.getElementById("iron").textContent =
format(data.iron);
document.getElementById("steel").textContent =
format(data.steel);
document.getElementById("aluminum").textContent =
format(data.aluminum);
document.getElementById("titanium").textContent =
format(data.titanium);
document.getElementById("liquid").textContent =
format(data.liquid);
document.getElementById("bodyLevel").textContent =
data.body;
document.getElementById("engineLevel").textContent =
data.engine;
document.getElementById("tankLevel").textContent =
data.tank;
document.getElementById("finsLevel").textContent =
data.fins;
const capacity = fuelCapacity();
document.getElementById("fuelBar").style.width =
Math.min(100,(data.fuel/capacity)*100) + "%";
}
function msg(text){
const el = document.getElementById("message");
el.textContent = text;
el.classList.add("show");
clearTimeout(window.messageTimer);
window.messageTimer =
setTimeout(()=>{
el.classList.remove("show");
},2200);
}
/* =========================================================
اقتصاد
========================================================= */
function buy(type){
const prices = {
iron:[35,"iron",1],
steel:[90,"steel",1],
aluminum:[70,"aluminum",1],
titanium:[250,"titanium",1],
liquid5:[80,"liquid",5],
liquid20:[290,"liquid",20]
};
const item = prices[type];
if(!item) return;
const price = item[0];
const material = item[1];
const amount = item[2];
if(data.money < price){
msg("💸 پول کافی نیست!");
return;
}
data.money -= price;
data[material] += amount;
save();
updateUI();
msg("✅ خرید انجام شد");
}
/* =========================================================
کارخانه
========================================================= */
function makeFuel(recipe){
let liquid = 0;
let iron = 0;
let steel = 0;
let titanium = 0;
let fuel = 0;
if(recipe===1){
liquid=5;
fuel=4;
}
if(recipe===2){
liquid=10;
iron=2;
fuel=10;
}
if(recipe===3){
liquid=15;
steel=2;
fuel=17;
}
if(recipe===4){
liquid=25;
titanium=2;
fuel=30;
}
if(
data.liquid < liquid ||
data.iron < iron ||
data.steel < steel ||
data.titanium < titanium
){
msg("❌ مواد اولیه کافی نیست!");
return;
}
data.liquid -= liquid;
data.iron -= iron;
data.steel -= steel;
data.titanium -= titanium;
data.fuel += fuel;
save();
updateUI();
msg("⛽ سوخت تولید شد!");
}
/* =========================================================
ارتقا
========================================================= */
function upgrade(part){
const level = data[part];
const costs = {
body:{
iron:8,
steel:2,
money:500
},
engine:{
steel:5,
aluminum:5,
money:1000
},
tank:{
aluminum:8,
steel:3,
money:800
},
fins:{
aluminum:5,
titanium:1,
money:700
}
};
const cost = costs[part];
const multiplier = level;
const ironCost =
(cost.iron || 0) * multiplier;
const steelCost =
(cost.steel || 0) * multiplier;
const aluminumCost =
(cost.aluminum || 0) * multiplier;
const titaniumCost =
(cost.titanium || 0) * multiplier;
const moneyCost =
cost.money * multiplier;
if(
data.money < moneyCost ||
data.iron < ironCost ||
data.steel < steelCost ||
data.aluminum < aluminumCost ||
data.titanium < titaniumCost
){
msg("❌ مواد یا پول کافی نیست!");
return;
}
data.money -= moneyCost;
data.iron -= ironCost;
data.steel -= steelCost;
data.aluminum -= aluminumCost;
data.titanium -= titaniumCost;
data[part]++;
rebuildRocket();
save();
updateUI();
msg("🔧 قطعه ارتقا پیدا کرد!");
}
/* =========================================================
مشخصات موشک
========================================================= */
function fuelCapacity(){
return 30 + data.tank * 25;
}
function thrustPower(){
return (
10 +
data.engine * 8 +
data.body * 1.5
);
}
function maxRocketSpeed(){
return (
70 +
data.engine * 35 +
data.body * 8
);
}
/* =========================================================
THREE.JS
========================================================= */
const scene =
new THREE.Scene();
scene.fog =
new THREE.FogExp2(0x87ceeb,.000045);
const camera =
new THREE.PerspectiveCamera(
65,
innerWidth/innerHeight,
.1,
30000
);
camera.position.set(
18,
12,
25
);
const renderer =
new THREE.WebGLRenderer({
antialias:true,
powerPreference:"high-performance"
});
renderer.setSize(
innerWidth,
innerHeight
);
renderer.setPixelRatio(
Math.min(devicePixelRatio,2)
);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type =
THREE.PCFSoftShadowMap;
document.getElementById("game")
.appendChild(renderer.domElement);
/* =========================================================
نور
========================================================= */
const hemi =
new THREE.HemisphereLight(
0xbfe8ff,
0x34422c,
2.2
);
scene.add(hemi);
const sun =
new THREE.DirectionalLight(
0xffffff,
3
);
sun.position.set(
-100,
180,
80
);
sun.castShadow = true;
sun.shadow.mapSize.width = 2048;
sun.shadow.mapSize.height = 2048;
scene.add(sun);
/* =========================================================
زمین
========================================================= */
const groundMat =
new THREE.MeshStandardMaterial({
color:0x334d2b,
roughness:1
});
const ground =
new THREE.Mesh(
new THREE.PlaneGeometry(
5000,
5000
),
groundMat
);
ground.rotation.x =
-Math.PI/2;
ground.receiveShadow = true;
scene.add(ground);
/* =========================================================
سکوی پرتاب
========================================================= */
const pad =
new THREE.Mesh(
new THREE.CylinderGeometry(
11,
11,
.7,
48
),
new THREE.MeshStandardMaterial({
color:0x555d66,
metalness:.7,
roughness:.35
})
);
pad.position.y=.35;
pad.receiveShadow=true;
pad.castShadow=true;
scene.add(pad);
const ring =
new THREE.Mesh(
new THREE.RingGeometry(
8,
8.35,
64
),
new THREE.MeshBasicMaterial({
color:0x22d3ee,
side:THREE.DoubleSide
})
);
ring.rotation.x =
-Math.PI/2;
ring.position.y=.72;
scene.add(ring);
/* =========================================================
دکل
========================================================= */
const towerMat =
new THREE.MeshStandardMaterial({
color:0x59636e,
metalness:.8,
roughness:.35
});
const tower =
new THREE.Group();
for(let i=0;i<4;i++){
const beam =
new THREE.Mesh(
new THREE.BoxGeometry(
.45,
20,
.45
),
towerMat
);
beam.position.set(
Math.cos(i*Math.PI/2)*5,
10,
Math.sin(i*Math.PI/2)*5
);
beam.castShadow=true;
tower.add(beam);
}
for(let y=3;y<20;y+=3){
const cross =
new THREE.Mesh(
new THREE.BoxGeometry(
10,
.18,
.18
),
towerMat
);
cross.position.y=y;
cross.rotation.y =
Math.PI/4;
tower.add(cross);
}
tower.position.z=-7;
scene.add(tower);
/* =========================================================
ابرها
========================================================= */
const cloudGroup =
new THREE.Group();
const cloudMat =
new THREE.MeshStandardMaterial({
color:0xffffff,
roughness:1
});
function createCloud(x,y,z,s){
const group =
new THREE.Group();
for(let i=0;i<5;i++){
const puff =
new THREE.Mesh(
new THREE.SphereGeometry(
4*s*(.65+Math.random()*.4),
16,
16
),
cloudMat
);
puff.position.x =
(i-2)*3*s;
puff.position.y =
Math.random()*2*s;
puff.position.z =
Math.random()*2*s;
group.add(puff);
}
group.position.set(x,y,z);
cloudGroup.add(group);
}
for(let i=0;i<25;i++){
createCloud(
(Math.random()-.5)*1000,
80+Math.random()*300,
(Math.random()-.5)*1000,
.5+Math.random()*1.4
);
}
scene.add(cloudGroup);
/* =========================================================
موشک
========================================================= */
let rocket =
new THREE.Group();
let rocketBody;
let engineGlow;
let flame;
let rocketVisualPosition;
function mat(color,metal=.2,rough=.5){
return new THREE.MeshStandardMaterial({
color,
metalness:metal,
roughness:rough
});
}
function rebuildRocket(){
if(rocket.parent){
scene.remove(rocket);
}
rocket =
new THREE.Group();
/* بدنه */
const bodyHeight =
7 + data.body*.35;
rocketBody =
new THREE.Mesh(
new THREE.CylinderGeometry(
1.55,
1.7,
bodyHeight,
32
),
mat(
0xe5e7eb,
.75,
.28
)
);
rocketBody.castShadow=true;
rocketBody.receiveShadow=true;
rocket.add(rocketBody);
/* نوک */
const nose =
new THREE.Mesh(
new THREE.ConeGeometry(
1.55,
3.2,
32
),
mat(
0xef4444,
.45,
.3
)
);
nose.position.y =
bodyHeight/2 + 1.6;
nose.castShadow=true;
rocket.add(nose);
/* پنجره */
const windowMat =
new THREE.MeshStandardMaterial({
color:0x38bdf8,
metalness:.8,
roughness:.15
});
const window =
new THREE.Mesh(
new THREE.SphereGeometry(
.72,
24,
16
),
windowMat
);
window.scale.set(
1,
.55,
.25
);
window.position.set(
0,
1.4,
-1.45
);
rocket.add(window);
/* نوارها */
for(let i=0;i<2;i++){
const band =
new THREE.Mesh(
new THREE.CylinderGeometry(
1.59,
1.59,
.28,
32
),
mat(
i===0?0x0f172a:0xf59e0b,
.5,
.3
)
);
band.position.y =
-1+i*2.1;
rocket.add(band);
}
/* موتور */
const engine =
new THREE.Mesh(
new THREE.CylinderGeometry(
.75,
.95,
1.4,
24
),
mat(
0x20242b,
.9,
.22
)
);
engine.position.y =
-bodyHeight/2-.7;
rocket.add(engine);
/* نازل */
const nozzle =
new THREE.Mesh(
new THREE.CylinderGeometry(
.65,
1.05,
.8,
24
),
mat(
0x111827,
.95,
.2
)
);
nozzle.position.y =
-bodyHeight/2-1.65;
rocket.add(nozzle);
/* بالهها */
const finMat =
mat(
data.fins>=4
?0x22c55e
:0x2563eb,
.6,
.35
);
for(let i=0;i<4;i++){
const fin =
new THREE.Mesh(
new THREE.BoxGeometry(
.35,
2.6+data.fins*.15,
1.8
),
finMat
);
const a =
i*Math.PI/2;
fin.position.set(
Math.sin(a)*1.65,
-bodyHeight/2+1,
Math.cos(a)*1.65
);
fin.rotation.y=a;
fin.castShadow=true;
rocket.add(fin);
}
/* شعله */
flame =
new THREE.Mesh(
new THREE.ConeGeometry(
.72,⚠️Content was pasted as plain text and auto-formatted as a code block. Use the Code Block button in the editor for proper formatting.