我正在尝试使用HTML5 / JS Canvas制作一个简单的足球罚球游戏。目标是制作一个控制守门员的游戏,你有三次尝试拯救球。
我完成了大部分功能,我有一个分数系统和碰撞检测。
我的问题是,在球被击中后,反馈文本只会出现一瞬间,它会重置我的画布,为下一次点球尝试做好准备。
有什么建议吗?我尝试使用setTimeout()来延迟它,但它仍然不起作用。
由于
<html>
<head>
<meta charset="utf-8" />
<title>Phantom football</title>
<style>
* { padding: 0; margin: 0; }
#myCanvas {
background: url('http://i754.photobucket.com/albums/xx182/rache_R/Phantom-Football_Title-v1_zpsuj9jgu27.jpg');
display: block;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="300" height="250"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.5/TweenMax.min.js"></script>
<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 = 20;
// 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 = [2.4, 2, 1.4, 1, 0.4, 0, -0.5, -1, -1.5, -2, -2.5, -3, -2.4];
// Gets a random value from the x_options array
var dx = -2.4;
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;
// Set default values for score and number of attempts left
var goalkeeper_blocked = 0;
var goalkeeper_missed = 0;
var attempts_left = 3;
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,
// is the game currently running
inGame : false,
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("Saved: "+goalkeeper_blocked, 8, 20);
},
missedScore : 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);
},
missedBallMessage : function(){
ctx.font = "16px Arial";
ctx.fillStyle = "#ffffff";
ctx.fillText("You missed the ball! Attempts left : " +attempts_left, 20, canvas.height / 2);
},
savedBallMessage : function(){
ctx.font = "16px Arial";
ctx.fillStyle = "#ffffff";
ctx.fillText("You saved the ball! Attempts left : " +attempts_left, 20, canvas.height / 2);
},
gameOverLoserMessage : function(){
ctx.font = "16px Arial";
ctx.fillStyle = "#ffffff";
ctx.fillText("GAME OVER! You Lose!" , 20, canvas.height / 2);
},
gameOverWinnerMessage : function(){
ctx.font = "16px Arial";
ctx.fillStyle = "#ffffff";
ctx.fillText("GAME OVER! You Win" , 20, canvas.height / 2);
}
},
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;
}
},
mouseMoveHandler : function(e){
var relativeX = e.clientX - canvas.offsetLeft;
if(relativeX > 0 && relativeX < canvas.width) {
goalieX = relativeX - goalieWidth/2;
}
}
},
calculateScore : function(){
if(goalkeeper_missed > goalkeeper_blocked){
footBall.shapes.gameOverLoserMessage();
document.location.reload();
} else {
footBall.shapes.gameOverWinnerMessage();
document.location.reload();
}
},
resetShapePositions : function(){
//Sets the original position of the ball
x = canvas.width/2;
y = 20;
// 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 shapes 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.missedScore();
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){
console.log("Shot time delay " + 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.shapes.missedBallMessage();
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.shapes.savedBallMessage();
footBall.resetShapePositions();
}
}
requestAnimationFrame(footBall.draw);
}
}
TweenMax.from("#myCanvas", 0.5, {opacity: 0, scale: 0, ease: Bounce.easeOut});
var hideIntro = function (e) {
if(e.keyCode == 32 && footBall.inGame == false) {
document.getElementById('myCanvas').style.background = '#a5bd7b';
console.log("hide");
requestAnimationFrame(footBall.draw);
footBall.nextShotTime = footBall.delayUntilNextShot;
footBall.inGame = true;
}
};
document.addEventListener("keydown", hideIntro, false);
// 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);
document.addEventListener("mousemove", footBall.controls.mouseMoveHandler, false);
</script>
</body>
</html>
答案 0 :(得分:1)
以下是如何在下次尝试开始前向用户显示最后的结果。
提示:由于您已经运行了requestAnimationFrame
循环,因此您可以使用rAF
来处理上次结果通知的时间。
创建一个footBall.lastResult
属性,其中包含上次尝试的结果(&#34;目标&#34;或&#34;已阻止&#34;)。在第一次尝试之前设置football.lastResult=''
以指示之前没有结果。
添加仅在footBall.shapes.showLastResult
为false时显示football.lastResult
的{{1}}方法。
示例代码和演示:
football.isShooting
&#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 lastAttempt='';
var isGameOver=false;
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);
},
lastAttempt : function(){
ctx.font = isGameOver?'18px Arial':'30px Arial';
ctx.fillStyle = "#ff0000";
ctx.textAlign='center';
ctx.fillText(lastAttempt,canvas.width/2,canvas.height/2);
ctx.textAlign='left';
},
},
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){
lastAttempt="GAME OVER! YOU HAVE LOST!";
isGameOver=true;
} else {
lastAttempt="GAME OVER! YOU HAVE WON!";
isGameOver=true;
}
setTimeout(function(){
document.location.reload();
isGameOver=false;
},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;
},
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();
footBall.shapes.lastAttempt();
},
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;
// clear the last attempt display while
// the shot is in progress
lastAttempt='';
}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;
// display shot result
lastAttempt='Missed!';
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;
// display shot result
lastAttempt='Saved!';
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;