Flood It check for colours at beginning isn't working - java

I am stuck on my Flood It game. I am trying to solve the problem of getting a starting matrix and finding the same color connected to the point (0,0). For instance if my starting matrix is generated:
1 4 5
1 1 1
5 3 2
It should capture the 1's so that on the next turn lets say I choose 4 then the matrix should be:
4 4 5
4 4 4
5 3 2
However when I choose 4 now the matrix is:
4 4 5
1 1 1
5 3 2
I know this is part of any normal Flood It game but I'm stuck on implementing it.
'
import java.awt.event.*;
import javax.swing.*;
public class GameController implements ActionListener {
private GameModel model;
private GameView view;
private MyStack<DotInfo> dots;
private int size;
private DotInfo dot;
/**
* Constructor used for initializing the controller. It creates the game's view
* and the game's model instances
*
* #param size
* the size of the board on which the game will be played
*/
public GameController(int size) {
this.size = size;
model = new GameModel(size);
view = new GameView(model, this);
dots = new MyStack<DotInfo>(size*size);
/*view.reset.addActionListener(this);
view.quit.addActionListener(this);
view.grey.addActionListener(this);
view.yellow.addActionListener(this);
view.blue.addActionListener(this);
view.green.addActionListener(this);
view.violet.addActionListener(this);
view.red.addActionListener(this);*/
}
/**
* resets the game
*/
public void reset(){
model.reset();
System.out.println(model);
}
/**
* Callback used when the user clicks a button (reset or quit)
*
* #param e
* the ActionEvent
*/
public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof JButton) {
JButton x = (JButton) e.getSource();
if (x.getText()=="Quit") { //Quit button
System.exit(0);
}
else if (x.getText()=="Reset") { //Reset button
reset();
view.update();
}
}
}
/**
* <b>selectColor</b> is the method called when the user selects a new color.
* If that color is not the currently selected one, then it applies the logic
* of the game to capture possible locations. It then checks if the game
* is finished, and if so, congratulates the player, showing the number of
* moves, and gives two options: start a new game, or exit
* #param color
* the newly selected color
*/
public void selectColor(int color){
model.setCurrentSelectedColor(color);
sendCapturedToStack();
equalityCheck(color);
System.out.println(model);
}
/**
* On every turn <b>sendCapturedToStack</b> will push every captured dot to the stack.
* It will also allow the colours to change every time a user picks a color.
*/
private void sendCapturedToStack() {
model.capture
for (int j=0;j<size;j++) {
for (int i=0;i<size;i++) {
if (model.isCaptured(i, j)) {
model.capture(i, j);
dots.push(model.get(i,j));
}
}
}
}
/**
* <b>equalityCheck</b> checks to see if there is a dot to the left, right, above, or below
* another dot. If there is then the dot will be captured and pushed to the top of the stack.
* #param newColor
* the newly selected color
*/
private void equalityCheck(int newColor) {
while (!dots.isEmpty()) {
dot = dots.pop();
int x = dot.getX();
int y = dot.getY();
if (y<size-1 && model.getColor(x,y+1)==newColor && !model.isCaptured(x,y+1)) {
model.capture(x, y+1);
dots.push(model.get(x,y+1));
} if (x<size-1 && model.getColor(x+1,y)==newColor && !model.isCaptured(x+1,y)) {
model.capture(x+1, y);
dots.push(model.get(x+1,y));
} if (y>0 && model.getColor(x,y-1)==newColor && !model.isCaptured(x,y-1)) {
model.capture(x, y-1);
dots.push(model.get(x,y-1));
} if (x>0 && model.getColor(x-1,y)==newColor && !model.isCaptured(x-1,y)) {
model.capture(x-1, y);
dots.push(model.get(x-1,y));
}
}
}
}

Related

How to check adjacent indices of a 2D array - Othello

