דילוג לתוכן הראשי

אב טיפוס HTML5 למשחק כדורגל, כמו Flick Kick, פותח ב-Phaser עם Typescript

Flick Cick זהו משחק של בעיטות עונשין לשער, של חברת PikPok. יצרתי prototype של המכניקה המרכזית שלו: בעיטת הכדור לשער.


אפשר לראות את זה בפעולה כאן.

יש כאן 2 חלקים חשובים:
1. תנועת ה-swipe שעושים עם האצבע (או עם העכבר, למי שבודק את זה עם המחשב) על מנת לשחרר בעיטה לכיוון המתאים ובעוצמה המתאימה (הפונקציה listenSwipe)
2. מה שקורה לכדור בזמן המעוף שלו אל השער (רוב הפונקציה update)


/**
 * Created by codactive on 13/03/2016.
 */

// reference to typescript files
/// <reference path="../lib/phaser.d.ts" />
module football{
    export class Game extends Phaser.State{
        // define variables
        ball: Phaser.Sprite;
        bar: Phaser.Sprite; // this is the bottom of the goal, used to simulate the floor line
        // these are the sides of the goal:
        leftSideBar: Phaser.Sprite;
        rightSideBar: Phaser.Sprite;
        ballMoving:boolean;
        ballIsOut:boolean;
        isTimerWorking:boolean;
        timerDelay:number;
        swipeDistance:number;
        target:Phaser.Sprite;
        shootingForce:number;
        shootingDistanceFromCenter:number
        scaleRate:number;
        bounceRate:number;
        collisionGoalScaleLimit:number;
        collisionOutScaleLimit:number;

        preload(){
        }

        // put all game elements in variables + on screen
        // and define their properties
        create(){
            this.initVariables();
            // background
            this.game.add.sprite(0,0, "background");
            // the goal
            this.target = this.game.add.sprite(this.game.width * 0.5, this.game.height * 0.5, "goal");
            this.target.anchor.set(0.5,0.5);
            // the ball
            this.ball = this.game.add.sprite(this.game.width * 0.5, this.game.height * 0.5, "ball");
            this.ball.anchor.set(0.5,0.5);
            // the transparent bars
            this.bar = this.game.add.sprite(0, this.target.bottom, "bar");
            this.bar.y -= this.bar.height;
            this.bar.anchor.setTo(0,0.5);
            this.leftSideBar = this.game.add.sprite(this.target.left, this.target.bottom, "sidebar");
            this.leftSideBar.anchor.setTo(0,1);
            this.rightSideBar = this.game.add.sprite(this.target.right, this.target.bottom, "sidebar");
            this.rightSideBar.anchor.setTo(1,1);
            this.leftSideBar.alpha = this.rightSideBar.alpha = this.bar.alpha = 0;
            // game physics
            this.game.physics.arcade.enable([this.ball,this.leftSideBar,this.rightSideBar,this.bar,this.target]);
            this.game.physics.arcade.gravity.y = 1500;
            // goal and bars will not respond to gravity
            this.target.body.allowGravity = false;
            this.bar.body.allowGravity = false;
            this.rightSideBar.body.allowGravity = false;
            this.leftSideBar.body.allowGravity = false;
            this.ball.body.allowGravity = false;
            // ball will bounce
            this.ball.body.bounce.y = this.bounceRate;
            this.resetBall();
            // upper bar will not respond to collisions from below and bars will not move
            this.bar.body.checkCollision.down = false;
            this.bar.body.immovable = true;
            this.rightSideBar.body.immovable = true;
            this.leftSideBar.body.immovable = true;

            this.listenSwipe();

        }
        initVariables(){
            this.scaleRate = 0.018;
            this.bounceRate = 0.7;
            this.collisionGoalScaleLimit = 0.3;
            this.collisionOutScaleLimit = 0.05;
            this.ballIsOut = false;
            this.isTimerWorking = false;
            this.swipeDistance = 0;
            this.shootingDistanceFromCenter = 180;
            this.timerDelay = 1.5;
        }
        update(){ // gets run as many time per second (up to 60)
            // check for collision between the ball and the bars
            // and make the ball bounce on it
            this.game.physics.arcade.collide(this.ball, this.bar);
            this.game.physics.arcade.collide(this.ball, this.leftSideBar);
            this.game.physics.arcade.collide(this.ball, this.rightSideBar);
            // scale down the ball over time until it's small enough
            if(this.ballMoving == true){
                this.ball.scale.x -= this.scaleRate;
                this.ball.scale.y -= this.scaleRate;
                if(this.ball.y < this.target.top){
                    console.log("ball out, over the top");
                    this.ballIsOut = true;
                    this.target.bringToTop(); // make the goal appear in front of the ball
                }
                else if (this.ball.scale.x < this.collisionGoalScaleLimit && !this.ballIsOut) {
                    console.log("ball hit goal");
                    this.ballMoving = false;
                }
                if (this.ball.scale.x < this.collisionOutScaleLimit && this.ballIsOut) {
                    console.log("ball reached out limit");
                    this.ballMoving = false;
                }

            }
            //rotate the ball accirding its x direction
            this.ball.rotation += this.ball.body.velocity.x / this.ball.height/30;
        }

