i started making a game that named GO at android (traditional japanese game).
refferer : GO
and i want to make a condition in each player gets a turn, so when the player get turn, the condition goes to see the position of the stone, if the stone position that placed it possible to obtain liberty, then run the conditions, otherwise not. here is the coding :
public void checkCondition(int position, View v){
final ImageButton[] arrPlayer1 = { //Board
g1 ,g2, g3, g4, g5, g6, g7, g8, g9,
g10, g11, g12, g13, g14, g15, g16, g17, g18,
g19, g20, g21, g22, g23, g24, g25, g26, g27,
g28, g29, g30, g31, g32, g33, g34, g35, g36,
g37, g38, g39, g40, g41, g42, g43, g44, g45,
g46, g47, g48, g49, g50, g51, g52, g53, g54,
g55, g56, g57, g58, g59, g60, g61, g62, g63,
g64, g65, g66, g67, g68, g69, g70, g71, g72,
g73, g74, g75, g76, g77, g78, g79, g80, g81};
int posT = position - 9; //Top Position
int posD = position + 9; //Down Position
int posL = position - 1; //Left Position
int posR = position + 1; //Right Position
ImageView BlackStone = (ImageView) findViewById(R.drawable.BlackStone);
if(v == arrPlayer1[position] && arrPlayer1[posT] != null){
if(arrPlayer1[posT] == BlackStone){
if(v == arrPlayer1[position] && arrPlayer1[posD] != null){
if(arrPlayer1[posD] == BlackStone){
if(v == arrPlayer1[position] && arrPlayer1[posR] != null){
if(arrPlayer1[posR] == BlackStone){
if(v == arrPlayer1[position] && arrPlayer1[posL] != null){
if(arrPlayer1[posL] == BlackStone){
ChangeTurn(v);
}else{
CheckLiberty(position, v);
}
}
}else{
CheckLiberty(position, v);
}
}
}else{
CheckLiberty(position, v);
}
}
}else{
CheckLiberty(position, v);
}
}
}
My logic is, I make a dynamic condition in this coding so wherever the player went turn, it would see the condition of the stone, ex : if player placed stone at G20, so the logic will see in G11, G19, G21, G29 or etc interconnected stone.
int posT = position - 9; //Top Position
int posD = position + 9; //Down Position
int posL = position - 1; //Left Position
int posR = position + 1; //Right Position
but it still error and the logcat give me error array out of bounds exception at the method (CheckCondition). so, what should I do ? any help is appreciated
First Change:
ImageView BlackStone = (ImageView) findViewById(R.drawable.BlackStone);
To
ImageView BlackStone = (ImageView) findViewById(R.id.IdOfImageview);
You need to find view of any component by its Id not its background as you are using findViewById.
Related
I am creating a reversi (othello) game on Java. Included below are my functions for when tiles need to flip to the left, right, below, or above the selected piece. For some reason, whenever a vertical flip is initiated, it ALWAYS works correctly. But, when a horizontal flip is initiated, sometimes it does nothing (when it should do something), or flips over blank tiles that are not supposed to be flipped. The gameboard is an 8 by 8 matrix using an extended JButton called BlankPiece. I will post that in addition to the functions. Can anyone suggest a more efficient / better way to run this game without bugs? Any help is greatly appreciated! If you need clarification, just ask.
public void checkFlipDown(BlankPiece temp)
{
for(int j = temp.getRow() - 1; j>=0; j--){
// j equals the square right above the clicked one, and it keeps going up until it hits the top of the board
if ((gameboard[j][temp.getCol()].pieceType() != 0) && (gameboard[j][temp.getCol()].pieceType() != temp.pieceType())){
//if the spot right above the clicked one is not black AND it is the other player's color,
continue;
// keep going with the block statement
}
if ((gameboard[j][temp.getCol()].pieceType() != 0) && (gameboard[j][temp.getCol()].pieceType() == temp.pieceType())){
// if the spot right above is not black AND it is the same player's color,
for(int i = temp.getRow(); i >= j; i--)
// i equals the row of the clicked spot, it goes until it finds J, where the other green / purple end piece is
{
// change the colors of all colors in the clicked color's column and rows in between the other border piece
gameboard[i][temp.getCol()].change(temp.pieceType());
}
}
else
{
// if no other border pieces exist, go out of the loop
break;
}
}
}
public void checkFlipUp(BlankPiece temp)
{
for(int j = temp.getRow() + 1; j<=7; j++){
// j equals the square right below the clicked one, and it keeps going down until it hits the bottom of the board
if ((gameboard[j][temp.getCol()].pieceType() != 0) && (gameboard[j][temp.getCol()].pieceType() != temp.pieceType())){
//if the spot right above the clicked one is not black AND it is the other player's color,
continue;
// keep going with the block statement 2,4 jj = 3,4,5,6,7
}
if ((gameboard[j][temp.getCol()].pieceType() != 0) && (gameboard[j][temp.getCol()].pieceType() == temp.pieceType())){
// if the spot right above is not black AND it is the same player's color,
for(int i = temp.getRow(); i <= j; i++)
// i equals the row of the clicked spot, it goes until it finds J, where the other green / purple end piece is
{
// change the colors of all colors in the clicked color's column and rows in between the other border piece
gameboard[i][temp.getCol()].change(temp.pieceType());
}
}
else
{
break;
}
}
}
public void checkFlipLeft(BlankPiece temp)
{
for(int j = temp.getCol() + 1; j<=7; j++){
// j equals the square right below the clicked one, and it keeps going down until it hits the bottom of the board
if ((gameboard[j][temp.getRow()].pieceType() != 0) && (gameboard[j][temp.getRow()].pieceType() != temp.pieceType())){
//if the spot right above the clicked one is not black AND it is the other player's color,
continue;
// keep going with the block statement 2,4 jj = 3,4,5,6,7
}
if ((gameboard[j][temp.getRow()].pieceType() != 0) && (gameboard[j][temp.getRow()].pieceType() == temp.pieceType())){
// if the spot right above is not black AND it is the same player's color,
for(int i = temp.getCol(); i <= j; i++)
// i equals the row of the clicked spot, it goes until it finds J, where the other green / purple end piece is
{
// change the colors of all colors in the clicked color's column and rows in between the other border piece
gameboard[temp.getRow()][i].change(temp.pieceType());
}
}
else
{
break;
}
}
}
public void checkFlipRight(BlankPiece temp)
{
for(int j = temp.getCol() - 1; j>=0; j--){
// j equals the square to the right of the clicked one, and it keeps going down until it hits the bottom of the board
if ((gameboard[j][temp.getRow()].pieceType() != 0) && (gameboard[j][temp.getRow()].pieceType() != temp.pieceType())){
//if the spot right above the clicked one is not black AND it is the other player's color,
continue;
// keep going with the block statement 2,4 jj = 3,4,5,6,7
}
if ((gameboard[j][temp.getRow()].pieceType() != 0) && (gameboard[j][temp.getRow()].pieceType() == temp.pieceType())){
// if the spot right above is not black AND it is the same player's color,
for(int i = temp.getCol(); i >= j; i--)
// i equals the row of the clicked spot, it goes until it finds J, where the other green / purple end piece is
{
// change the colors of all colors in the clicked color's column and rows in between the other border piece
gameboard[temp.getRow()][i].change(temp.pieceType());
}
}
else if (gameboard[j][temp.getRow()].pieceType() == 0)
{
break;
}
}
}
So those are my four functions (one for west, east, north, and south). BlankPiece is below:
import java.awt.Color;
import javax.swing.*;
public class BlankPiece extends JButton
{
private final ImageIcon bbutton = new ImageIcon("bbutton.png");
private final ImageIcon gbutton = new ImageIcon("gbutton.jpg");
private final ImageIcon pbutton = new ImageIcon("pbutton.png");
private int x;
private int y;
BlankPiece(int x, int y)
{
this.setBackground(Color.BLACK);
this.setIcon(bbutton);
this.x = x;
this.y = y;
}
public void setGreen()
{
this.setBackground(Color.BLACK);
this.setIcon(gbutton);
}
public void setPurple()
{
this.setBackground(Color.BLACK);
this.setIcon(pbutton);
}
public int getRow() {
// TODO Auto-generated method stub
return x;
}
public int getCol() {
return y;
}
public void resetImage(int count)
{
if (count % 2 == 0)
{
this.setIcon(gbutton);
}
else
{
this.setIcon(pbutton);
}
}
public boolean isSet()
{
String image = "" + this.getIcon();
if((image.equals("pbutton.png")) || (image.equals("gbutton.jpg")))
{
}
return false;
}
public int pieceType()
{
if(getIcon().equals(pbutton)) // purple
{
return -1;
}
else if(getIcon().equals(bbutton)) // blank
{
return 0;
}
else // green
{
return 1;
}
}
public void change(int i) {
if (i == -1)
{
setIcon(pbutton);
}
else if(i == 1)
{
setIcon(gbutton);
}
else
{
setIcon(bbutton);
}
}
}
The problem is not that any checkflip isn't called (they are all called with the same correct parameters), but something in checkFlipRight or CheckFlipLeft functions...
EDIT: full working example by request.
Make a folder with TWO files
One is called Reversi.java
and the other is BlankPiece.java
REVERSI.JAVA:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Reversi extends JPanel {
BlankPiece [][] gameboard = new BlankPiece[8][8];
JPanel toparea = new JPanel();
JPanel gamearea = new JPanel();
JPanel greenarea = new JPanel();
JPanel purplearea = new JPanel();
JPanel logo = new JPanel();
JLabel logoarea = new JLabel();
JLabel greenlogo = new JLabel();
JLabel purplelogo = new JLabel();
ImageIcon blackicon = new ImageIcon("bbutton.png");
ImageIcon icon = new ImageIcon("reversilogo.png");
ImageIcon dgreen = new ImageIcon("DarkGreen.png");
ImageIcon lgreen = new ImageIcon("LightGreen.png");
ImageIcon dpurple = new ImageIcon("DarkPurple.png");
ImageIcon lpurple = new ImageIcon("LightPurple.png");
int count = 0;
int jplus = 0;
public Reversi()
{
gamearea.setLayout(new GridLayout(8,8));
for (int row = 0; row < gameboard.length; row++)
{
for(int col = 0; col < gameboard.length; col++)
{
gameboard[row][col] = new BlankPiece(row, col);
gamearea.add(gameboard[row][col]);
gameboard[row][col].addActionListener(new ButtonListener());
}
}
logoarea.setPreferredSize(new Dimension(304,73));
toparea.setLayout(new BorderLayout());
this.setLayout(new BorderLayout());
toparea.setBackground(new Color(97,203,242));
gamearea.setBackground(new Color(83,35,215));
logo.setBackground(new Color(97,203,242));
logoarea.setIcon(icon);
greenlogo.setIcon(dgreen);
purplelogo.setIcon(lpurple);
toparea.add(greenlogo, BorderLayout.WEST);
toparea.add(purplelogo, BorderLayout.EAST);
toparea.add(logo, BorderLayout.CENTER);
logo.add(logoarea);
this.add(toparea, BorderLayout.NORTH);
this.add(gamearea, BorderLayout.CENTER);
gameboard[3][3].setGreen();
gameboard[3][4].setPurple();
gameboard[4][3].setPurple();
gameboard[4][4].setGreen();
}
private class ButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
BlankPiece temp = (BlankPiece)e.getSource(); // #1
int row = temp.getRow(); // #2
System.out.println(row);
int col = temp.getCol();
System.out.println(col);
temp.isSet();
// col and row are the column and row of blankpiece that was clicked
String image = "" + temp.getIcon();
if((image.equals("pbutton.png")) || (image.equals("gbutton.jpg")))
{
JOptionPane.showMessageDialog(null, "This spot is already occupied by " +
"a piece. Please pick an empty tile.");
}
else
{
temp.resetImage(count++);
System.out.println("About to check");
checkFlipDown(gameboard[row][col]);
checkFlipUp(gameboard[row][col]);
checkFlipLeft(gameboard[row][col]);
checkFlipRight(gameboard[row][col]);
}
if (count % 2 == 0)
{
greenlogo.setIcon(dgreen);
purplelogo.setIcon(lpurple);
}
else
{
greenlogo.setIcon(lgreen);
purplelogo.setIcon(dpurple);
}
}
}
public void checkFlipDown(BlankPiece temp)
{
for(int j = temp.getRow() - 1; j>=0; j--){
// j equals the square right above the clicked one, and it keeps going up until it hits the top of the board
if ((gameboard[j][temp.getCol()].pieceType() != 0) && (gameboard[j][temp.getCol()].pieceType() != temp.pieceType())){
//if the spot right above the clicked one is not black AND it is the other player's color,
continue;
// keep going with the block statement
}
if ((gameboard[j][temp.getCol()].pieceType() != 0) && (gameboard[j][temp.getCol()].pieceType() == temp.pieceType())){
// if the spot right above is not black AND it is the same player's color,
for(int i = temp.getRow(); i >= j; i--)
// i equals the row of the clicked spot, it goes until it finds J, where the other green / purple end piece is
{
// change the colors of all colors in the clicked color's column and rows in between the other border piece
gameboard[i][temp.getCol()].change(temp.pieceType());
}
}
else
{
// if no other border pieces exist, go out of the loop
break;
}
}
}
public void checkFlipUp(BlankPiece temp)
{
for(int j = temp.getRow() + 1; j<=7; j++){
// j equals the square right below the clicked one, and it keeps going down until it hits the bottom of the board
if ((gameboard[j][temp.getCol()].pieceType() != 0) && (gameboard[j][temp.getCol()].pieceType() != temp.pieceType())){
//if the spot right above the clicked one is not black AND it is the other player's color,
continue;
// keep going with the block statement 2,4 jj = 3,4,5,6,7
}
if ((gameboard[j][temp.getCol()].pieceType() != 0) && (gameboard[j][temp.getCol()].pieceType() == temp.pieceType())){
// if the spot right above is not black AND it is the same player's color,
for(int i = temp.getRow(); i <= j; i++)
// i equals the row of the clicked spot, it goes until it finds J, where the other green / purple end piece is
{
// change the colors of all colors in the clicked color's column and rows in between the other border piece
gameboard[i][temp.getCol()].change(temp.pieceType());
}
}
else
{
break;
}
}
}
public void checkFlipLeft(BlankPiece temp)
{
for(int j = temp.getCol() + 1; j<=7; j++){
// j equals the square right below the clicked one, and it keeps going down until it hits the bottom of the board
if ((gameboard[j][temp.getRow()].pieceType() != 0) && (gameboard[j][temp.getRow()].pieceType() != temp.pieceType())){
//if the spot right above the clicked one is not black AND it is the other player's color,
continue;
// keep going with the block statement 2,4 jj = 3,4,5,6,7
}
if ((gameboard[j][temp.getRow()].pieceType() != 0) && (gameboard[j][temp.getRow()].pieceType() == temp.pieceType())){
// if the spot right above is not black AND it is the same player's color,
for(int i = temp.getCol(); i <= j; i++)
// i equals the row of the clicked spot, it goes until it finds J, where the other green / purple end piece is
{
// change the colors of all colors in the clicked color's column and rows in between the other border piece
gameboard[temp.getRow()][i].change(temp.pieceType());
}
}
else
{
break;
}
}
}
public void checkFlipRight(BlankPiece temp)
{
for(int j = temp.getCol() - 1; j>=0; j--){
// j equals the square to the right of the clicked one, and it keeps going down until it hits the bottom of the board
if ((gameboard[j][temp.getRow()].pieceType() != 0) && (gameboard[j][temp.getRow()].pieceType() != temp.pieceType())){
//if the spot right above the clicked one is not black AND it is the other player's color,
continue;
// keep going with the block statement 2,4 jj = 3,4,5,6,7
}
if ((gameboard[j][temp.getRow()].pieceType() != 0) && (gameboard[j][temp.getRow()].pieceType() == temp.pieceType())){
// if the spot right above is not black AND it is the same player's color,
for(int i = temp.getCol(); i >= j; i--)
// i equals the row of the clicked spot, it goes until it finds J, where the other green / purple end piece is
{
// change the colors of all colors in the clicked color's column and rows in between the other border piece
gameboard[temp.getRow()][i].change(temp.pieceType());
}
}
else if (gameboard[j][temp.getRow()].pieceType() == 0)
{
break;
}
}
}
}
BLANKPIECE.JAVA
import java.awt.Color;
import javax.swing.*;
public class BlankPiece extends JButton
{
private final ImageIcon bbutton = new ImageIcon("bbutton.png");
private final ImageIcon gbutton = new ImageIcon("gbutton.jpg");
private final ImageIcon pbutton = new ImageIcon("pbutton.png");
private int x;
private int y;
BlankPiece(int x, int y)
{
this.setBackground(Color.BLACK);
this.setIcon(bbutton);
this.x = x;
this.y = y;
}
public void setGreen()
{
this.setBackground(Color.BLACK);
this.setIcon(gbutton);
}
public void setPurple()
{
this.setBackground(Color.BLACK);
this.setIcon(pbutton);
}
public int getRow() {
// TODO Auto-generated method stub
return x;
}
public int getCol() {
return y;
}
public void resetImage(int count)
{
if (count % 2 == 0)
{
this.setIcon(gbutton);
}
else
{
this.setIcon(pbutton);
}
}
public boolean isSet()
{
String image = "" + this.getIcon();
if((image.equals("pbutton.png")) || (image.equals("gbutton.jpg")))
{
}
return false;
}
public int pieceType()
{
if(getIcon().equals(pbutton)) // purple
{
return -1;
}
else if(getIcon().equals(bbutton)) // blank
{
return 0;
}
else // green
{
return 1;
}
}
public void change(int i) {
if (i == -1)
{
setIcon(pbutton);
}
else if(i == 1)
{
setIcon(gbutton);
}
else
{
setIcon(bbutton);
}
}
}
Unfortunately I wasn't able to run your code since it uses images and without them it is impossible to tell what part is working or not. However I have a suggestion for a different approach which I think it would help you to solve the problem (please pay attention to the ideas described and not necessarily to the code).
Problem description: (as I understand it) When a player puts a piece of one color on the board (there are two colors in the game, one for each player), the system needs to traverse all blocks along all directions (there are 8 of them) until it encounters one of the following:
a piece of the same color: in this case all in-between pieces of opposite color are flipped to the player's color (i.e. they are "captured")
a blank piece/block: in this case no color flipping occurs
an edge of the board: again no flipping occurs.
The above description implies that the problem can be divided further to smaller problems that we need to solve first.
Problems to solve:
how can we identify "directions"
how can we traverse along a direction considering each time the next block
how can we identify pieces that are supposed to be captured
how can we identify the edge of the board
Your approach tries to solve all the above problems together. This makes it complicated. Furthermore the same work is repeated for different directions which does not need to be the case. As per the above description, no special action is required for a specific direction. If we solve the problem for a single direction then it should be solved for all.
Suggested approach: Below you can find the algorithm to use (pseudo-code) to find all the pieces to capture. Note how the piece itself tries to solve the problem and propagates the work to the next piece until all captured pieces are found. This way you don't solve the problem yourself. You just describe it correctly to your objects. I have put comments inline to explain what each class is supposed to be. I hope it is clear and useful to you.
// Convenient class to hold together a row and a column pair
public class Index { ... }
// Checks if an index falls out of board edges
public static boolean isValid(Index index) {...}
// Holds the array of pieces. Has method to get a piece by index
public class Board { ... }
public enum ColorType { BLANK, WHITE, BLACK; } // the types of a Piece
// The possible directions to traverse
public enum Direction {
UP_LEFT, UP, UP_RIGHT, RIGHT, BOTTOM_RIGHT, BOTTOM, BOTTOM_LEFT, LEFT;
// given an index it returns the next index along the same direction
public Index next(Index index) {
switch (this) {
case UP_LEFT:
return new Index(index.row() - 1, index.column() - 1);
case BOTTOM:
return new Index(index.row() + 1, index.column());
... // similar for the rest of cases
}
}
}
public class Piece {
private Board board;
private ColorType color = ColorType.BLANK;
private Index index;
....
// Should be called privately when the piece is put on the board and from BLANK becomes WHITE or BLACK
private void checkCaptures() {
Direction[] directions = Direction.values();
for (Direction direction : directions) {
// get next piece's index along the direction
Index nextIndex = direction.next(this.index);
if ( isValid(nextIndex) ) { // if the index is not valid (i.e. edge of the board) ignore it
// get next piece in the same direction
Piece piece = board.getPiece(nextIndex);
// find all pieces that should be captured in this direction
List<Piece> candidatesToCapture = new ArrayList<Piece>();
piece.findCaptureCandidates(candidatesToCapture, this.color, direction);
for (Piece candidate : candidatesToCapture) {
// flip the color (WHITE to BLACK and vice-versa)
candidate.capture();
}
}
}
}
private void findCaptureCandidates(List<Piece> captured, ColorType firstColor, Direction d) {
Index next = d.next(this.index);
if (this.color == firstColor) {
// This piece has the same color with the first one.
// No need to search further for this direction. All pieces collected in the list
// between the first one and this one, have opposite color and should be captured.
} else if (this.color == ColorType.BLANK) {
// found a blank piece. Stop the search and clear any captured pieces found so far
captured.clear();
} else {
// this piece has the opposite color of the first
if ( isValid(next) ) {
// this is not the last piece in this direction.
// Since it has a flipped color it is a candidate for capturing
captured.add(this);
// ask the next piece recursively to also check itself
Piece piece = board.getPiece(next);
piece.findCaptureCandidates(captured, firstColor, d);
} else {
// next index is not valid i.e. we have reached board edge.
// Stop the search and clear any captured pieces found so far
captured.clear();
}
}
}
}
onTouch method of my View:
public boolean onTouch(View view, MotionEvent event) {
Log.d("Touch", "Touch");
int mNewX = (int) Math.floor(event.getX());
int mNewY = (int) Math.floor(event.getY());
boolean isPositionFree = isPositionFree(mNewX, mNewY);
if (!isPositionFree) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
int i = 0;
for (Point point : points) {
if (point.spotted) {
points.remove(i);
invalidate();
break;
}
i++;
}
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
int i = 0;
for (Point point : points) {
if (point.spotted) {
points.remove(i);
Point p = new Point(mNewX, mNewY, point.TYPE);
points.add(i, p);
invalidate();
break;
}
i++;
}
}
}
}
There are multiple items in the canvas. Their positions are saved in "points". They get drawn to the canvas in a onDraw method via the position of those "points", means Point point.x and point.y.
Now, when I click an item (a point on the canvas), it should disappear.
Then, when the MotionEvent.ACTION_MOVE is true, I want to move the point, depending on the event.getX() and event.getY().
the method "isPositionFree(newX,newY)" checks if the point.x and point.y equals newX and newY (the position I just touched on the screen).
if the position is taken (means, there is an item where I just clicked), I'll get to the motionevent-IFs.
Here comes the problem:
my code removes the point before I can actually move it. I didnt find any way I could fix this problem for hours. :/ I find it difficult, since the onTouch is always called from the beginning, means ACTION_DOWN and ACTION_MOVE never take place at the same time.
Do you know any fix for this?
thanks in advance, Sebastian
Got it to work!
For everbody having the same issue, feel free to take this sample code as a help :)
Stuff I declared in the beginning
Vector<Point> points = new Vector<Point>();
Bitmap[] monsterTypes = new Bitmap[3];
Vector<Integer> distanceMovedX = new Vector<Integer>();
Vector<Integer> distanceMovedY = new Vector<Integer>();
int mNewX = -1;
int mNewY = -1;
OnTouch-Method
public boolean onTouch(View view, MotionEvent event) {
mNewX = (int) FloatMath.floor(event.getX());
mNewY = (int) FloatMath.floor(event.getY());
boolean touchedPoint = touchedPoint(mNewX, mNewY);
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
distanceMovedX.add(mNewX);
distanceMovedY.add(mNewY);
break;
case MotionEvent.ACTION_UP:
isMoveEvent = isMoveEvent();
if (isMoveEvent) {
for (Point point : points) {
if (point.spotted) {
// Your code
}
i++;
}
} else {
if (touchedPoint) {
for (Point point : points) {
if (point.spotted) {
// Your code
}
}
}
}
distanceMovedX.clear();
distanceMovedY.clear();
return true;
}
return true;
}
touchedPoint-Method
public boolean touchedPoint(int mNewX, int mNewY) {
boolean touchedPoint = false;
int height = 0;
int width = 0;
for (Point point : points) {
height = monsterTypes[point.TYPE - 1].getHeight();
width = monsterTypes[point.TYPE - 1].getWidth();
if (point.x + width < mNewX || point.x > mNewX + width
|| point.y + height < mNewY || point.y > mNewY + height) {
touchedPoint = false;
point.spotted = false;
} else {
touchedPoint = true;
point.spotted = true;
return touchedPoint;
}
}
return touchedPoint;
}
isMoveEvent-Method
public boolean isMoveEvent() {
boolean isMoveEvent = false;
boolean isMoveEventX = false;
boolean isMoveEventY = false;
for (int i = 0; i <= (points.size() -1); i++) {
Log.d("point", "for loop entered");
if (!distanceMovedY.isEmpty()) {
Log.d("point.x", "distanceMovedY is not empty");
int dMY = distanceMovedY.get(distanceMovedY.size() - 1) - distanceMovedY.get(0);
if ((dMY > 50 || dMY <= 0) && dMY != 0) {
Log.d("point.y", "is move event");
Log.d("point.y", "dMY: " + dMY);
isMoveEventY = true;
} else {
Log.d("point.x", "is no move event");
Log.d("point.x", "dMY: " + dMY);
isMoveEvent = false;
return isMoveEvent;
}
}
if (!distanceMovedX.isEmpty()) {
Log.d("point.x", "distanceMovedX is not empty");
int dMX = distanceMovedX.get(distanceMovedX.size() - 1) - distanceMovedX.get(0);
if (dMX <= 50 && dMX >= -50 && dMX != 0) {
Log.d("point.x", "is move event");
Log.d("point.x", "dMX: " + dMX);
isMoveEventX = true;
} else {
Log.d("point.x", "is no move event");
Log.d("point.x", "dMX: " + dMX);
isMoveEvent = false;
return isMoveEvent;
}
}
if (isMoveEventX && isMoveEventY) {
Log.d("point", "is move event");
isMoveEvent = true;
return isMoveEvent;
}
}
Log.d("point", "is no move event");
return isMoveEvent;
}
Point Class
class Point {
int x, y;
int TYPE;
boolean spotted;
boolean halfSpotted;
public Point() {
}
public Point(int x, int y, int t) {
this.x = x;
this.y = y;
this.TYPE = t;
}
#Override
public String toString() {
return x + ", " + y;
}
}
EXPLANATION:
Point:
we got a class Point. All those points declared in the Vector are x- and y-coordinates on your canvas. They help us to check the position we clicked.
monsterTypes:
its the different graphics I use. If you only use one graphic that you draw onto the canvas, change it to your needs
distanceMovedX & Y:
saves all the X and Y Coordinates of your "ACTION_MOVE". From pos 0 (the first touched point) to pos Z (the last touched point, where ACTION_UP occurs). Though its not the original X and Y position. Its the result of posZ - pos0.
With these values you can determine, after what distance travelled you wanna invoke "onMove" and BELOW which distance "onClick" should be invoked.
mNewX & Y:
the currently position of your onTouch-Method. Everytime you move your finger, newX & Y become overwritten.
Methods:
onTouch():
First, we'll overwrite mNewX and Y to the current position touched. Then we check if we clicked on an existing spot (in my case some 48px*48px area)
Next we record the taken distance in ACTION_MOVE.
After that we continue with ACTION_UP, where we check if we just performed some moveEvent or clickEvent.
touchedPoint():
calculates if we touched some existing point on the canvas, or not. returns true or false
isMoveEvent():
checks if we moved the certain distance. in my case i wanna move down, 50px or more. though im not allowed to move sidewards -50px or +50px. If its NOT a move event, the last spot touched still has to be on the in the giving distance (in my case in the 48px*48px range of the point).
Thats it. took me days to only figure out that option ;/ ashamed of that ... though I coded it pretty fast, what makes me feeling better again :D
I'm just suggesting some walk-around :
Instead of removing the point when clicking it,
make a privata Point in your class, where you currently remove the point, just set your new Variable Point to the Point you would remove...
Then, after using it in action or action move, the last place you would use it,
check if your private variable is not null, if so, remove it, then, set it to null.
try using a switch case statement:
switch finger_action:
case(ACTION_MOVE)
{
//move code
return false;
}
case(ACTION_TOUCH)
{
//dissappear code
return false;
}
note the up above code is pseudo code, but what it does it checks to see if you are moving the dot before just touching it. this way the dot will attempt a move first instead of being removed first.
thanks,
Alex
I'm trying to move sprites to stop the frames in center(or move them to certain x position) when right or left pressed on screen. There are 3 sprites created using box.java in the view, placed one after another with padding, stored in arraylist.
The problem: No smooth movement and doesn't stop in the center of each frames after movement has begun, sometimes all boxes are moving on top of each others, padding is totally lost. Please let me know what I'm doing wrong, thanks a lot!
//BEGINING OF BOX.JAVA >> The problem is in this class!
//This goes in Update();
private void boxMove()
{
int get_moved_pos = getMovedPos(); //get moved pos
int sprite_size = view.getSpriteSize(); //get sprite arraylist size
currentDirection = view.getDirection(); //get direction "left" or "right" from view
if(currentDirection == "right" && isMoving == false)
{
setSpriteMovedNext();
}else
if(currentDirection == "left" && isMoving == false)
{
setSpriteMovedPrev();
}
if(currentDirection != lastDirection)
{
lastDirection = currentDirection;
//MOVE RIGHT
if(currentDirection == "right" && get_moved_pos > 0) //move left and make sure that moved pos isn't overlapping / or moving to empty space
{
//Animate left until it reaches the new x position
if(x > get_new_pos_left)
{
x -= pSpeedX;
}
Log.d("RIGHT","POS: " + get_moved_pos);
}else
//MOVE LEFT
if(currentDirection == "left" && get_moved_pos < sprite_size-1) //move left and make sure that moved pos isn't overlapping / or moving to empty space
{
//Animate right until it reaches the new x position
if(x < get_new_pos_right)
{
x += pSpeedX;
}
}
}
}
//Call when screen is touched (in View.java), to set a new position to move to.
public void resetMoving()
{
isMoving = false;
this.lastDirection = "";
Log.d("RESET", "MOVING RESET");
}
public int getMovedPos()
{
return this.smoved_pos;
}
private void setSpriteMovedNext()
{
int get_max_moved = getMovedPos();
int s_size = view.getSpriteSize();
if (isMoving == false) //take a break between movements
{
if(get_max_moved < s_size-1)
{
Log.d("NEXT", "CALLED");
this.get_new_pos_right = x + view.getNextPosX(); //current x and next stop position
this.smoved_pos += 1;
this.isMoving = true; //set to avoid double touch
Log.d("NEXT", "X POS SET: " + get_max_moved);
}
}
}
private void setSpriteMovedPrev()
{
int get_max_moved = getMovedPos();
if (isMoving == false) //take a break between movements
{
if(get_max_moved > 0)
{
Log.d("PREV", "CALLED");
this.get_new_pos_left = x - view.getNextPosX(); //get current x pos and prev stop position
this.smoved_pos -= 1; //to limit the movements
this.isMoving = true; //set to avoid double touch
Log.d("PREV", "X POS SET: " + get_max_moved);
}
}
}
//END OF BOX.JAVA
//VIEW
//Add boxes
public void addBox()
{
int TOTAL_BOXES = 3;
int padding_left = 200;
int padding_tmp = this.getWidth()/2;
box.clear(); //clear old
//Box 1
box.add(new Boxes(box, this, "box1",
padding_tmp,
this.getHeight()/2,
boxSpriteImage, 1, 2, 0, 0));
padding_tmp += boxSpriteImage.getWidth()/TOTAL_BOXES + padding_left;
//Box 2
box.add(new Boxes(box, this, "box2",
padding_tmp,
this.getHeight()/2,
boxSpriteImage, 1, 2, 1, 1));
padding_tmp += boxSpriteImage.getWidth()/TOTAL_BOXES + padding_left;
//Box 3
box.add(new Boxes(box, this, "box3",
padding_tmp,
this.getHeight()/2,
boxSpriteImage, 1, 2, 2, 1));
}
public boolean onTouchEvent(MotionEvent event){
if (System.currentTimeMillis() - lastClick > 100){
lastClick = System.currentTimeMillis();
float x = event.getX();
float y = event.getY();
synchronized (getHolder())
{
if(isBoxWindow() == true)
{
if(x >= this.getWidth()/2)
{
Direction = "right";
}else
{
Direction = "left";
}
}
}
}
//called in box.java to get next x pos to move
public float getNextPosX()
{
int PADDING = 200; //padding between frames
next_pos_x = boxSprite.getWidth()/TOTAL_COLUMNS + PADDING;
return next_pos_x;
}
I think your error is in the if statements, where you compare currentDirection and lastDirection (I'm assuming that lastDirection is a String) with other Strings using the == operator. The == almost operator never works when you want to compare Objects for equality. You should use the equals() method.
For eg.
if(currentDirection != lastDirection)
should be written as:
if(!currentDirection.equals(lastDirection)
Make such changes in your code(They are needed at many places!) and I think your problem should be solved.
A good debugging practice would be logging data about your app, from each of the if blocks, to see if each of them is executed. You could have found out if your if statements are being executed.
EDIT: Why have you put this code?
if (System.currentTimeMillis() - lastClick > 100)
This means onTouchEvents are only interpreted after 100ms. remove it and check, probably that's what is causing the problem.
Alrite, decided to use onFling() method and call via View instead of adding the animations separately into the class itself, works really well when called box.get(i).update() in a loop of all added boxes, all of them animated equally. Thanks udiboy.
I am working on an Android game similar to the Rush Hour/Traffic Jam/Blocked puzzle games. The board is a square containing rectangular pieces. Long pieces may only move horizontally, and tall pieces may only move vertically. The object is to free the red piece and move it out of the board. This game is only my second ever programming project in any language, so any tips or best practices would be appreciated along with your answer.
I have a class for the game pieces called Pieces that describes how they are sized and drawn to the screen, gives them drag-and-drop functionality, and detects and handles collisions.
I then have an activity class called GameView which creates my layout and creates Pieces objects to add to a RelativeLayout called Board. I have considered making Board its own class, but haven't needed to yet.
Here's what my work in progress looks like:
My Question:
Most of this works perfectly fine except for my collision handling. It seems to be detecting collisions well but instead of pushing the pieces outside of each other when there is a collision, it frantically snaps back and forth between (what seems to be) where the piece is being dragged to and where it should be. It looks something like this:
Another oddity: when the dragged piece collides with a piece to its left, the collision handling seems to work perfectly. Only piece above, below, and to the right cause problems.
Here's the collision code:
#Override
public boolean onTouchEvent(MotionEvent event){
float eventX = event.getX();
float eventY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//check if touch is on piece
if (eventX > x && eventX < (x+width) && eventY > y && eventY < (y+height)){
initialX=x;
initialY=y;
break;
}else{
return false;
}
case MotionEvent.ACTION_MOVE:
//determine if piece should move horizontally or vertically
if(width>height){
for (Pieces piece : aPieces) {
//if object equals itself in array, skip to next object
if(piece==this){
continue;
}
//if next to another piece,
//do not allow to move any further towards said piece
if(eventX<x&&(x==piece.right+1)){
return false;
}else if(eventX>x&&(x==piece.x-width-1)){
return false;
}
//move normally if no collision
//if collision, do not allow to move through other piece
if(collides(this,piece)==false){
x = (eventX-(width/2));
}else if(collidesLeft(this,piece)){
x = piece.right+1;
break;
}else if(collidesRight(this,piece)){
x = piece.x-width-1;
break;
}
}
break;
}else if(height>width){
for (Pieces piece : aPieces) {
if(piece==this){
continue;
}else if(collides(this,piece)==false){
y = (eventY-(height/2));
}else if(collidesUp(this,piece)){
y = piece.bottom+1;
break;
}else if(collidesDown(this,piece)){
y = piece.y-height-1;
break;
}
}
}
invalidate();
break;
case MotionEvent.ACTION_UP:
// end move
if(this.moves()){
GameView.counter++;
}
initialX=x;
initialY=y;
break;
}
// parse puzzle
invalidate();
return true;
}
This takes place during onDraw:
width = sizedBitmap.getWidth();
height = sizedBitmap.getHeight();
right = x+width;
bottom = y+height;
My collision-test methods look like this with different math for each:
private boolean collidesDown(Pieces piece1, Pieces piece2){
float x1 = piece1.x;
float y1 = piece1.y;
float r1 = piece1.right;
float b1 = piece1.bottom;
float x2 = piece2.x;
float y2 = piece2.y;
float r2 = piece2.right;
float b2 = piece2.bottom;
if((y1<y2)&&(y1<b2)&&(b1>=y2)&&(b1<b2)&&((x1>=x2&&x1<=r2)||(r1>=x2&&x1<=r2))){
return true;
}else{
return false;
}
}
private boolean collides(Pieces piece1, Pieces piece2){
if(collidesLeft(piece1,piece2)){
return true;
}else if(collidesRight(piece1,piece2)){
return true;
}else if(collidesUp(piece1,piece2)){
return true;
}else if(collidesDown(piece1,piece2)){
return true;
}else{
return false;
}
}
As a second question, should my x,y,right,bottom,width,height variables be ints instead of floats like they are now?
Also, any suggestions on how to implement things better would be greatly appreciated, even if not relevant to the question! Thanks in advance for the help and for sitting through such a long question!
Update:
I have gotten it working almost perfectly with the following code (this doesn't include the code for vertical pieces):
#Override
public boolean onTouchEvent(MotionEvent event){
float eventX = event.getX();
float eventY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//check if touch is on piece
if (eventX > x && eventX < (x+width) && eventY > y && eventY < (y+height)){
initialX=x;
initialY=y;
break;
}else{
return false;
}
case MotionEvent.ACTION_MOVE:
//determine if piece should move horizontally or vertically
if(width>height){
for (Pieces piece : aPieces) {
//if object equals itself in array, skip to next object
if(piece==this){
continue;
}
//check if there the possibility for a horizontal collision
if(this.isAllignedHorizontallyWith(piece)){
//check for and handle collisions while moving left
if(this.isRightOf(piece)){
if(eventX>piece.right+(width/2)){
x = (int)(eventX-(width/2)); //move normally
}else{
x = piece.right+1;
}
}
//check for and handle collisions while moving right
if(this.isLeftOf(piece)){
if(eventX<piece.x-(width/2)){
x = (int)(eventX-(width/2));
}else{
x = piece.x-width-1;
}
}
break;
}else{
x = (int)(eventX-(width/2));
}
The only problem with this code is that it only detects collisions between the moving piece and one other (with preference to one on the left). If there is a piece to collide with on the left and another on the right, it will only detect collisions with the one on the left. I think this is because once it finds a possible collision, it handles it without finishing looping through the array holding all the pieces. How do I get it to check for multiple possible collisions at the same time?
My best guess is that the dragged piece is dragged into the other piece, then moved back so it is no longer colliding, then dragged into the other piece again. At least that is what I would expect if collision response happens after drawing.
On a side note, the following code makes me wonder a bit:
//if next to another piece,
//do not allow to move any further towards said piece
if(eventX<x&&(x==piece.right+1)){
return false;
}else if(eventX>x&&(x==piece.x-width-1)){
return false;
}
Checking for equality (==) on floats is generally a very bad idea, see zillions of "floating point precision" topics. Alternative a) use ints instead of floats. b) use ranged comparisions (>=, etc.). Don't use (a) though, there are many drawbacks with tiny (time) steps and such.
Try using the same approach as with the touch detection instead:
//check if touch is on piece
if (eventX > x && eventX < (x+width) && eventY > y && eventY < (y+height))
You should be able to do this more simply :)
Note that I made some assumptions on how you store the direction of movement, which you may have to adjust to your likings.
Also note that I treat piece1 as the moving piece we are concerned with, and piece2 simply as an object it collides with. So piece1 is repositioned, piece2 is not.
// Horizontal:
if( piece1.isMovingLeft )
piece1.x += Math.max( 0, piece2.right - piece1.x );
else if( piece1.isMovingRight )
piece1.x -= Math.max( 0, piece1.right - piece2.x );
// Vertical:
if( piece1.isMovingUp )
piece1.y -= Math.max( 0, piece2.bottom - piece1.y );
else if( piece1.isMovingDown )
piece1.y += Math.max( 0, piece1.bottom - piece2.y )
What I do here is as follows:
If the piece is moving in a certain direction, we move it back (a little bit) in the opposite direction to compensate for (possible) collision. We need to move it back by exactly the amount of overlapping pixels.
The amount of overlap, when moving left, for instance, is the right side of the second object minus the left side of the first object. (Negative means no overlap.)
The Math.max( 0, overlap ) ensures that said negative values become 0, i.e. no collision leads to no compensation.
The compensation is then applied in the direction opposite of movement, effectively taking piece1 out of piece2. (You can then choose to invert its movement direction or respond in any further way.)
You can apply this simple routine to every possible combination of two pieces, and they will no longer penetrate.
I hope this helps you out!
In reply to your second question:
The only problem with this code is that it only detects collisions between the moving piece and one other (with preference to one on the left). If there is a piece to collide with on the left and another on the right, it will only detect collisions with the one on the left.
There is a break statement within your loop - specifically, in the left collision check. ;)
I made a few changes and, so far, it has been working perfectly. Here is my new code:
case MotionEvent.ACTION_MOVE:
//determine if piece should move horizontally or vertically
if(width>height){
for (Pieces piece : aPieces) {
//if object equals itself in array, skip to next object
if(piece==this){
continue;
}
//check if there the possibility for a horizontal collision
if(this.isAllignedHorizontallyWith(piece)){
//check for and handle collisions while moving left
if(this.isRightOf(piece)){
if(eventX>piece.right+(width/2)){
x = (int)(eventX-(width/2)); //move normally
continue;
}else{
x = piece.right+1;
}
}else if(this.isLeftOf(piece)){ //check for and handle collisions while moving right
if(eventX<piece.x-(width/2)){
x = (int)(eventX-(width/2));
continue;
}else{
x = piece.x-width-1;
}
}else{
continue;
}
break;
}else{
x = (int)(eventX-(width/2));
}
}
}
if(height>width){
for (Pieces piece : aPieces) {
//if object equals itself in array, skip to next object
if(piece==this){
continue;
}
//check if there the possibility for a vertical collision
if(this.isAllignedVerticallyWith(piece)){
//check for and handle collisions while moving up
if(this.isBelow(piece)){
if(eventY>piece.bottom+(height/2)){
y = (int)(eventY-(height/2)); //move normally
continue;
}else{
y = piece.bottom+1;
}
}else if(this.isAbove(piece)){ //check for and handle collisions while moving down
if(eventY<piece.y-(height/2)){
y = (int)(eventY-(height/2));
continue;
}else{
y = piece.y-height-1;
}
}else{
continue;
}
break;
}else{
y = (int)(eventY-(height/2));
}
}
}
invalidate();
break;
And these are the methods I use:
private boolean isLeftOf(Pieces piece) {
int r1 = this.right;
int x2 = piece.initialX;
boolean bool = false;
if (r1<=x2){
for(Pieces piece2: aPieces){
if (piece2==piece || piece2==this){
continue;
}
if (this.isAllignedHorizontallyWith(piece2) && r1<=piece2.initialX){
if (piece.x>piece2.x){
bool = false;
break;
}else{
bool = true;
continue;
}
}else{
bool = true;
}
}
}else{
bool = false;
}
return bool;
}
private boolean isRightOf(Pieces piece) {
//True means that "this" is right of "piece" and "piece" is farther right than other possible pieces
int x1 = this.initialX;
int r2 = piece.right;
boolean bool = false;
if (x1>=r2){
for(Pieces piece2: aPieces){
if (piece2==piece || piece2==this){
continue;
}
if (this.isAllignedHorizontallyWith(piece2) && x1>=piece2.right){
if (piece.x<piece2.x){
bool = false;
break;
}else{
bool = true;
continue;
}
}else{
bool = true;
}
}
}else{
bool = false;
}
return bool;
}
private boolean isBelow(Pieces piece){
int y1 = this.initialY;
int b2 = piece.bottom;
boolean bool = false;
if (y1>=b2){
for(Pieces piece2: aPieces){
if (piece2==piece || piece2==this){
continue;
}
if (this.isAllignedVerticallyWith(piece2) && y1>=piece2.bottom){
if (piece.y<piece2.y){
bool = false;
break;
}else{
bool = true;
continue;
}
}else{
bool = true;
}
}
}else{
bool = false;
}
return bool;
}
private boolean isAbove(Pieces piece){
int y2 = piece.initialY;
int b1 = this.bottom;
boolean bool = false;
if (b1<=y2){
for(Pieces piece2: aPieces){
if (piece2==piece || piece2==this){
continue;
}
if (this.isAllignedVerticallyWith(piece2) && b1<=piece2.y){
if (piece.y>piece2.y){
bool = false;
break;
}else{
bool = true;
continue;
}
}else{
bool = true;
}
}
}else{
bool = false;
}
return bool;
}
private boolean isAllignedHorizontallyWith(Pieces piece) {
int y1 = this.y;
int b1 = this.bottom;
int y2 = piece.y;
int b2 = piece.bottom;
if((y1>=y2&&y1<=b2)||(b1>=y2&&b1<=b2)){
return true;
}else{
return false;
}
}
private boolean isAllignedVerticallyWith(Pieces piece) {
int x1 = this.x;
int r1 = this.right;
int x2 = piece.x;
int r2 = piece.right;
if((x1>=x2&&x1<=r2)||(r1>=x2&&r1<=r2)){
return true;
}else{
return false;
}
}
This could be commented better and probably done much simpler, but I am leaving it here for reference.
Nothing just get the your imageviews Left,right,top,bottom, and intersect with current x and y and find this solution more about this go to this link its also help i hop you got a right answer on this link
/technical/game-programming/collision-detection-algorithm-r754">http://www.gamedev.net/page/resources//technical/game-programming/collision-detection-algorithm-r754
I'm trying to create a word jumble game where you drag a letter right or left in the jumbled word and the letters swap. What is the best way to reorder items in a RelativeLayout programmatically so when the letter is dragged left the letters that the tile passes are positioned to the right of the dragged letter.
I've tried something like this as a basic test.
public static void moveTile(Tile tile, int x, RelativeLayout parent) {
if (x < tile.getWidth()) {
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.LEFT_OF, tile.getId() - 1);
tile.setLayoutParams(params);
RelativeLayout.LayoutParams p = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
p.addRule(RelativeLayout.RIGHT_OF, tile.getId());
Tile t = (Tile) parent.findViewById(tile.getId() - 1);
t.setLayoutParams(p);
}
parent.invalidate();
}
But this causes the app to crash with an error about "Circular dependancies cannot exist in a RelativeLayout" which I understand but I'm just not sure what other way to do this.
Any help will be much appreciated.
Yes, this error means that you must not have an object1 be toRightOf object2 and object2 toLeftOf object 1
I think in your case you should not use toRightOf and toLeftOf to position your views but try to use just margin left and margin top setting for all of them. In this way your child views would be independed of each other and you can move them around by changing their margins.
I ended up using a LinearLayout and just removing the tile before or after and replacing it with the currently selected tile something like this.
public static void moveTile(Tile tile, int x, LinearLayout parent) {
if (x < 0) {
int t = Math.abs(x) / tile.getWidth() + 1;
if (tile.getId() - t >= 0) {
Tile new_tile = (Tile) parent.findViewById(tile.getId() - t);
parent.removeViewAt(new_tile.getId());
parent.addView(new_tile, tile.getId());
int id = tile.getId();
tile.setId(new_tile.getId());
new_tile.setId(id);
}
} else if (x > tile.getWidth()) {
int t = x / tile.getWidth();
if (tile.getId() + t < word.length()) {
Tile new_tile = (Tile) parent.findViewById(tile.getId() + t);
parent.removeViewAt(new_tile.getId());
parent.addView(new_tile, tile.getId());
int id = tile.getId();
tile.setId(new_tile.getId());
new_tile.setId(id);
}
}
}