我刚加入这个精彩的社区,但遗憾的是我承认我在这里的第一篇文章与一个痛苦的错误有关。当我正在做我的家庭作业,一个破砖机的单一项目时,我遇到了各种各样的错误。到目前为止的故事:
到目前为止的课程:
基本砖类
package gr.teicrete.epp.ooplab.brickbreaker;
import java.awt.Color;
import java.awt.Container;
import java.awt.Point;
import javax.swing.JButton;
import javax.swing.JFrame;
/**
* The Brick class will provide general functionality to our bricks.
*
* @author Fokis
*/
public abstract class Brick extends JButton{
private Point brickPosition; // The brick's position
private Container cont;
/**
* The Brick constructor used to initialize the bricks. Not really used as
* we cannot instantiate the brick class, being abstract and such.
*
* @param posx The brick's x position
* @param posy The brick's y position
*/
public Brick(int posx, int posy) {
this.brickPosition = new Point(posx, posy);
this.setVisible(true);
}
/**
* The public accessor method to the brick's position
* @return The brick's position
*/
public Point getBrickPosition() {
return this.brickPosition;
}
/**
* The public accessor method to the brick's container.
*
* @return The grid's container.
*/
public Grid getContainer() {
return (Grid) this.cont;
}
public abstract int brickSpecialAction(Brick brickie);
}
基本的ColourBrick类:
package gr.teicrete.epp.ooplab.brickbreaker;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.util.Random;
/**
* The ColourBrick class provides functionality to the colourful bricks.
*
* @author Fokis
*/
public class ColourBrick extends Brick {
/**
* The constructor used to initialize our colour bricks.
*
* @param posx The x position of the brick. Used for indexing later.
* @param posy The y position of the brick. Used for indexing later.
* @param seed The seed to the random number generator, so as to pick
* colours available at each level.
*/
public ColourBrick(int posx, int posy, int seed) {
super(posx, posy);
this.setBackground(this.pickColour(seed));
this.setPreferredSize(new Dimension(50, 44));
}
/**
* Public method used to initialise our bricks with a colour.
*
* @param seed the initial seed we provide to the random number generator
* @return The color of the brick to be initialized.
*/
public Color pickColour(int seed) {
Random randomColour = new Random(); // A random object, for RNG
Color assignedColor; // Used to store the color we picked
int potentialColour = randomColour.nextInt(seed); // Picking a random num
switch (potentialColour) {
case 0:
assignedColor = Color.RED;
break;
case 1:
assignedColor = Color.CYAN;
break;
case 2:
assignedColor = Color.GREEN;
break;
case 3:
assignedColor = Color.YELLOW;
break;
case 4:
assignedColor = Color.PINK;
break;
case 5:
assignedColor = Color.MAGENTA;
break;
case 6:
assignedColor = Color.BLACK;
break;
case 7:
assignedColor = Color.ORANGE;
break;
case 8:
assignedColor = Color.GREEN;
break;
default:
// Not really needed, but we provide it to ensure that the compiler
// won't argue that assignedColor might be uninitialized
assignedColor = null;
}
return assignedColor;
}
/**
* The method used to destroy the bricks that we click on.
*
* @param brickie Used for the recursive calls of the method.
* @return The total number of bricks destroyed.
*/
@Override
public int brickSpecialAction(Brick brickie) {
int totalRemovedBricks = 0; // Used to calculate the total number of removed bricks
this.setVisible(false); // Making it invisible
totalRemovedBricks++; // Counting it as a brick destroyed, in order to calculate the score later
Grid omnigrid = (Grid) this.getTopLevelAncestor();
Point brickPosition = this.getBrickPosition();
for (int i = 0; i < 4; i++) {
switch (i) {
case 0:
// Checking to see if the brick above the one we have now has the same colour as the one we are in now
if (omnigrid.getBrickByXAndY(brickPosition.x, brickPosition.y + 1).getBackground().equals(this.getBackground())) {
totalRemovedBricks += brickSpecialAction(omnigrid.getBrickByXAndY(brickPosition.x, brickPosition. y + 1));
}
break;
case 1:
// Checking to see if the brick beyond the one that we have now has the same colour as the one we are in now
if (omnigrid.getBrickByXAndY(brickPosition.x, brickPosition.y - 1).getBackground().equals(this.getBackground())) {
totalRemovedBricks += brickSpecialAction(omnigrid.getBrickByXAndY(brickPosition.x, brickPosition.y - 1));
}
break;
case 2:
// Checking to see if the brick on the left of the one we have now has the same colour as the one we are in now
if (omnigrid.getBrickByXAndY(brickPosition.x - 1, brickPosition.y).getBackground().equals(this.getBackground())) {
totalRemovedBricks += brickSpecialAction(omnigrid.getBrickByXAndY(brickPosition.x - 1, brickPosition.y));
}
break;
case 3:
// Checking to see if the brick on the right of the one we have now has the same colour as the one we are in now
if (omnigrid.getBrickByXAndY(brickPosition.x + 1, brickPosition.y).getBackground().equals(this.getBackground())) {
totalRemovedBricks += brickSpecialAction(omnigrid.getBrickByXAndY(brickPosition.x + 1, brickPosition.y));
}
break;
}
}
return totalRemovedBricks; // returning the total ammount of bricks destroyed used to calculate the score later
}
}
网格类:
package gr.teicrete.epp.ooplab.brickbreaker;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
/**
* The Grid class will provide objects that will be used as our board for the
* game.
*
* @author Fokis
*/
public class Grid extends JFrame implements ActionListener {
private Levels currentLevel; // A reference to the current level
private int generalHiscore; // A variable storing the current HiScore
private float currentScore = 0.0f; // A variable storing the current Score
private int levelsElevated = 1; // A variable used to store the levels the player has elevated each time
private boolean changed;
private String playerName; // A variable used to store the current player's name
/**
* The Grid constructor. Pretty much handles everything. From initialising
* player score to filling the grid with bricks.
*
* @param playerName The current player's name.
*/
public Grid(String playerName) {
super();
this.currentLevel = new Levels(levelsElevated);
this.generalHiscore = 0;
this.currentScore = 0;
this.playerName = playerName;
this.setLayout(new GridLayout(currentLevel.getLevelRows(), currentLevel.getLevelColumns()));
initialize();
pack();
this.setVisible(true);
this.setTitle("Player name: " + playerName + " Current Score: " + currentScore + " Hiscore: " + currentLevel.getHiScore()); // To be reviewed.
this.setDefaultCloseOperation(Grid.EXIT_ON_CLOSE);
}
/**
* The method that will be invoked everytime we need to change the level
*
* @return Whether or not the method was successful.
*/
public boolean changeLevel() {
levelsElevated++;
this.currentLevel = new Levels(levelsElevated);
this.setLayout(new GridLayout(currentLevel.getLevelRows(), currentLevel.getLevelColumns()));
return true;
}
/**
* The method that will be invoked everytime we need to see if the game
* should change level, or if the player lost.
*/
public void checkState() {
if (hasAvailableMoves() == false && isAboveScoreThreshold() == true) {
changed = changeLevel();
} else if (hasAvailableMoves() == false && isAboveScoreThreshold() == false) {
System.out.println("What a pity. You lost.");
}
}
/**
* The method that will be used to calculate the score.
*
* @param removedBricks The total number of bricks removed each time. Used
* to actually calculate the score.
* @return The player's current score.
*/
public float calculateScore(int removedBricks) {
if (removedBricks <= 4) {
currentScore += removedBricks;
} else if (removedBricks >= 5 && removedBricks <= 12) {
currentScore += (removedBricks * 1.5);
} else {
currentScore += 2 * removedBricks;
}
if (currentScore > currentLevel.getHiScore()) {
currentLevel.setHiScore(currentScore);
}
return currentScore;
}
/**
* The method that will be used to check if the player is above each level's
* winning score threshold.
*
* @return The current state of the player's score.
*/
public boolean isAboveScoreThreshold() {
if (currentScore >= currentLevel.getLevelRequiredScore()) {
return true;
} else {
return false;
}
}
/**
* The method that will be used to check if the player has available moves
* left. Will later be used to check whether or not we should change level.
* NOT YET IMPLEMENTED.
*
* @return Whether or not the player has available moves left
*/
public boolean hasAvailableMoves() {
return true;
}
/**
* The method that will be invoked everytime we need to parse one of the
* bricks.
*
* @param x The x position of the brick
* @param y The y position of the brick
* @return The brick that we want to manipulate.
*/
public Brick getBrickByXAndY(int x, int y) {
return (Brick) this.getContentPane().getComponent((y * this.currentLevel.getLevelRows()) + x);
}
/**
* The method that will be invoked to actually fill our Grid with bricks.
*/
public void initialize() {
int acceptedBricks; // To be used for calculation of acceptedBricks
for (acceptedBricks = 0; acceptedBricks < currentLevel.getLevelTotalBricks(); acceptedBricks++) {
for (int x = 1; x <= currentLevel.getLevelRows(); x++) {
for (int y = 1; y <= currentLevel.getLevelColumns(); y++) {
Brick newBrick = new ColourBrick(x, y, currentLevel.getLevelAvailableColours());
newBrick.addActionListener(this);
this.add(newBrick);
acceptedBricks++;
}
}
}
}
@Override
public void actionPerformed(ActionEvent evt) {
Brick brickClicked = (Brick) evt.getSource();
calculateScore(brickClicked.brickSpecialAction(brickClicked));
this.setTitle("Player name: " + playerName + " Current Score: " + currentScore + " Hiscore: " + currentLevel.getHiScore());
this.checkState();
}
}
重要提示:我不是那么便宜,要求别人解决项目或问题,我只是想让别人向我解释为什么我有这个错误。在那之后,我将尝试单独解决这个问题。但请帮助我。我已经努力了。
编辑:堆栈跟踪:
Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
at java.awt.Component.isVisible_NoClientCode(Component.java:1288)
at java.awt.Component.isVisible(Component.java:1285)
at javax.swing.JComponent.setVisible(JComponent.java:2639)
at gr.teicrete.epp.ooplab.brickbreaker.ColourBrick.brickSpecialAction(ColourBrick.java:90)
at gr.teicrete.epp.ooplab.brickbreaker.ColourBrick.brickSpecialAction(ColourBrick.java:101)
at gr.teicrete.epp.ooplab.brickbreaker.ColourBrick.brickSpecialAction(ColourBrick.java:101)
at gr.teicrete.epp.ooplab.brickbreaker.ColourBrick.brickSpecialAction(ColourBrick.java:101)
at gr.teicrete.epp.ooplab.brickbreaker.ColourBrick.brickSpecialAction(ColourBrick.java:101)
at gr.teicrete.epp.ooplab.brickbreaker.ColourBrick.brickSpecialAction(ColourBrick.java:101)
at gr.teicrete.epp.ooplab.brickbreaker.ColourBrick.brickSpecialAction(ColourBrick.java:101)
at gr.teicrete.epp.ooplab.brickbreaker.ColourBrick.brickSpecialAction(ColourBrick.java:101)
at gr.teicrete.epp.ooplab.brickbreaker.ColourBrick.brickSpecialAction(ColourBrick.java:101)
at gr.teicrete.epp.ooplab.brickbreaker.ColourBrick.brickSpecialAction(ColourBrick.java:101)
at
并且它一直保持这样的状态。
答案 0 :(得分:2)
您的brickSpecialAction()方法包含对自身的调用。如果没有适当的控制,这将使您进入无限递归循环。 StackOverflow错误通常是由这种情况引起的。
答案 1 :(得分:1)
问题出现了,因为您检查上面的块是否是相同的颜色,如果是,重复相同的逻辑,并且该逻辑正在检查下面的块是否是相同的颜色,如果是这样,重复同样的逻辑。因此,如果顶部的块与底部的块颜色相同,则它会来回反弹,直到出现堆栈溢出。也许在你检查时删除块,或者做一些标记以表示它们已被标记为删除,并更改逻辑以检查它而不是无限地重新诅咒。
我猜你的代码存在其他问题,但这可能会让你超越当前的错误......
public int brickSpecialAction(Brick brickie) {
int totalRemovedBricks = 0; // Used to calculate the total number of removed bricks
if (!this.isVisible) //Or whatever you can check to see if you have set this invisible already
return; // You've already executed on this block
this.setVisible(false); // Making it invisible
答案 2 :(得分:1)
你的问题肯定是brickSpecialAction()
中的递归 从概念上讲,This与你想要完成的事情非常相似。