        listenSwipe(){
            //console.log("listenSwipe");
            var eventDuration:number;
            var startPoint = {x:0,y:0};
            var endPoint = {x:0,y:0};
            var minimum = {duration: 150,distance: 150};
            // pressing, start of swipe
            this.game.input.onDown.add(function(pointer){
                startPoint.x = pointer.position.x;
                startPoint.y = pointer.position.y;
            }, this);
            // releasing, end of swipe
            this.game.input.onUp.add(function(pointer){
                eventDuration = this.game.input.activePointer.duration;
                if (eventDuration > minimum.duration) {
                    endPoint.x = pointer.position.x;
                    endPoint.y = pointer.position.y;
                    this.swipeDistance = Phaser.Point.distance(endPoint,startPoint);
                    // in order to shoot the ball, the following conditions should me met:
                    // the swipe distance should be greater than the required minimum
                    // also, the release point should be pretty close to the center of the screen
                    // also, the release point should be above the press point
                    // also, the release point should be above a certain point
                    if(this.swipeDistance > minimum.distance && endPoint.x > this.game.world.centerX -
 this.shootingDistanceFromCenter && endPoint.x < this.game.world.centerX + this.shootingDistanceFromCenter 
&& endPoint.y < startPoint.pan> && endPoint.y < this.ball.y - this.ball.height*2){
                        // here move the ball
                        if (!this.isTimerWorking) {
                            this.isTimerWorking = true;
                            this.ball.body.allowGravity = true;
                            this.moveBall();
                            // timer delay before reset
                            this.game.time.events.add(Phaser.Timer.SECOND * this.timerDelay, () => {
                                this.resetBall();
                            }, this);
                        }
                    }
                }
            }, this);
        }

        // position the ball at the start, initialize its scale
        // and define it as not moving
        resetBall(){
            console.log("resetBall");
            this.ballMoving = false;
            this.ball.body.allowGravity = false;
            this.ball.scale.x=this.ball.scale.y=1;
            this.ball.y = this.game.world.height-this.ball.height;
            this.ball.x = this.game.world.width/2;
            this.ball.body.velocity.x = 0;
            this.ball.body.velocity.y = 0;
            this.isTimerWorking = false;
        }

        // this function gets called on tap
        // apply shooting force, moving the ball to a position using this force
        // and mark the ball as "moving"
        moveBall(){
            var force:number = Math.min(320,this.swipeDistance/3);
            this.shootingForce = 1080+force;
            this.game.physics.arcade.moveToPointer(this.ball, this.shootingForce);
            this.ballMoving = true;
            this.ball.bringToTop();
            this.ballIsOut = false;
        }
    }
}


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

תגובות

פוסטים פופולריים מהבלוג הזה

איך לבנות משחק HTML5 ב-Phaser עם Typescript - חלק 2

