我在设计国际象棋游戏时需要帮助。我已经开始了,但还没有走得太远,因为我对Java很陌生,实际上是编程新手。
无论如何,我有我的抽象类Piece和各个部分作为子类。 我有一个方法movePiece,在我的抽象类中,我想为所有子类定义。
目前所做的只是将棋子从一个方格移动到另一个方格。我有一个可以容纳Piece对象的Square类,该板由64x1 Square数组组成。
我知道碎片是如何移动的,但我如何实际编程呢? 我想尝试应用MVC模式,但这是我第一次使用模式。
基本上我正在考虑使用Graphics2D为每个Square创建一个盒子。然后,当玩家点击一块时,移动后可用作目的地的方块将以某种颜色勾勒出轮廓。玩家点击其中一个方格后,我在movePiece方法中已有的代码将会运行。
我想要做的是在Piece的每个子类中覆盖我的movePiece方法。问题是,代码如何在其中一种方法中看到?以Pawn子类为例。
我不是要求复制/粘贴代码,只是关于如何执行此操作的一些指示,最后是一些示例代码。
谢谢!
public class Game {
@SuppressWarnings("unused")
public static void main(String[] args){
Board board = new Board();
} }
public class Board {
Square[] grid;
public Board(){
grid = new Square[64];
}
public Square getSquare(int i){
return grid[i];
}
public void setDefault(){
}
public Boolean isMoveValid(){
return null;
} }
public class Square {
private Piece piece;
public void addPiece(Piece pieceType, String pieceColour, String pieceOwner)
throws ClassNotFoundException, InstantiationException, IllegalAccessException{
PieceFactory factory = new PieceFactory();
Piece piece = factory.createPiece(pieceType);
piece.setColour(pieceColour);
piece.setOwner(pieceOwner);
this.piece = piece;
}
public void addPiece(Piece pieceType){
this.piece = pieceType;
}
public void removePiece(){
piece = null;
}
public Piece getPiece(){
return piece;
}
class PieceFactory {
@SuppressWarnings("rawtypes")
public Piece createPiece(Piece pieceType)
throws ClassNotFoundException, InstantiationException, IllegalAccessException{
Class pieceClass = Class.forName(pieceType.toString());
Piece piece = (Piece) pieceClass.newInstance();
return piece;
} }
public void setColour(String colour){
} }
public abstract class Piece {
Board board;
public void setColour(String pieceColour) {
}
public void setOwner(String pieceOwner) {
}
public String getColour() {
return "";
}
public String getOwner() {
return "";
}
public void movePiece(int oldIndex, int newIndex){
board.getSquare(oldIndex).removePiece();
board.getSquare(newIndex).addPiece(this);
}
public String toString(){
return this.getClass().getSimpleName();
} }
你想看看我知道的非常基本的代码。我会将[64]更改为[8] [8]。 我试图不要让它变得更难。我可以将Color和Owner结合起来作为一个属性,并使它成为枚举(黑色或白色)。
如果格式不正确,请注意。
答案 0 :(得分:18)
在设计软件时,我发现考虑如何使用方法,然后记下方法签名(如果你做测试驱动开发,单元测试),那么只考虑我将如何实现它
在此处执行此操作,我发现需求
用之类的方法无法满足然后当玩家点击一块时, 可用的正方形 移动后的目的地将是 以某种颜色勾勒出来。
void move(Square destination);
因为没有实际制作它们就无法找到可能的动作。要突出显示方块,最好是我们有一个像
这样的方法Collection<Square> getPossibleMoves();
然后我们可以实现
void move(Square destination) {
if (!getPossibleMoves().contains(destination) {
throw new IllegalMoveException();
}
this.location.occupyingPiece = null;
this.location = destination;
this.location.occupyingPiece = this;
}
实施getPossibleMoves:
class Pawn extends Piece {
@Override Collection<Square> getPossibleMoves() {
List<Square> possibleMoves = new ArrayList<Square>();
int dy = color == Color.white ? 1 : -1;
Square ahead = location.neighbour(0, dy);
if (ahead.occupyingPiece == null) {
possibleMoves.add(ahead);
}
Square aheadLeft = location.neighbour(-1, dy);
if (aheadLeft != null && aheadLeft.occupyingPiece != null && aheadLeft.occupyingPiece.color != color) {
possibleMoves.add(aheadLeft);
}
Square aheadRight = location.neighbour(1, dy);
if (aheadRight != null && aheadRight.occupyingPiece != null && aheadRight.occupyingPiece.color != color) {
possibleMoves.add(aheadRight);
}
return possibleMoves;
}
}
修改强>:
class Knight extends Piece {
@Override Collection<Square> getPossibleMoves() {
List<Square> possibleMoves = new ArrayList<Square>();
int[][] offsets = {
{-2, 1},
{-1, 2},
{1, 2},
{2, 1},
{2, -1},
{1, -2},
{-1, -2},
{-2, -1}
};
for (int[] o : offsets) {
Square candidate = location.neighbour(o[0], o[1]);
if (candidate != null && (candidate.occupyingPiece == null || candidate.occupyingPiece.color != color)) {
possibleMoves.add(candidate);
}
}
return possibleMoves;
}
}
答案 1 :(得分:2)
你描述它的方式,不仅仅是movePiece方法,你需要一个getPossibleMoves
方法,它可以为你提供所有可以移动的地方。或者或另外使用moveAllowed
方法来判断一件作品是否允许移动到给定位置。
您可以创建一个类来定义板中的Location
,而不是使用原始(x,y)坐标。这可以为您提供将位置转换为国际象棋文献中使用的“国际象棋坐标”的方法。位置将构建为new Location(x, y)
。
此外,我宁愿选择代表8x8单元板的Board
类,并且是片段的容器,并且可以拥有比数组更丰富的逻辑(例如,可以给你一个pathClear(from, to)
告诉你是否有任何碎片阻止你从一个地方到另一个地方的通道等)
答案 2 :(得分:1)
我会做一个isValidMove(Board boardState,int square)抽象方法,它会在每个部分中被覆盖并被调用以突出显示有效的移动(在每个绘图迭代中。)同样的方法将在movePiece中调用(int square )检查移动是否有效,如果是,则执行移动。实际上,movePiece方法属于Board本身(并且会调用Piece.isValidMove(...)来检查。)
Pawn的isValidMove会是这样的(注意这是伪代码):
if ( boardState.getSquare(square).isFree() && square == this.square+ONE_FILE)
return true;
else
return false;
答案 3 :(得分:1)
我将创建一个名为getValidMoves()的方法,该方法返回给定片段的所有可能移动的列表。这样你就不必遍布整个电路板来找到要突出显示的方块。我还将基类抽象化,以便这样的方法不需要基本实现。
答案 4 :(得分:0)
我刚刚完成自己的国际象棋游戏。以下是我想要分享的一些提示/要点。
请记住,Java是面向对象的语言,将游戏划分为逻辑对象并与方法交互。
让方法尽可能简单(像往常一样)。制作人类可读代码。 有时! 8种不同的方法来检查碎片(King)可用的移动更具可读性,然后一些神秘的句子试图完成所有计算工作。
你想要应用MVC模式,你可能想要认为你的gui也是你的控制器,它可以引用你的实际电路板。
Piece.java protected List allowedSquares; public abstract void calculateAllowedSquares(ChessBoard chessBoard); public void move(ChessBoard chessBoard,Square from Square,Square toSquare)
在King类中,您可能需要覆盖move-method。例如,在铸造移动中,您需要同时移动车辆。
制作国际象棋游戏的整个概念中的两个主要问题是: 1.你如何消除让你自己的国王检查的动作。有时碎片根本无法移动。 2.如何让一块物品移动只是为了在检查情况下保护你的王。意思是,如果for.ex主教威胁你的国王,你可以移动一些东西阻止这种威胁,但不管其他地方。
最后,我建议你与你的逻辑一起创造你的gui。当你点击你的作品(或作品所在的正方形)时,这是一个很大的帮助,你可以立即在屏幕上看到可用的正方形。它可以节省您数小时的调试时间。
答案 5 :(得分:0)
首先你应该为每个项目创建一个类,并为每个项目添加可能的移动,并且还实现一种方法来检查游戏中可能的移动, 然后使用Netbeans GUI并添加一些JLabel并将其颜色更改为白色和黑色,这样您就可以很好地了解整个过程。
刚开始,不要犹豫,删除旧代码并使用新的更好的代码更改它们。 这就是它的工作方式。
祝你好运。