javascript - 如何添加 "Play Again"按钮

标签 javascript arrays p5.js

引用代码链接: https://editor.p5js.org/tpant963/sketches/wQy1zfKBW

你好!因此,我使用 p5.js 制作一个 Java OOP 概念复习游戏,其中屏幕上出现一个问题,周围漂浮着带有单词关联的气泡。如果单击时气泡变成绿色,则表示您单击了正确的答案/关联。如果它变成红色,则表明您点击了错误的按钮。

我想制作我的游戏,以便如果单击所有正确答案(意味着单击所有可能变绿的气泡),则会显示“再次玩”按钮,如果您单击它,则游戏重新启动,您可以再次玩。

我该怎么做?这是一个尝试的示例,它让我在美学上最接近我想要的最终结果,但当我单击“再次玩”时,它无法返回主菜单并实际重新启动游戏此外,我仍然可以单击“游戏过程中出现“不正确”的气泡并产生相同的结果,这是我不想要的。

let menu = 0;

function draw() {
    if (menu == 1) {
    background(bubblepopperG)
    fill(0)
    textSize(25)
    text(currentQuestion.question, 25, 300);
    
    //Allow the bubbles to move and be displayed on the screen.
    bubbles.forEach(bubble => {
      bubble.move();
      bubble.display();
    })
    
    if (answerCount > currentQuestion.correct.length){
      background(bubblepopperG)
      textSize(30)
      text('YOU GOT ALL THE RIGHT BUBBLES!', 25, height / 2)
    
      //Add button to return to main menu.
      fill(255, 0, 255);
      rect(180, 400, 250, 75);
      stroke(100);
      strokeWeight(3);
      textSize(26);
      text('PLAY AGAIN', 230, 450);
      }  
  }

然后我尝试了同样的操作,但尝试在游戏结束时将 mousePressed() 函数分配给“再次玩”按钮。这是代码:

if (answerCount > currentQuestion.correct.length){
      menu = 4;
      background(bubblepopperG)
      textSize(30)
      text('YOU GOT ALL THE RIGHT BUBBLES!', 25, height / 2)
    
      //Add button to return to main menu.
      fill(255, 0, 255);
      rect(180, 400, 250, 75);
      stroke(100);
      strokeWeight(3);
      textSize(26);
      text('PLAY AGAIN', 230, 450);
      }  
  }
  
  function mousePressed(){
        if (menu == 4) {
    if (mouseX < 430 && mouseX > 180) {
      if (mouseY < 475 && mouseY > 400) {
        menu = 0
      }
    }
  }
  }

但是,这个甚至根本不允许出现游戏后屏幕。它只是直接带我回到我制作的游戏菜单,但当我到达那里时我无法点击任何内容。

谢谢

最佳答案

非常接近!

简短回答:您已经有一个条件来检查是否在边界框中按下了按钮,以及一个条件来检查是否应显示再次播放菜单(例如 if(answerCount > currentQuestion.correct.length) )。

记住您所处的状态/菜单并使用正确的条件。

模仿你的代码,你会得到类似的东西:

if(menu == 1){
    if (mouseX < 430 && mouseX > 180) {
      if (mouseY < 475 && mouseY > 400) {
        // reset answer count
        answerCount = 0;
        // return to start menu
        menu = 0;
      }
    }
  }

更新: 根据您的评论,您需要计算正确气泡的数量(一种方法可能是过滤 CorrectBubble 实例并计算它们(例如 bubbles.filter(bubble => bubble instanceof CorrectBubble) )以及正确气泡的总数以及已单击的正确气泡的数量(再次过滤可以提供帮助:例如 correctBubbles.filter(bubble => bubble.col === bubble.clickedColor).length) )

