处理:如何修复计时器显示以及如何在游戏结束时显示时间分数?
Processing: How to fix timer display and how to display time score at end of game?
我正在研究一个升序拼图,记录用户完成拼图所花费的时间,一旦拼图完成,它会将用户带到一个游戏结束屏幕,显示用户他们的时间。我的问题是显示的时间重叠并且没有按应有的方式更新。我也不确定如何节省用户完成拼图所花费的时间。
final int NUM_SQUARES = 4;
int[][] board = new int[NUM_SQUARES][NUM_SQUARES];
int sqSide;
Timer startTimer;
void setup(){
size(500, 500);
setupGame();
sqSide = width/NUM_SQUARES;
}
void setupGame(){
sqSide = width/NUM_SQUARES;
startTimer = new Timer(0);
//populate the board
//generate random number
//check if we have it already inside the array
//if we have, then go on to generate another random number
//if we do not have it, then we can store inside array
for(int row=0; row<NUM_SQUARES; row++){
for(int col=0; col<NUM_SQUARES; col++){
int randVal;
do{
randVal = int(random(1, NUM_SQUARES*NUM_SQUARES+1) );
}while( searchFor(randVal) );
board[row][col] = randVal;
}
}
//visual representation of the board
for(int row=0; row<NUM_SQUARES; row++){
for(int col=0; col<NUM_SQUARES; col++){
fill(random(0,255), random(0,255), random(0,255));
rect(col*sqSide, row*sqSide, sqSide, sqSide);
fill(0);
textSize(30);
text(board[row][col], (col+0.5)*sqSide, (row+0.5)*sqSide);
}
}
}
class Timer{
float Time;
Timer(float set){
Time = set;
}
float getTime(){
return(Time);
}
void setTime(float set){
Time = set;
}
void countUP(){
Time += 1/frameRate;
}
}
boolean searchFor(int itemToBeSearched){
for(int i=0; i<NUM_SQUARES; i++){
for(int j=0; j<NUM_SQUARES; j++){
if(itemToBeSearched == board[i][j]){
return true;
}
}
}
return false;
}
void draw(){
startTimer.countUP();
fill(0);
text(startTimer.getTime(), 20,20);
}
int clickedRow, clickedCol, releasedRow, releasedCol;
void mousePressed(){
clickedRow = int(mouseY/sqSide);
clickedCol = int(mouseX/sqSide);
}
void mouseReleased(){
releasedRow = int(mouseY/sqSide);
releasedCol = int(mouseX/sqSide);
//swap
int buffer = board[clickedRow][clickedCol];
board[clickedRow][clickedCol] = board[releasedRow][releasedCol];
board[releasedRow][releasedCol] = buffer;
//visual representation - finish up
//show what is inside board[clickedRow][clikedCol]
//then show what is inside board[releasedRow][releasedCol]
//where the child pressed
fill(random(0,255), random(0,255), random(0,255));
rect(clickedCol*sqSide, clickedRow*sqSide, sqSide, sqSide);
fill(0);
text(board[clickedRow][clickedCol],(clickedCol+0.5)*sqSide, (clickedRow+0.5)*sqSide) ;
//where the child released
fill(random(0,255), random(0,255), random(0,255));
rect(releasedCol*sqSide, releasedRow*sqSide, sqSide, sqSide);
fill(0);
text(board[releasedRow][releasedCol],(releasedCol+0.5)*sqSide, (releasedRow+0.5)*sqSide);
if(gameOver()==true){ //calling function gameOver
background(255);
String s = "Congratulations!";
String d = "Click to start again!";
fill(0);
text(s, 125, 225);
text(d, 125, 250);
if(mousePressed == true){
setupGame();
}
}
}
//definition of gameOver
boolean gameOver(){
int counter=1;
for(int row=0; row<NUM_SQUARES; row++){
for(int col=0; col<NUM_SQUARES; col++){
if(board[row][col] !=counter){
return false;
}
counter++;
}
}
return true;
}
那里有很多好的工作,尤其是在管理板/交换元素等方面。需要重点关注它。
看起来在绘图方面也有点混乱。
您可以在 draw() 中绘制一次元素;像现在一样在顶部渲染重叠元素,但是您需要注意需要渲染一次或多次的内容。
计时器文本留下痕迹,因为背景永远不会被清除,但棋盘只绘制一次。您将需要重新绘制 background/board 以修复文本,但某些代码位需要移动或需要以不同方式处理。
例如:
fill(random(0,255), random(0,255), random(0,255));
如果你在 draw()
中调用它,颜色会不断变化,这是你不想要的。
但是,您可以在 setup()
中生成一次颜色,然后在 draw() 中 re-use 生成它们,而无需重置值。
鼠标事件和何时或应该在哪个状态下重置似乎也有些混淆。
考虑到上述注释,这是您的代码的 re-organised 版本:
final int NUM_SQUARES = 4;
int[][] board = new int[NUM_SQUARES][NUM_SQUARES];
// also remember the colours set once in setup() to re-use in draw()
int[][] boardColors = new int[NUM_SQUARES][NUM_SQUARES];
int sqSide;
Timer startTimer;
int clickedRow, clickedCol, releasedRow, releasedCol;
// this will store the result of gameOver() once so it can be re-used
boolean isGameOver;
void setup(){
size(500, 500);
setupGame();
}
void setupGame(){
sqSide = width/NUM_SQUARES;
startTimer = new Timer(0);
clearBoard();
//populate the board
//generate random number
//check if we have it already inside the array
//if we have, then go on to generate another random number
//if we do not have it, then we can store inside array
shuffleBoard();
}
void clearBoard(){
for(int row = 0; row < NUM_SQUARES; row++){
for(int col = 0; col < NUM_SQUARES; col++){
board[row][col] = 0;
}
}
}
void shuffleBoard(){
for(int row = 0; row < NUM_SQUARES; row++){
for(int col = 0; col < NUM_SQUARES; col++){
int randVal;
do{
randVal = int(random(1, NUM_SQUARES*NUM_SQUARES+1) );
}while( searchFor(randVal) );
board[row][col] = randVal;
boardColors[row][col] = color(random(0,255), random(0,255), random(0,255));
}
}
}
void drawBoard(){
//visual representation of the board
for(int row = 0; row < NUM_SQUARES; row++){
for(int col = 0; col < NUM_SQUARES; col++){
fill(boardColors[row][col]);
rect(col * sqSide, row * sqSide, sqSide, sqSide);
fill(255);
textSize(30);
text(board[row][col], (col + 0.5) * sqSide, (row + 0.5) * sqSide);
}
}
}
boolean searchFor(int itemToBeSearched){
for(int i = 0; i < NUM_SQUARES; i++){
for(int j = 0; j < NUM_SQUARES; j++){
if(itemToBeSearched == board[i][j]){
return true;
}
}
}
return false;
}
void draw(){
background(255);
// draw based on state
if(gameOver()){
// render game over state
String s = "Congratulations!";
String d = "Click to start again!";
fill(0);
text(s, 125, 225);
text(d, 125, 250);
// reset game only if clicking in game over state
if(mousePressed == true){
setupGame();
}
}else{
// render game state
startTimer.countUp();
// re-render board
drawBoard();
// render text on top
fill(0);
text(startTimer.getTime(), 20, 30);
}
}
void mousePressed(){
clickedRow = int(mouseY/sqSide);
clickedCol = int(mouseX/sqSide);
}
void mouseReleased(){
releasedRow = int(mouseY/sqSide);
releasedCol = int(mouseX/sqSide);
//swap
int buffer = board[clickedRow][clickedCol];
board[clickedRow][clickedCol] = board[releasedRow][releasedCol];
board[releasedRow][releasedCol] = buffer;
}
//definition of gameOver
boolean gameOver(){
int counter=1;
for(int row=0; row<NUM_SQUARES; row++){
for(int col=0; col<NUM_SQUARES; col++){
if(board[row][col] !=counter){
return false;
}
counter++;
}
}
return true;
}
class Timer{
float time;
Timer(float set){
time = set;
}
float getTime(){
return(time);
}
void setTime(float set){
time = set;
}
void countUp(){
time += 1 / frameRate;
}
}
它可能会更容易组织一个基本的 finite state machine(FSM)。
这听起来比实际更复杂:基本思想是隔离每个状态的功能并严格处理状态之间的转换,从而允许您相应地 reset/update 数据。例如,一个游戏运行状态将只需要处理与游戏玩法相关的数据,直到该状态完成。同样,游戏结束状态只处理它的数据,直到它完成(当用户点击时)。有多种写法。
这里有一个围绕处理草图如何运行的建议:
- setup() 是在开始时设置一次的地方
- draw() 是事情发生的地方updated/rendered
- 鼠标/键/等事件处理用户输入
您已经在使用 class (Timer
) 这将非常相似:
// the two states
StateDisplay playState;
StateDisplay gameOverState;
// a reference to the current state
StateDisplay currentState;
void setup(){
size(500, 500);
textAlign(CENTER);
// setup each state
playState = new PlayState();
gameOverState = new GameOverState();
// set the reference to the 1st state
currentState = playState;
}
// forward events to the current state: doesn't matter if it's play or game over, they're can all handle it
void draw(){
currentState.draw();
}
void mousePressed(){
currentState.mousePressed();
}
void mouseReleased(){
currentState.mouseReleased();
}
// global function to be called by each state as it exits
// this does the state switch: reset state data as required
void onStateExit(StateDisplay exitingState){
// game play state to game over state
if(exitingState == playState){
// cast each state to access specialised variables
// in this case store the last timer value to display on the game over screen
((GameOverState)gameOverState).timerValue = ((PlayState)playState).startTimer.getTimeFormatted();
// set the state
currentState = gameOverState;
}
// game over state to game play state
if(exitingState == gameOverState){
// reset game
playState.setup();
// set the state
currentState = playState;
}
}
class Timer{
float time;
Timer(float set){
time = set;
}
float getTime(){
return time;
}
String getTimeFormatted(){
return nfc(time, 2);
}
void setTime(float set){
time = set;
}
void countUp(){
time += 1 / frameRate;
}
}
// "parent" state class that all other states will extend
// and inherit functionality from
class StateDisplay{
StateDisplay(){
// as soon as the constructor is called, set up this state
this.setup();
}
void setup(){
// to be overriden by subclass
}
void draw(){
// to be overriden by subclass
}
void mousePressed(){
// to be overriden by subclass
}
void mouseReleased(){
// to be overriden by subclass
}
}
class PlayState extends StateDisplay{
final int NUM_SQUARES = 4;
int[][] board;
int[][] boardColors;
int sqSide;
Timer startTimer;
int clickedRow, clickedCol, releasedRow, releasedCol;
void setup(){
setupGame();
}
void setupGame(){
this.board = new int[NUM_SQUARES][NUM_SQUARES];
this.boardColors = new int[NUM_SQUARES][NUM_SQUARES];
sqSide = width/NUM_SQUARES;
startTimer = new Timer(0);
//populate the board
//generate random number
//check if we have it already inside the array
//if we have, then go on to generate another random number
//if we do not have it, then we can store inside array
for(int row = 0; row < NUM_SQUARES; row++){
for(int col = 0; col < NUM_SQUARES; col++){
int randVal;
do{
randVal = int(random(1, NUM_SQUARES*NUM_SQUARES+1) );
}while( searchFor(randVal) );
board[row][col] = randVal;
boardColors[row][col] = color(random(0,255), random(0,255), random(0,255));
}
}
}
boolean searchFor(int itemToBeSearched){
for(int i = 0; i < NUM_SQUARES; i++){
for(int j = 0; j < NUM_SQUARES; j++){
if(itemToBeSearched == board[i][j]){
return true;
}
}
}
return false;
}
//definition of gameOver
boolean gameOver(){
int counter=1;
for(int row=0; row<NUM_SQUARES; row++){
for(int col=0; col<NUM_SQUARES; col++){
if(board[row][col] !=counter){
return false;
}
counter++;
}
}
return true;
}
void drawBoard(){
//visual representation of the board
for(int row = 0; row < NUM_SQUARES; row++){
for(int col = 0; col < NUM_SQUARES; col++){
fill(boardColors[row][col]);
rect(col * sqSide, row*sqSide, sqSide, sqSide);
fill(255);
textSize(30);
text(board[row][col], (col+0.5) * sqSide, (row + 0.5) * sqSide);
}
}
}
void draw(){
// clear screen
background(255);
// redraw board
drawBoard();
// optional: drag and drop visual cue
if(mousePressed){
fill(255, 192);
text(board[clickedRow][clickedCol], mouseX, mouseY);
}
startTimer.countUp();
fill(255);
text(startTimer.getTimeFormatted()+"s", width * 0.5, 30);
}
void mousePressed(){
clickedRow = int(mouseY/sqSide);
clickedCol = int(mouseX/sqSide);
}
void mouseReleased(){
releasedRow = int(mouseY/sqSide);
releasedCol = int(mouseX/sqSide);
//swap
int buffer = board[clickedRow][clickedCol];
board[clickedRow][clickedCol] = board[releasedRow][releasedCol];
board[releasedRow][releasedCol] = buffer;
if(gameOver()){
onStateExit(this);
}
}
}
class GameOverState extends StateDisplay{
// time taken to solve
String timerValue = "";
void draw(){
String s = "Congratulations!\n" +
"Solved in " + timerValue + "s\n" +
"Click to start again!";
background(255);
fill(0);
text(s, width * 0.5, 225);
}
void mouseReleased(){
onStateExit(this);
}
}
代码可能看起来很冗长,但基本上所做的大部分工作都是按状态对功能进行分组:就好像您是 运行 mini-sketches 并在它们之间交换。
可能是新的东西是:
- 扩展一个class:扩展(subclass)的class将从父class继承properties/methods(superclass)
- polymorphism:依靠 subclasses 与 superclass 的共同点来对待它们,就好像它们是一样的(尽管每个内部的实现是不同的) ). (例如,所有州都有
draw()
,但每个州都呈现其他内容)
- casting:在这种特殊情况下,允许 subclass 表现得像它自己(所有它都是额外的 properties/methods),而不仅仅是从 superclass 共享的东西.更具体地说,在上面的代码中,计时器数据从游戏进行状态传递到游戏结束状态以显示。
尽管以这种方式进行设置需要做更多的工作,但保持状态隔离并使用相同的逻辑轻松添加更多状态(例如高分稳定、开始/游戏菜单屏幕等)可能是值得的.).将每个状态作为 min-sketch 您还可以使用选项卡将其组织起来,从而节省一直上下滚动的时间:
我正在研究一个升序拼图,记录用户完成拼图所花费的时间,一旦拼图完成,它会将用户带到一个游戏结束屏幕,显示用户他们的时间。我的问题是显示的时间重叠并且没有按应有的方式更新。我也不确定如何节省用户完成拼图所花费的时间。
final int NUM_SQUARES = 4;
int[][] board = new int[NUM_SQUARES][NUM_SQUARES];
int sqSide;
Timer startTimer;
void setup(){
size(500, 500);
setupGame();
sqSide = width/NUM_SQUARES;
}
void setupGame(){
sqSide = width/NUM_SQUARES;
startTimer = new Timer(0);
//populate the board
//generate random number
//check if we have it already inside the array
//if we have, then go on to generate another random number
//if we do not have it, then we can store inside array
for(int row=0; row<NUM_SQUARES; row++){
for(int col=0; col<NUM_SQUARES; col++){
int randVal;
do{
randVal = int(random(1, NUM_SQUARES*NUM_SQUARES+1) );
}while( searchFor(randVal) );
board[row][col] = randVal;
}
}
//visual representation of the board
for(int row=0; row<NUM_SQUARES; row++){
for(int col=0; col<NUM_SQUARES; col++){
fill(random(0,255), random(0,255), random(0,255));
rect(col*sqSide, row*sqSide, sqSide, sqSide);
fill(0);
textSize(30);
text(board[row][col], (col+0.5)*sqSide, (row+0.5)*sqSide);
}
}
}
class Timer{
float Time;
Timer(float set){
Time = set;
}
float getTime(){
return(Time);
}
void setTime(float set){
Time = set;
}
void countUP(){
Time += 1/frameRate;
}
}
boolean searchFor(int itemToBeSearched){
for(int i=0; i<NUM_SQUARES; i++){
for(int j=0; j<NUM_SQUARES; j++){
if(itemToBeSearched == board[i][j]){
return true;
}
}
}
return false;
}
void draw(){
startTimer.countUP();
fill(0);
text(startTimer.getTime(), 20,20);
}
int clickedRow, clickedCol, releasedRow, releasedCol;
void mousePressed(){
clickedRow = int(mouseY/sqSide);
clickedCol = int(mouseX/sqSide);
}
void mouseReleased(){
releasedRow = int(mouseY/sqSide);
releasedCol = int(mouseX/sqSide);
//swap
int buffer = board[clickedRow][clickedCol];
board[clickedRow][clickedCol] = board[releasedRow][releasedCol];
board[releasedRow][releasedCol] = buffer;
//visual representation - finish up
//show what is inside board[clickedRow][clikedCol]
//then show what is inside board[releasedRow][releasedCol]
//where the child pressed
fill(random(0,255), random(0,255), random(0,255));
rect(clickedCol*sqSide, clickedRow*sqSide, sqSide, sqSide);
fill(0);
text(board[clickedRow][clickedCol],(clickedCol+0.5)*sqSide, (clickedRow+0.5)*sqSide) ;
//where the child released
fill(random(0,255), random(0,255), random(0,255));
rect(releasedCol*sqSide, releasedRow*sqSide, sqSide, sqSide);
fill(0);
text(board[releasedRow][releasedCol],(releasedCol+0.5)*sqSide, (releasedRow+0.5)*sqSide);
if(gameOver()==true){ //calling function gameOver
background(255);
String s = "Congratulations!";
String d = "Click to start again!";
fill(0);
text(s, 125, 225);
text(d, 125, 250);
if(mousePressed == true){
setupGame();
}
}
}
//definition of gameOver
boolean gameOver(){
int counter=1;
for(int row=0; row<NUM_SQUARES; row++){
for(int col=0; col<NUM_SQUARES; col++){
if(board[row][col] !=counter){
return false;
}
counter++;
}
}
return true;
}
那里有很多好的工作,尤其是在管理板/交换元素等方面。需要重点关注它。
看起来在绘图方面也有点混乱。 您可以在 draw() 中绘制一次元素;像现在一样在顶部渲染重叠元素,但是您需要注意需要渲染一次或多次的内容。
计时器文本留下痕迹,因为背景永远不会被清除,但棋盘只绘制一次。您将需要重新绘制 background/board 以修复文本,但某些代码位需要移动或需要以不同方式处理。
例如:
fill(random(0,255), random(0,255), random(0,255));
如果你在 draw()
中调用它,颜色会不断变化,这是你不想要的。
但是,您可以在 setup()
中生成一次颜色,然后在 draw() 中 re-use 生成它们,而无需重置值。
鼠标事件和何时或应该在哪个状态下重置似乎也有些混淆。
考虑到上述注释,这是您的代码的 re-organised 版本:
final int NUM_SQUARES = 4;
int[][] board = new int[NUM_SQUARES][NUM_SQUARES];
// also remember the colours set once in setup() to re-use in draw()
int[][] boardColors = new int[NUM_SQUARES][NUM_SQUARES];
int sqSide;
Timer startTimer;
int clickedRow, clickedCol, releasedRow, releasedCol;
// this will store the result of gameOver() once so it can be re-used
boolean isGameOver;
void setup(){
size(500, 500);
setupGame();
}
void setupGame(){
sqSide = width/NUM_SQUARES;
startTimer = new Timer(0);
clearBoard();
//populate the board
//generate random number
//check if we have it already inside the array
//if we have, then go on to generate another random number
//if we do not have it, then we can store inside array
shuffleBoard();
}
void clearBoard(){
for(int row = 0; row < NUM_SQUARES; row++){
for(int col = 0; col < NUM_SQUARES; col++){
board[row][col] = 0;
}
}
}
void shuffleBoard(){
for(int row = 0; row < NUM_SQUARES; row++){
for(int col = 0; col < NUM_SQUARES; col++){
int randVal;
do{
randVal = int(random(1, NUM_SQUARES*NUM_SQUARES+1) );
}while( searchFor(randVal) );
board[row][col] = randVal;
boardColors[row][col] = color(random(0,255), random(0,255), random(0,255));
}
}
}
void drawBoard(){
//visual representation of the board
for(int row = 0; row < NUM_SQUARES; row++){
for(int col = 0; col < NUM_SQUARES; col++){
fill(boardColors[row][col]);
rect(col * sqSide, row * sqSide, sqSide, sqSide);
fill(255);
textSize(30);
text(board[row][col], (col + 0.5) * sqSide, (row + 0.5) * sqSide);
}
}
}
boolean searchFor(int itemToBeSearched){
for(int i = 0; i < NUM_SQUARES; i++){
for(int j = 0; j < NUM_SQUARES; j++){
if(itemToBeSearched == board[i][j]){
return true;
}
}
}
return false;
}
void draw(){
background(255);
// draw based on state
if(gameOver()){
// render game over state
String s = "Congratulations!";
String d = "Click to start again!";
fill(0);
text(s, 125, 225);
text(d, 125, 250);
// reset game only if clicking in game over state
if(mousePressed == true){
setupGame();
}
}else{
// render game state
startTimer.countUp();
// re-render board
drawBoard();
// render text on top
fill(0);
text(startTimer.getTime(), 20, 30);
}
}
void mousePressed(){
clickedRow = int(mouseY/sqSide);
clickedCol = int(mouseX/sqSide);
}
void mouseReleased(){
releasedRow = int(mouseY/sqSide);
releasedCol = int(mouseX/sqSide);
//swap
int buffer = board[clickedRow][clickedCol];
board[clickedRow][clickedCol] = board[releasedRow][releasedCol];
board[releasedRow][releasedCol] = buffer;
}
//definition of gameOver
boolean gameOver(){
int counter=1;
for(int row=0; row<NUM_SQUARES; row++){
for(int col=0; col<NUM_SQUARES; col++){
if(board[row][col] !=counter){
return false;
}
counter++;
}
}
return true;
}
class Timer{
float time;
Timer(float set){
time = set;
}
float getTime(){
return(time);
}
void setTime(float set){
time = set;
}
void countUp(){
time += 1 / frameRate;
}
}
它可能会更容易组织一个基本的 finite state machine(FSM)。 这听起来比实际更复杂:基本思想是隔离每个状态的功能并严格处理状态之间的转换,从而允许您相应地 reset/update 数据。例如,一个游戏运行状态将只需要处理与游戏玩法相关的数据,直到该状态完成。同样,游戏结束状态只处理它的数据,直到它完成(当用户点击时)。有多种写法。
这里有一个围绕处理草图如何运行的建议:
- setup() 是在开始时设置一次的地方
- draw() 是事情发生的地方updated/rendered
- 鼠标/键/等事件处理用户输入
您已经在使用 class (Timer
) 这将非常相似:
// the two states
StateDisplay playState;
StateDisplay gameOverState;
// a reference to the current state
StateDisplay currentState;
void setup(){
size(500, 500);
textAlign(CENTER);
// setup each state
playState = new PlayState();
gameOverState = new GameOverState();
// set the reference to the 1st state
currentState = playState;
}
// forward events to the current state: doesn't matter if it's play or game over, they're can all handle it
void draw(){
currentState.draw();
}
void mousePressed(){
currentState.mousePressed();
}
void mouseReleased(){
currentState.mouseReleased();
}
// global function to be called by each state as it exits
// this does the state switch: reset state data as required
void onStateExit(StateDisplay exitingState){
// game play state to game over state
if(exitingState == playState){
// cast each state to access specialised variables
// in this case store the last timer value to display on the game over screen
((GameOverState)gameOverState).timerValue = ((PlayState)playState).startTimer.getTimeFormatted();
// set the state
currentState = gameOverState;
}
// game over state to game play state
if(exitingState == gameOverState){
// reset game
playState.setup();
// set the state
currentState = playState;
}
}
class Timer{
float time;
Timer(float set){
time = set;
}
float getTime(){
return time;
}
String getTimeFormatted(){
return nfc(time, 2);
}
void setTime(float set){
time = set;
}
void countUp(){
time += 1 / frameRate;
}
}
// "parent" state class that all other states will extend
// and inherit functionality from
class StateDisplay{
StateDisplay(){
// as soon as the constructor is called, set up this state
this.setup();
}
void setup(){
// to be overriden by subclass
}
void draw(){
// to be overriden by subclass
}
void mousePressed(){
// to be overriden by subclass
}
void mouseReleased(){
// to be overriden by subclass
}
}
class PlayState extends StateDisplay{
final int NUM_SQUARES = 4;
int[][] board;
int[][] boardColors;
int sqSide;
Timer startTimer;
int clickedRow, clickedCol, releasedRow, releasedCol;
void setup(){
setupGame();
}
void setupGame(){
this.board = new int[NUM_SQUARES][NUM_SQUARES];
this.boardColors = new int[NUM_SQUARES][NUM_SQUARES];
sqSide = width/NUM_SQUARES;
startTimer = new Timer(0);
//populate the board
//generate random number
//check if we have it already inside the array
//if we have, then go on to generate another random number
//if we do not have it, then we can store inside array
for(int row = 0; row < NUM_SQUARES; row++){
for(int col = 0; col < NUM_SQUARES; col++){
int randVal;
do{
randVal = int(random(1, NUM_SQUARES*NUM_SQUARES+1) );
}while( searchFor(randVal) );
board[row][col] = randVal;
boardColors[row][col] = color(random(0,255), random(0,255), random(0,255));
}
}
}
boolean searchFor(int itemToBeSearched){
for(int i = 0; i < NUM_SQUARES; i++){
for(int j = 0; j < NUM_SQUARES; j++){
if(itemToBeSearched == board[i][j]){
return true;
}
}
}
return false;
}
//definition of gameOver
boolean gameOver(){
int counter=1;
for(int row=0; row<NUM_SQUARES; row++){
for(int col=0; col<NUM_SQUARES; col++){
if(board[row][col] !=counter){
return false;
}
counter++;
}
}
return true;
}
void drawBoard(){
//visual representation of the board
for(int row = 0; row < NUM_SQUARES; row++){
for(int col = 0; col < NUM_SQUARES; col++){
fill(boardColors[row][col]);
rect(col * sqSide, row*sqSide, sqSide, sqSide);
fill(255);
textSize(30);
text(board[row][col], (col+0.5) * sqSide, (row + 0.5) * sqSide);
}
}
}
void draw(){
// clear screen
background(255);
// redraw board
drawBoard();
// optional: drag and drop visual cue
if(mousePressed){
fill(255, 192);
text(board[clickedRow][clickedCol], mouseX, mouseY);
}
startTimer.countUp();
fill(255);
text(startTimer.getTimeFormatted()+"s", width * 0.5, 30);
}
void mousePressed(){
clickedRow = int(mouseY/sqSide);
clickedCol = int(mouseX/sqSide);
}
void mouseReleased(){
releasedRow = int(mouseY/sqSide);
releasedCol = int(mouseX/sqSide);
//swap
int buffer = board[clickedRow][clickedCol];
board[clickedRow][clickedCol] = board[releasedRow][releasedCol];
board[releasedRow][releasedCol] = buffer;
if(gameOver()){
onStateExit(this);
}
}
}
class GameOverState extends StateDisplay{
// time taken to solve
String timerValue = "";
void draw(){
String s = "Congratulations!\n" +
"Solved in " + timerValue + "s\n" +
"Click to start again!";
background(255);
fill(0);
text(s, width * 0.5, 225);
}
void mouseReleased(){
onStateExit(this);
}
}
代码可能看起来很冗长,但基本上所做的大部分工作都是按状态对功能进行分组:就好像您是 运行 mini-sketches 并在它们之间交换。
可能是新的东西是:
- 扩展一个class:扩展(subclass)的class将从父class继承properties/methods(superclass)
- polymorphism:依靠 subclasses 与 superclass 的共同点来对待它们,就好像它们是一样的(尽管每个内部的实现是不同的) ). (例如,所有州都有
draw()
,但每个州都呈现其他内容) - casting:在这种特殊情况下,允许 subclass 表现得像它自己(所有它都是额外的 properties/methods),而不仅仅是从 superclass 共享的东西.更具体地说,在上面的代码中,计时器数据从游戏进行状态传递到游戏结束状态以显示。
尽管以这种方式进行设置需要做更多的工作,但保持状态隔离并使用相同的逻辑轻松添加更多状态(例如高分稳定、开始/游戏菜单屏幕等)可能是值得的.).将每个状态作为 min-sketch 您还可以使用选项卡将其组织起来,从而节省一直上下滚动的时间: