יצירת ספר אינטראקטיבי - חלק 24 - אפקט להבה ב-HTML5


יריב 08/05/2013 (נערך לאחרונה ב-28/05/2013)


 

 

הקוד שנעסוק בו בפוסט זה מבוסס על דוגמא ללהבה צבעונית מבוססת חלקיקים אקראיים מאתר נחמד מאוד שמצאתי שמלמד HTML5 בעזרת דוגמאות חיות שניתן לשנות בהן את הקוד באתר ולראות את השינוי בזמן אמת: thecodeplayer.com.
במקור מדובר על להבה צבעונית, לא כל כך מציאותית, העוקבת אחר תנועת סמן העכבר.
אנו נקח את הקוד הזה ונבצע את ההתאמות הרצויות כדי ליצור להבה הנראית יותר מציאותית, נוסיף אפקט של עשן, ולבסוף נגרום לה להופיע במקום קבוע על תמונת הרקע ללא קשר לגודל ופרופורציות החלון.

נמשיך ממה שכבר התחלנו בחלק הקודם. מה שיש לנו בינתיים זה תמונת רקע המתאימה את הפריסה בהתאם למנח הצד - אופקי או אנכי בכל רזולוציה.

נוסיף קובץ javascript ריק לתיקיית JS ונקשור אותו לדף ה-HTML כמתואר בתמונה 2.
בדף ה-CSS אין שינוי מיוחד (תמונה 3).
כל הקסם קורה מתוך קוד ה-javascript להלן (ראו גם בתמונות 4 ו-5) ועליו נרחיב את ההסבר.


 
window.onload = function () {
    //Hardcoded... I know..
    var backgroundWidth = 4901;
    var backgroundHeight = 3427;
    var fireX = 2371;
    var fireY = 2700;
 
    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
 
    //Make the canvas occupy the full page
    var W = window.innerWidth, H = window.innerHeight;
    canvas.width = W;
    canvas.height = H;
 
    var particles = [];
 
    //Lets create some particles now
    var particle_count = 100;
    for (var i = 0; i < particle_count; i++) {
        particles.push(new particle());
    }
 
    function particle() {
        W = window.innerWidth, H = window.innerHeight;
 
        //speed
        this.speed = { x: -1 + Math.random() * 2, y: -12 + Math.random() * 4 };
 
        //location
        var x1 = W / 2 - 50;
 
        if (W / H > backgroundWidth / backgroundHeight) {
            var y1 = H - ((W / backgroundWidth) * backgroundHeight - (W / backgroundWidth) * (fireY));
        }
        else {
            var y1 = 0.78 * H - (backgroundHeight / backgroundWidth) * ((H - fireY) / H);
        }
 
        this.location = { x: x1 + Math.random() * 40, y: y1 + Math.random() * 7 };
 
        //radius range
        this.radius = (2 + Math.random() * 15);
 
        //life range = 20-30
        this.life = 1 + Math.random() * 15;
        this.remaining_life = this.life;
 
        //colors
        this.r = 255;
        this.g = 130;
        this.b = 10;
    }
 
    function draw() {
        W = window.innerWidth, H = window.innerHeight;
        canvas.width = W;
        canvas.height = H;
 
        //Painting the canvas black particles are painted with "lighter"
        //In the next frame the background is painted normally without blending to the
        //previous frame
        ctx.globalCompositeOperation = "destination-out";
        ctx.fillStyle = "black";
        ctx.fillRect(0, 0, W, H);
        ctx.globalCompositeOperation = "lighter";
 
        for (var i = 0; i < particles.length; i++) {
            var p = particles[i];
            ctx.beginPath();
 
            //changing opacity according to the life.
            //opacity goes to 0 at the end of life of a particle
            p.opacity = Math.round(p.remaining_life / p.life * 100) / 100
 
            //a gradient instead of white fill
            var gradient = ctx.createRadialGradient(p.location.x, p.location.y, 0, p.location.x, p.location.y, p.radius);
            gradient.addColorStop(0, "rgba(" + p.r + ", " + p.g + ", " + p.b + ", " + p.opacity + ")");
            gradient.addColorStop(0.5, "rgba(" + p.r + ", " + p.g + ", " + p.b + ", " + p.opacity + ")");
            gradient.addColorStop(1, "rgba(" + p.r + ", " + p.g + ", " + p.b + ", 0)");
            ctx.fillStyle = gradient;
            ctx.arc(p.location.x, p.location.y, p.radius, Math.PI * 2, false);
            ctx.fill();
 
            //lets move the particles
            p.remaining_life--;
            p.radius--;
            p.location.x += p.speed.x;
            p.location.y += p.speed.y;
 
            //Smoke
            p.r -= 5;
            p.g += 10;
            p.b += 20;
 
            //regenerate particles
            if (p.remaining_life < 0 || p.radius < 0) {
                //a brand new particle replacing the dead one
                particles[i] = new particle();
            }
        }
    }

    setInterval(draw, 100);
}




  • ()window.onload
    הקוד יבוצע רק לאחר טעינת הדף במלואו כולל התמונות והעיצוב.
  • בשורות הראשונות מופיעים הגדלים הקבועים של תמונת הרקע - אורך, רוחב ומיקום הלהבה בפיקסלים.
    מצב טוב יותר יהיה מציאת הגדלים באופן דינאמי, כך שבמקרה ונחליף את תמונת הרקע אז נצטרך לשנות פחות את הקוד.
  • ;("var canvas = document.getElementById("canvas
    מציאת האלמנט בדף ה-HTML עליו רוצים לבצע מניפולציות ושינויים.
  • ;("var ctx = canvas.getContext("2d
    נותן את היכולות ליצור גרפיקה תוך כדי ריצה על הקנבס.
  • לאחר מכן לקחנו את מידות הדפדפן וקבענו את המידות האלה גם לקנבס.
  • יצרנו מערך אובייקטים ומילאנו אותו לפי מספר החלקיקים הרצוי.
  • בכל פעם ש"נדחף" אובייקט חדש לתוך מערך החלקיקים יש קריאה לפונקציה ()particle שהיא סוג של בנאי המגדיר את תכונותיו של כל חלקיק חדש.
  • בתחילת הבנאי יש דגימה מחדש של מידות החלון כדי לאפשר את שינוי מנח המכשיר (תצוגה לאורך/רוחב) ומיקום נכון של החלקיק.
  • שאר השורות בפונקציה ()particle קובעים את נתוני המהירות, המיקום היחסי, קוטר, משך זמן חיי החלקיק והצבע.
    שימו לב שכאשר החלקיקים חופפים, כלומר נמצאים אלה מעל אלה, הצבעים מתחברים ואם כל הצבעים קיימים, אדום ירוק וכחול, אז השילוב יהיה לבן.
    שיפור אפשרי בקוד יכול להיות קשירת הגדלים האלה אל מול גודל החלון, למשל במסך עם פיקסלים רבים קוטר החלקיקים ופריסתם תגדל בהתאם.
  • ()draw זו הפונקציה שתקרא בלולאה אינסופית על ידי הפונקציה ()setInterval שבסוף הקוד.
    היא עוברת כל פעם על כל מערך החלקיקים ועושה להם מניפולציות כמו שינוי מיקום, שקיפות וכו'.
  • ;"ctx.globalCompositeOperation = "destination-out
    המטרה פה היא להעלים את הרקע השחור ועליו לצייר את החלקיקים כאשר בכל "סיבוב" השכבה הקודמת נמחקת ולא נוצר מראה מרוח (עשוי להיות שימושי למקרים אחרים).
  • ;()ctx.beginPath
    כדי להפריד בין כל יצירה של חלקיק חדש. המחשה טובה ניתן לראות בקישור של המטודה.
  • השקיפות תלויה במשך זמן החיים שנותר לחלקיק.
  • ;()var gradient = ctx.createRadialGradient
    ליצירת אובייקט מעגלי עם צבע הדרגתי במיקום של החלקיק.
  • ;()gradient.addColorStop
    ממרכז המעגל עד לאמצעו אין שינוי, מהאמצע עד לקצה יש שינוי הדרגתי של השקיפות עד לשקיפות מלאה. למעשה אין כלל שינוי בצבע לכל חלקיק, שינויי הצבע במקרה הזה נגרמים כתוצאה מהחפיפה של החלקיקים.
  • לבסוף ציור של מעגל שלם ומילויו באופן מדורג כפי שהגדרנו.
  • הקטנת הרדיוס בפיקסל אחד עם כל סיבוב.
  • הזזת החלקיקים בהתאם לטווח המהירות שהוגרל בהתחלה לכל חלקיק.
  • העשן נוצר באופן קצת שרירותי וניתן לשפר את הקוד. המטרה היא להביא את שלושת הצבעים (R,G,B) לאותו ערך ואז הצבע הוא אפור, ככל שהערך גבוה יותר אז האפור כהה יותר. אפשר להתנסות בקישור שהוזכר גם קודם לגבי הצבע.
  • כאשר חלקיק מגיע לסוף חייו יוצרים במקומו בעזרת הבנאי חלקיק חדש.


את התוצאה ניתן לראות כאן.
הקוד איך שהוא כרגע עובד ונותן תוצאה מספקת, מכאן זה מה שנקרא "לעשות מסאז' לקוד", כלומר לשחק עם מספר החלקיקים, הצבעים, המהירות, משך זמן חיי החלקיקים וכו'.

אפקט הלהבה בעזרת שימוש בחלקיקים יכול להיות שימושי לדברים רבים אחרים:
עשן, בועות אוויר העולות במים, טיפות גשם, להבת "קסם" צבעונית, זיקוקים, מזרקות.. ועוד כיד הדמיון הטובה עליכם.
אשמח אם תשתפו בתגובות דברים דומים שיצרתם להשראה.




<-- חלק 23                                                                                                                                                           חלק 25 -->

 

         






תגובות

 



הגב/הגיבי לרשומה:

שם


תוכן התגובה                                               


  Skip Navigation Links







אלא אם צויין אחרת בגוף המאמר התוכן חופשי להפצה תחת רשיון ייחוס 3.0 לא מותאם של Creative Commons.

Created by yarriva.com