קבלו את החלק השני בסדרה - איך בונים משחק HTML5 ב-Phaser עם Typescript. בחלק הראשון בניתי את ה-HTML וה-CSS והורדתי את קבצי פייזר. הפעם אני בונה את ה-class הראשי של המשחק ומאתחל אותו. תהנו! לחץ כאן על מנת להוריד את קוד המקור הסופי הלינק להדרכה החינמית:  http://www.codactive.com

כלים לפיתוח משחקים בלי ידע בתכנות

מאחר ויש לי די הרבה נסיון בהדרכת תכנות למתחילים (ובפרט בתחום פיתוח משחקים) אני מתעניין כל הזמן בכלים טובים עם ערך מוסף גם לפיתוח משחקים מהיר וגם ללמידה של תכנות על הדרך. לאחרונה החלטתי לפתוח קורס\חוג מקומי לנוער שילמד פיתוח משחקים לחסרי נסיון, או בעלי נסיון בסיסי בתכנות וזה הוביל אותי לבדוק באופן יותר מעמיק אילו כלים קיימים כרגע שעשויים לתמוך בקורס כזה. אחד הקריטריונים החשובים לדעתי בבחינת כלים כאלה היא עד כמה אפשרי ונוח ליצור באמצעותם משחקי HTML5 שאפשר בקלות לפרסם באתר עצמאי, או באתרי מפיצים, כי לשם אני מאמין שהתעשיה הולכת. לכן, קודם כל הלכתי וחיפשתי רשימת השוואה למנועי משחק שמאפשרים ליצור משחקי HTML5 והגעתי לרשימה הזאת. אפשר לראות כאן גם frameworks כמו Phaser, שמאפשרות בניית משחק ע"י תכנות בלבד וגם כלים כמו Construct 2 שלא מצריכות ידע בתכנות בכלל ונותנות ממשק גרפי עם אפשרויות בחירה והזנת פרמטרים מסוגים שונים על מנת להגיע לאותן תוצאות. מנסיוני יש 2 אסכולות של מפתחים: 1. כאלה שבאו מרקע של תכנות פרופר (מדעי המחשב) - מעדיפים לתכנת הכל באמצעות עורכי קוד למיניהם...

קונסטרקט 3 - הכלי הכי אפקטיבי שאני מכיר לפיתוח משחקים קטנים-בינוניים

את הפוסט הקודם (על Stencyl) כתבתי לפני כמעט שנה ומאז עברתי לעבוד עם Construct 3 שפתר לי 2 בעיות משמעותיות: רספונסיביות וזמן להגיע לתוצאה. בנוסף, יש לקונסטרקט המון מדריכים באינטרנט, קהילת משתמשים גדולה ופעילה ועדכונים שוטפים בתדירות מרשימה. מהר מאד התחלתי לפתח משחקים בקונסטרקט וזה פשוט כיף גדול להבין שבמקום להשקיע כמה שבועות בכתיבת קוד אפשר להגיע לאותה תוצאה בכמה ימים בלי לכתוב שום קוד ורק להתרכז ביצירה עצמה. האמת היא שכל כך התלהבתי מהפשטות שבתוכנה, שהחלטתי לפתוח קורס לפיתוח משחקים בקונסטרקט והיום אני מעביר הדרכות פיזית ב-2 כיתות לתלמידים שהצטרפו לקורס שמתקיים בגדרה. במקביל אני ממשיך לפתח משחקים בקונסטרקט בשעות הפנאי ונהנה מכל רגע. בשלב הבא אני מתכנן לפתוח קורס אינטרנטי בקונסטרקט, כך שכל אחד שרוצה יוכל לפתח משחקים, אבל בינתיים עד שזה יקרה, אני רוצה לפרסם הדרכות קצרות מדי פעם שיתנו לכם טעימה מתוך החוויה של פיתוח בקונסטרקט. בהדרכה  הזאת אציג בקצרה את התוכנה - איך מגיעים אליה ומתחילים לעבוד איתה. בהדרכות הבאות אציג דוגמאות קצרות של עבודה עם התוכנה כחלק מתהליך בניית משחק...