画布游戏中的不同页面

6

问题

我正在使用HTML5 Canvas创建一个游戏,游戏有一个主菜单,主菜单有多个按钮供用户选择。我发现很难和困惑的是,例如如果用户按下“播放”按钮,我该如何展示游戏。这里是主菜单的图片:

游戏主菜单

问题

问题是我该如何从这个页面跳转到我的游戏中的另一个页面。

进入图像说明此处

我想你已经明白了。我特意使用canvas创建了菜单,我知道我可以使用HTML等方法创建菜单,但我不能,因为这只是一个为学生展示Canvas功能的例子,好坏之类的。

<html>
<head>
    <title>Sean Coyne</title>
</head>
<body onload="start_game()">
<body>
    <div style id="canvas">
        <canvas id="myCanvas" style="border:5px solid #410b11" height="320" width="480">
            <p>Your browser does not support HTML5!</p>
        </canvas>

        <script type="text/javascript">

            //Referencing the canvas
            var canvas = document.getElementById("myCanvas");
            var context = canvas.getContext("2d");
            var width = canvas.getAttribute('width');
            var height = canvas.getAttribute('height');

            //Finding the position of the mouse
            var mouseX;
            var mouseY;

            //Images
            var bgImage = new Image();
            var logoImage = new Image();
            var playImage = new Image();
            var instructImage = new Image();
            var settingsImage = new Image();
            var aboutImage = new Image();
            var peaceImage = new Image();

            var backgroundY = 0;
            var speed = 1;

            //Arrays below used for mouse over function
            var buttonX = [130,110,130,160];
            var buttonY = [100,140,180,220];
            var buttonWidth = [96,260,182,160];
            var buttonHeight = [40,40,40,40];

            var peaceX = [0,0];
            var peaceY = [0,0];
            var peaceWidth = 35;
            var peaceHeight = 35;

            var peaceVisible = false;
            var peaceSize = peaceWidth;
            var peaceRotate = 0;

            var frames = 30;
            var timerId = 0;
            var fadeId = 0;
            var time = 0.0;

            peaceImage.src = "Images/peace.png";
            bgImage.onload = function(){
                context.drawImage(bgImage, 0, backgroundY);
            };
            bgImage.src = "Images/background.png";
            logoImage.onload = function(){
                context.drawImage(logoImage, 50, -10);
            }
            logoImage.src = "Images/logo.png";
            playImage.onload = function(){
                context.drawImage(playImage, buttonX[0], buttonY[0]);
            }
            playImage.src = "Images/play.png";
            instructImage.onload = function(){
                context.drawImage(instructImage, buttonX[1], buttonY[1]);
            }
            instructImage.src = "Images/instructions.png";
            settingsImage.onload = function(){
                context.drawImage(settingsImage, buttonX[2], buttonY[2]);
            }
            settingsImage.src = "Images/settings.png";
            aboutImage.onload = function(){
                context.drawImage(aboutImage, buttonX[3], buttonY[3]);
            }
            aboutImage.src = "Images/about.png";

            timerId = setInterval("update()", 1000/frames);

            canvas.addEventListener("mousemove", checkPos);
            canvas.addEventListener("mouseup", checkClick);

            function update() {
                clear();
                move();
                draw();
            }
            function clear() {
                context.clearRect(0, 0, width, height);
            }
            function move(){
                backgroundY -= speed;
                if(backgroundY == -1 * height){
                    backgroundY = 0;
                }
                if(peaceSize == peaceWidth){
                    peaceRotate = -1;
                }
                if(peaceSize == 0){
                    peaceRotate = 1;
                }
                peaceSize += peaceRotate;
            }


            function draw(){
                context.drawImage(bgImage, 0, backgroundY);
                context.drawImage(logoImage, 50,-10);
                context.drawImage(playImage, buttonX[1], buttonY[0]);
                context.drawImage(instructImage, buttonX[2], buttonY[1]);
                context.drawImage(settingsImage, buttonX[2], buttonY[2]);
                context.drawImage(aboutImage, buttonX[3], buttonY[3]);
                    if(peaceVisible == true){
                    context.drawImage(peaceImage, peaceX[0] - (peaceSize/2), peaceY[0], peaceSize, peaceHeight);
                    context.drawImage(peaceImage, peaceX[2] - (peaceSize/2), peaceY[2], peaceSize, peaceHeight);
                }
            }

            function checkPos(mouseEvent){
                if(mouseEvent.pageX || mouseEvent.pageY == 0){
                    mouseX = mouseEvent.pageX - this.offsetLeft;
                    mouseY = mouseEvent.pageY - this.offsetTop;
                }else if(mouseEvent.offsetX || mouseEvent.offsetY == 0){
                    mouseX = mouseEvent.offsetX;
                    mouseY = mouseEvent.offsetY;
                }
                for(i = 0; i < buttonX.length; i++){
                    if(mouseX > buttonX[i] && mouseX < buttonX[i] + buttonWidth[i]){
                        if(mouseY > buttonY[i] && mouseY < buttonY[i] + buttonHeight[i]){
                            peaceVisible = true;
                            peaceX[0] = buttonX[i] - (peaceWidth/2) - 2;
                            peaceY[0] = buttonY[i] + 2;
                            peaceX[1] = buttonX[i] + buttonWidth[i] + (peaceWidth/2); 
                            peaceY[1] = buttonY[i] + 2;
                        }
                    }else{
                        peaceVisible = false;
                    }
                }
            }
            function checkClick(mouseEvent){
                for(i = 0; i < buttonX.length; i++){
                    if(mouseX > buttonX[i] && mouseX < buttonX[i] + buttonWidth[i]){
                        if(mouseY > buttonY[i] && mouseY < buttonY[i] + buttonHeight[i]){
                            fadeId = setInterval("fadeOut()", 1000/frames);
                            clearInterval(timerId);
                            canvas.removeEventListener("mousemove", checkPos);
                            canvas.removeEventListener("mouseup", checkClick);
                        }
                    }
                }
            }
            function fadeOut(){
                context.fillStyle = "rgba(0,0,0, 0.2)";
                context.fillRect (0, 0, width, height);
                time += 0.1;
                if(time >= 2){
                    clearInterval(fadeId);
                    time = 0;
                    timerId = setInterval("update()", 1000/frames);
                    canvas.addEventListener("mousemove", checkPos);
                    canvas.addEventListener("mouseup", checkClick);
                }
            }
        </script>
    </body>
