如何在HTML5 JS Canvas足球点球游戏

时间:2016-06-18 22:48:34

标签: javascript html5 canvas requestanimationframe

我正在尝试使用HTML5 / JS Canvas制作一个简单的足球罚球游戏。目标是制作一个控制守门员的游戏,你有三次尝试拯救球。

我完成了大部分功能,我有一个分数系统和碰撞检测。

目前我第一次尝试有延迟。然而,在第二次和第三次尝试将球射入球门之前,我发现很难加入延迟。

我正在使用requestAnimationFrame()方法在画布上绘制我的形状。如果仍有尝试可用,则将球定位到其原始位置,但是没有延迟并立即发射球。

有什么建议吗?谢谢!

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Football</title>
    <style>
        * { padding: 0; margin: 0; }
        canvas { background: #a5bd7b; display: block; margin: 0 auto; }
    </style>
</head>
<body>

<canvas id="myCanvas" width="300" height="250"></canvas>

<script>

var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext("2d");

//Sets the original position of the ball
var x = canvas.width/2;
var y = 50;

// Defines  values that will be added to the position of x and y values
// List of possible values for the x position
var x_options = [3.5, 3, 2.5, 2, 1.5, 1, 0.5, 0, -0.5, -1, -1.5, -2, -2.5, -3, -3.5];

// Gets a random value from the x_options array
var dx = x_options[Math.floor(Math.random() * x_options.length)];
var dy = 5;

var ballRadius = 10;

// Defines the height and width of the goal
var goal_height = 40;
var goal_width = 200


// Defines the height, width and position of goalie
var goalieHeight = 20;
var goalieWidth = 40;
var goalieX = (canvas.width-goalieWidth)/2;
var goalieY = (canvas.height - goal_height) - 30;

// Set to false by default
var rightPressed = false;
var leftPressed = false;

var goalkeeper_blocked = 0;
var goalkeeper_missed = 0;
var attempts_left = 3;

var attempt1 = true;
var attempt2 = false;
var attempt3 = false;



var footBall = {

    shapes : {
        ball: function (){
            ctx.beginPath();
            ctx.arc(x, y, ballRadius, 0, Math.PI*2, false);
            ctx.fillStyle = "red";
            ctx.fill();
            ctx.closePath();

        },

        goal : function (){
            ctx.beginPath();
            ctx.rect((canvas.width - goal_width) / 2 , canvas.height - goal_height, goal_width, goal_height);
            ctx.strokeStyle = "#000000";
            ctx.stroke();
            ctx.closePath();
        },

        goalie : function(){
            ctx.beginPath();
            ctx.rect(goalieX, goalieY, goalieWidth, goalieHeight);
            ctx.fillStyle = "#666666";
            ctx.fill();
            ctx.closePath();
        },

        score : function(){
            ctx.font = "16px Arial";
            ctx.fillStyle = "#ffffff";
            ctx.fillText("Score: "+goalkeeper_blocked, 8, 20);
        },

        missed : function(){
            ctx.font = "16px Arial";
            ctx.fillStyle = "#ffffff";
            ctx.fillText("Missed: "+goalkeeper_missed, 8, 40);
        },

        attempts : function(){
            ctx.font = "16px Arial";
            ctx.fillStyle = "#ffffff";
            ctx.fillText("Attempts left: "+attempts_left, canvas.width-110, 20);
        }


    },

    controls : {
        keyDownHandler : function (e){
            if(e.keyCode == 39) {
                rightPressed = true;
            }
            else if(e.keyCode == 37) {
                leftPressed = true;
            }

        },

        keyUpHandler : function(e){
            if(e.keyCode == 39) {
                rightPressed = false;
            }
            else if(e.keyCode == 37) {
                leftPressed = false;
            }

        }


    },

    calculateScore : function(){
        if(goalkeeper_missed > goalkeeper_blocked){
            alert("GAME OVER! YOU HAVE LOST!");
            document.location.reload();

        } else {
            alert("GAME OVER! YOU HAVE WON!");
            document.location.reload();
        }
    },

    animateBall : function (){
        // Sets a delay of 3 second before it shoots
        setTimeout(function(){ 
            x += dx;
            y += dy;

        }, 3000);

    },

    resetShapePositions : function(){
        //Sets the original position of the ball
        x = canvas.width/2;
        y = 50;

        // Sets a new shooting path
        dx = x_options[Math.floor(Math.random() * x_options.length)];
        dy = 5;

        // Resets the goalie to the middle
        goalieX = (canvas.width-goalieWidth)/2;

    },

    draw : function(){

        // This ensures that the ball doesn't leave a trail
        // Clears the canvas of this shape each frame
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        // Draws shapes on the canvas
        footBall.shapes.ball();
        footBall.shapes.goal();
        footBall.shapes.goalie();
        footBall.shapes.score();
        footBall.shapes.missed();
        footBall.shapes.attempts();

        // adds values to the balls  x and y position every frame
        footBall.animateBall();


        // Ball hits the goal 
        if(y + dy > canvas.height - goal_height) {

            attempts_left--;
            goalkeeper_missed++;
            if (!attempts_left){
                footBall.calculateScore();
            } 
            else {
                footBall.resetShapePositions();

            }

        } // Ball saved by goalie
        else if (x  > goalieX && x  < goalieX + goalieWidth && y + dy > goalieY - ballRadius){

            attempts_left--;
            goalkeeper_blocked++;

            if (!attempts_left){
                footBall.calculateScore();
            } 
            else {
                footBall.resetShapePositions();

            }


        } 


        //   makes paddle move left and right and only within the canvas
        if(rightPressed && goalieX < canvas.width-goalieWidth) {
            goalieX += 7;
        }
        else if(leftPressed && goalieX > 0) {
          goalieX -= 7;
        }
        requestAnimationFrame(footBall.draw);


    }


}

footBall.draw();


// Defines what functions are fired when keydown or keyup event triggers
document.addEventListener("keydown", footBall.controls.keyDownHandler, false);
document.addEventListener("keyup", footBall.controls.keyUpHandler, false);

</script>

</body>
</html>

1 个答案:

答案 0 :(得分:1)

向足球添加一些属性,控制是否/何时出现射门:

// is a shot in progress?
isShooting:false,

// the time when next shot will start
nextShotTime:0,

// delay between shots
delayUntilNextShot:3000,

然后在动画循环中,使用这些属性来适当延迟下一个镜头:

  • 如果isShooting,请处理镜头,
  • 如果不是isShooting,请查看拍摄之间是否已经过了所需的延迟。如果是,请设置isShooting=true
  • 当守门员阻挡或错过投篮时,设置isShooting=false并设置nextShotTime=currentTime+delayUntilNextShot

示例代码和演示:

&#13;
&#13;
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext("2d");

//Sets the original position of the ball
var x = canvas.width/2;
var y = 50;

// Defines  values that will be added to the position of x and y values
// List of possible values for the x position
var x_options = [3.5, 3, 2.5, 2, 1.5, 1, 0.5, 0, -0.5, -1, -1.5, -2, -2.5, -3, -3.5];

// Gets a random value from the x_options array
var dx = x_options[Math.floor(Math.random() * x_options.length)];
var dy = 5;

var ballRadius = 10;

// Defines the height and width of the goal
var goal_height = 40;
var goal_width = 200

// Defines the height, width and position of goalie
var goalieHeight = 20;
var goalieWidth = 40;
var goalieX = (canvas.width-goalieWidth)/2;
var goalieY = (canvas.height - goal_height) - 30;

// Set to false by default
var rightPressed = false;
var leftPressed = false;

var goalkeeper_blocked = 0;
var goalkeeper_missed = 0;
var attempts_left = 3;

var attempt1 = true;
var attempt2 = false;
var attempt3 = false;

var footBall = {

    // is a shot in progress
    isShooting:false,
    
    // time when next shot will run
    nextShotTime:0,
    
    // delay until next shot will run
    delayUntilNextShot:3000,
    
    shapes : {
        ball: function (){
            ctx.beginPath();
            ctx.arc(x, y, ballRadius, 0, Math.PI*2, false);
            ctx.fillStyle = "red";
            ctx.fill();
            ctx.closePath();
        },

        goal : function (){
            ctx.beginPath();
            ctx.rect((canvas.width - goal_width) / 2 , canvas.height - goal_height, goal_width, goal_height);
            ctx.strokeStyle = "#000000";
            ctx.stroke();
            ctx.closePath();
        },

        goalie : function(){
            ctx.beginPath();
            ctx.rect(goalieX, goalieY, goalieWidth, goalieHeight);
            ctx.fillStyle = "#666666";
            ctx.fill();
            ctx.closePath();
        },

        score : function(){
            ctx.font = "16px Arial";
            ctx.fillStyle = "#ffffff";
            ctx.fillText("Score: "+goalkeeper_blocked, 8, 20);
        },

        missed : function(){
            ctx.font = "16px Arial";
            ctx.fillStyle = "#ffffff";
            ctx.fillText("Missed: "+goalkeeper_missed, 8, 40);
        },

        attempts : function(){
            ctx.font = "16px Arial";
            ctx.fillStyle = "#ffffff";
            ctx.fillText("Attempts left: "+attempts_left, canvas.width-110, 20);
        }


    },

    controls : {
        keyDownHandler : function (e){
            if(e.keyCode == 39) {
                rightPressed = true;
            }
            else if(e.keyCode == 37) {
                leftPressed = true;
            }

        },

        keyUpHandler : function(e){
            if(e.keyCode == 39) {
                rightPressed = false;
            }
            else if(e.keyCode == 37) {
                leftPressed = false;
            }

        }

    },

    calculateScore : function(){
        if(goalkeeper_missed > goalkeeper_blocked){
            alert("GAME OVER! YOU HAVE LOST!");
            document.location.reload();

        } else {
            alert("GAME OVER! YOU HAVE WON!");
            document.location.reload();
        }
    },

    resetShapePositions : function(){
        //Sets the original position of the ball
        x = canvas.width/2;
        y = 50;

        // Sets a new shooting path
        dx = x_options[Math.floor(Math.random() * x_options.length)];
        dy = 5;

        // Resets the goalie to the middle
        goalieX = (canvas.width-goalieWidth)/2;

    },

    drawField: function(){
        // This ensures that the ball doesn't leave a trail
        // Clears the canvas of this shape each frame
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        // Draws shapes on the canvas
        footBall.shapes.ball();
        footBall.shapes.goal();
        footBall.shapes.goalie();
        footBall.shapes.score();
        footBall.shapes.missed();
        footBall.shapes.attempts();
    },

    draw : function(currentTime){

        //   makes paddle move left and right and only within the canvas
        if(rightPressed && goalieX < canvas.width-goalieWidth) {
            goalieX += 7;
        }
        else if(leftPressed && goalieX > 0) {
          goalieX -= 7;
        }

        // draw the scene
        footBall.drawField();

        // delay until next shot time is due 
        if(!footBall.isShooting){
            // time has elapsed, let's shoot again
            if(currentTime>footBall.nextShotTime){
                footBall.isShooting=true;
            }else{
                // time has not elapsed, just request another loop
                requestAnimationFrame(footBall.draw);
                return;
            }
        }

        // adds values to the balls  x and y position every frame
        x += dx;
        y += dy;

        // Ball hits the goal 
        if(y + dy > canvas.height - goal_height) {

            // end the shot
            footBall.isShooting=false;
            // delay the next shot
            footBall.nextShotTime=currentTime+footBall.delayUntilNextShot;

            attempts_left--;
            goalkeeper_missed++;
            if (!attempts_left){
                footBall.calculateScore();
            } 
            else {
                footBall.resetShapePositions();
            }

        } // Ball saved by goalie
        else if (x  > goalieX && x  < goalieX + goalieWidth && y + dy > goalieY - ballRadius){

            // end the shot
            footBall.isShooting=false;
            // delay the next shot
            footBall.nextShotTime=currentTime+footBall.delayUntilNextShot;

            attempts_left--;
            goalkeeper_blocked++;

            if (!attempts_left){
                footBall.calculateScore();
            } 
            else {
                footBall.resetShapePositions();

            }

        } 

        requestAnimationFrame(footBall.draw);
    }

}

footBall.drawField();
footBall.nextShotTime=footBall.delayUntilNextShot;
requestAnimationFrame(footBall.draw);

// Defines what functions are fired when keydown or keyup event triggers
document.addEventListener("keydown", footBall.controls.keyDownHandler, false);
document.addEventListener("keyup", footBall.controls.keyUpHandler, false);
&#13;
* { padding: 0; margin: 0; }
canvas { background: #a5bd7b; display: block; margin: 0 auto; }
&#13;
<canvas id="myCanvas" width="300" height="250"></canvas>
&#13;
&#13;
&#13;