الألعاب النارية
مرحبًا بك في Sky Adventure، الشركة المستقبلية التي تقدم أفضل الألعاب النارية في المجرة! 🎇
سنقوم بإنشاء موقع ويب ثلاثي الأبعاد لعرض ألعابنا النارية باستخدام Three.js وReact Three Fiber ومحرك VFX الخاص بنا.
هذا ما سنقوم ببنائه معًا!
مشروع البداية
مشروع البداية لدينا يشمل بالفعل ما يلي:
- إعداد أساسي لـ React Three Fiber مع جزيرة عائمة جميلة نطلق منها الألعاب النارية.
- تأثيرات ما بعد المعالجة لجعل الأضواء من النموذج تتوهج (ولاحقًا الألعاب النارية).
- واجهة مستخدم بسيطة مصنوعة بـ Tailwind CSS مع ثلاثة أزرار لتشغيل الألعاب النارية لاحقًا.
هذا ما نحصل عليه عندما نشغل مشروع البداية.
الألعاب النارية
لإنشاء الألعاب النارية، سنستخدم محرك VFX الذي قمنا ببنائه في الدرس السابق. هذا المحرك يسمح لنا بإنشاء وإدارة أنظمة جسيمات متعددة ذات سلوكيات مختلفة.
useFireworks
لإدارة الألعاب النارية بكفاءة، سنقوم بإنشاء hook مخصص يسمى useFireworks
. هذا الـ hook سيتولى إنشاء وإدارة الألعاب النارية.
لنقم بإضافة مكتبة zustand إلى مشروعنا:
yarn add zustand
الآن في مجلد يسمى hooks
، قم بإنشاء ملف جديد يسمى useFireworks.js
:
import { create } from "zustand"; const useFireworks = create((set, get) => { return { fireworks: [], }; }); export { useFireworks };
متجر بسيط يحتوي على مصفوفة فارغة للألعاب النارية.
لنقم بإضافة طريقة لإنشاء لعبة نارية:
// ... import { randFloat, randInt } from "three/src/math/MathUtils.js"; const useFireworks = create((set) => { return { fireworks: [], addFirework: () => { set((state) => { return { fireworks: [ ...state.fireworks, { id: `${Date.now()}-${randInt(0, 100)}-${state.fireworks.length}`, position: [0, 0, 0], velocity: [randFloat(-8, 8), randFloat(5, 10), randFloat(-8, 8)], delay: randFloat(0.8, 2), color: ["skyblue", "pink"], }, ], }; }); }, }; }); // ...
سيقوم addFirework
بإضافة لعبة نارية جديدة إلى المتجر تضم:
id
: معرّف فريد لاستخدامه كمفتاح في مكون React.position
: موقع البداية للعبة النارية.velocity
: الاتجاه والسرعة للعبة النارية قبل أن تنفجر.delay
: الزمن قبل أن تنفجر اللعبة النارية.color
: مصفوفة من الألوان لاستخدامها لجسيمات انفجار اللعبة النارية.
يمكننا الآن ربط هذا الـ hook مع واجهة المستخدم لإطلاق الألعاب النارية.
افتح UI.jsx
ولنقم بربط الميثود addFirework
مع الأزرار:
import { useFireworks } from "../hooks/useFireworks"; export const UI = () => { const addFirework = useFireworks((state) => state.addFirework); return ( <section className="fixed inset-0 z-10 flex items-center justify-center"> {/* ... */} <div // ... > {/* ... */} <div className="flex gap-4"> <button // .. onClick={addFirework} > 🎆 Classic </button> <button // .. onClick={addFirework} > 💖 Love </button> <button // .. onClick={addFirework} > 🌊 Sea </button> </div> {/* ... */} </div> </section> ); };
للتحقق مما إذا كان يعمل، لنقم بإنشاء مكون Fireworks.jsx
. سنقوم فقط بتسجيل الألعاب النارية في وحدة التحكم في الوقت الحالي:
import { useFireworks } from "../hooks/useFireworks"; export const Fireworks = () => { const fireworks = useFireworks((state) => state.fireworks); console.log(fireworks); };
ودعنا نضيفه إلى مكون Experience
// ... import { Fireworks } from "./Fireworks"; export const Experience = () => { // ... return ( <> {/* ... */} <Float speed={0.6} rotationIntensity={2} position-x={4} floatIntensity={2} > <Fireworks /> <Gltf src="/models/SkyIsland.glb" /> </Float> {/* ... */} </> ); };
نقوم باستيراد مكون Fireworks
ونضيفه بجانب SkyIsland في مكون <Float />
.
عند الضغط على الأزرار، يمكننا رؤية الألعاب النارية تُضاف بشكل صحيح إلى المتجر في وحدة التحكم.
قبل تمثيلها في المشهد، نحتاج إلى إدارة دورة حياة الألعاب النارية. حاليًا، يتم إضافتها ولكن لا يمكن إزالتها.
في الميثود addFirework
في الـ hook useFireworks
، يمكننا إضافة setTimeout
لإزالة اللعبة النارية بعد مرور وقت معين.
أولاً نحتاج إلى معرفة متى تم إضافة اللعبة النارية. يمكننا إضافة خاصية time
إلى كائن اللعبة النارية:
{ id: `${Date.now()}-${randInt(0, 100)}-${state.fireworks.length}`, // ... time: Date.now(), },
ثم نقوم باستدعاء setTimeout
لإزالة الألعاب النارية التي انفجرت وتلاشت:
addFirework: () => { set((state) => { // ... }); setTimeout(() => { set((state) => ({ fireworks: state.fireworks.filter( (firework) => Date.now() - firework.time < 4000 // الحد الأقصى للتأخير هو 2 ثانية + الحد الأقصى لعمر الجسيمات هو 2 ثانية ), })); }, 4000); },
نقوم بتصفية الألعاب النارية التي تم إضافتها منذ أكثر من 4 ثواني مضت. بهذه الطريقة، نستبقي الألعاب النارية الفعّالة.
قم بتعديل الوقت بناءً على الإعدادات النهائية التي ستستخدمها للألعاب النارية.
عند الضغط على الأزرار، يمكننا رؤية الألعاب النارية تُزال بشكل صحيح بعد وقت معين في وحدة التحكم.
يمكننا الآن الخوض في الجزء الذي كنت تنتظره: إنشاء الألعاب النارية في المشهد!
محرك الـ VFX (Wawa VFX)
لتجنب النسخ/اللصق للمكون من الدرس السابق، قمت بنشر محرك VFX كحزمة على npm: Wawa VFX. يمكنك تثبيته عن طريق تشغيل:
yarn add wawa-vfx@^1.0.0
باستخدام
@^1.0.0
، نضمن دائماً استخدام الإصدار الرئيسي 1 من الحزمة، ولكن بما في ذلك أحدث الإصدارات الفرعية والإصدارات الإصلاحية. بهذه الطريقة، يمكننا الاستفادة من أحدث الميزات وإصلاحات الأخطاء دون تغييرات متعطلة.
يمكننا الآن استخدام <VFXParticles />
و <VFXEmitter />
في مشروعنا!
في التجربة، دعونا نضيف المكون VFXParticles
إلى المشهد:
// ... import { VFXParticles } from "wawa-vfx"; export const Experience = () => { const controls = useRef(); return ( <> {/* ... */} <VFXParticles name="firework-particles" settings={{ nbParticles: 100000, gravity: [0, -9.8, 0], renderMode: "billboard", intensity: 3, }} /> <EffectComposer> <Bloom intensity={1.2} luminanceThreshold={1} mipmapBlur /> </EffectComposer> </> ); };
نضيف المكون VFXParticles
مع الإعدادات التالية:
100000
جسيم. حيث عندما نصل إلى الحد، سيتم إزالة الجسيمات الأقدم، يجب أن يكون ذلك كافياً للعديد من الألعاب النارية في نفس الوقت.gravity
لمحاكاة الجاذبية على الجسيمات.-9.8
هو الجاذبية على الأرض. (لكن انتظر نحن في الفضاء! 👀)renderMode
إلىbillboard
ليواجه دائماً الكاميرا.intensity
إلى3
لجعل الجسيمات تتوهج في سماء الليل.
مكان وضع المكون
<VFXParticles />
ليس مهماً جداً. فقط تأكد من أنه في المستوى العلوي من المشهد.
ودعونا نضيف مكون VFXEmitter
بجانب VFXParticles
لتشكيل الانفجار في وضع debug
والوصول إلى التحكم البصري:
// ... import { VFXEmitter, VFXParticles } from "wawa-vfx"; export const Experience = () => { const controls = useRef(); return ( <> {/* ... */} <VFXParticles name="firework-particles" settings={{ nbParticles: 100000, gravity: [0, -9.8, 0], renderMode: "billboard", intensity: 3, }} /> <VFXEmitter emitter="firework-particles" debug /> {/* ... */} </> ); };
تأكد من تعيين الخاصية emitter
إلى نفس name
مثل المكون VFXParticles
وتعيين debug
إلى true
لرؤية التحكمات.
*اصنع نسخة أولية من انفجار الألعاب النارية. *💥
بمجرد أن تكون راضياً عن الإعدادات، يمكنك إزالة الخاصية debug
من المكون VFXEmitter
، اضغط على زر التصدير وألصق الإعدادات في المكون VFXEmitter
.
<VFXEmitter emitter="firework-particles" settings={{ nbParticles: 5000, delay: 0, spawnMode: "burst", colorStart: ["skyblue", "pink"], particlesLifetime: [0.1, 2], size: [0.01, 0.4], startPositionMin: [-0.1, -0.1, -0.1], startPositionMax: [0.1, 0.1, 0.1], directionMin: [-1, -1, -1], directionMax: [1, 1, 1], startRotationMin: [degToRad(-90), 0, 0], startRotationMax: [degToRad(90), 0, 0], rotationSpeedMin: [0, 0, 0], rotationSpeedMax: [3, 3, 3], speed: [1, 12], }} />
لدينا كل شيء جاهز لتوصيل الألعاب النارية بمحرك VFX!
الألعاب النارية الانفجار
داخل ملف Fireworks.jsx
، دعنا ننشئ مكون Firework
الذي سيمثل واحدة من الألعاب النارية:
// ... import { useRef } from "react"; import { VFXEmitter } from "wawa-vfx"; export const Fireworks = () => { // ... }; const Firework = ({ velocity, delay, position, color }) => { const ref = useRef(); return ( <> <group ref={ref} position={position}> <VFXEmitter emitter="firework-particles" settings={{ nbParticles: 5000, delay: 0, spawnMode: "burst", colorStart: ["skyblue", "pink"], particlesLifetime: [0.1, 2], size: [0.01, 0.4], startPositionMin: [-0.1, -0.1, -0.1], startPositionMax: [0.1, 0.1, 0.1], directionMin: [-1, -1, -1], directionMax: [1, 1, 1], startRotationMin: [degToRad(-90), 0, 0], startRotationMax: [degToRad(90), 0, 0], rotationSpeedMin: [0, 0, 0], rotationSpeedMax: [3, 3, 3], speed: [1, 12], }} /> </group> </> ); };
ببساطة قطع/لصق VFXEmitter
من مكون Experience
إلى مكون Firework
.
نقوم بتغليفه في <group />
لنتمكن من تحريك الألعاب النارية في المشهد بناءً على position
و velocity
.
React Three Fiber: The Ultimate Guide to 3D Web Development
✨ You have reached the end of the preview ✨
Go to the next level with Three.js and React Three Fiber!
Get full access to this lesson and the complete course when you enroll:
- 🔓 Full lesson videos with no limits
- 💻 Access to the final source code
- 🎓 Course progress tracking & completion
- 💬 Invite to our private Discord community
One-time payment. Lifetime updates included.