🚗 كيف تصنع لعبة سباق سيارات ثلاثية الأبعاد على موبايلك باستخدام Three.js
مقدمة:
تعد الألعاب ثلاثية الأبعاد من أروع أنواع الألعاب في العصر الحديث، والمميز أن إنشاء لعبة 3D لم يعد صعبًا كما كان في الماضي. في هذا المقال، سوف نتعرف على كيفية بناء لعبة سباق سيارات ثلاثية الأبعاد تعمل على المتصفح باستخدام مكتبة Three.js.
سنقوم بتصميم اللعبة بشكل يتوافق مع الأجهزة المحمولة، بحيث يمكن للمستخدمين التحكم في السيارة بواسطة الأزرار، إضافة إلى وجود عوائق وأعداء، كما سيتم حساب النقاط وإظهارها في الوقت الفعلي. كل هذا سيتم تنفيذه باستخدام JavaScript وThree.js.
الخطوات الأساسية لإنشاء اللعبة:
-
إعداد البيئة الأساسية: أول شيء، نحتاج إلى ملف HTML يحتوي على كل شيء مثل البنية الأساسية للصفحة والروابط الخاصة بالمكتبات مثل Three.js وصوت الاصطدام.
-
إنشاء مشهد Three.js: سنستخدم Three.js لإنشاء مشهد ثلاثي الأبعاد، الكاميرا، والإضاءة. هذا المشهد سيحتوي على الطريق، السيارة، العوائق، والمباني.
-
إضافة التحكمات: نضيف أزرار تحكم للمستخدم (يسار/يمين) ليتحكم في حركة السيارة.
-
إضافة التفاعل مع اللعبة: نضيف تأثير الاصطدامات، حساب النقاط، وإظهار النتيجة النهائية عندما تنتهي اللعبة.
الكود الكامل للعبة سباق السيارات ثلاثية الأبعاد:
<!DOCTYPE html>
<html lang="ar">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>🚗 لعبة سباق السيارات ثلاثية الأبعاد</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body, html { width: 100%; height: 100%; overflow: hidden; font-family: 'Poppins', sans-serif; background: linear-gradient(#87CEEB, #ffffff); }
#game-container { position: relative; width: 100%; height: 100%; }
#score { position: absolute; top: 20px; left: 20px; background: rgba(0,0,0,0.5); padding: 10px 20px; border-radius: 10px; color: #fff; font-size: 20px; }
#restart { position: absolute; top: 20px; right: 20px; background: #00b894; color: white; border: none; border-radius: 10px; padding: 10px 20px; font-size: 18px; cursor: pointer; transition: 0.3s; display: none; }
#restart:hover { background: #019875; transform: scale(1.05); }
.controls { position: absolute; bottom: 30px; width: 100%; text-align: center; }
.button { background: rgba(0,0,0,0.6); color: white; border: none; margin: 0 15px; padding: 15px 20px; border-radius: 50%; font-size: 28px; cursor: pointer; transition: 0.3s; }
.button:active { background: #444; transform: scale(0.9); }
</style>
</head>
<body>
<div id="game-container">
<div id="score">النقاط: 0</div>
<button id="restart">إعادة اللعب</button>
<div class="controls">
<button class="button" id="left">⟵</button>
<button class="button" id="right">⟶</button>
</div>
</div>
<audio id="crash-sound" src="https://cdn.pixabay.com/download/audio/2022/03/15/audio_71cb8946fc.mp3?filename=car-crash-109211.mp3"></audio>
<script src="https://cdn.jsdelivr.net/npm/three@0.150.1/build/three.min.js"></script>
<script>
let scene, camera, renderer;
let car, road, centerLine;
let enemies = [], trees = [], buildings = [], smokes = [];
let score = 0;
let moveLeft = false, moveRight = false;
let gameSpeed = 0.1;
let crashSound = document.getElementById('crash-sound');
init();
animate();
function init() {
scene = new THREE.Scene();
scene.fog = new THREE.Fog(0x87CEEB, 10, 100);
camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
camera.position.set(0, 5, 10);
camera.lookAt(0, 0, 0);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById('game-container').appendChild(renderer.domElement);
const light = new THREE.HemisphereLight(0xffffff, 0x444444, 1.5);
scene.add(light);
const roadGeometry = new THREE.PlaneGeometry(10, 5000);
const roadMaterial = new THREE.MeshStandardMaterial({ color: 0x333333 });
road = new THREE.Mesh(roadGeometry, roadMaterial);
road.rotation.x = -Math.PI/2;
road.position.z = -2000;
scene.add(road);
const lineGeometry = new THREE.PlaneGeometry(0.2, 5000);
const lineMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff });
centerLine = new THREE.Mesh(lineGeometry, lineMaterial);
centerLine.rotation.x = -Math.PI/2;
centerLine.position.z = -2000;
centerLine.position.y = 0.01;
scene.add(centerLine);
car = createCar(0x00ff00);
car.position.y = 0.5;
scene.add(car);
for (let i = 0; i < 10; i++) createEnemy();
for (let i = 0; i < 30; i++) createTree();
for (let i = 0; i < 20; i++) createBuilding();
document.getElementById('left').addEventListener('mousedown', () => moveLeft = true);
document.getElementById('left').addEventListener('mouseup', () => moveLeft = false);
document.getElementById('left').addEventListener('touchstart', (e) => { e.preventDefault(); moveLeft = true; });
document.getElementById('left').addEventListener('touchend', (e) => { e.preventDefault(); moveLeft = false; });
document.getElementById('right').addEventListener('mousedown', () => moveRight = true);
document.getElementById('right').addEventListener('mouseup', () => moveRight = false);
document.getElementById('right').addEventListener('touchstart', (e) => { e.preventDefault(); moveRight = true; });
document.getElementById('right').addEventListener('touchend', (e) => { e.preventDefault(); moveRight = false; });
document.getElementById('restart').addEventListener('click', () => location.reload());
window.addEventListener('resize', onWindowResize);
}
function createCar(color) {
const carGroup = new THREE.Group();
const bodyGeometry = new THREE.BoxGeometry(1, 0.5, 2);
const bodyMaterial = new THREE.MeshStandardMaterial({ color: color, metalness: 0.5, roughness: 0.3 });
const body = new THREE.Mesh(bodyGeometry, bodyMaterial);
carGroup.add(body);
const glassGeometry = new THREE.BoxGeometry(0.8, 0.3, 0.8);
const glassMaterial = new THREE.MeshStandardMaterial({ color: 0x88ccee, transparent: true, opacity: 0.6 });
const glass = new THREE.Mesh(glassGeometry, glassMaterial);
glass.position.y = 0.4;
carGroup.add(glass);
for (let i = 0; i < 4; i++) {
const wheelGeometry = new THREE.CylinderGeometry(0.2, 0.2, 0.1, 32);
const wheelMaterial = new THREE.MeshStandardMaterial({ color: 0x000000 });
const wheel = new THREE.Mesh(wheelGeometry, wheelMaterial);
wheel.rotation.z = Math.PI / 2;
wheel.position.set(i < 2 ? -0.4 : 0.4, 0.2, i % 2 == 0 ? 0.8 : -0.8);
carGroup.add(wheel);
}
return carGroup;
}
function createEnemy() {
const color = Math.random() * 0xffffff;
const enemyCar = createCar(color);
enemyCar.position.set((Math.random() - 0.5) * 8, 0.5, -(Math.random() * 500 + 20));
scene.add(enemyCar);
enemies.push(enemy
Car); }
function createTree() { const trunkGeometry = new THREE.CylinderGeometry(0.2, 0.2, 3); const trunkMaterial = new THREE.MeshStandardMaterial({ color: 0x8B4513 }); const trunk = new THREE.Mesh(trunkGeometry, trunkMaterial); trunk.position.set((Math.random() - 0.5) * 8, 1.5, -(Math.random() * 500 + 20)); scene.add(trunk);
const leavesGeometry = new THREE.SphereGeometry(1.5, 10, 10); const leavesMaterial = new THREE.MeshStandardMaterial({ color: 0x228B22 }); const leaves = new THREE.Mesh(leavesGeometry, leavesMaterial); leaves.position.set(0, 2.5, 0); trunk.add(leaves); trees.push(trunk); }
function createBuilding() { const buildingGeometry = new THREE.BoxGeometry(2, 5, 2); const buildingMaterial = new THREE.MeshStandardMaterial({ color: 0x888888 }); const building = new THREE.Mesh(buildingGeometry, buildingMaterial); building.position.set((Math.random() - 0.5) * 8, 2.5, -(Math.random() * 500 + 20)); scene.add(building); buildings.push(building); }
function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); }
function animate() { requestAnimationFrame(animate); road.position.z += gameSpeed; centerLine.position.z += gameSpeed; enemies.forEach(enemy => enemy.position.z += gameSpeed); trees.forEach(tree => tree.position.z += gameSpeed); buildings.forEach(building => building.position.z += gameSpeed);
if (moveLeft) car.position.x -= 0.1; if (moveRight) car.position.x += 0.1;
enemies.forEach(enemy => { if (enemy.position.z > 5) enemy.position.z = -2000; if (car.position.distanceTo(enemy.position) < 2) handleCrash(); });
trees.forEach(tree => { if (tree.position.z > 5) tree.position.z = -2000; if (car.position.distanceTo(tree.position) < 2) handleCrash(); });
buildings.forEach(building => { if (building.position.z > 5) building.position.z = -2000; if (car.position.distanceTo(building.position) < 2) handleCrash(); });
score++;
document.getElementById('score').innerText = النقاط: ${score};
renderer.render(scene, camera);
}
function handleCrash() { crashSound.play(); gameSpeed = 0; document.getElementById('restart').style.display = 'block'; }
شرح الكود:
-
المشهد (Scene):
-
يتم إعداد المشهد باستخدام
THREE.Sceneوضبط الإضاءة والكاميرا.
-
-
الطرق والعوائق:
-
قمنا بإنشاء الطريق باستخدام
THREE.PlaneGeometryوتم إضافة خطوط وسط الطريق باستخدامMeshBasicMaterial.
-
-
السيارة:
-
تم تصميم السيارة باستخدام مجموعة من
THREE.BoxGeometryوالـCylinderGeometryلإنشاء العجلات.
-
-
الأزرار والتحكم:
-
تم إضافة أزرار تحكم على الشاشة للتحرك بالسيارة يمينًا ويسارًا عبر استخدام الأحداث
mousedownوmouseupوtouchstartوtouchend.
-
-
تأثير الاصطدام:
-
إذا اصطدمت السيارة مع أي عنصر في اللعبة (مثل الأشجار أو المباني)، سيظهر الصوت وتُوقف اللعبة.
-
-
إعادة التشغيل:
-
بعد الاصطدام، يمكن للمستخدم النقر على زر "إعادة اللعب" لبدء اللعبة من جديد
- تعلميات ل chat gpt
- HopWeb APK (Android App) - تنزيل مجاني
🛠️ معايير كتابة الكود بواسطة ChatGPT:
-
كتابة الكود البرمجي بالكامل:
-
يجب أن يتم كتابة الكود بشكل مفصل وكامل داخل ملف واحد.
-
يجب كتابة الكود باستخدام اللغات المناسبة للمشروع مثل:
(HTML, CSS, JavaScript, Three.js, SVG, PHP) أو أي لغة أخرى ضرورية للمشروع.
-
-
وظائف البرنامج:
-
يجب أن يكون البرنامج الناتج قابلًا للتنفيذ بالكامل وفوريًا عند التنفيذ.
-
يجب عدم تقديم أجزاء ناقصة من الكود أو أمثلة غير مكتملة، بل يجب أن يكون الكود الجاهز عملًا كاملًا.
-
-
تصميم الواجهة:
-
يجب أن تكون واجهة المستخدم عصريّة وحديثة (Modern UI) بحيث تكون جذابة وسهلة الاستخدام.
-
يجب تصميم جميع العناصر (مثل الأزرار، النماذج، الخلفيات) لتكون بسيطة وجذابة، وتمنح المستخدم تجربة سلسة.
-
الألوان والخطوط يجب أن تتماشى مع الاتجاهات الحديثة وتضمن وضوح المحتوى، مع تأثيرات ديناميكية.
-
-
التفاعل مع الأزرار:
-
أي زر يتم تصميمه يجب أن يتضمن حركة (Animation) عند النقر عليه، لتحسين تجربة المستخدم (UX).
-
مثال: تغيير الحجم عند النقر أو التبديل بين الألوان.
-
-
هذه التأثيرات تساعد على إضافة حيوية للأزرار وتجعل التفاعل ممتعًا.
-
-
التوافق مع الأجهزة:
-
يجب أن يكون الكود متجاوبًا (Responsive)، أي أن واجهته تتكيف مع جميع الأجهزة، بما في ذلك الهواتف المحمولة والتابلت، وضمان عمله بسلاسة على جميع الأحجام.
-
لا يُقبل أن يكون هناك مشاكل في العرض على الشاشات الصغيرة أو الكبيرة.
-
تأكد من أن الأزرار والتحكمات تعمل بسلاسة عند اللمس على الأجهزة المحمولة.
-
-
الخاتمة:
لقد أنشأنا معًا لعبة سباق سيارات ثلاثية الأبعاد باستخدام Three.js التي يمكن تشغيلها مباشرة على المتصفح. يمكنك تحسين هذه اللعبة بإضافة مزيد من المزايا مثل مستويات متعددة، سيارات مختلفة، أو خلفيات متنوعة.

إرسال تعليق