I am creating a reversi game for my intro CS class.
I found an error in SearchN() that would cause it to give false playableN flags and created isSame() as a work around.
Now the game is crashing when I attempt a move.
I have the bug isolated to isPlayable() which causes the program to stop running without error message.
I thought it was because the program was searching out of bounds; however, when i run .isPlayable(0,0) it returns a NullPointerException (also something I don't quite know how to get rid of).
So it must be some error with handling un-played spaces.
Anyone have any thoughts?
/**
* a method to return the color of a tile
*#params x y tile coordinates
*/
public Color getColor(int x, int y){
try{
return buttons[x][y].getBackground();
}
catch(ArrayIndexOutOfBoundsException e){
return null;
}
}
/**
* a method to determine whether a tile has been played
*#params x y tile coordinates
*/
public boolean isPlayed(int x, int y){
if(this.isBlack(x,y) || this.isWhite(x,y)){
return true;
}else{
return false;
}
}
/**
* a method to determine whether a tile has a color opposite to a given color
*#params x y c tile coordinates and color to compare
*/
public boolean isOpposite(int x, int y, Color c){
if(this.isPlayed(x,y)){
return(!(this.getColor(x,y).equals(c)));
} else
return false; // this was giving the false playableN flag
}
/**
* a method to determine weather a tile has the same color as the one given
*#params x y c tile coordinates and color to compare
*/
public boolean isSame(int x, int y, Color c){
if(this.isPlayed(x,y)){
return(this.getColor(x,y).equals(c));
}else{
return false;
}
}
/**
* a method used to check tiles north of an attempted play to verify legal moves
*#params x y c tile coordinates and comparing color
*/
public void searchN(int x, int y, int increment, Color c){
if(increment>1 && (this.isSame(x-increment,y, c))){
playableN = true;
leadN = false;
} else {
if(this.isOpposite(x-increment,y,c)){
leadN=true;
}
}
}
/**
* a method used to determine if a tile is playable
*#params x y tile coordinates
*/
public boolean isPlayable(int x, int y){
this.searchN(x,y,1,turnColor);
// search 7 other directions
while(leadN||leadNE||leadE||leadSE||leadS||leadSW||leadW||leadNW){
int i = 2;
if(leadN)
this.searchN(x,y,i,turnColor);
// search 7 other directions
i++;
}
if(playableN||playableNE||playableE||playableSE||playableS||playableSW||playableW||playableNW)
return true;
else
return false;
}
** all tiles are black, white or the default tile color (green) and in a 2D array of JButtons displayed in gridLayout().
I see two ways that a NullPointerException could be happening:
You are getting an ArrayIndexOutOfBoundsException in getColor. In that case you are catching the exception and returning null.
or
getBackground is returning null.
In either case getColor will return null, which causes a NullPointerException to be thrown when you call .equals in isOpposite or isSame.
You should check the result of getColor before attempting to calls .equals on it. Then you should figure out why getBackground is returning null or ArrayIndexOutOfBoundsException is being thrown.
Because #goto10 already gave the direction you need to look, here are some other notes:
You need to learn better separation of concerns. Specifically, you're mixing your display code with your game-rule code. With proper design, almost all programs should be runnable from a command line - a GUI is solely there to help out the end-user.
When you have two (or more) related parameters, you really have a single one - a composite class containing them. For example, your x and y parameters for searching your array really represent one CoordinatePair, Location, or Point instance. Although the likelihood is small here, this will help avoid issues in the future - what happens if somebody accidentally swaps the y and increment parameters in searchN(), for example? Code up an immutable Point class and use that - it'll completely remove that problem:
public final class Point {
// Yes, public variables are almost universally frowned upon, with good reason.
// Here, though, it's kind of the 'point'
public final int x;
public final int y;
// Note: private constructor - can't call this from outside.
private Point(final int x, final int y) {
this.x = x;
this.y = y;
}
// Static factory method for construction instead.
// It is left as an exercise for the reader to implement caching.
public static Point fromCoordinates(final int x, final int y) {
return new Point(x, y);
}
}
You'll need to implement a good .hashCode() and .equals() method to make this work, but what Eclipse (or any of the other good tools) spits out should be good. There are some performance considerations with using immutable objects, but for your needs here it's not an issue.
Strive to make methods have as few side-effects as possible; that is, try to make them modify as little (preferably NO) external state as possible. This includes state that is part of your object (such as leadN) but is not otherwise 'part' of the method. Side-effects make it extremely difficult to 'reason' (figure out what's going on) about the state of an object, and make good testing an actual nightmare. Writing methods that depend solely on the (hopefully immutable) state of the objects passed in, and the immutable state of the 'host' (this) object may be somewhat more difficult, but much more easy to reason about; systems that are almost all (or perhaps completely) immutable are much easier to think about, and you get thread-safety/parallel execution for free.
Your methods .isSame() and .isOpposite() are a bit hacked together because the only difference between a played/unplayed square is it's color. The relevant rule-side code should be unaware of display-side code - there's no such thing as a green-sided piece (there technically isn't a white or a black piece either - there's a piece for player 1, and a piece for player 2. Even in the physical world, it's a display only effect, and rules which read 'white gets 4.5 extra points' really mean 'the player who goes second gets 4.5 extra points'). Also, those two methods don't return inverse results for un-played squares (.isSame() returns false), which isn't logical.
Whenever you have a long list of similar elements (the leadX and playableX variable sets), try and reformat them into an actual list. This would also help immensely if you wanted to make a 3D version... Also, there's a way to use what's known as the Strategy Pattern (along with a hash map or array list) to make moving/searching in different directions far easier.
Related
I am currently working on a 2d game in which a player sprite pushes other sprites around on the screen.
My current code (within subclass):
//x and y being the co-ords i want this object to move to (e.g 50 pixels
right of its starting point etc.)
public Boolean move(float x, float y, int delta) {
this.setx(x);
}
How do i make the object move say 50 pixels every 1 second? or alternatively every x frames.
I've tried using delta but that results in smooth motion which is much harder to control for my particular needs.
Any help would be much appreciated
Your approach to accomplish it with the deltas is right. Assuming you have your move method inside your update method and call it in there (or implementing it in a similar way). One way you could achieve these would be the following:
class YourGameStateWithUpdateRenderInit extends BasicGameOrWhatever{
//Global variables for updating movement eacht second.
float myDelta = 0; // your current counter
float deltaMax = 1000; // 1 second, determines how often your object should move
public void update(...){
objectToMove.move(50,50,delta); //The object which contains the move method and you move it by 50 x/y per second.
}
}
Inside your objectToMove class you have your move method:
public Boolean move(float x, float y, float pDelta) {
myDelta += pDelta;
if(myDelta >= deltaMax){
this.setx(x);
myDelta = 0;
}
}
This should work for an update every second. However this implementation is not really good or precise since as you stated you probably have that move method in a sub class or something similar. So you need to adapt it to your needs, but i hope you get the idea behind it. I think it demonstrates the purpose of counting an class attribute up by the delta values until a certain value (e.g. 1000 for 1 second) and after that set it back to zero.
Problem: my player model is supposed to turn into the direction of the last mouse click but instead of turning slowly it spins in all possible ways(Game has an isometric view, the model is supposed to rotate only around the Y-axis but it rotates around the X- and Z-axis too).
Following method(called in render()) is responsible for the turning behavior of the model:
public static void turnUnit(){
if(Gdx.input.isButtonPressed(Input.Buttons.LEFT)){
mX = Gdx.input.getX();
mY = Gdx.input.getY();
angle = (float) (180+Math.atan2(mX-Gdx.graphics.getWidth()/2, mY-Gdx.graphics.getHeight()/2)*(180/Math.PI));
newAngle = ((((currentAngle - angle) % 360) + 540) % 360) - 180;
turning = newAngle/60*turnRate;
currentAngle = currentAngle-turning;
}
TestGround.player.transform.setToRotation(Vector3.Y, currentAngle).setTranslation(posX,0,posZ);
}
And the movement-method(also called in render()):
public static void movement(){
if(northM==true){
TestGround.player.transform.trn(0,0,-1f);
}
if(southM==true){
TestGround.player.transform.trn(0,0,1f);
}
if(westM==true){
TestGround.player.transform.trn(-1f,0,0);
}
if(eastM==true){
TestGround.player.transform.trn(1f,0,0);
}
posX = TestGround.player.transform.getTranslation(Vector3.X).x;
posY = TestGround.player.transform.getTranslation(Vector3.Y).y;
posZ = TestGround.player.transform.getTranslation(Vector3.Z).z;
}
Tried to use "rotate" in the last line but then it just spins faster.
Also, even though this makes no sense to me but after some testing it seems the movement-method somehow interferes with the turn-method(moving in a certain direction will rotate the model in a certain way).
Am I doing something fundamentally wrong here?
Additional Info:
originally I used simple polling to get all keyboard and mouse input
calculated movement/rotation in one big method and everything worked
fine
decided to use the inputprocessor of libgdx to make the code more readable and open-ended
The Matrix4#getTranslation(Vector3) method will set the specified vector to the translation component of the matrix and return it for chaining. What this means is that the vector you supply as argument to the TestGround.player.transform.getTranslation(vector) method, will be set (read: overwritten) to the translation (position) of the model instance.
So, in the case of the call to:
TestGround.player.transform.getTranslation(Vector3.Y)
This will practically modify the Vector3.Y variable from the default [x:0, y:1, z:0], to whatever the translation component of the matrix is set to. This will result in any other call that uses the Vector3.Y variable (like your call to setToRotation) to behave differently.
To fix that you can modify the last few lines to:
Vector3 pos = new Vector3();
TestGround.player.transform.getTranslation(pos);
posX = pos.x;
posY = pos.y;
posZ = pos.z;
Note that you should move the creation of the Vector3 out of the method and therefor might as well remove the posX, posY and posZ members in favor of the pos member.
So, you might be wondering two questions:
Why does the getTranslation method modify its arguments? This is because libGDX is designed to avoid creating garbage, because that will create hick-ups on some platforms, like Android. So instead of creating a new Vector3 every time the method is called, it allows you to specify an instance of that class which you want to reuse. You will see this pattern throughout the lib at multiple places because of this reason.
Why is it even possible to modify Vector3.Y, making it useless and cause all kind of problems? This is because the Vector3 class is mutable and does not encapsulate its members. So practically it allows you to do vector.x += 3; instead of forcing you to call vector.setX(vector.getX() + 3);. This is both for readability and performance reasons (although the latter might vary on your target platform). Also, java does not support something comparable to const.
I'm making apong game, in a boolean method in the Paddle class I want to determine if the ball touching any of the two paddles, I'm struggling of finding the proper logic...
here are the variables:
// instance variables
private Screen theScreen;
private MyroRectangle theRectangle;
private int topLeftX;
private int topLeftY;
// constants
private final int HEIGHT = 100; //the paddle's fixed height
private final int WIDTH = 5; //the paddle's fixed width
private final int PIXELS_PER_MOVE = 20; //the number of pixels a paddle can move either up or down in one timestep
here is the method: * this method is just to determine if the ball touch or not it doesn't do anything with bounce the ball back
public boolean isTouching(Ball b)
{
boolean t = false;
if ((theScreen.getWidth()-(b.getX() + b.getRadius())) >= theScreen.getWidth()-theRectangle.getCenterX() )
{
t= true;
}
return t;
also I tried:
if ((b.getX() > theRectangle.getCenterX()/2) && (b.getY() < theRectangle.getCenterY()/2))
==========
** the methods of the ball class that might be needed:
getX()
getY()
getRadius()
==============
** the Rectangle class:
getCenterX()
getCenterY()
===============
** the Screen class:
getWidth()
getHeight()
I just want to determine at least on of the conditions then I can figure out the rest of them.
In my junior year in college I worked on a Collision detection system algorithm for the windows phone. It is hardly perfect but it was EXTREMELY efficient and can be adapted to a majority of games.
The way that it worked was pretty simple. There were two types of objects; Collidable objects (such as enemies or buildings) and Objects that you wish to check for collisions with these collidable objects.
I had this idea when I was going through a data structures class and we spoke about Linked Lists. I thought what if each link was a collidable object that you could stick your game objects that were already created in it. Then as the game objects moved around you would have a lightweight way of checking their locations for collisions. Thus my system was born.
Basically what it comes down to is using
C (or the distance between to points) = SqrRoot(A^2 + B^2) - radius of ball
this formula should look very familiar to you.
You can see the full answer on this question:
Java More Resourceful Collision Detection
This problem can be seen as solving the question if two 2d-areas, the paddle (a rectangle) and the ball (a circle) intersect. You can just google/wiki formulas for that.
If you don't want to go into the math for solving the problem through geometry, package java.awt.geom contains classes that can do the calculations for you, namely java.awt.Area. You would just create Area instances for paddle and ball and then call the intersects() method to know if they collided.
I am creating a program that displays several bases and the amount of troops each base has. There are two types of bases, friendly and enemy bases. Each Base extends GCompound and consists of a GRect and a GLabel(to display the number of troops). Two arrays are used to keep track of the bases, one for friendly, one for enemy.
I want the user to be able to press the mouse down on one friendly base and release on a different friendly base, causing the troop amount to be transferred from the first base to the second one.
My problem currently is I am only able to detect the base the user presses the mouse down on, and not the base that the mouse is released on. I am using the method getElementAt from the ACM library to return the GObject that a mouse action takes place on.
Code for the mouse press:
public void mousePressed(MouseEvent e){
int mouseX = e.getX();
int mouseY = e.getY();
for(int i = 0; i < PlayerBaseArray.length; i++){
if(getClickedObject(mouseX, mouseY) == PlayerBaseArray[i]){ //Checks to see if the clicked base is in the Array of friendly bases.
pressedIndex = i;
pressedBaseTroopCount = PlayerBaseArray[pressedIndex].getTroopCount();
}
}
}
Code for the mouse release:
public void mouseReleased(MouseEvent m){
int mouseX = m.getX();
int mouseY = m.getY();
for(int i = 0; i < PlayerBaseArray.length; i++){
if(getClickedObject(mouseX, mouseY) == PlayerBaseArray[i]){ // This is always false for some reason.
PlayerBaseArray[i].changeTroopCount(pressedBaseTroopCount);
PlayerBaseArray[pressedIndex].changeTroopCount(-pressedBaseTroopCount);
}
}
}
Method to see what object is clicked:
private GObject getClickedObject(int x, int y){
GObject clicked = getElementAt(x, y);
if(clicked == null) return null;
else return clicked;
}
For some reason the if statement in mouseReleased() is never true, even though it works properly in mousePressed(). Any idea on why the if statement in mouseReleased() does not work?
I've tried researching the problem to no avail, and instead of wasting another night on it I thought I would ask here. Thanks!
You shouldn't use the == operator to compare Objects. You should use the .equals() method:
if (getClickedObject(mouseX, mouseY).equals(PlayerBaseArray[i]))
Put simply, you can only use == only when comparing java primitives (eg int, long etc).
For all "normal" objects, always use objecta.equals(objectb).
This article discusses this issue in more detail.
Attention anal retentives:
Yes, you are right, under some circumstances you can safely use == between objects such as String contants, Integers between -128 and 127, etc, etc. But this guy needed a clear answer and not to be confused. Please resist the temptation to comment about this.
I'm working on to do my assignment. It is a chess design(AI, GUI not required), I have piece class. The piece class has two variables: color and name. So far I have a "move method" like this in this class.
`
public void move(Piece piece,int x,int y)
{
int a=0;
int b=0;
for(int i=0;i<Board.grid.length;i++) {
for(int r=0;r<Board.grid[i].length;r++) {
if(Board.grid[i][r]==piece)
a=i;
b=r;
if(Board.getisnull(x, y)){
Board.grid[a][b]=null;
Board.grid[x][y]=piece;
}
}
}
Board.grid[u][t]=null;
}
`
In this code, I want to find an index which is the old index of the piece I want to move, then moving it then setting its old index to null but this is not working. I can see the name on screen but not the color. Also, old index is not set to null. How to do it? I started to think using an object(piece) array but how?
Just a small hint:
//finds the piece equal to name and color of our piece.so
if(Board.grid[i][y].equals(name) || Piece.color.equals(color))
This doesn't fit together, since the check is "equal to name OR equal color". I think you want to change it to: if(Board.grid[i][y].equals(name) && Piece.color.equals(color))
Piece.setColor(color);//set this piece's color
Huh? What are you doing that for? Shouln't Piece keep its color all the time?
if(Board.getisnull(x, y)==true)
You're redefining y in your loop so y is not the parameter you passed in to the method.
Basically, I'd redefine the method (to keep is as close to the OP as possible, note that OOP wise there could be even better design, subclassing Piece etc.):
//Board.grid[][] should be a 'Piece[8][8]';
//edit: rename parameters for clarity
public void move( Piece piece,int targetX,int targetY)
{
if( Board.getisnull(targetX, targetY) )//method in other class checks the indexes if null
{
//remove the piece from the field/index
Board.grid[piece.x][piece.y]=null;
//add the piece to the target field and update its position
piece.x = targetX;
piece.y = targetY;
Board.grid[targetX][targetY]=piece;
}
else
{
//handle that case, e.g. by throwing an exeption
}
}
Now you'd get the piece you want to move (which knows its index), calculate the target position and call move(piece, targetX, targetY);