clicked()可以更新内部 bool 属性,这将使代码更具可读性(例如,在 this.isClicked = true; 中添加 clicked() 将使点击的气泡过滤器读取为 correctBubbles.filter(bubble => bubble.isClicked) 。 还有一个小的碰撞检测错误,您可能的意思是类似 if (d < this.r * 0.5) (也许将 this.r 重命名为 this.diameter 以反射(reflect)它的使用方式)。 更好的是,reset()方法可以添加到 Bubble类来重置 boolean旗帜和颜色:

reset(){
    this.isClicked = false;
    this.col = '#000000';
  }

气泡被很好地封装到类中。您可以对最小化 repetition 的按钮执行相同的操作.

这是主草图的修改版本,其中包含基本 Button类封装了显示和在边界矩形内单击的功能:

let menu = 0 //Variable to show the game main menu.
let bubblepopper; //A variable for the image
let bubblepopperM; //A variable for the menu background image
let bubblepopperG; //A variable for the game background image
const bubbles = []; //Array to store the bubbles.
let currentQuestion = null;
const questions = [
  {
    question: 'What are the 4 types of access modifiers?',
    correct: ['public', 'private', 'protected', 'default'],
    incorrect: ['method', 'class', 'protection', 'published', 'nested', 'abstract'],
  },
  {
    question: 'Words that go with encapsulation:',
    correct: ['class', 'method', 'variable','access modifiers'],
    incorrect: ['initial', 'encapsulate', 'complex', 'automatic', 'primitive', 'interface'],
  },
  {
    question: 'Things you can put in a UML OBJECT diagram:',
    correct: ['classes', 'variables', 'components', 'methods'],
    incorrect: ['packages', 'Java Project', 'client code', 'no booleans', 'no objects', 'concatenation'],
  },
  {
    question: 'Abstract classes...',
    correct: ['declare abstract', 'extend subclass', 'no instantiation', 'static & non-static'],
    incorrect: ['interface', 'only static', 'slow', 'only public access', 'default methods', 'multiple inheritance'],
  },
  {
    question: 'OOP important words:',
    correct: ['encapsulation', 'inheritance', 'polymorphism', 'abstraction'],
    incorrect: ['capsuling', 'aggravation', 'adhesion', 'dissociation', 'array', 'submethod'],
  },
  {
    question: 'Which of the following words go together?',
    correct: ['private class', 'getter', 'setter', 'protect data'],
    incorrect: ['public class', 'char', 'float', 'array', 'settings', 'extends class'],
  },
];

class Button{
  
  constructor(x, y, width, height, label, textSize, fillColor){
    
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
    
    this.label = label;
    this.textSize = textSize;
    this.fillColor = fillColor;
  }
  
  draw(){
    push();
    textAlign(CENTER);
    fill(this.fillColor);
    rect(this.x, this.y, this.width, this.height);
    stroke(100);
    strokeWeight(3);
    textSize(this.textSize);
    fill(255);
    text(this.label, this.x + (this.width * 0.5), this.y + (this.height * 0.75));
    pop();
  }
  
  isPressed(){
    return ((mouseX >= this.x && mouseX <= this.x + this.width) && 
            (mouseY >= this.y && mouseY <= this.y + this.height)); 
  }
  
}

let playButton;
let exitButton;
let instructionsButton;

function preload() {
  bubblepopper = loadImage('Bubble Popper Logo.png');
  bubblepopperM = loadImage('Bubble Popper Menu Background.jpg');
  bubblepopperG = loadImage('Bubble Popper Game Background.jpg');
}

function setup() {
  currentQuestion = questions[Math.floor(Math.random() * questions.length)];
  createCanvas(600, 600);
  for(let i = 0; i < currentQuestion.correct.length; i++) {
    bubbles.push(new CorrectBubble(random(-3, 3), random(-3, 3), currentQuestion.correct[i], random(width), random(height), random(80,100)));
  } //The new bubbles will be added to the bubbles array.
  
  
  for(let i = 0; i < currentQuestion.incorrect.length; i++) {
    bubbles.push(new IncorrectBubble(random(-3, 3), random(-3, 3), currentQuestion.incorrect[i], random(width), random(height), random(80,100)));
  } //The new bubbles will be added to the bubbles array.
  
  playButton = new Button(50, 100, 200, 75, 'PLAY', 50, color(64,224,208));
  exitButton = new Button(50, 400, 200, 75, 'EXIT', 50, color(255, 0, 255));
  instructionsButton = new Button(50, 250, 200, 75, 'INSTRUCTIONS', 26, color(64,224,208));
  playAgainButton = new Button(180, 400, 250, 75, 'PLAY AGAIN', 26, color(255, 0, 255));
  returnToMenuButton = new Button(180, 400, 250, 75, 'RETURN TO MENU', 26, color(255, 0, 255));
}

function mousePressed() {
  //For each bubble in the array, click it and allow it to change to it's correct colour.
  bubbles.forEach(bubble => bubble.clicked(mouseX, mouseY));
}

function draw() {
  //Set up the main menu and the buttons in it.
  background(bubblepopperM);
  playButton.draw();
  exitButton.draw();
  instructionsButton.draw();
  image(bubblepopper, 275, 150, 300, 300); //Add the Bubble Popper logo.

  if (menu == 1) {
    background(bubblepopperG)
    fill(0)
    textSize(25)
    text(currentQuestion.question, 25, 300);
    
    //Allow the bubbles to move and be displayed on the screen.
    bubbles.forEach(bubble => {
      bubble.move();
      bubble.display();
    })
    
    const correctBubbles = getCorrectBubbles();
    if (countClickedBubbles(correctBubbles) === correctBubbles.length){
      background(bubblepopperG)
      textSize(30)
      text('YOU GOT ALL THE RIGHT BUBBLES!', 25, height / 2)
      //Add button to return to main menu.
      playAgainButton.draw();
    }  
  }
  
  //When clicked this will show the user instructions on how to play the game.
  if (menu == 2) {
    background(bubblepopperM)
    fill(255);
    stroke(100);
    strokeWeight(3);
    textSize(20)
    text('1. A question will be displayed to do with object-oriented', 50, 150)
    text('programming (OOP) concepts.', 80, 175)
    text('2. Click on the bubbles with the correct word associations', 50, 225)
    text('to the question. Correct answers will turn green,', 80, 250)
    text(' incorrect answers will turn red when clicked on.', 80, 275)
    text('3. The round is over when you select all the correct bubbles', 50, 325)
    
    returnToMenuButton.draw();
  } 
  
  //Will exit out of the program.
  if (menu == 3) {
    background(bubblepopperM);
    fill(255);
    textSize(50);
    text('THANKS FOR PLAYING!', 25, height / 2);
    
    playAgainButton.draw();
  }  
}


function getCorrectBubbles(){
  return bubbles.filter(bubble => bubble instanceof CorrectBubble);
}

function countClickedBubbles(bubbles){
  return bubbles.filter(bubble => bubble.col === bubble.clickedColor).length;
}

//Determine the mouse coordinates so that the user can click on the buttons.
function mouseClicked() {
  
  if (menu == 0) {
    if(playButton.isPressed()){
      menu = 1;
    }
    if(instructionsButton.isPressed()){
      menu = 2;
    }
    if(exitButton.isPressed()){
      console.log('exit');
      menu = 3;
    }
  }
  
  if(menu == 1){
    if (playAgainButton.isPressed()) {
      // return to start menu
      menu = 0;
    }
    
  }
  
  //Allow the user to go back to the main menu if they click instructions.
  if (menu == 2) {
    if(returnToMenuButton.isPressed()){
      menu = 0;
    }
  }
  
  //Allow the user to go back to the main menu if they click exit.
  if (menu == 3) {
    if(playAgainButton.isPressed()){
      menu = 0;
    }
  }
}

此外,menu基于的功能也可以封装到类中。以下是上述代码的变体,带有说明多态性的基本状态机:

let bubblepopper; //A variable for the image
let bubblepopperM; //A variable for the menu background image
let bubblepopperG; //A variable for the game background image
const bubbles = []; //Array to store the bubbles.
let currentQuestion = null;
const questions = [
  {
    question: 'What are the 4 types of access modifiers?',
    correct: ['public', 'private', 'protected', 'default'],
    incorrect: ['method', 'class', 'protection', 'published', 'nested', 'abstract'],
  },
  {
    question: 'Words that go with encapsulation:',
    correct: ['class', 'method', 'variable','access modifiers'],
    incorrect: ['initial', 'encapsulate', 'complex', 'automatic', 'primitive', 'interface'],
  },
  {
    question: 'Things you can put in a UML OBJECT diagram:',
    correct: ['classes', 'variables', 'components', 'methods'],
    incorrect: ['packages', 'Java Project', 'client code', 'no booleans', 'no objects', 'concatenation'],
  },
  {
    question: 'Abstract classes...',
    correct: ['declare abstract', 'extend subclass', 'no instantiation', 'static & non-static'],
    incorrect: ['interface', 'only static', 'slow', 'only public access', 'default methods', 'multiple inheritance'],
  },
  {
    question: 'OOP important words:',
    correct: ['encapsulation', 'inheritance', 'polymorphism', 'abstraction'],
    incorrect: ['capsuling', 'aggravation', 'adhesion', 'dissociation', 'array', 'submethod'],
  },
  {
    question: 'Which of the following words go together?',
    correct: ['private class', 'getter', 'setter', 'protect data'],
    incorrect: ['public class', 'char', 'float', 'array', 'settings', 'extends class'],
  },
];

class Button{
  
  constructor(x, y, width, height, label, textSize, fillColor){
    
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
    
    this.label = label;
    this.textSize = textSize;
    this.fillColor = fillColor;
  }
  
  draw(){
    push();
    textAlign(CENTER);
    fill(this.fillColor);
    rect(this.x, this.y, this.width, this.height);
    stroke(100);
    strokeWeight(3);
    textSize(this.textSize);
    fill(255);
    text(this.label, this.x + (this.width * 0.5), this.y + (this.height * 0.75));
    pop();
  }
  
  isPressed(){
    return ((mouseX >= this.x && mouseX <= this.x + this.width) && 
            (mouseY >= this.y && mouseY <= this.y + this.height)); 
  }
  
}

class State{
  constructor(){
    
  }
  mouseClicked(){}
  draw(){}
}

class MainMenuState extends State{
  
  draw(){
    background(bubblepopperM);
    playButton.draw();
    exitButton.draw();
    instructionsButton.draw();
    image(bubblepopper, 275, 150, 300, 300); //Add the Bubble Popper logo.  
  }
  
  mouseClicked(){
    if(playButton.isPressed()){
      currentState = playState;
    }
    if(instructionsButton.isPressed()){
      currentState = instructionsState;
    }
    if(exitButton.isPressed()){
      currentState = exitState;
    }

  }
}

class PlayState extends State{
  draw(){
    background(bubblepopperG)
    fill(0)
    textSize(25)
    text(currentQuestion.question, 25, 300);
    
    //Allow the bubbles to move and be displayed on the screen.
    bubbles.forEach(bubble => {
      bubble.move();
      bubble.display();
    })
  }
  mouseClicked(){
    //For each bubble in the array, click it and allow it to change to it's correct colour.
    bubbles.forEach(bubble => bubble.clicked(mouseX, mouseY));
    // check if all correct bubbles have been clicked
    const correctBubbles = getCorrectBubbles();
    if (countClickedBubbles(correctBubbles) === correctBubbles.length){
      currentState = winState;
    }
  }
}

class WinState extends State{
  draw(){
    background(bubblepopperG);
    fill(255);
    textSize(30);
    text('YOU GOT ALL THE RIGHT BUBBLES!', 25, height / 2);
    //Add button to return to main menu.
    playAgainButton.draw();
  }
  mouseClicked(){
    if(playAgainButton.isPressed()){
      // reset clicked answers first
      bubbles.forEach(bubble => bubble.reset());
      // then change state
      currentState = menuState;
    }
  }
}

class InstructionsState extends State{
  draw(){
    background(bubblepopperM)
    fill(255);
    stroke(100);
    strokeWeight(3);
    textSize(20);
    text('1. A question will be displayed to do with object-oriented', 50, 150);
    text('programming (OOP) concepts.', 80, 175);
    text('2. Click on the bubbles with the correct word associations', 50, 225);
    text('to the question. Correct answers will turn green,', 80, 250);
    text(' incorrect answers will turn red when clicked on.', 80, 275);
    text('3. The round is over when you select all the correct bubbles', 50, 325);
    
    returnToMenuButton.draw();
  }
  mouseClicked(){
    if(returnToMenuButton.isPressed()){
      currentState = menuState;
    } 
  }
}

class ExitState extends State{
  draw(){
    background(bubblepopperM);
    fill(255);
    textSize(50);
    text('THANKS FOR PLAYING!', 25, height / 2);
    
    playAgainButton.draw();
  }
  mouseClicked(){
    if(returnToMenuButton.isPressed()){
      currentState = menuState;
    } 
  }
}

let playButton;
let exitButton;
let instructionsButton;

let menuState = new MainMenuState();
let playState = new PlayState();
let winState  = new WinState();
let instructionsState = new InstructionsState();
let exitState = new ExitState();

let currentState = menuState;

function preload() {
  bubblepopper = loadImage('Bubble Popper Logo.png');
  bubblepopperM = loadImage('Bubble Popper Menu Background.jpg');
  bubblepopperG = loadImage('Bubble Popper Game Background.jpg');
}

function setup() {
  currentQuestion = questions[Math.floor(Math.random() * questions.length)];
  createCanvas(600, 600);
  for(let i = 0; i < currentQuestion.correct.length; i++) {
    bubbles.push(new CorrectBubble(random(-3, 3), random(-3, 3), currentQuestion.correct[i], random(width), random(height), random(80,100)));
  } //The new bubbles will be added to the bubbles array.
  
  
  for(let i = 0; i < currentQuestion.incorrect.length; i++) {
    bubbles.push(new IncorrectBubble(random(-3, 3), random(-3, 3), currentQuestion.incorrect[i], random(width), random(height), random(80,100)));
  } //The new bubbles will be added to the bubbles array.
  
  playButton = new Button(50, 100, 200, 75, 'PLAY', 50, color(64,224,208));
  exitButton = new Button(50, 400, 200, 75, 'EXIT', 50, color(255, 0, 255));
  instructionsButton = new Button(50, 250, 200, 75, 'INSTRUCTIONS', 26, color(64,224,208));
  playAgainButton = new Button(180, 400, 250, 75, 'PLAY AGAIN', 26, color(255, 0, 255));
  returnToMenuButton = new Button(180, 400, 250, 75, 'RETURN TO MENU', 26, color(255, 0, 255));
}

function draw() {
  currentState.draw();
}

function mouseClicked() {
  currentState.mouseClicked();
}

function getCorrectBubbles(){
  return bubbles.filter(bubble => bubble instanceof CorrectBubble);
}

function countClickedBubbles(bubbles){
  return bubbles.filter(bubble => bubble.isClicked).length;
}

当然是Button类(class)可以住在 button.js以及 states.js 中的状态类例如:这将大大减少主草图中的代码。

关于javascript - 如何添加 "Play Again"按钮,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68042779/

相关文章:

javascript - 使用 javascript 在 h5 中添加 span 标签

Android:如何获取不同变量中的JSONArray字符串

javascript - 将对象数组添加到现有对象

javascript - p5.j​​s 顶点形状换行

javascript - p5.j​​s 如何停止某些元素的旋转

javascript - 在p5js中沿着弧线移动

javascript - jquery settimeout 和 .focus() 一起不能在 firefox 浏览器中工作

javascript - 仅在 Safari 中 window.onerror 中出现 "Script Error."错误

javascript - 使用拼接从数组中删除元素后。它没有重置。我的代码有什么错误吗

javascript - 如何检测 AngularJs 表单中的对象 $error 是否为空?