3d promote (Fixes #14)
All checks were successful
Linux arm64 / Build (push) Successful in 35s

This commit is contained in:
2025-05-18 12:18:09 +02:00
parent fd9aabb6a1
commit 523eb094e1
11 changed files with 82 additions and 37 deletions

View File

@@ -11,7 +11,7 @@ public class OpenGLMain {
Game game = new Game();
CommandExecutor commandExecutor = new CommandExecutor(game);
PgnFileSimulator fileSimulator = new PgnFileSimulator(commandExecutor, "games/FoolCheckmate.pgn");
PgnFileSimulator fileSimulator = new PgnFileSimulator(commandExecutor, "games/PromoteTest.pgn");
DDDView ddd = new DDDView(commandExecutor);

View File

@@ -11,6 +11,7 @@ import chess.controller.event.EmptyGameDispatcher;
import chess.controller.event.GameAdapter;
import chess.model.ChessBoard;
import chess.model.Color;
import chess.model.Coordinate;
import chess.model.Game;
import chess.model.Move;
import chess.model.PermissiveGame;
@@ -26,7 +27,7 @@ public class GameSimulation extends GameAdapter implements CommandSender {
}
@Override
public void onPawnPromoted(PromoteType promotion) {
public void onPawnPromoted(PromoteType promotion, Coordinate coordinate) {
sendPawnPromotion(promotion);
}

View File

@@ -56,7 +56,7 @@ public class PromoteCommand extends PlayerCommand {
this.oldPawn = pawn;
board.pieceComes(createPiece(this.promoteType, pawn.getColor()), this.pieceCoords);
outputSystem.onPawnPromoted(this.promoteType);
outputSystem.onPawnPromoted(this.promoteType, this.pieceCoords);
// invalidate the last move cache
board.setLastMove(null);

View File

@@ -101,8 +101,8 @@ public class AsyncGameDispatcher extends GameDispatcher {
}
@Override
public void onPawnPromoted(PromoteType promotion) {
asyncForEachCall((l) -> l.onPawnPromoted(promotion));
public void onPawnPromoted(PromoteType promotion, Coordinate coordinate) {
asyncForEachCall((l) -> l.onPawnPromoted(promotion, coordinate));
}
@Override

View File

@@ -64,7 +64,7 @@ public class EmptyGameDispatcher extends GameDispatcher {
}
@Override
public void onPawnPromoted(PromoteType promotion) {
public void onPawnPromoted(PromoteType promotion, Coordinate coordinate) {
}
@Override

View File

@@ -50,6 +50,6 @@ public abstract class GameAdapter implements GameListener {
public void onCastling(boolean bigCastling, Move kingMove, Move rookMove) {}
@Override
public void onPawnPromoted(PromoteType promotion) {}
public void onPawnPromoted(PromoteType promotion, Coordinate coordinate) {}
}

View File

@@ -99,8 +99,8 @@ public interface GameListener {
* Invoked when a pawn is promoted
*
* @param promotion the type of promotion
* @param player the player who promoted the pawns
* @param coordinate the coordinate of the old pawn
*/
void onPawnPromoted(PromoteType promotion);
void onPawnPromoted(PromoteType promotion, Coordinate coordinate);
}

View File

@@ -6,6 +6,7 @@ import java.util.List;
import java.util.function.Consumer;
import chess.controller.commands.*;
import chess.controller.commands.PromoteCommand.PromoteType;
import imgui.ImGui;
import imgui.ImVec2;
import imgui.flag.ImGuiCond;
@@ -242,6 +243,15 @@ public class DDDView extends GameAdapter implements CommandSender {
}
}
private PieceEntity createDefault(Piece piece, Coordinate coordinate) throws IOException {
Vector2f pieceBoardPos = DDDPlacement.coordinatesToVector(coordinate);
Vector3f pieceWorldPos = new Vector3f(pieceBoardPos.x(), 0, pieceBoardPos.y());
return new PieceEntity(piece, pieceWorldPos,
piece.getColor() == Color.White ? WHITE : BLACK,
piece.getColor() == Color.White ? 0.0f : (float) Math.PI);
}
private void initBoard() throws IOException {
for (int i = 0; i < Coordinate.VALUE_MAX; i++) {
for (int j = 0; j < Coordinate.VALUE_MAX; j++) {
@@ -250,14 +260,7 @@ public class DDDView extends GameAdapter implements CommandSender {
if (piece == null)
continue;
Vector2f pieceBoardPos = DDDPlacement.coordinatesToVector(pos);
Vector3f pieceWorldPos = new Vector3f(pieceBoardPos.x(), 0, pieceBoardPos.y());
PieceEntity entity = new PieceEntity(piece, pieceWorldPos,
piece.getColor() == Color.White ? WHITE : BLACK,
piece.getColor() == Color.White ? 0.0f : (float) Math.PI);
this.world.addPiece(entity, pos);
this.world.addPiece(createDefault(piece, pos), pos);
}
}
this.boardEntity = new BoardEntity();
@@ -303,7 +306,7 @@ public class DDDView extends GameAdapter implements CommandSender {
consumers.add(moveConsumer);
this.window.addRegularTask(moveConsumer);
}
try {
Thread.sleep((long) (animationTime * 1000.0f));
} catch (InterruptedException e) {
@@ -315,16 +318,19 @@ public class DDDView extends GameAdapter implements CommandSender {
final PieceEntity pEntity = pEntities.get(i);
this.window.removeRegularTask(moveConsumer);
Vector2f pieceDestBoardPos = DDDPlacement.coordinatesToVector(move.getFinish());
Vector3f pieceDestWorldPos = new Vector3f(pieceDestBoardPos.x(), 0, pieceDestBoardPos.y());
if (move.getDeadPieceCoords() != null) {
this.world.ejectPiece(move.getDeadPieceCoords());
}
final PieceEntity pDead = this.world.getPiece(move.getDeadPieceCoords());
this.world.setPieceCoords(null, move.getDeadPieceCoords());
// we must do that on the rendering thread to avoid
// ConcurrentModificationException
this.window.scheduleTask(() -> this.world.ejectPiece(pDead));
pEntity.setPosition(pieceDestWorldPos);
this.world.movePiece(pEntity, move);
}
@@ -371,25 +377,47 @@ public class DDDView extends GameAdapter implements CommandSender {
}
}
private void renderPopup(String title, String text) {
private void renderPopup(String title, Runnable content) {
ImVec2 center = ImGui.getMainViewport().getCenter();
ImGui.setNextWindowPos(center, ImGuiCond.Appearing, new ImVec2(0.5f, 0.5f));
if (ImGui.beginPopupModal(title, null, ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoMove)) {
ImGui.text(text);
content.run();
if (ImGui.button("Close")) {
ImGui.closeCurrentPopup();
synchronized (this) {
notifyAll();
}
closeCurrentPopup();
}
ImGui.endPopup();
}
}
private void closeCurrentPopup() {
ImGui.closeCurrentPopup();
synchronized (this) {
notifyAll();
}
}
private void renderPopup(String title, String text) {
renderPopup(title, () -> ImGui.text(text));
}
private void renderPromoteDialog() {
renderPopup("Promotion", () -> {
ImGui.text("Select the promotion type :");
for (PromoteType promoteType : PromoteType.values()) {
if (ImGui.button(promoteType.toString())) {
sendPawnPromotion(promoteType);
closeCurrentPopup();
}
ImGui.sameLine();
}
ImGui.newLine();
});
}
private void renderPopups() {
renderPopup("Check", "Your king is in check");
renderPopup("Checkmate", "Checkmate, it's a win!");
renderPopup("Promotion", "Please promote your pawn.");
renderPromoteDialog();
renderPopup("Pat", "It's a pat!");
renderPopup("Tie", "It's a tie!");
renderPopup("White surrender", "The white player has surrendered!");
@@ -451,4 +479,21 @@ public class DDDView extends GameAdapter implements CommandSender {
public void onCastling(boolean bigCastling, Move kingMove, Move rookMove) {
move3DPieces(List.of(kingMove, rookMove));
}
@Override
public void onPromotePawn(Coordinate pieceCoords) {
openPopup("Promotion");
}
@Override
public void onPawnPromoted(PromoteType promotion, Coordinate coordinate) {
this.window.scheduleTask(() -> {
this.world.ejectPiece(this.world.getPiece(coordinate));
try {
this.world.addPiece(createDefault(getPieceAt(coordinate), coordinate), coordinate);
} catch (IOException e) {
e.printStackTrace();
}
});
}
}

View File

@@ -36,7 +36,7 @@ public class World implements Closeable{
setPieceCoords(entity, coordinate);
}
private void setPieceCoords(PieceEntity entity, Coordinate coordinate) {
public void setPieceCoords(PieceEntity entity, Coordinate coordinate) {
pieces[coordinate.toIndex()] = entity;
}
@@ -45,11 +45,9 @@ public class World implements Closeable{
setPieceCoords(null, move.getStart());
}
public void ejectPiece(Coordinate coordinate) {
PieceEntity entity = getPiece(coordinate);
public void ejectPiece(PieceEntity entity) {
if (entity != null)
this.entites.remove(entity);
setPieceCoords(null, coordinate);
}
public PieceEntity getPiece(Coordinate coordinate) {

View File

@@ -2,6 +2,7 @@ package chess.view.audio;
import chess.controller.commands.PromoteCommand.PromoteType;
import chess.controller.event.GameAdapter;
import chess.model.Coordinate;
import chess.model.Move;
public class GameAudio extends GameAdapter {
@@ -51,7 +52,7 @@ public class GameAudio extends GameAdapter {
}
@Override
public void onPawnPromoted(PromoteType promotion) {
public void onPawnPromoted(PromoteType promotion, Coordinate coordinate) {
playSound("promote");
}

View File

@@ -291,7 +291,7 @@ public class Window extends JFrame implements GameListener, CommandSender {
public void onCastling(boolean bigCastling, Move kingMove, Move rookMove) {}
@Override
public void onPawnPromoted(PromoteType promotion) {}
public void onPawnPromoted(PromoteType promotion, Coordinate coordinate) {}
@Override
public CommandExecutor getCommandExecutor() {