Just to be clear, I have looked at problems somewhat similar to this on Stack Overflow and other websites before asking for help. I also included all of the code below just in case it could help anyone understand the problem.
In the game Othello, also known as Reversi, there are two players who use tiles of opposite colors. The player needs to place a tile so it is adjacent to a tile of the opposite color and the opposite color must be surrounded by a tile on either side in the same direction. For example, if there is a white tile to the left of a black tile, then another black tile needs to be placed on the left of the white tile so it is surrounded. If a tile is surrounded it flips.
(Black - White - Black) --> (Black - Black - Black)
Surrounding can happen either horizontally, diagonally or vertically.
The problem I'm having is I do not know how to check all of the indices and see if they work at once. I have tried checking for the values adjacent to a tile of the opposite color, by checking all possible values next to it. This doesn't work properly as it can't make sure that a tile is surrounded on both sides or apply to a line of more than one tile in a row.
/**
* Checks to see if a valid move can be made at the indicated OthelloCell,
* for the given player.
* #param xt The horizontal coordinate value in the board.
* #param yt The vertical coordinate value in the board.
* #param bTurn Indicates the current player, true for black, false for white
* #return Returns true if a valid move can be made for this player at
* this position, false otherwise.
*/
public boolean isValidMove(int xt, int yt, boolean bTurn)
{
int length = board[0].length;
// checks if the tile has already been picked, meaning it can no longer be selected
if(board[xt][yt].hasBeenPlayed())
{
return false;
}
else
{
/* For BLACK (Working) */
if(bTurn)
{
// checks tiles one row above
if(xt + 1 < length && board[xt + 1][yt].getBlackStatus() == false)
{
System.out.println("the one 1 row up and in the same column doesn't work");
return true;
}
if(xt + 1 < length && board[xt + 1][yt + 1].getBlackStatus() == false)
{
System.out.println("the one 1 row up and in the right column doesn't work");
return true;
}
if(xt + 1 < length && board[xt + 1][yt - 1].getBlackStatus() == false)
{
System.out.println("the one 1 row up and in the left column doesn't work");
return true;
}
// checks tiles left and right
if(yt + 1 < length && board[xt][yt + 1].getBlackStatus() == false)
{
System.out.println("the one in the same row and in the right column doesn't work");
return true;
}
if(yt > 1 && board[xt][yt - 1].getBlackStatus() == false)
{
System.out.println("the one in the same row and in the left column doesn't work");
return true;
}
// checks tiles one row below
if(xt > 1 && board[xt - 1][yt].getBlackStatus() == false)
{
System.out.println("The one 1 row down and in the same column doesn't work");
return true;
}
if(xt > 1 && board[xt - 1][yt + 1].getBlackStatus() == false)
{
System.out.println("The one 1 row down and in the right column doesn't work");
return true;
}
if(xt > 1 && board[xt - 1][yt - 1].getBlackStatus() == false)
{
System.out.println("The one 1 row down and in the left column doesn't work");
return true;
}
}
}
return false;
}
/**
* Checks to see if a valid move can be made at the indicated OthelloCell, in a
* particular direction (there are 8 possible directions). These are indicated by:
* (1,1) is up and right
* (1,0) is right
* (1,-1) is down and right
* (0,-1) is down
* (-1,-1) is down and left
* (-1,0) is left
* (-1,1) is left and up
* (0,1) is up
* #param xt The horizontal coordinate value in the board.
* #param yt The vertical coordinate value in the board.
* #param i -1 is left, 0 is neutral, 1 is right,
* #param j -1 is down, - is neutral, 1 is up.
* #param bTurn Indicates the current player, true for black, false for white.
* #return Returns true if this direction has pieces to be flipped, false otherwise.
*/
public boolean directionValid(int xt, int yt, int i, int j, boolean bTurn)
{
return true;
}
Above are the two methods I'm having trouble with.
public class Othello
{
/** The board object. This board will be 8 x 8, and filled with OthelloCells.
* The cell may be empty, hold a white game piece, or a black game piece. */
private OthelloCell [][] board;
/** The coordinates of the active piece on the board. */
private int x, y;
/** Booleans indicating that the mouse is ready to be pressed, that it is
* black's turn to move (false if white's turn), and that the game is over. */
private boolean mousePressReady, blackTurn, gameOver;
/**
* Creates an Othello object, with a sized graphics canvas, and a 2D (8 x 8) array
* of OthelloCell, setting up initial values.
*/
/* COMPLETE */
public Othello ( )
{
StdDraw.setCanvasSize(500,650);
StdDraw.setXscale(0,1);
StdDraw.setYscale(0,1.3);
StdDraw.enableDoubleBuffering();
Font font = new Font("Arial", Font.BOLD, 30);
StdDraw.setFont(font);
startBoard();
}
/**
* Called by the constructor, or when the player hits the "RESET" button,
* initializing the game board (an 8 x 8 array of OthelloCell).
*/
/* COMPLETE */
public void startBoard ( )
{
mousePressReady = blackTurn = true;
gameOver = false;
board = new OthelloCell[8][8];
for ( int i = 0; i < board.length; i++ )
{
for ( int j = 0; j < board[i].length; j++ )
{
board[i][j] = new OthelloCell(i,j);
}
}
board[3][3].playIt();
board[3][3].setBlack(true);
board[4][4].playIt();
board[4][4].setBlack(true);
board[4][3].playIt();
board[4][3].setBlack(false);
board[3][4].playIt();
board[3][4].setBlack(false);
}
/**
* Sets up and runs the game of Othello.
*/
/* COMPLETE */
public static void main(String [] args)
{
Othello game = new Othello();
game.run();
}
/**
* Runs an endless loop to play the game. Even if the game is over, the
* loop is still ready for the user to press "RESET" to play again.
*/
/* COMPLETE */
public void run ( )
{
do
{
drawBoard();
countScoreAnddrawScoreBoard();
StdDraw.show();
StdDraw.pause(30);
makeChoice();
gameOver = checkTurnAndGameOver();
}
while(true);
}
/**
* Draws the board, in its current state, to the GUI.
*/
/* COMPLETE */
public void drawBoard ( )
{
StdDraw.setPenColor(new Color(150,150,150));
StdDraw.filledRectangle(0.5,0.75,0.5,0.75);
StdDraw.setPenColor(new Color(0,110,0));
StdDraw.filledSquare(0.5,0.5,0.45);
StdDraw.setPenColor(new Color(0,0,0));
StdDraw.filledSquare(0.5,0.5,0.42);
for ( int i = 0; i < board.length; i++ )
{
for ( int j = 0; j < board[i].length; j++ )
{
board[i][j].drawCell();
}
}
}
/**
* Waits for the user to make a choice. The user can make a move
* placing a black piece or the white piece (depending on whose turn
* it is), or click on the "RESET" button to reset the game.
*/
/* COMPLETE */
public void makeChoice ( )
{
boolean moveChosen = false;
while(!moveChosen)
{
if(mousePressReady && StdDraw.isMousePressed())
{
mousePressReady = false;
double xval = StdDraw.mouseX();
double yval = StdDraw.mouseY();
if(xval > 0.655 && xval < 0.865 && yval > 1.15 && yval < 1.23) // This if checks for a reset.
{
startBoard();
return;
}
if(xval < 0.1 || xval > 0.9 || yval < 0.1 || yval > 0.9) // This if checks for a press off the board.
{
return;
}
int tempx = (int)(10 * (xval - 0.1));
int tempy = (int)(10 * (yval - 0.1));
if(isValidMove(tempx,tempy,blackTurn)) // This if checks to see if the move is valid.
{
x = tempx;
y = tempy;
playAndFlipTiles();
blackTurn = !blackTurn;
System.out.println(x + " " + y);
}
}
if(!StdDraw.isMousePressed() && !mousePressReady) // This if gives back control when the mouse is released.
{
mousePressReady = true;
return;
}
StdDraw.pause(20);
}
}
/**
* Checks to see if a valid move can be made at the indicated OthelloCell,
* for the given player.
* #param xt The horizontal coordinate value in the board.
* #param yt The vertical coordinate value in the board.
* #param bTurn Indicates the current player, true for black, false for white
* #return Returns true if a valid move can be made for this player at
* this position, false otherwise.
*/
public boolean isValidMove(int xt, int yt, boolean bTurn)
{
int length = board[0].length;
// checks if the tile has already been picked, meaning it can no longer be selected
if(board[xt][yt].hasBeenPlayed())
{
return false;
}
else
{
}
return false;
}
/**
* Checks to see if a valid move can be made at the indicated OthelloCell, in a
* particular direction (there are 8 possible directions). These are indicated by:
* (1,1) is up and right
* (1,0) is right
* (1,-1) is down and right
* (0,-1) is down
* (-1,-1) is down and left
* (-1,0) is left
* (-1,1) is left and up
* (0,1) is up
* #param xt The horizontal coordinate value in the board.
* #param yt The vertical coordinate value in the board.
* #param i -1 is left, 0 is neutral, 1 is right,
* #param j -1 is down, - is neutral, 1 is up.
* #param bTurn Indicates the current player, true for black, false for white.
* #return Returns true if this direction has pieces to be flipped, false otherwise.
*/
public boolean directionValid(int xt, int yt, int i, int j, boolean bTurn)
{
return true;
}
/**
* Places a game piece on the current cell for the current player. Also flips the
* appropriate neighboring game pieces, checking the 8 possible directions from the
* current cell.
*/
public void playAndFlipTiles ( )
{
board[x][y].setBlack(blackTurn);
board[x][y].playIt();
// To be completed by you.
}
/**
* A helper method for playAndFlipTiles. Flips pieces in a given direction. The
* directions are as follows:
* (1,1) is up and right
* (1,0) is right
* (1,-1) is down and right
* (0,-1) is down
* (-1,-1) is down and left
* (-1,0) is left
* (-1,1) is left and up
* (0,1) is up
* #param xt The horizontal coordinate value in the board.
* #param yt The vertical coordinate value in the board.
* #param i -1 is left, 0 is neutral, 1 is right,
* #param j -1 is down, - is neutral, 1 is up.
*/
public void flipAllInThatDirection(int xt, int yt, int i, int j)
{
}
/**
* Counts the white pieces on the board, and the black pieces on the board.
* Displays these numbers toward the top of the board, for the current state
* of the board. Also prints whether it is "BLACK'S TURN" or "WHITE'S TURN"
* or "GAME OVER".
*/
/* COMPLETE */
public void countScoreAnddrawScoreBoard ( )
{
int whiteCount = 0, blackCount = 0;
for(int i = 0; i < board.length; i++)
{
for(int j = 0; j < board[i].length; j++)
{
if(board[i][j].hasBeenPlayed())
{
if(board[i][j].getBlackStatus())
{
blackCount++;
}
else
{
whiteCount++;
}
}
}
}
drawScoresAndMessages(whiteCount,blackCount);
}
/**
* A helper method for countScoreAnddrawScoreBoard. Draws the scores
* and messages.
* #param whiteCount The current count of the white pieces on the board.
* #param blackCount The current count of the black pieces on the board.
*/
/* COMPLETE */
public void drawScoresAndMessages(int whiteCount, int blackCount)
{
StdDraw.setPenColor(new Color(0,0,0));
StdDraw.filledRectangle(0.41,1.05,0.055,0.045);
StdDraw.filledRectangle(0.80,1.05,0.055,0.045);
StdDraw.filledRectangle(0.76,1.19,0.11,0.045);
StdDraw.setPenColor(new Color(255,255,255));
StdDraw.filledRectangle(0.41,1.05,0.05,0.04);
StdDraw.filledRectangle(0.80,1.05,0.05,0.04);
StdDraw.filledRectangle(0.76,1.19,0.105,0.04);
StdDraw.setPenColor(new Color(0,0,0));
StdDraw.text(0.24,1.04,"BLACK");
StdDraw.text(0.41,1.04,"" + blackCount);
StdDraw.text(0.63,1.04,"WHITE");
StdDraw.text(0.80,1.04,"" + whiteCount);
StdDraw.text(0.76,1.18,"RESET");
if(gameOver)
{
StdDraw.text(0.34,1.18,"GAME OVER");
}
else if(blackTurn)
{
StdDraw.text(0.34,1.18,"BLACK'S TURN");
}
else
{
StdDraw.text(0.34,1.18,"WHITE'S TURN");
}
}
/**
* Checks to see if black can play. Checks to see if white can play.
* If neither can play, the game is over. If black can't go, then set
* blackTurn to false. If white can't go, set blackTurn to true.
* #return Returns true if the game is over, false otherwise.
*/
/* COMPLETE */
public boolean checkTurnAndGameOver ( )
{
boolean whiteCanGo = false, blackCanGo = false;
// To be completed by you.
return false;
}
}
/**
* Represents a single cell in the game of Othello. By default, a cell is black, and
* has not been played. When a game piece is "placed" on the board, the boolean played
* is set to true. If the game piece is black, then the boolean black is true, and if
* the game piece is white, then the boolean black is false. The ints x and y
* represent the coordinate values of the cell within the game board, with the lower
* left at (0,0) and the upper right at (7,7).
*/
class OthelloCell
{
/** The coordinates of the active piece on the board. */
private int x, y;
/** Booleans indicating if a piece has been played (or is empty), and indicating
* if the piece is black (or white) */
private boolean played, black;
/**
* Creates an OthelloCell object, at the given coordinate pair.
* #param i The horizontal coordinate value for the cell on the board.
* #param j The vertical coordinate value for the cell on the board.
*/
/* COMPLETE */
public OthelloCell(int i, int j)
{
played = false;
x = i;
y = j;
black = true;
}
/**
* Draws the cell on the board, in its current state.
*/
/* COMPLETE */
public void drawCell ( )
{
StdDraw.setPenColor(new Color(0,0,0));
StdDraw.filledSquare(0.15 + 0.1 * x, 0.15 + 0.1 * y, 0.05);
StdDraw.setPenColor(new Color(0,110,0));
StdDraw.filledSquare(0.15 + 0.1 * x, 0.15 + 0.1 * y, 0.048);
if(played)
{
for(int i = 0; i <= 20; i++)
{
if(black)
{
StdDraw.setPenColor(new Color(5+8*i,5+8*i,5+8*i));
}
else
{
StdDraw.setPenColor(new Color(255-8*i,255-8*i,255-8*i));
}
StdDraw.filledCircle(0.15 + 0.1 * x - i*0.001, 0.15 + 0.1 * y + i*0.001, 0.043-i*0.002);
}
}
}
/**
* Sets the piece to black (black true) or white (black false).
* #param bool The value to be assigned to the game piece.
*/
/* COMPLETE */
public void setBlack(boolean bool)
{
if(bool)
{
black = true;
}
else
{
black = false;
}
}
/**
* Return the status of black; true for a black piece, false for a white piece.
* #return Returns true for a black piece, false for a white piece.
*/
/* COMPLETE */
public boolean getBlackStatus ( )
{
return black;
}
/**
* Sets the value of played to true, to indicate that a piece has been placed on this cell.
*/
/* COMPLETE */
public void playIt ( )
{
played = true;
}
/**
* Return the status of played, indicating whether or not there is a game piece on this cell.
* #return Returns true if a game piece is on this cell, false otherwise.
*/
/* COMPLETE */
public boolean hasBeenPlayed ( )
{
return played;
}
}
You can get the 8 adjacent cells using two different arrays. These arrays are used to get row and column numbers of 8 neighbors of a given cell
int rowNbr[] = new int[] {-1, -1, -1, 0, 0, 1, 1, 1};
int colNbr[] = new int[] {-1, 0, 1, -1, 1, -1, 0, 1};
And iterate the given matrix by adding the current row/col to above arrays like :
for (int k = 0; k < 8; ++k) {
sop(matrix[row + rowNbr[k], col + colNbr[k]])
}
Also,you might want to check https://www.geeksforgeeks.org/find-number-of-islands/
Hope this will get you the further thought process. Thnx
This is my approach, although its in C# I am sure its of some use.
Also uses part of the solution from Ashutosh.
My Board is the two dimensional array "pieces", lowercase "length" is just the size of the board and num is an indicator for a color: Empty is 0, num is whats currently being played, 1 for White and 2 for Black.
All its doing is looking for the closest matching color in either direction without empty spaces inbetween and then placing the current playing color in all the array spaces inbetween.
This can probably be done way smarter, I dont even like my approach of always checking for the full size of the field in every direction and just ignoring index out of range exceptions, but it was the simplest
int[] rowNbr = { -1, -1, -1, 0, 0, 1, 1, 1 };
int[] colNbr = { -1, 0, 1, -1, 1, -1, 0, 1 };
for (int x = 0; x < 8; x++)
{
int facX = rowNbr[x];
int facY = colNbr[x];
try
{
for (int i = 1; i < length; i++)
{
if (pieces[click.X + i * facX, click.Y + i * facY] == 0) break;
if (pieces[click.X + i * facX, click.Y + i * facY] == (byte)num)
{
for (int j = i - 1; j > 0; j--)
{
pieces[click.X + j * facX, click.Y + j * facY] = (byte)num;
}
break;
}
}
}
catch { }
}

