我正在尝试使用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>
答案 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
,示例代码和演示:
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;