</html>

我会根据用户的选择,简单地用正确的画布替换当前的画布...? - Salketer
因此,使用多个画布,根据用户的选择,显示相应的画布? - RushFan2112
调试帮助问题需要遵循 [help] 中的 [mcve]。你的代码不够简洁。请 [edit] 你的问题,确保你的代码是 Minimal(只包含在问题中重现你的问题所需的代码)、Complete(用户不需要其他任何东西来重现你的问题)和 Verifiable(提供的代码确实重现了你所面临的确切问题)。目前你的问题不适合在 Stack Overflow 上发布。请注意,这也是一个常见的 downvote reason - Kyll
你可以选择仅存储屏幕/游戏的状态,并根据其在同一画布上进行更新/绘制。或者交换不同的画布元素。或者只使用HTML来处理菜单等(我认为这是处理菜单的最佳方式,HTML最适合文本标记,没有必要在这里重新发明轮子)。 - ManoDestra
谢谢ManoDestra,我确实说过为什么不使用HTML来制作菜单,但我知道你的意思。 - RushFan2112
2个回答

5
我通常会在draw循环中使用switch语句,并有一个状态变量来保存当前游戏状态(菜单、游戏中等等)。

然后,根据当前游戏状态,只绘制当前场景所需的对象。

类似于这样:

var STATES = { 
  Menu: 0,
  PauseMenu: 1,
  Playing: 2
};
var currentState = STATES.Menu;
...
function draw() {
  switch(currentState) {
    case STATES.Menu:
      // Draw buttons, etc..
    break;
    case STATES.Playing:
      // Draw the game screen, the player, etc...
    break;
  }
}

当用户按下“播放”按钮时,您需要做的唯一事情就是:
function onPlayButtonClick() {
   currentState = STATES.Playing;
   // Starting the next frame the new state will be "magically" drawn
}

如果您不喜欢使用switch语句,您可以创建一个State类,其中包含一个draw方法。然后,您可以简单地创建新的状态,每个状态都有自己的绘制方法,在主绘制循环中只调用当前状态的绘制方法。
同样,对于update函数,每个状态都有自己的update函数(在主菜单中,您更新按钮或动画,而在玩游戏时,您更新游戏世界并运行物理引擎)。因此,根据当前状态,您的update函数实际上是不同的。您可以自由地构建代码结构,并根据当前状态调用不同的函数。

+1,这是正确的方法。将其与游戏循环(更新、渲染等)结合使用,这将非常强大。编辑:我看到您已经更新了答案以包括此内容,不用管 =) - Lewis
现在我只需要理解如何实现它,至少我有一整天的时间哈哈! - RushFan2112
1
@RushFan2112 当你习惯了它,它真的不像你想象的那么复杂!在构建游戏时,请使用由Update()和Draw()方法组成的游戏循环。在update中,跟踪游戏状态的变化。在Draw()方法中,在渲染到画布之前检查当前状态是什么。这是一个相当深入的教程,但看一下它-它很有帮助!编辑:http://blog.sklambert.com/html5-game-tutorial-game-ui-canvas-vs-dom/ - Lewis
@Lewis 谢谢你的教程,我会立刻查看!在我的脑海中,这一切都很有道理,但我发现实践起来很困难,多练习一下,我相信我会没问题的! - RushFan2112

1
在每个文本选项中,您应该创建一个较小的画布,只包含选项文本,并添加一个“click”事件和回调函数。
提示:您不需要另一页,只需清除主画布并绘制所需内容即可。

那么为菜单中的每个选项创建4个画布? - RushFan2112
是的,每个选项都需要一个画布,然后添加事件处理程序。 - mariodiniz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接