libgdx animated sprite no method error

Whenever I upload a sprite atlas for animation purposes into a scene in overlaps2d version 0.1.2-snapshot. My app crashes with the following line (slightly redacted):
java.lang.NoSuchMethodError: No virtual method getKeyFrame(F)Lcom/badlogic/gdx/graphics/g2d/TextureRegion; in class Lcom/badlogic/gdx/graphics/g2d/Animation; or its super classes (declaration of 'com.badlogic.gdx.graphics.g2d.Animation' appears in /data/data/xxx.xxx.xxx/files/instant-run/dex/slice-gdx-1.9.5_xxx-classes.dex)
And it points to this line in my code:
sceneLoader.getEngine().update(Gdx.graphics.getDeltaTime());
Could this be a issue with a version mismatch as overlap2d hasn't been updated in over a year, but libgdx was just updated about a month ago? The crash only happens with an animated image, otherwise app runs fine. I looked at the libgdx file the error refers to and this is what it looks like:
package com.badlogic.gdx.graphics.g2d;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.utils.Array;
public class Animation<T> {
/** Defines possible playback modes for an {#link Animation}. */
public enum PlayMode {
NORMAL,
REVERSED,
LOOP,
LOOP_REVERSED,
LOOP_PINGPONG,
LOOP_RANDOM,
}
/** Length must not be modified without updating {#link #animationDuration}. See {#link #setKeyFrames(T[])}. */
T[] keyFrames;
private float frameDuration;
private float animationDuration;
private int lastFrameNumber;
private float lastStateTime;
private PlayMode playMode = PlayMode.NORMAL;
/** Constructor, storing the frame duration and key frames.
*
* #param frameDuration the time between frames in seconds.
* #param keyFrames the objects representing the frames. */
public Animation (float frameDuration, Array<? extends T> keyFrames) {
this.frameDuration = frameDuration;
T[] frames = (T[]) new Object[keyFrames.size];
for (int i = 0, n = keyFrames.size; i < n; i++) {
frames[i] = keyFrames.get(i);
}
setKeyFrames(frames);
}
/** Constructor, storing the frame duration and key frames.
*
* #param frameDuration the time between frames in seconds.
* #param keyFrames the objects representing the frames. */
public Animation (float frameDuration, Array<? extends T> keyFrames, PlayMode playMode) {
this(frameDuration, keyFrames);
setPlayMode(playMode);
}
/** Constructor, storing the frame duration and key frames.
*
* #param frameDuration the time between frames in seconds.
* #param keyFrames the objects representing the frames. */
public Animation (float frameDuration, T... keyFrames) {
this.frameDuration = frameDuration;
setKeyFrames(keyFrames);
}
/** Returns a frame based on the so called state time. This is the amount of seconds an object has spent in the
* state this Animation instance represents, e.g. running, jumping and so on. The mode specifies whether the animation is
* looping or not.
*
* #param stateTime the time spent in the state represented by this animation.
* #param looping whether the animation is looping or not.
* #return the frame of animation for the given state time. */
public T getKeyFrame (float stateTime, boolean looping) {
// we set the play mode by overriding the previous mode based on looping
// parameter value
PlayMode oldPlayMode = playMode;
if (looping && (playMode == PlayMode.NORMAL || playMode == PlayMode.REVERSED)) {
if (playMode == PlayMode.NORMAL)
playMode = PlayMode.LOOP;
else
playMode = PlayMode.LOOP_REVERSED;
} else if (!looping && !(playMode == PlayMode.NORMAL || playMode == PlayMode.REVERSED)) {
if (playMode == PlayMode.LOOP_REVERSED)
playMode = PlayMode.REVERSED;
else
playMode = PlayMode.LOOP;
}
T frame = getKeyFrame(stateTime);
playMode = oldPlayMode;
return frame;
}
/** Returns a frame based on the so called state time. This is the amount of seconds an object has spent in the
* state this Animation instance represents, e.g. running, jumping and so on using the mode specified by
* {#link #setPlayMode(PlayMode)} method.
*
* #param stateTime
* #return the frame of animation for the given state time. */
public T getKeyFrame (float stateTime) {
int frameNumber = getKeyFrameIndex(stateTime);
return keyFrames[frameNumber];
}
/** Returns the current frame number.
* #param stateTime
* #return current frame number */
public int getKeyFrameIndex (float stateTime) {
if (keyFrames.length == 1) return 0;
int frameNumber = (int)(stateTime / frameDuration);
switch (playMode) {
case NORMAL:
frameNumber = Math.min(keyFrames.length - 1, frameNumber);
break;
case LOOP:
frameNumber = frameNumber % keyFrames.length;
break;
case LOOP_PINGPONG:
frameNumber = frameNumber % ((keyFrames.length * 2) - 2);
if (frameNumber >= keyFrames.length) frameNumber = keyFrames.length - 2 - (frameNumber - keyFrames.length);
break;
case LOOP_RANDOM:
int lastFrameNumber = (int) ((lastStateTime) / frameDuration);
if (lastFrameNumber != frameNumber) {
frameNumber = MathUtils.random(keyFrames.length - 1);
} else {
frameNumber = this.lastFrameNumber;
}
break;
case REVERSED:
frameNumber = Math.max(keyFrames.length - frameNumber - 1, 0);
break;
case LOOP_REVERSED:
frameNumber = frameNumber % keyFrames.length;
frameNumber = keyFrames.length - frameNumber - 1;
break;
}
lastFrameNumber = frameNumber;
lastStateTime = stateTime;
return frameNumber;
}
/** Returns the keyframes[] array where all the frames of the animation are stored.
* #return The keyframes[] field. */
public T[] getKeyFrames () {
return keyFrames;
}
protected void setKeyFrames (T... keyFrames) {
this.keyFrames = keyFrames;
this.animationDuration = keyFrames.length * frameDuration;
}
/** Returns the animation play mode. */
public PlayMode getPlayMode () {
return playMode;
}
/** Sets the animation play mode.
*
* #param playMode The animation {#link PlayMode} to use. */
public void setPlayMode (PlayMode playMode) {
this.playMode = playMode;
}
/** Whether the animation would be finished if played without looping (PlayMode#NORMAL), given the state time.
* #param stateTime
* #return whether the animation is finished. */
public boolean isAnimationFinished (float stateTime) {
int frameNumber = (int)(stateTime / frameDuration);
return keyFrames.length - 1 < frameNumber;
}
/** Sets duration a frame will be displayed.
* #param frameDuration in seconds */
public void setFrameDuration (float frameDuration) {
this.frameDuration = frameDuration;
this.animationDuration = keyFrames.length * frameDuration;
}
/** #return the duration of a frame in seconds */
public float getFrameDuration () {
return frameDuration;
}
/** #return the duration of the entire animation, number of frames times frame duration, in seconds */
public float getAnimationDuration () {
return animationDuration;
}
From what i understand getting the key frame is what retrieves the frame out of the image atlas and changes it based on time to give the illusion of movement.
Use the previous version of libgdx, i.e., 1.9.4. In libgdx version 1.9.5 Animation class having some change, that is not updated with overlap2d snapshot version, so you are facing the problem.
Downgrade version in build.gradle of root project. Hopefully, it may be helpful.
Thanks.

Create a star rating system using swt components in Eclipse

Essentially I'm trying to create a star rating system.
I can create the components I need using a toolbar and toolitems as follows.
ToolBar toolBar = new ToolBar(Composite, SWT.FLAT);
toolBar.layout();
ToolItem starButton1 = new ToolItem(toolBar, SWT.NONE);
starButton1.setImage("imgpath/img.png");
ToolItem starButton2 = new ToolItem(toolBar, SWT.NONE);
starButton2.setImage("imgpath/img.png");
ToolItem starButton3 = new ToolItem(toolBar, SWT.NONE);
starButton3.setImage("imgpath/img.png");
ToolItem starButton4 = new ToolItem(toolBar, SWT.NONE);
starButton4.setImage("imgpath/img.png");
ToolItem starButton5 = new ToolItem(toolBar, SWT.NONE);
starButton5.setImage("imgpath/img.png");
From here I can add listeners/etc.. to change the appearance of the stars if they are selected. However this doesn't use the behavior of a rating system (i.e. if you select the third star, the first two change to selected too).
I thought of trying to use a list, something along the lines of this that would give the stars some sort of ordering information:
List<ToolItem> stars = new LinkedList<ToolItem>();
stars.add(new ToolItem(toolBar, SWT.NONE).setImage("imgpath/img.png"));
etc...
So the problem here is that the set methods return void, keeping me from modifying the settings of the ToolItem object in the add
Is there an easy way to do this that I'm overcomplicating?
Also I would like to avoid 3rd party libraries. I'm aware of this:
opal widgets
I've written a star rating widget myself a while ago. Feel free to use it:
/**
* The StarRaring is a widget that displays a predefined number of images side
* by side to realize a "star ranking". This star ranking has listeners to
* listen to the user input and adjust the number of stars painted with full
* alpha. The remaining stars are painted with a user defined alpha value
* (default: 150)
*
* #author Sebastian Raubach
*
*/
public class StarRating extends Composite
{
private Image image;
private int hoverSelected = 0;
private int selected = 0;
private int nrOfImages = 5;
private int alpha = 150;
private int width;
private int height;
private boolean vertical = false;
/**
* <p>
* Creates a star rating widget with a default selection of 1 star
* </p>
*
* #param parent
* the hosting composite
* #param style
* the widget style
*/
public StarRating(Composite parent, int style)
{
super(parent, style);
/* Add dispose listener for the image */
addListener(SWT.Dispose, new Listener()
{
#Override
public void handleEvent(Event arg0)
{
if(image != null)
image.dispose();
}
});
/* Add custom paint listener that paints the stars */
addListener(SWT.Paint, new Listener()
{
#Override
public void handleEvent(Event e)
{
paintControl(e);
}
});
/*
* Keep track of the mouse movements and highlight possible new
* selection
*/
addListener(SWT.MouseMove, new Listener()
{
#Override
public void handleEvent(Event arg0)
{
int x = arg0.x;
int y = arg0.y;
/* Determine direction */
int step = (vertical ? height : width) + 1;
int location = vertical ? y : x;
/* Determine current index */
int current = (location / step);
/* Redraw if necessary */
if (current != hoverSelected)
{
hoverSelected = current;
redraw();
}
}
});
/* On mouse exit, reset selection */
addListener(SWT.MouseExit, new Listener()
{
#Override
public void handleEvent(Event arg0)
{
hoverSelected = selected;
redraw();
}
});
/* On mouse up, set new selection based on hover selection */
addListener(SWT.MouseUp, new Listener()
{
#Override
public void handleEvent(Event arg0)
{
selected = hoverSelected;
}
});
}
/**
* <p>
* Draws the images. Selected images are drawn with full alpha, unselected
* images with the user defined alpha value
* </p>
*
* #param event
* The source event
*/
private void paintControl(Event event)
{
GC gc = event.gc;
if (image != null)
{
int stepX = vertical ? 0 : width + 1;
int stepY = vertical ? height + 1 : 0;
for (int i = 0; i < nrOfImages; i++)
{
if (i == hoverSelected + 1)
gc.setAlpha(alpha);
gc.drawImage(image, 1 + stepX * i, 1 + stepY * i);
}
/* Reset alpha value */
gc.setAlpha(255);
}
}
/**
* <p>
* Returns the image used for the star painting
* </p>
*
* #return the image used for the star painting
*/
public Image getImage()
{
return image;
}
/**
* <p>
* Set the image used for the star painting
* </p>
*
* #param image
* the image used for the star painting
*/
public void setImage(Image image)
{
this.image = new Image(Display.getDefault(), image, SWT.IMAGE_COPY);
width = image.getBounds().width;
height = image.getBounds().height;
redraw();
}
/**
* <p>
* Set the number of stars to be shown on the star rating
* </p>
* <p>
* Minimum = 1, Maximum = unrestricted
* </p>
*
* #param nrOfStars
* the number of stars to be shown on the star rating
*/
public void setNrOfStars(int nrOfStars)
{
if (nrOfStars < 1)
throw new IllegalArgumentException("Invalid value for number of stars. Minimum: 1, Selection: " + nrOfStars);
else
nrOfImages = nrOfStars;
}
/**
* <p>
* Returns the number of stars to be shown on the star rating
* </p>
*
* #return the number of stars to be shown on the star rating
*/
public int getNrOfStars()
{
return nrOfImages;
}
/**
* <p>
* Get the number of selected stars of the star rating
* </p>
*
* #return the number of selected stars of the star rating
*/
public int getSelection()
{
return selected + 1;
}
/**
* <p>
* Set the number of selected stars of the star rating
* </p>
* <p>
* Minimum = 1, Maximum = nr. of stars available
* </p>
*
* #param selection
* the number of selected stars of the star rating
*/
public void setSelection(int selection)
{
if (selection < 0 || selection > nrOfImages)
throw new IllegalArgumentException("Invalid value for star selection. Minimum: 0, Maximum: " + nrOfImages + ", Selection: " + selection);
else
selected = selection - 1;
hoverSelected = selected;
}
/**
* <p>
* Set the alpha value used for painting the non-selected stars
* </p>
* <p>
* Minimum = 0, Maximum = 255
* </p>
*
* #param alpha
* The alpha value used for painting the non-selected stars
*/
public void setAlpha(int alpha)
{
if (alpha < 0 || alpha > 255)
throw new IllegalArgumentException("Invalid alpha value. Minimum: 0, Maximum: 255, Selection: " + alpha);
else
this.alpha = alpha;
}
/**
* <p>
* Returns the alpha value used for painting the non-selected stars
* </p>
*
* #return the alpha value used for painting the non-selected stars
*/
public int getAlpha()
{
return alpha;
}
/**
* <p>
* Set the orientation of the widget to vertical
* </p>
*
* #param vertical
* Set to true if the stars should be aligned in a vertical and
* to false if the stars should be aligned in a horizontal line
*/
public void setVertical(boolean vertical)
{
this.vertical = vertical;
}
/**
* <p>
* Returns the orientation of the widget
* </p>
*
* #return true, if the widget is vertical, false if the widget is
* horizontal
*/
public boolean getVertical()
{
return vertical;
}
#Override
public Point computeSize(int wHint, int hHint, boolean changed)
{
int overallWidth = 0;
int overallHeight = 0;
/* Determine the preferred dimensions of the widget */
if (image != null)
{
overallWidth = vertical ? width : width * nrOfImages + nrOfImages - 1;
overallHeight = vertical ? height * nrOfImages + nrOfImages - 1 : height;
}
/* Consider hints */
if (wHint != SWT.DEFAULT && wHint < overallWidth)
overallWidth = wHint;
if (hHint != SWT.DEFAULT && hHint < overallHeight)
overallHeight = hHint;
/* Return computed dimensions plus border */
return new Point(overallWidth + 2, overallHeight + 2);
}
public static void main(String[] args)
{
Display display = Display.getDefault();
Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1, false));
StarRating star = new StarRating(shell, SWT.NONE);
star.setImage(new Image(display, "star.png"));
star.setVertical(true);
star.setNrOfStars(10);
star.setSelection(3);
star.setAlpha(100);
star.setVertical(false);
shell.pack();
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
Looks like this:

Collision detection and reaction java

I am writing a small game where 20 balloons are created on screen and mouse released on them expands them. They are supposed to 'pop' when one balloon touches another, but at present when I click a balloon it pops a random one and throws an 'Array index out of bounds' exception. I've racked my brain to figure out why my code isn't working but just can't get it. Here's some of the code causing the problem:
import comp102.*;
import java.util.*;
import java.awt.Color;
public class BalloonGame implements UIButtonListener, UIMouseListener{
// Fields
private final int numBalloons = 20;
private int currentScore; // the score for the current game
private int highScore = 0; // highest score in all games so far.
private int totalPopped = 0;
Balloon balloons[] = new Balloon[numBalloons];
// Constructor
/** Set up the GUI, start a new game.
*/
public BalloonGame(){
UI.setMouseListener(this);
UI.addButton("New Game", this);
UI.addButton("Lock Score", this);
this.newGame();
}
// GUI Methods to respond to buttons and mouse
/** Respond to button presses, to start a new game and to end the current game */
public void buttonPerformed(String cmd){
if (cmd.equals("New Game")) { this.newGame(); }
else if (cmd.equals("Lock Score")) { this.endGame(); }
}
/** Respond to mouse released with the main action of the game*/
public void mousePerformed(String action, double x, double y) {
if (action.equals("released")) {
this.doAction(x, y);
}
}
/** Start the game:
Clear the graphics pane
Initialise the score information
Make a new set of Balloons at random positions
*/
public void newGame(){
UI.clearGraphics();
this.currentScore = 0;
this.totalPopped = 0;
for (int i = 0; i < this.balloons.length; i++) {
this.balloons[i] = new Balloon(50 + Math.random()*400, 50 + Math.random()*400);
this.balloons[i].draw();
}
UI.printMessage("New game: click on a balloon. High score = "+this.highScore);
}
/** Main game action.
Find the balloon at (x,y) if any,
Expand it
Check whether it is touching another balloon,
If so, update totalPopped, pop both balloons, and remove them from the list
Recalculate the score.
If there are no balloons left, end the game.
*/
public void doAction(double x, double y) {
for (int i = 0; i < this.balloons.length; i++) {
if (this.balloons[i].on(x, y) && !this.balloons[i].isPopped()) {
this.balloons[i].expand();
}
for (int j = 1; j <this.balloons.length; j++) {
if (this.balloons[i].isTouching(this.balloons[j]) && this.balloons[j] != null)
{
this.totalPopped +=2;
this.balloons[i].pop();
this.balloons[j].pop();
this.balloons[i] = null;
this.balloons[j] = null;
}
}
}
this.calculateScore();
if (totalPopped == numBalloons) {
this.endGame();
}
}
/** Find a balloon that the point (x, y) is on.
* Returns null if point is not on any balloon*/
public Balloon findBalloon(double x, double y){
return null;
}
/** Find and return another balloon that is touching this balloon
* Returns null if no such Balloon. */
public Balloon findTouching(Balloon balloon){
return null;
}
/** Calculate the score: sum of the sizes of current ballons, minus
the total of the popped balloons (totalPopped).
Report the score as a message */
public void calculateScore(){
for (Balloon b: balloons) {
this.currentScore += b.size();
}
if (currentScore >= highScore) {
this.highScore = this.currentScore;
}
UI.printMessage("Score = "+this.currentScore+" High score = "+this.highScore);
}
/** Returns true if all the balloons have been popped,
* Returns false if any of the balloons is not popped */
public boolean allPopped(){
for (Balloon b : this.balloons){
if (!b.isPopped()){
return false;
}
}
return true;
}
/** End the current game.
Record the the score as the new high score if it is better
Print a message
Clear the list of balloons (so the player can't keep playing)
*/
public void endGame(){
this.highScore = this.currentScore;
UI.println("High score = " + this.highScore);
Arrays.fill(balloons, null);
}
// Main
public static void main(String[] arguments){
BalloonGame ob = new BalloonGame();
}
}
uses the balloon class also:
import comp102.*;
import java.util.*;
import java.awt.Color;
import java.io.*;
/** Represents a balloon that can grow until it pops.
A Balloon can say whether a particular point is on it, and
whether it is touching another balloon.
It can also return its size.
Once it has popped, no point is on it, and it can't touch another balloon.
Also, its size is reported as a negative value.
*/
public class Balloon{
// Fields
private double radius = 10;
private double centerX, centerY;
private Color color;
private boolean popped = false;
// Constructors
/** Construct a new Balloon object.
Parameters are the coordinates of the center of the balloon
Does NOT draw the balloon yet.
*/
public Balloon(double x, double y){
this.centerX = x;
this.centerY = y;
this.color = Color.getHSBColor((float)Math.random(), 1.0f, 1.0f);
}
public void draw(){
UI.setColor(color);
UI.fillOval(centerX-radius, centerY-radius, radius*2, radius*2);
if (!this.popped){
UI.setColor(Color.black);
UI.drawOval(centerX-radius, centerY-radius, radius*2, radius*2);
}
}
/** Make the balloon larger by a random amount between 4 and 10*/
public void expand(){
if (! this.popped){
this.radius = this.radius + (Math.random()*6 + 4);
this.draw();
}
}
/** pop the balloon (changes colour to gray, draws, and pauses briefly)*/
public void pop(){
this.color = Color.lightGray;
this.popped = true;
this.draw();
UI.sleep(20);
}
/** Returns true if the balloon has been popped */
public boolean isPopped(){
return this.popped;
}
/** Returns true if the point (x,y) is on the balloon, and false otherwise */
public boolean on(double x, double y){
if (popped) return false;
double dx = this.centerX - x;
double dy = this.centerY - y;
return ((dx*dx + dy*dy) < (this.radius * this.radius));
}
/** Returns true if this Balloon is touching the other balloon, and false otherwise
* Returns false if either balloon is popped. */
public boolean isTouching(Balloon other){
if (this.popped || other.popped) return false;
double dx = other.centerX - this.centerX;
double dy = other.centerY - this.centerY;
double dist = other.radius + this.radius;
return (Math.hypot(dx,dy) < dist);
}
/** Calculates and returns the area of the balloon
* Returns it in "centi-pixels" (ie, number of pixels/100)
* to keep them in a reasonable range.
* Returns a negative size if it is popped.*/
public int size(){
int s = (int) ((this.radius * this.radius * Math.PI)/100);
if (popped) { s = 0 - s; }
return s;
}
}
is this right?
for (int j = 1; j <this.balloons.length; j++) {
doesn't it allow i and j to be equal, so you end up asking whether a balloon is touching itself? Do you mean j = i + 1 ?
If you are now getting null pointer exceptions, get into a debugger and step through until you see where. My guess is that you are visiting array items that have been popped, and hence are null.
if (this.balloons[i].isTouching(this.balloons[j]) && this.balloons[j] != null)
You are testing this.balloons[j] for null after you are using it. I'd put some null checks before trying to work with each item.

Android bitmap animation

I am adding bitmap animations into my simple 2D android game engine(if you can call it one yet.. :D) and I am facing problem of cycling through frames at pre defined FPS/rate.
What I have done for now is simply use System to get currentTimeMillis and use it as reference but I am pretty sure that's not the best decision.. I was thinking I could pass current frame to the drawing method and use that to the drawing method.
Currently I have object that you get the drawable from and I use it on renderer like this:
canvas.drawBitmap(animation.getDrawable(), (int)x, (int)y, null);
and getDrawable() returns current frame of the animation or the only frame if its still image and heres the code
if(frames.size() > 1) {
long current = System.currentTimeMillis();
if (currentFrame == frames.size() - 1 && frameDirection == 1) {
frameDirection = -1;
} else if (currentFrame == 0 && frameDirection == -1) {
frameDirection = 1;
}
if ((current - lastFrame) > delay) {
currentFrame += frameDirection;
lastFrame = current;
}
}
return frames.get(currentFrame);
and in my eyes that just looks so bad and unefficient.. What can I do about this? Is the only way to go passing current frame to getDrawable or how should this be done?
If I understand this right, you want to create an animation class for you game engine?
In my Game Engine I've got a class called SpriteSheetAnimation, which basically iterates through every frame of the animation when the update method is called - I'm sure you'll understand the logic behind it and you'll find a way to use it:
public class SpriteSheetAnimation extends GameObjectTemplate {
int animationSheetLength;
int animationSheetHeight;
int columns;
int rows;
Rect srcRect;
int left;
int bottom;
int lengthOfSpriteInSheet;
int heightOfSpriteInSheet;
boolean repeatAnimation;
boolean animationCompleted;
boolean animationStarted;
Bitmap bitmap;
/**
* You input a bitmap and the number of sprites (by defining the number of rows and columns), and this class will
* take care of animating the sheet.
*
*/
public SpriteSheetAnimation(WorldTemplate world, Bitmap animationSheet, int amountOfRows, int amountOfColumns) {
super(world);
this.animationSheetLength = animationSheet.getWidth();
this.animationSheetHeight = animationSheet.getHeight();
this.columns = amountOfColumns;
this.rows = amountOfRows;
this.lengthOfSpriteInSheet = this.animationSheetLength/this.columns;
this.heightOfSpriteInSheet = this.animationSheetHeight/this.rows;
srcRect = new Rect();
left = 0;
bottom = this.heightOfSpriteInSheet;
repeatAnimation = false;
animationCompleted = false;
animationStarted = false;
this.bitmap = animationSheet;
this.drawShapesOfSprites = true;
this.gameObjectShape.addRectangle(new Rect(0, 0, 0 + this.heightOfSpriteInSheet, 0 + this.lengthOfSpriteInSheet));
}
#Override
public void defineGameObjectPositionShape() {
this.gameObjectShape.addRectangle(new Rect());
}
/**
* <b><i>public Rect getSrcRect()</i></b>
* <br>
* Since: API 1
* <br>
* <br>
* Retrieve the rect that will cover the current source of the sheet.
*
* #return
* The current rect that will cover the current source of the sheet.
*
*/
public Rect getSrcRect() {
return srcRect;
}
/**
* <b><i>public Rect getDstRect()</i></b>
* <br>
* Since: API 1
* <br>
* <br>
* Retrieve the rect where the bitmap will be scaled to fit into.
*
* #return
* The current rect where the bitmap will be scaled to fit into.
*
*/
public Rect getDstRect() {
return this.getGameObjectPositionRect();
}
/**
* <b><i>public void repeatAnimation(boolean repetition)</i></b>
* <br>
* Since: API 1
* <br>
* <br>
* This method will set if the animation should be repeated or not.
*
* #param state
* <br><br>
* 1. True = The animation will repeat once completed and keep on doing so.
* <br><br>
* 2. False = The animation will play only once.
*
*
*/
public void repeatAnimation(boolean repetition) {
this.repeatAnimation = repetition;
}
/**
* <b><i>public boolean isAnimationFinished()</i></b>
* <br>
* Since: API 1
* <br>
* <br>
* Retrieve if the animation has finished.
*
* #return
* If the animation has finished.
*
*/
public boolean isAnimationFinished() {
return animationCompleted;
}
/**
* <b><i>public boolean hasBeenStarted()</i></b>
* <br>
* Since: API 1
* <br>
* <br>
* Retrieve if the animation has started.
*
* #return
* If the animation has started.
*
*/
public boolean hasBeenStarted() {
return animationStarted;
}
/**
* <b><i>public void render()</i></b>
* <br>
* Since: API 1
* <br>
* <br>
* This method will render the animation (the current picture of the sheet).
*
*/
public void render() {
world.game.getGraphics().getCanvasGameScreen().drawBitmap(this.bitmap, this.getSrcRect(), this.getGameObjectPositionRect(), null);
}
/**
* <b><i>public void update()</i></b>
* <br>
* Since: API 1
* <br>
* <br>
* This method will update the animation.
*
*/
#Override
public void update() {
// Every update will advance to the next frame of the animation
// Set if animation has started
if(!animationStarted) {
animationStarted = true;
}
// Set the frame
srcRect.set(left, (bottom - this.heightOfSpriteInSheet), (left + this.lengthOfSpriteInSheet), bottom);
// Change the location, so the next time the frame is set, it will be set accordingly
left = left + this.lengthOfSpriteInSheet;
if(left == this.animationSheetLength && bottom == this.animationSheetHeight) {
if(repeatAnimation == true) {
left = 0;
bottom = 0;
}
else {
animationCompleted = true;
}
}
if(left == this.animationSheetLength) {
bottom = bottom + this.heightOfSpriteInSheet;
left = 0;
}
}
}
I hope this helps you and gets you started.

Categories

Resources