So I've been working on this chess app for about a week now (a few hours a day)-- and I seem to have hit a snag. All of the pieces move as they should, with collision and all-- I have promotion and castling working, and I can successfully check for being in check.
However, I can't seem to check if a move legally gets out of check. My current approach is to move the piece-- check if the person is still in check, and if not then the move is legal.
It seems that when I do this, however, it doesn't correctly calculate the check after the faux-move.
Any help would be great.
public abstract class Piece {
private Type type = Type.BLANK;
private int locX, locY, preX, preY;
private Player player;
private boolean moved = false;
Piece(Type type, int locX, int locY, Player player) {
this.locX = locX;
this.locY = locY;
this.player = player;
this.type = type;
}
public void movePiece(int x, int y) {
if (player.isTurn()) {
if (isLegalMove(x, y)) {
if (checkCollision(x, y)) {
if (clearsCheck(x, y)) {
preX = locX;
preY = locY;
setLoc(x, y);
specialPreMove(x, y);
moved = true;
Chess.chessBoard.bitBoard[preX][preY] = null;
if (Chess.chessBoard.bitBoard[x][y] != null) {
Chess.chessBoard.bitBoard[x][y].getPlayer().pieces.remove(Chess.chessBoard.bitBoard[x][y]);
}
Chess.chessBoard.bitBoard[x][y] = this;
specialPostMove(x, y);
Chess.chessBoard.getGui().repaint();
Chess.changeTurns();
}
}
}
}
}
protected void specialPreMove(int x, int y) {}
protected void specialPostMove(int x, int y) {}
protected abstract boolean checkCollision(int x, int y);
protected abstract boolean isLegalMove(int x, int y);
private boolean clearsCheck(int x, int y) {
boolean checkCk = false;
preX = locX;
preY = locY;
setLoc(x, y);
Piece locPiece = null;
Chess.chessBoard.bitBoard[preX][preY] = null;
if (Chess.chessBoard.bitBoard[x][y] != null) {
locPiece = Chess.chessBoard.bitBoard[x][y];
Chess.chessBoard.bitBoard[x][y].getPlayer().pieces.remove(Chess.chessBoard.bitBoard[x][y]);
System.out.println("Piece there: " + locPiece);
}
Chess.chessBoard.bitBoard[x][y] = this;
System.out.println(Chess.chessBoard.bitBoard[x][y]);
Chess.chessBoard.getGui().repaint();
Chess.checkCheck();
checkCk = !player.inCheck();
setLoc(preX, preY);
Chess.chessBoard.bitBoard[preX][preY] = this;
if (locPiece != null) {
Chess.chessBoard.bitBoard[x][y] = locPiece;
Chess.chessBoard.bitBoard[x][y].getPlayer().pieces.add(Chess.chessBoard.bitBoard[x][y]);
} else {
Chess.chessBoard.bitBoard[x][y] = null;
}
System.out.println(checkCk);
return checkCk;
}
public ArrayList<Move> getLegalMoves() {
ArrayList<Move> moves = new ArrayList<Move>();
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
if (isLegalMove(row, col) && checkCollision(row, col)) {
moves.add(new Move(row, col));
}
}
}
return moves;
}
is the piece class, and then the check method
public static void checkCheck() {
for (Move m : player1.getLegalMoves()) {
if (m.getX() == player2.getKing().getLocX()
&& m.getY() == player2.getKing().getLocY()) {
player2.setCheck(true);
System.out.println("IN CHECK PLAYER 2");
break;
}
}
for (Move m : player2.getLegalMoves()) {
if (m.getX() == player1.getKing().getLocX()
&& m.getY() == player1.getKing().getLocY()) {
player1.setCheck(true);
System.out.println("IN CHECK PLAYER 1");
break;
}
}
}
and then here is some other stuff that is useful
public class Player {
private Color color;
private Direction direction;
private boolean turn;
private boolean check = false;
public ArrayList<Piece> pieces = new ArrayList<>();
public Player(Color color, Direction direction) {
this.color = color;
this.turn = false;
this.direction = direction;
}
public ArrayList<Move> getLegalMoves() {
ArrayList<Move> moves = new ArrayList<>();
for (Piece p : pieces) {
for (Move m : p.getLegalMoves()) {
moves.add(m);
}
}
return moves;
}
public Piece getKing() {
for (Piece p : pieces) {
if (p.getType() == Type.KING) {
return p;
}
}
return null;
}
Looks like once you set a player in check you're not setting his status later on to unchecked.
public static void checkCheck() {
boolean isInCheck = false;
for (Move m : player1.getLegalMoves()) {
if (m.getX() == player2.getKing().getLocX()
&& m.getY() == player2.getKing().getLocY()) {
isInCheck = true;
System.out.println("IN CHECK PLAYER 2");
break;
}
}
player2.setCheck(isInCheck);
isInCheck = false;
for (Move m : player2.getLegalMoves()) {
if (m.getX() == player1.getKing().getLocX()
&& m.getY() == player1.getKing().getLocY()) {
isInCheck = true;
System.out.println("IN CHECK PLAYER 1");
break;
}
}
player1.setCheck(isInCheck);
}
Related
I can't succeed in making the enemies move from node to node.
I managed to set up the whole pathfinding, I'm getting a full path to the player and the position of the next node all the way to the end.
How do I move the box2d body from node to node?
Or even simpler - how do I move a box2d body to a certain position?
I tried applying impulses, forces weren't able to do it.
Here is my simplified code. Both Monster and Player classes extend Sprite:
public class B2dSteeringEntity implements Steerable<Vector2>, Updateable {
public static final String TAG = B2dSteeringEntity.class.getName();
Body body;
boolean tagged;
float maxLinearSpeed, maxLinearAcceleration;
float maxAngularSpeed, maxAngularAcceleration;
float boundingRadius;
SteeringBehavior<Vector2> behavior;
SteeringAcceleration<Vector2> steeringOutput;
public B2dSteeringEntity(Body body, float boundingRadius) {
this.body = body;
this.boundingRadius = boundingRadius;
this.maxLinearSpeed = 250;
this.maxLinearAcceleration = 200;
this.maxAngularSpeed = 0;
this.maxAngularAcceleration = 0;
this.tagged = false;
this.steeringOutput = new SteeringAcceleration<Vector2>(new Vector2());
}
#Override
public Vector2 getLinearVelocity() {
return body.getLinearVelocity();
}
#Override
public float getAngularVelocity() {
return body.getAngularVelocity();
}
#Override
public float getBoundingRadius() {
return 0;
}
#Override
public boolean isTagged() {
return tagged;
}
#Override
public void setTagged(boolean tagged) {
this.tagged = tagged;
}
#Override
public float getZeroLinearSpeedThreshold() {
return 0;
}
#Override
public void setZeroLinearSpeedThreshold(float value) {
}
#Override
public float getMaxLinearSpeed() {
return maxLinearSpeed;
}
#Override
public void setMaxLinearSpeed(float maxLinearSpeed) {
this.maxLinearSpeed = maxLinearSpeed;
}
#Override
public float getMaxLinearAcceleration() {
return maxLinearAcceleration;
}
#Override
public void setMaxLinearAcceleration(float maxLinearAcceleration) {
this.maxLinearAcceleration = maxLinearAcceleration;
}
#Override
public float getMaxAngularSpeed() {
return maxAngularSpeed;
}
#Override
public void setMaxAngularSpeed(float maxAngularSpeed) {
this.maxAngularSpeed = maxAngularSpeed;
}
#Override
public float getMaxAngularAcceleration() {
return maxAngularAcceleration;
}
#Override
public void setMaxAngularAcceleration(float maxAngularAcceleration) {
this.maxAngularAcceleration = maxAngularAcceleration;
}
#Override
public Vector2 getPosition() {
return body.getPosition();
}
#Override
public float getOrientation() {
return body.getAngle();
}
#Override
public void setOrientation(float orientation) {
}
#Override
public float vectorToAngle(Vector2 vector) {
return SteeringUtils.vectorToAngle(vector);
}
#Override
public Vector2 angleToVector(Vector2 outVector, float angle) {
return SteeringUtils.angleToVector(outVector, angle);
}
#Override
public Location<Vector2> newLocation() {
return null;
}
public Body getBody() {
return body;
}
public void setBehavior(SteeringBehavior<Vector2> behavior) {
this.behavior = behavior;
}
public SteeringBehavior<Vector2> getBehavior() {
return behavior;
}
private void applySteering(float deltaTime) {
boolean anyAccelerations = false;
if(!steeringOutput.linear.isZero()) {
Vector2 force = steeringOutput.linear.scl(deltaTime);
body.applyForceToCenter(force, true);
anyAccelerations = true;
}
if(anyAccelerations) {
Vector2 velocity = body.getLinearVelocity();
float currentSpeedSquare = velocity.len2();
if(currentSpeedSquare > maxLinearSpeed * maxLinearSpeed) {
body.setLinearVelocity(velocity.scl(maxLinearSpeed / (float) Math.sqrt(currentSpeedSquare)));
}
if (body.getAngularVelocity() > maxAngularSpeed) {
body.setAngularVelocity(maxAngularSpeed);
}
}
}
#Override
public void update(float deltaTime) {
if (behavior != null) {
behavior.calculateSteering(steeringOutput);
applySteering(deltaTime);
}
}
}
public Skeleton(B2WorldCreator creator, GameScreen screen, float x, float y, State state, HeroKnight player) {
super(creator, screen, x, y, state, player);
controller = screen.getController();
setBounds(x, y, 150 / Constants.PPM, 150 / Constants.PPM);
enemyAgentComponent = new EnemyAgentComponent(b2body, b2dSteeringEntity, controller, player);
}
And here is the EnemyAgentComponent class:
public class EnemyAgentComponent implements Component, Telegraph, Updateable, Pather<Node> {
public static final String TAG = EnemyAgentComponent.class.getName();
public StateMachine<EnemyAgentComponent, EnemyState> stateMachine;
public boolean isInProximity() {
return inProximity;
}
public boolean inProximity = false;
public boolean lowHP = false;
public boolean isShot = false;
private boolean isRequested = false;
private boolean requestingMovement;
private Steering wayPoint;
private Body body;
private Controller controller;
private HeroKnight player;
private Node startNode, endNode, previousStartNode, previousEndNode;
private Vector2 goal;
private PathfindingTarget newGoal;
private float impulseMag;
private boolean nodeReached;
private boolean pathGenerated;
private Arrive<Vector2> arriveSB;
private Steering waypoint;
private B2dSteeringEntity steering;
private IndexedAStarPathFinder<Node> pathFinder;
private GraphPathImp resultPath = new GraphPathImp();
private float pathfindingTimer;
private boolean firstPathGenerated;
public boolean isTouchingPlayer() {
return touchingPlayer;
}
public void setTouchingPlayer(boolean touchingPlayer) {
this.touchingPlayer = touchingPlayer;
}
private boolean touchingPlayer;
public EnemyAgentComponent(Body body, B2dSteeringEntity steering, Controller controller, HeroKnight player) {
construct(body, steering, controller, player);
}
public void construct(Body body, B2dSteeringEntity steering, Controller controller, HeroKnight player) {
this.steering = steering;
this.controller = controller;
this.body = body;
this.player = player;
stateMachine = new DefaultStateMachine<>(this, EnemyState.SEEKING);
MessageManager.getInstance().addListener(this, Messages.PLAYER_IN_SIGHT);
MessageManager.getInstance().addListener(this, Messages.PLAYER_ATTACKED_ENEMY);
MessageManager.getInstance().addListener(this, Messages.LOW_HP);
MessageManager.getInstance().addListener(this, Messages.PLAYER_OUT_OF_SIGHT);
MessageManager.getInstance().addListener(this, Messages.TOUCHING_PLAYER);
pathFinder = new IndexedAStarPathFinder<Node>(LevelManager.groundGraph, false);
requestingMovement = false;
goal = null;
nodeReached = false;
pathGenerated = false;
firstPathGenerated = false;
pathfindingTimer = 0;
touchingPlayer = false;
}
public Vector2 getGoal() {
return goal;
}
public boolean isRequestingMovement() {
return requestingMovement;
}
public void setRequestingMovement(boolean requestingMovement) {
this.requestingMovement = requestingMovement;
}
public boolean isPathGenerated() {
return pathGenerated;
}
public GraphPathImp getResultPath() {
return resultPath;
}
public void generatePath() {
previousEndNode = endNode;
previousStartNode = startNode;
resultPath.clear();
pathFinder.searchNodePath(startNode, endNode, new HeuristicImp(), resultPath);
newGoal = new PathfindingTarget(resultPath.get(0).getNodePosition());
pathGenerated = true;
}
public void update(float deltaTime) {
startNode = LevelManager.groundGraph.getNodeByXY(body.getPosition().x, body.getPosition().y);
endNode = LevelManager.groundGraph.getNodeByXY(player.b2body.getPosition().x, player.b2body.getPosition().y);
//If player gets in certain range of the enemy and is not touching the enemy, enemy's path is being generated
if (inProximity) {
if (!firstPathGenerated && !touchingPlayer)
if ((pathfindingTimer == 0)) {
generatePath();
previousStartNode = startNode;
previousEndNode = endNode;
firstPathGenerated = true;
}
//If a path was already created, a new path is being requested only if player's position changes
if (firstPathGenerated && (previousEndNode != endNode) && pathfindingTimer == 0 && !touchingPlayer) {
generatePath();
}
if (firstPathGenerated)
pathfindingTimer += deltaTime;
//Paths are generated every 2 seconds
if (pathfindingTimer >= 2) {
pathfindingTimer = 0;
}
//If enemy touches the player pathfinding ends
if (touchingPlayer) {
pathfindingTimer = 0;
pathGenerated = false;
resultPath.clear();
body.setLinearVelocity(0, 0);
}
}
//The arrive behaviour is set, newGoal being the position of next node
if (steering.getLinearVelocity().x == 0 && steering.getLinearVelocity().y == 0 && newGoal != null) {
steering.setBehavior(new Arrive<Vector2>(steering, newGoal));
}
steering.update(deltaTime);
//Updating the next node position based on the enemy reaching a node
if (pathGenerated)
if (Math.abs(body.getPosition().x - newGoal.getPosition().x) <= 0.1f && Math.abs(body.getPosition().y - newGoal.getPosition().y) <= 51 / 2f / Constants.PPM)
{
updatePath();
}
}
public void updatePath() {
//Setting the next target position
if (resultPath.getCount() > 0) {
resultPath.removeIndex(0);
if (!touchingPlayer && resultPath.getCount() > 0) {
newGoal.setPosition(resultPath.get(0).getNodePosition());
requestingMovement = true;
nodeReached = false;
}
}
}
#Override
public boolean handleMessage(Telegram telegram) {
if (telegram.message == Messages.PLAYER_IN_SIGHT) {
inProximity = true;
return true;
}
if (telegram.message == Messages.PLAYER_OUT_OF_SIGHT) {
inProximity = false;
firstPathGenerated = false;
pathGenerated = false;
pathfindingTimer = 0;
resultPath.clear();
}
if (telegram.message == Messages.LOW_HP) {
lowHP = true;
return true;
}
if (telegram.message == Messages.PLAYER_ATTACKED_ENEMY) {
isShot = true;
return true;
}
if (telegram.message == Messages.TOUCHING_PLAYER) {
touchingPlayer = true;
return true;
}
return false;
}
#Override
public void acceptPath(PathFinderRequest<Node> request) {
if (request.pathFound) {
resultPath = (GraphPathImp) request.resultPath;
}
}
}
Skeleton class is being updated and drawn using skeleton.update(deltaTime) and skeleton.draw(deltaTime).
EDIT2:
Now tried using linear impulses, movement is very clunky:
if (newGoal != null) {
Vector2 direction = new Vector2(newGoal.getPosition().x - body.getPosition().x, newGoal.getPosition().y - body.getPosition().y).nor();
float speed = Constants.SKELETON_SPEED;
Vector2 velocity = new Vector2(speed * direction.x, speed * direction.y);
body.applyLinearImpulse(velocity.x * body.getMass(), velocity.y * body.getMass(), body.getWorldCenter().x, body.getWorldCenter().y, true);
}
if (pathGenerated)
if (Math.abs(body.getPosition().x - newGoal.getPosition().x) <= 0.1f && Math.abs(body.getPosition().y - newGoal.getPosition().y) <= 51 / 2f / Constants.PPM)
{
Gdx.app.debug(TAG, "Node reached!");
updatePath();
}
Moving an entity is not directly related to AI. The AI just finds a way, the entity follows it.
With box2d, you have to apply forces or impulses into the right directions, make sure your box2d world's step() method is being called and update your entites rendering coordinates (e.g. the sprite) to match the box2d's body coordinates. Then call your AI from the new coordinates in the next loop again, determine in which direction you have to move now and apply your forces again.
So the loop looks like
Find a way via AI
Find direction to the next node from your position
Apply forces/impulses
box2d world step
Adapt the entities rendering coordinates to match the box2d body position
Repeat
Giving you a more detailed answer requires more knowledge about how you render your entities and what your loop looks like. Please share some example code.
Edit: After you added some code I find it still unclear what you actual problem is. Can you move your entity but fail to stop it? Does it move at all? Do you call world.step()? The only obvious issue I could find after a quick look is that you scale applyForceToCenter with deltaTime which is not needed as world.step already takes a timeStep as a parameter.
Hello I'm fairly new to programming and this is my first time posting here so any help would be appreciated so:
my problem is that I"m trying to create some kind of 2D shooter game in java but I don't know if my simple game loop is good because when i shoot a missile it shoots a one every 20 ms and it's too fast and shoots a ton of missiles at once so is there any way to adjust it ? Like to keep some delay between every missile and the other??
and please tell me if i have problems or bad programming in my code !!
this is my game panel where most of the game happens and where my loop and adding missiles method in
public class GamePanel extends JPanel implements KeyListener {
Measurments mesure = new Measurments();
int panel_width = mesure.getUniversalWidth();
int panel_height = mesure.getUniversalHeight();
Timer timer;
Random rand = new Random();
ArrayList<Enemy> enemies = new ArrayList<>();
ArrayList<Missile> missiles = new ArrayList<>();
Player player = new Player(0, 0);
boolean up = false;
boolean down = false;
boolean right = false;
boolean left = false;
boolean isShooting = false;
boolean isRunning = true;
public boolean gameRunning() {
return isRunning;
}
int count = 5;
int missilesCount = 6;
public GamePanel() {
timer = new Timer(20, new ActionListener() {
public void actionPerformed(ActionEvent e) {
StartGame();
repaint();
}
});
setSize(panel_width, panel_height);
addKeyListener(this);
timer.start();
for (int i = 0; i < count; i++) {
addEnemy(new Enemy(rand.nextInt(750), rand.nextInt(500)));
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
player.paint(g2d);
for (int i = 0; i < enemies.size(); i++) {
Enemy temp = enemies.get(i);
temp.paint(g2d);
}
for (int i = 0; i < missiles.size(); i++) {
Missile mis = missiles.get(i);
mis.paint(g2d);
mis.behave();
}
}
public void StartGame() {
if (isRunning) {
runGame();
setBackground(Color.YELLOW);
} else {
setBackground(Color.BLACK);
}
}
public void runGame() {
update();
};
public void update() {
player.checkBorders();
checkColls();
if (up) {
player.updateUp();
}
if (down) {
player.updateDown();
}
if (right) {
player.updateRight();
}
if (left) {
player.updateLeft();
}
if (isShooting) {
for (int i = 0; i < 5; i++) {
missiles.add(new Missile(player.getX() + 16, player.getY() + 16));
}
}
for (int i = 0; i < missiles.size(); i++) {
Missile temp = missiles.get(i);
if (temp.getX() == panel_width) {
RemoveMissile(temp);
}
}
}
public void addEnemy(Enemy e) {
enemies.add(e);
}
public void removeEnemy(Enemy e) {
enemies.remove(e);
}
public void addMissile(Missile e) {
missiles.add(e);
}
public void RemoveMissile(Missile e) {
missiles.add(e);
}
public void checkColls() {
for (int i = 0; i < enemies.size(); i++) {
Enemy tempEnm = enemies.get(i);
for (int e = 0; e < missiles.size(); e++) {
Missile tempMis = missiles.get(e);
if (tempMis.missileRect().intersects(tempEnm.enemyRect())) {
enemies.remove(tempEnm);
missiles.remove(tempMis);
}
}
}
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == e.VK_UP) {
up = true;
}
if (key == e.VK_DOWN) {
down = true;
}
if (key == e.VK_RIGHT) {
right = true;
}
if (key == e.VK_LEFT) {
left = true;
}
if (key == e.VK_ENTER) {
isRunning = true;
}
if (key == e.VK_SPACE) {
isShooting = true;
}
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == e.VK_UP) {
up = false;
}
if (key == e.VK_DOWN) {
down = false;
}
if (key == e.VK_RIGHT) {
right = false;
}
if (key == e.VK_LEFT) {
left = false;
}
if (key == e.VK_SPACE) {
isShooting = false;
}
}
public void keyTyped(KeyEvent e) {
}
}
Thanks in advance !!
private long fired = 0L;
public void update() {
...
// firing missiles: only if the missile count is less than the max., and the elapsed
// time is more than a limit (100 ms)
if ( isShooting && missiles.size() < missilesCount &&
( System.currentTimeMilis() - this.fired ) > 100 ) {
missiles.add( new Missile( player.getX() + 16, player.getY() + 16 ) );
// time of last firing
this.fired = System.currentTimeMilis();
}
...
}
public void RemoveMissile(Missile e) {
// as Guest is asked in another answer, this method should remove, not add...
missiles.remove(e);
}
I'm currently making a space invaders-esque game for my software engineering course. I've already got everything working that satisfies the requirements, so this isn't a 'solve my homework' kind of question. My problem is that the game will lag (at what seems like random times & intervals) to the point where it becomes too frustrating to play. Some things I think might be causing this - though I'm not positive - are as follows:
Problem with timer event every 10 ms (I doubt this because of the very limited resources required for this game).
Problem with collision detection (checking for collision with every visible enemy every 10 ms seems like it would take up a large chunk of resources)
Problem with repainting? This seems unlikely to me however...
#SuppressWarnings("serial")
public class SIpanel extends JPanel {
private SIpanel panel;
private Timer timer;
private int score, invaderPace, pulseRate, mysteryCount, distanceToEdge;
private ArrayList<SIthing> cast;
private ArrayList<SIinvader> invaders, dead;
private ArrayList<SImissile> missileBase, missileInvader;
private SIinvader[] bottomRow;
private SIbase base;
private Dimension panelDimension;
private SImystery mysteryShip;
private boolean gameOver, left, right, mysteryDirection, space, waveDirection;
private boolean runningTimer;
private Music sound;
private void pulse() {
pace();
processInputs();
if (gameOver) gameOver();
repaint();
}
private void pace() {
// IF invaders still live
if (!invaders.isEmpty()) {
invaderPace++;
// Switch back manager
if (distanceToEdge <= 10) {
switchBack();
pulseRate = (pulseRate >= 16) ? (int) (pulseRate*(0.8)) : pulseRate;
waveDirection = !waveDirection;
distanceToEdge = calculateDistanceToEdge();
}
// Move invaders left/right
else if (invaderPace >= pulseRate) {
invaderPace = 0;
distanceToEdge = calculateDistanceToEdge();
moveAI();
invadersFire();
if (!dead.isEmpty()) removeDead();
if (mysteryCount < 1) tryInitMysteryShip();
}
// All invaders are kill, create new wave
} else if (missileBase.isEmpty() && missileInvader.isEmpty() && !cast.contains(mysteryShip)) {
// System.out.println("New Wave!");
newWave();
}
// Every pace
if (!missileBase.isEmpty()) moveMissileBase();
// Every two paces
if (invaderPace % 2 == 0) {
if (!missileInvader.isEmpty()) moveMissileInvader();
if (mysteryCount > 0) moveMysteryShip();
}
}
private void processInputs() {
if (left) move(left);
if (right) move(!right);
if (space) fireMissile(base, true);
}
protected void fireMissile(SIship ship, boolean isBase) {
if(isBase && missileBase.isEmpty()) {
base.playSound();
SImissile m = new SImissile(ship.getX()+(ship.getWidth()/2), ship.getY()-(ship.getHeight()/4));
missileBase.add(m);
cast.add(m);
} else if (!isBase && missileInvader.size()<3) {
base.playSound();
SImissile m = new SImissile(ship.getX()+(ship.getWidth()/2), ship.getY()+(ship.getHeight()/4));
missileInvader.add(m);
cast.add(m);
}
}
private void newWave() {
pulseRate = 50;
int defaultY=60, defaultX=120, defaultWidth=30, defaultHeight=24;
for(int i=0; i<5; i++) {
for(int j=0; j<10; j++) {
if (i<1) invaders.add(new SItop((j*defaultWidth)+defaultX, (i*defaultHeight)+defaultY, defaultWidth, defaultHeight));
else if (i<3) invaders.add(new SImiddle((j*defaultWidth)+defaultX, (i*defaultHeight)+defaultY, defaultWidth, defaultHeight));
else if (i<5) invaders.add(new SIbottom((j*defaultWidth)+defaultX, (i*defaultHeight)+defaultY, defaultWidth, defaultHeight));
}
}
for (SIinvader s: invaders) {
cast.add(s);
}
if (!cast.contains(base)) {
cast.add(base);
}
bottomRow = getBottomRow();
}
private void tryInitMysteryShip() {
Random rand = new Random();
int x=rand.nextInt(1000);
if (x<=3) {
mysteryCount = 1;
if (rand.nextBoolean()) {
mysteryDirection = true;
}
if (mysteryDirection) {
mysteryShip = new SImystery(0, 60, 36, 18);
} else {
mysteryShip = new SImystery(480, 60, 36, 18);
}
cast.add(mysteryShip);
}
}
private void moveMysteryShip() {
int distance = 0;
if (mysteryDirection) {
mysteryShip.moveRight(5);
distance = getWidth() - mysteryShip.getX();
} else {
mysteryShip.moveLeft(5);
distance = 30+mysteryShip.getX()-mysteryShip.getWidth();
}
if (distance <= 5) {
dead.add(mysteryShip);
mysteryShip = null;
mysteryCount = 0;
}
}
private void removeDead() {
#SuppressWarnings("unchecked")
ArrayList<SIinvader> temp = (ArrayList<SIinvader>) dead.clone();
dead.clear();
for (SIinvader s : temp) {
invaders.remove(s);
cast.remove(s);
}
bottomRow = getBottomRow();
}
private void invadersFire() {
int[] p = new int[bottomRow.length];
for (int i=0; i<p.length; i++) {
for (int j=0; j<p.length; j++) {
p[j] = j;
}
Random rand = new Random();
int a=rand.nextInt(101);
if (a>=20) {
int b=rand.nextInt(p.length);
fireMissile(bottomRow[b], false);
}
}
}
private int calculateDistanceToEdge() {
int distance = 0;
SIinvader[] outliers = getOutliers();
if (waveDirection) {
distance = getWidth() - outliers[0].getX()-outliers[0].getWidth();
} else {
distance = outliers[1].getX();
}
return distance;
}
private SIinvader[] getOutliers() {
SIinvader leftMost = invaders.get(0), rightMost = invaders.get(0);
for (SIinvader s : invaders) {
if (s.getX() < leftMost.getX()) {
leftMost = s;
}
if (s.getX() > rightMost.getX()) {
rightMost = s;
}
}
return new SIinvader[] { rightMost, leftMost };
}
private SIinvader[] getBottomRow() {
SIinvader[] x = new SIinvader[(invaders.size()>10)?10:invaders.size()];
for (int i=0; i<x.length; i++) {
x[i] = invaders.get(i);
for (SIinvader s:invaders) {
if (s.getX() == x[i].getX()) {
if (s.getY() > x[i].getY()) {
x[i] = s;
}
}
}
}
return x;
}
private void move(boolean b) {
int defaultX = 5;
if (b) base.moveLeft(defaultX);
else base.moveRight(defaultX);
}
private void moveAI() {
for(SIinvader s : invaders) {
s.changeImage();
int defaultX = 5;
if (waveDirection) s.moveRight(defaultX);
else s.moveLeft(defaultX);
}
}
private void moveMissileBase() {
if (invaders.isEmpty()) return;
int movement = -5, bound = 0;
SImissile missile = missileBase.get(0);
missile.moveDown(movement);
SIinvader lowestInvader = getLowestInvader();
if (missile.getY() < (lowestInvader.getY() + lowestInvader.getHeight())) {
for (SIinvader s:bottomRow) {
if (checkCollision(missile, s)) {
s.setHit();
dead.add(s);
cast.remove(missile);
missileBase.clear();
score += s.value;
return;
}
}
if (mysteryCount > 0) {
if (checkCollision(missile, mysteryShip)) {
mysteryShip.setHit();
dead.add(mysteryShip);
cast.remove(missile);
missileBase.clear();
score += mysteryShip.value;
return;
}
}
if (missile.getY() < bound) {
missileBase.remove(missile);
cast.remove(missile);
}
}
}
private SIinvader getLowestInvader() {
SIinvader lowest = bottomRow[0];
for (SIinvader invader : bottomRow) {
if (invader.getY() > lowest.getY()) {
lowest = invader;
}
}
return lowest;
}
private void moveMissileInvader() {
int movement = 5, bound = (int) panelDimension.getHeight();
for (SImissile missile : missileInvader) {
missile.moveDown(movement);
if(missile.getY() >= base.getY()) {
if (checkCollision(missile, base)) {
base.setHit();
gameOver = true;;
missileInvader.remove(missile);
cast.remove(missile);
return;
} else if (missile.getY() >= bound-25) {
missileInvader.remove(missile);
cast.remove(missile);
return;
}
}
}
}
private boolean checkCollision(SIthing missile, SIthing ship) {
Rectangle2D rect1 = new Rectangle2D.Double(
missile.getX(),
missile.getY(),
missile.getWidth(),
missile.getHeight()
);
Rectangle2D rect2 = new Rectangle2D.Double(
ship.getX(),
ship.getY(),
ship.getWidth(),
ship.getHeight()
);
return rect1.intersects(rect2);
}
private void switchBack() {
int defaultY = 12;
for (SIinvader s : invaders) {
if (s.getY() > getHeight()) {
gameOver = true;
return;
}
s.moveDown(defaultY);
}
}
private void gameOver() {
pause(true);
SI.setGameOverLabelVisibile(true);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.GREEN);
Font font = new Font("Arial", 0, 20);
setFont(font);
String score = "Score: "+this.score;
Rectangle2D rect = font.getStringBounds(score, g2.getFontRenderContext());
int screenWidth = 0;
try { screenWidth = (int) panelDimension.getWidth(); }
catch (NullPointerException e) {}
g2.setColor(Color.GREEN);
g2.drawString(score, (int) (screenWidth - (10 + rect.getWidth())), 20);
for(SIthing a:cast) {
a.paint(g);
}
}
public SIpanel() {
super();
setBackground(Color.BLACK);
cast = new ArrayList<SIthing>();
missileBase = new ArrayList<SImissile>();
score = invaderPace = mysteryCount = pulseRate = 0;
sound = new Music("AmbientMusic.wav");
panel = this;
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT : left = true; break;
case KeyEvent.VK_RIGHT : right = true; break;
case KeyEvent.VK_SPACE : space = true; break;
}
}
#Override
public void keyReleased(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT : left = false; break;
case KeyEvent.VK_RIGHT : right = false; break;
case KeyEvent.VK_SPACE : space = false; break;
}
}
});
setFocusable(true);
timer = new Timer(10, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pulse();
}
});
}
public void reset() {
SI.setGameOverLabelVisibile(false);
score = invaderPace = mysteryCount = 0;
pulseRate = 50;
cast = new ArrayList<SIthing>();
invaders = new ArrayList<SIinvader>();
dead = new ArrayList<SIinvader>();
missileBase = new ArrayList<SImissile>();
missileInvader = new ArrayList<SImissile>();
base = new SIbase(230, 370, 26, 20);
waveDirection = true;
gameOver = false;
sound.stop();
sound.loop();
panelDimension = SI.getFrameDimensions();
bottomRow = getBottomRow();
newWave();
timer.start();
runningTimer=true;
}
public SIpanel getPanel() {
return this.panel;
}
public void pause(boolean paused) {
if (paused) timer.stop();
else timer.start();
}
}
I believe that collision detection may be the reason for lagging and you should simply investigate it by trying to increase and decrease count of enemies or missiles drastically to see if that makes a difference.
Consider garbage collector your enemy. In your checkCollision method you are instantiating two (very simple) objects. It may not seem like a lot, but consider that your might be creating them for each collision check, and that at 60fps it adds up until it may reach critical mass when GC says "stop the world" and you see noticeable lag.
If that is the case, possible solution to that would be to not instantiate any objects in a method called so frequently. You may create Rectangle2D once, and then update its position, instead of creating a new one each time, so you will avoid unnecessary memory allocation.
Hello I am new in Java and I have stuck. I am trying to make chess game, I made everything except check and checkmate method, and if you have any suggestions I will be happy to read them. Here is my work till now:
This is the board class where we play the game:
public class Board {
public static final int COLOR_WHITE = 1;
public static final int COLOR_BLACK = 2;
public static PlayingPiece[][] board;
private boolean isFirstMove;
private int color;
public Board() {
this.setBoard(new PlayingPiece[8][8]);
this.isFirstMove = true;
this.initializePieces();
}
// Initialize the chess pieces
public void initializePieces() {
for (int i = 0; i < 8; i++) {
board[1][i] = new Pawn(1, i, COLOR_WHITE);
}
for (int i = 0; i < 8; i++) {
board[6][i] = new Pawn(6, i, COLOR_BLACK);
}
board[0][0] = new Rook(0, 0, COLOR_WHITE);
board[0][7] = new Rook(0, 7, COLOR_WHITE);
board[7][0] = new Rook(7, 0, COLOR_BLACK);
board[7][7] = new Rook(7, 7, COLOR_BLACK);
board[0][1] = new Knight(0, 1, COLOR_WHITE);
board[0][6] = new Knight(0, 6, COLOR_WHITE);
board[7][1] = new Knight(7, 1, COLOR_BLACK);
board[7][6] = new Knight(7, 6, COLOR_BLACK);
board[0][2] = new Officer(0, 2, COLOR_WHITE);
board[0][5] = new Officer(0, 5, COLOR_WHITE);
board[7][2] = new Officer(7, 2, COLOR_BLACK);
board[7][5] = new Officer(7, 5, COLOR_BLACK);
board[0][3] = new Queen(3, 0, COLOR_WHITE);
board[0][4] = new King(4, 0, COLOR_WHITE);
board[7][3] = new Queen(7, 3, COLOR_BLACK);
board[7][4] = new King(7, 4, COLOR_BLACK);
this.printBoard();
}
public boolean play(int color, int fromX, int fromY, int toX, int toY) {
boolean isTrue = false;
// Check if this is the first turn and only white can move
if (isFirstMove && color == COLOR_WHITE) {
isTrue = true;
} else if (isFirstMove && color == COLOR_BLACK) {
return false;
}
// check if player plays 2 times in a raw and if you move the piece from
// current possition
if (color == this.color || (toX == fromX && toY == fromY)) {
return false;
}
isTrue = true;
if (isTrue == true) {
this.isFirstMove = false;
// Check if player plays with his own color
if (((board[fromX][fromY]).getColor() != color)) {
return false;
}
// Check the isLegal movement of every chess piece
if ((board[fromX][fromY]).move(toX, toY)) {
board[toX][toY] = board[fromX][fromY];
board[fromX][fromY] = null;
}
this.printBoard();
}
return isTrue;
}
public PlayingPiece[][] getBoard() {
return board;
}
public void setBoard(PlayingPiece[][] board) {
Board.board = board;
}
This is the Pieces class with all kind of pieces:
package com.chess.www;
public class PlayingPiece {
public static final int COLOR_WHITE = 1;
public static final int COLOR_BLACK = 2;
public static final char BLACK_PAWN = '\u265F';
public static final char BLACK_ROOK = '\u265C';
public static final char BLACK_KNIGHT = '\u265E';
public static final char BLACK_BISHOP = '\u265D';
public static final char BLACK_QUEEN = '\u265B';
public static final char BLACK_KING = '\u265A';
public static final char WHITE_PAWN = '\u2659';
public static final char WHITE_ROOK = '\u2656';
public static final char WHITE_KNIGHT = '\u2658';
public static final char WHITE_BISHOP = '\u2657';
public static final char WHITE_QUEEN = '\u2655';
public static final char WHITE_KING = '\u2654';
public static final char NO_PIECE = ' ';
private int x, y;
private boolean isAlive;
private int color;
private char symbol;
protected PlayingPiece (int newX, int newY, int newColor) {
this.setX(newX);
this.setY(newY);
this.color = newColor;
this.isAlive = true;
}
protected PlayingPiece(int newX, int newY) {
this.setX(newX);
this.setY(newY);
}
protected PlayingPiece() {
}
public int getX() {
return x;
}
public void setY(int y) {
this.y = y;
}
public int getY() {
return y;
}
public void setX(int x) {
this.x = x;
}
protected boolean moveIsLegal (int newX, int newY) {
boolean isLegal = false;
if ((0 <= newX && newX <= 7) && (0 <= newY && newY <= 7)){
isLegal = true;
}
return isLegal;
}
public boolean move (int newX, int newY) {
if (moveIsLegal(newX, newY)) {
setX(newX);
setY(newY);
return true;
}
return false;
}
public int getColor() {
return color;
}
public boolean isAlive() {
return isAlive;
}
public void setAlive(boolean isAlive) {
this.isAlive = isAlive;
}
public char getSymbol() {
return symbol;
}
public void setSymbol(char symbol) {
this.symbol = symbol;
}
}
And here is the King class:
package com.chess.www;
public class King extends PlayingPiece {
public King(int newX, int newY, int color) {
super(newX, newY, color);
if (color == COLOR_BLACK) {
this.setSymbol(BLACK_KING);
} else {
this.setSymbol(WHITE_KING);
}
}
#Override
protected boolean moveIsLegal(int newX, int newY) {
int newPositionX = newX - getX();
int newPositionY = newY - getY();
int checkX = this.getX();
int checkY = this.getY();
if (super.moveIsLegal(newX, newY)) {
if ((Math.abs(newPositionX) == 1) && (newY == getY())) {
while (checkX != newX) {
if (this.isValidTraceX(checkX, newY, newX)) {
return true;
}
if (checkX > newX) {
checkX--;
} else if (this.getX() < newX) {
checkX++;
}
}
} else if ((newX == getX()) && (Math.abs(newPositionY) == 1)) {
while (checkY != newY) {
if (this.isValidTraceY(newX, checkY, newY)) {
return true;
}
if (checkY > newY) {
checkY--;
} else if (this.getY() < newY) {
checkY++;
}
}
} else if ((Math.abs(newPositionY) == 1) == (Math.abs(newPositionX) == 1)) {
while (checkX != newX && checkY != newY) {
if (this.isValidTrace(checkX, checkY, newX, newY)) {
return true;
}
if (checkX > newX) {
checkX--;
} else if (this.getX() < newX) {
checkX++;
}
if (checkY > newY) {
checkY--;
} else if (this.getY() < newY) {
checkY++;
}
}
}
}
return false;
}
public boolean isValidTraceX(int newX, int newY, int lastX) {
boolean isValid = true;
if ((Board.board[newX][newY]) != null) {
isValid = false;
}
if (((Board.board[lastX][newY]) != null)) {
if (Board.board[lastX][newY].getColor() == this.getColor()) {
isValid = false;
} else {
isValid = true;
}
}
return isValid;
}
public boolean isValidTraceY(int newX, int newY, int lastY) {
boolean isValid = true;
if ((Board.board[newX][newY]) != null) {
isValid = false;
}
if (((Board.board[newX][lastY]) != null)) {
if (Board.board[newX][lastY].getColor() == this.getColor()) {
isValid = false;
} else {
isValid = true;
}
}
return isValid;
}
public boolean isValidTrace(int newX, int newY, int lastX, int lastY) {
boolean isValid = true;
if ((Board.board[newX][newY]) != null) {
isValid = false;
}
if (((Board.board[lastX][lastY]) != null)) {
if (Board.board[lastX][lastY].getColor() == this.getColor()) {
isValid = false;
} else {
isValid = true;
}
}
return isValid;
}
}
I want to implement the method for check in board class do you have any suggestions?
The way I would implement would be just a method in the King class called something like, isChecked.
boolean isChecked() {
/* Check straight lines */
for (directions) { // up, down, left and right
for (square in direction) { // square by square from the king and out in the current direction
if (square contains opponent rook or queen)
return true;
else if (square contains friendly piece)
continue;
/* Check diagonals */
for (directions) { // left-up, left-down, right-up and right-down
for (square in direction) { // square by square from the king and out in the current direction
if (square contains opponent bishop or queen)
return true;
else if (square contains friendly piece)
continue;
/* Check pawns */
if (squares where pawns would threaten the king contains pawns)
return true;
/* Check king, this is to find if a square is legal to move to only */
if (squares where a king would threaten the king contains king)
return true;
/* Check knights */
if (squares where knights would threaten the king contains knights)
return true;
Sorry, I haven't really got time to write the entire code now, but the pseudo code should be enough to understand the concept. If you need I could fix it later today.
The principle is just, check every possible way a king can be checked.
If a king is checked and all possible moves are also checked, it is a checkmate.
Hope it helps :)
import java.util.Arrays;
public class KingsChecker {
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
String[][] chess = new String[n][n];
print(chess,n);
}
public static void print (String[][] chess,int n) {
for(int i = 0; i< chess.length; i++) {
double random = Math.random()*n; //to generate a random number.
for(int j = 0; j < chess[i].length; j++) {
int column = (int)random;
int[] count = new int[n];
chess[i][j]= "+";
count[column]++;
if (count[column]<=1){
chess[i][column]="k";
System.out.print(chess[i][j]);
}
}
System.out.println();
}
}
}
i want to select rows in grid on mouse drag for that i have following piece of code :
my mouse event listener is DragMultiSelectListener.java
import java.util.List;
import com.myexample.client.ui.items.AbstractContentItem;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.GridEvent;
import com.extjs.gxt.ui.client.event.Listener;
public class DragMultiSelectListener implements Listener<BaseEvent> {
Presenter presenter = null;
/* multiple select on drag */
private boolean mousePressed = false;
private boolean dragEnable = false;
private boolean selected = false;
private List<AbstractContentItem> currentSelected = null;
private int startIndex = -1;
private int endIndex = -1;
private int startX=0;
private int startY=0;
private int endX=0;
private int endY=0;
/** mouseMovedStarted used for preventing calling Grid onClick event for IE while using multiple select on DND **/
private boolean mouseMovedStarted = false;
public DragMultiSelectListener(Presenter pPresenter) {
this.presenter = pPresenter;
}
#Override
public void handleEvent(BaseEvent be) {
if(be.getType() == Events.OnMouseDown){
GridEvent ge = (GridEvent) be;
/* Multiple Row Select */
mouseMovedStarted = false;
mousePressed = true;
startIndex = ge.getRowIndex();
/* Deselect All */
if(ge.getTarget().getClassName().equals("x-grid3-scroller")){
if(ge.getTarget().getClientWidth() < ge.getTarget().getScrollWidth()){
if(ge.getTarget().getClientHeight() < (ge.getClientY() - ge.getTarget().getAbsoluteTop())){
mousePressed = false;
}
if(ge.getTarget().getClientWidth() < (ge.getClientX() - ge.getTarget().getAbsoluteLeft())){
mousePressed = false;
}
}
presenter.deselectAllContentItem();
}
/* Select Record */
if(currentSelected != null && (!presenter.getSelectedContent().isEmpty())){
selected = false;
for(AbstractContentItem item : currentSelected){
AbstractContentItem clickedItem = (AbstractContentItem) ge.getGrid().getStore().getAt(ge.getRowIndex());
if(clickedItem != null && item.getDTO().getId() == clickedItem.getDTO().getId()){
selected = true;
}
}
}else{
currentSelected = presenter.getSelectedContent();
selected = false;
}
dragEnable = false;
if(ge.getTarget().getNodeName().equalsIgnoreCase("SPAM")){
dragEnable = true;
}
if(selected){
dragEnable = true;
}
/* draw box */
if(mousePressed){
startX = ge.getClientX();
startY = ge.getClientY();
}
}else if(be.getType() == Events.OnMouseMove){
GridEvent ge = (GridEvent) be;
if(mousePressed && !dragEnable && (ge.getRowIndex() != -1) ){
if(startIndex == -1){
startIndex = ge.getRowIndex();
}
endIndex = ge.getRowIndex();
presenter.deselectAllContentItem();
if((startIndex - endIndex) >= 0){
for(int i = endIndex; i<=startIndex; i++ ){
presenter.selectContentItem(i, true);
}
}else{
for(int i = startIndex; i<=endIndex; i++ ){
presenter.selectContentItem(i, true);
}
}
/* Show selection box */
endX = ge.getClientX();
endY = ge.getClientY();
}else if(mousePressed && !dragEnable){
/* Show selection box */
endX = ge.getClientX();
endY = ge.getClientY();
if(ge.getTarget().getClassName().equals("x-grid3-scroller")){
if(startY > endY){
presenter.deselectAllContentItem();
}
}
displaySelectionBox(ge.getGrid().getAbsoluteLeft(), ge.getGrid().getAbsoluteTop());
}
mouseMovedStarted = true;
}else if(be.getType() == Events.OnMouseUp){
GridEvent ge = (GridEvent) be;
mousePressed = false;
currentSelected = presenter.getSelectedContent();
}
}
public boolean isMouseMovedStarted() {
return mouseMovedStarted;
}
public boolean isDragEnable() {
return dragEnable;
}
public void setEndX(int endX) {
this.endX = endX;
}
public void setEndY(int endY) {
this.endY = endY;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
public List<AbstractContentItem> getCurrentSelected() {
return currentSelected;
}
public void setCurrentSelected(List<AbstractContentItem> currentSelected) {
this.currentSelected = currentSelected;
}
public void setMousePressed(boolean mousePressed) {
this.mousePressed = mousePressed;
}
}
Register grid event by following code
dragMultiSelectListener = new DragMultiSelectListener(presenter);
grid.addListener(Events.OnMouseDown, dragMultiSelectListener);
grid.addListener(Events.OnMouseMove, dragMultiSelectListener);
grid.addListener(Events.OnMouseUp, dragMultiSelectListener);
problem is that when i move mouse fast than it will skip selecting some of row.
i don't understand, how to improve execution speed to prevent of skipping rows.
Thanks
You can select all rows from dragStart x y, till your current x y. Only thing, you will need row hight to calculate rows then.