I'm not sure what is wrong but there's some weird happening in my Paint() concerning some variables.
this code works just fine:
public void paint(Graphics g)
{
Point[] positions = {new Point(20,50),new Point(60,30),new Point(80,20),new Point(80,30)};
}
but this one don't, i wanted this one, because im changing position formations on user's selection:
// declared somewhere
Point[] selectedFormation = {new Point(20,50),new Point(60,30),new Point(80,20),new Point(80,30)};
public void paint(Graphics g)
{
Point[] positions = selectedFormation;
}
when you do positions = selectedFormation you are not creating a copy of selectedFormation, you are just storing a reference of it into position. Both point to the same object (the same array). If the array is changed by using position, it is the same array as selectedFormation.
Use clone() to create a copy of the array:
public void paint(Graphics g)
{
Point[] positions = selectedFormation.clone();
}
but consider that clone does not copy the elements of the array, both list will contain the same instances. If you only change the coordinates of any point, it will affect both lists. In that case you need to make a deep copy of the list:
public Point[] deepCopy(Point[] array) {
Point[] copy = new Point[array.length];
for (int i = 0; i < array.length; i++) {
copy[i] = new Point(array[i]);
}
return copy;
}
could use generalization for this... but lets keep it simple
Related
I am working on 2D graphical optimal fitting project. I was coding in C++ and changed to Java, therefore I know the algorithm works. But I am having a problem with reaching elements of ArrayList outside of the scope of loop or more likely adding to an ArrayList.
I can reach to an element I want in this scope, but outside of this scope some elements are lost. I know this is irrelevant and probably something occurs beyond my attention.
Triangle Class:
public class Triangle implements Shape, Cloneable
{
private double length; // size of equaliteral triangle's each edge.
private double x,y;
private boolean rotate; // Flag for rotate by 90 degress around pos(x,y)
private boolean fill; // Flag for fill
private static double total_area = 0;
private static double total_perim = 0;
private int[] xPoints;
private int[] yPoints;
.
...
}
Definitions:
Triangle t2 = (Triangle)small;
Triangle t = (Triangle)t2.clone();
List<Shape> shape = new ArrayList<Shape>();
In the code below, I draw it as soon as I added it into the List. Method draw() does not matter in this case, it only uses fields such as x and y.
Code 1:
// (a,width-a*sqrt(3)) init for fill inside without rotating
for(y = r1.getHeight()-tri_height;y>=0;y-=tri_height)
{
x=t.getLength()/2.0;
while(x+t.getLength()/2.0<=r1.getWidth())
{
t.setPosition(x+_x,y+_y);
shape.add((Triangle)t.clone());
shape.get(size).draw(g); // check this line.
++size;
x+=t.getLength();
}
}
In this same piece of code, I only draw/print them after insertion is done.
Code 2:
// (a,width-a*sqrt(3)) init for fill inside without rotating
for(y = r1.getHeight()-tri_height;y>=0;y-=tri_height)
{
x=t.getLength()/2.0;
while(x+t.getLength()/2.0<=r1.getWidth())
{
t.setPosition(x+_x,y+_y);
shape.add((Triangle)t.clone());
x+=t.getLength();
}
}
for(Shape s:shape)
s.draw(g);
clone() method:
#Override
public Object clone() throws CloneNotSupportedException
{
return super.clone();
}
Output 1(Wrong)
Output 2(Expected)
I am only using draw() method to show the difference better. The problem is the elements are gone after the scope. Or I didn't achieve to add them properly. It shows me that last element I added instead of every element I appended. What am I missing in this case?
It seems that your problem is in Triangle.clone() method. You have references in Triangle, like int[] xPoints or int[] yPoints.
Defualt implementation of Object.clone() works only for simple types, but not for references.
Triangle t = (Triangle)t2.clone();
t.xPoints == t2.xPoints; // this is same array (not a copy)
All your rectangles are drawn on the same place.
How to solve
Do not use clone() method. In general it is outdated. You have to create like C++ copy constructor and manually create copy of your object.
public class Triangle implements Shape {
private static double total_area = 0;
private static double total_perim = 0;
private double length;
private double x,y;
private boolean rotate;
private boolean fill;
private int[] xPoints;
private int[] yPoints;
public Triangle(Triangle triangle) {
this.length = triangle.length;
this.x = triangle.x;
this.y = triangle.y;
this.rotate = triangle.rotate;
this.fill = triangle.fill;
this.xPoints = xPoints != null ? Arrays.copyOf(xPoints, xPoints.length) : null;
this.yPoints = yPoints != null ? Arrays.copyOf(yPoints, yPoints.length) : null;
}
}
P.S.
int[] xPoints: xPoints - is not an array, this is reference to the array of int.
int[] xPointsCopy = xPoints: xPointsCopy - this is another reference to the same array of int.
I am working on a small project using Java and Swing. I'm making a very, very small and simple RPG that is in the style of Earthbound for mainly it's combat style. Alongside this project, I'm working on a framework to make it easier to create games of a similar genre and feel (i.e. screen, game loop, state manager, audio manager, etc). The issue I'm running into is that the "image to game object" converter class I made is overwriting the list with the final game object that is created. I am converting from a PNG to a GameObject (class created within the framework).
I diagnosed this by printing out the position and type of all the elements in the list to receive the same X, Y, and types for each element. I checked to make sure the HashMap I passed through was setup correctly and that each tile type was added correctly. Below is the relevant section of code to the top along with it's output:
private void init() {
tileMap.put(new Color(0,255,0), new Tile(16,16, TileType.GRASS));
tileMap.put(new Color(250,255,0), new Tile(16,16, TileType.SAND));
tileMap.put(new Color(135,135,135), new Tile(16,16, TileType.ROCK));
tileMap.put(new Color(255,0,233), new Tile(16,16, TileType.DIRT_PATH_SIDE));
for(Color t : tileMap.keySet()) {
System.out.println(((Tile) tileMap.get(t)).getTileType());
}
....
}
----- OUTPUT -----
GRASS
ROCK
DIRT_PATH_SIDE
SAND
The image loads correctly and the HashMap's values are added correctly so I decided to see where in the framework the issue was. I checked the position when it was being set and it was fine (ie (0,0), (0,16), (0,32)...) until I looped through the finished list where the game objects in the list are all the same.
I know that static variables cause an issue but the only "static" variable I am using is the enums to denote what the tile type is. I used an integer just to see what would happened and yielded the same result. I took the final list, made it a variable the class could read as opposed to just the function, and tried to see if that would work but still was just the final game object created after reading.
I've checked over SO and other websites but nothing is working. I fear that I looked at this problem the wrong way as I was trying to implement a solution I used in Unity/C# here but probably had a disconnect somewhere along the way.
Here is the full function from earlier:
private void init() {
tileMap.put(new Color(0,255,0), new Tile(16,16, TileType.GRASS));
tileMap.put(new Color(250,255,0), new Tile(16,16, TileType.SAND));
tileMap.put(new Color(135,135,135), new Tile(16,16, TileType.ROCK));
tileMap.put(new Color(255,0,233), new Tile(16,16, TileType.DIRT_PATH_SIDE));
for(Color t : tileMap.keySet()) {
System.out.println(((Tile) tileMap.get(t)).getTileType());
}
try {
im.loadImage();
} catch (IOException e) {
e.printStackTrace();
}
im.readImage(tileMap);
objects = im.getMap(); // objects is a list within the class that contains all Tile game objects.
}
And the converter class's relevant code:
public void readImage(HashMap<Color, GameObject> tileDict) {
for(int x=0; x<img.getWidth(); x++) {
for(int y=0; y<img.getHeight(); y++) {
GameObject g = determineObject(tileDict, x, y);
if(g != null) {
map.add(g);
}
}
}
}
private GameObject determineObject(HashMap<Color, GameObject> tileDict,
int x, int y) {
GameObject g = null;
for(Color c : tileDict.keySet()) {
if(c.getRGB() == img.getRGB(x, y)) {
g = tileDict.get(c);
g.setXPos(x*g.getWidth());
g.setYPos(y*g.getHeight());
}
}
return g;
}
--- EDIT: 8/10/2017 ---
I am sorry for not clarifying what the structure looks like. GameObject is an abstract class within the framework I've made that is extended by Tile in the game. As well, TileType is an enum type that I created within the game and not the framework. The framework is in a separate jar/project so it is unaware of what extends GameObject and what TileType is.
--- EDIT 2: 8/10/2017 ---
I tried implementing a solution using the Serializableclass but that didn't work. I followed the example from this question. The copy() function I created in the abstract GameObject looks like this:
public final GameObject copy() {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
new ObjectOutputStream(baos).writeObject(this);
return (GameObject) new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())).readObject();
} catch (Exception e) {
throw new AssertionError();
}
}
I have also tried this as an abstract method and wrote the function in Tile but there is no current result. I'll keep mucking around here to see if anything comes up.
Resources
Java ArrayList.add() replaces all elements in array with the final element
List overriding objects java [closed]
Add elements to Arraylist and it replaces all previous elements in Java [duplicate]
Why does my ArrayList contain N copies of the last item added to the list?
I think, the problem here is, that you get the GameObject from the map and then modify it. So if you get the same GameObject twice, it gets modified two times and also gets added to the list twice.
To have different GameObject's, you have to create a new one in determineObject().
BTW: it's very confusing to name a list map.
If I got it correctly tileMap is a static member of your class and you pass it to the readImage and thus to the determineObject method?!
In determineObject you change the xPos and yPos attributes of your objects in your static tile dictionary:
g = tileDict.get(c);
g.setXPos(x*g.getWidth());
g.setYPos(y*g.getHeight());
That is you modify the attributes of an entry in the global map.
You will need to create a copy of the GameObject instance you get from the map and continue with the copy instead of modifying the original object. Your code should do something like this:
GameObject globalGameObject = tileDict.get(c);
g = globalGameObject.createCopy();
g.setXPos(x*g.getWidth());
g.setYPos(y*g.getHeight());
Where createCopy() is a new method that creates a copy of the current instance. Each implementation of GameObject has to implement this method:
public abstract class GameObject {
...
public abstract GameObject createCopy();
...
}
You could use the Cloneable feature of Java to create the copies for you as well, but Cloneable is easy to use wrong and I've actually not seen anyone using it for real life code till now.
Alright so I found out the issue. While doing research on dpr's and Claus Radloff's answers, I came across the solution here. Seeing as in my case I was using an abstract class, I could not do what both Claus and dpr recommended per-say as you can't instantiate an abstract class. In order to solve this, I made the abstract class implement the Serializable class as I said in my question. I created the abstract method GameObject copy(); which the objects extending from this can implement or ignore (return null). From here, only one line of code is required inside said method:
return new Tile(this.width, this.height, this.type);
A big thank you to those that guided me in the right direction! I apologize again for not clarifying my structure in my initial post.
I think your map should containe TileTypes instead of Tiles:
tileMap.put(new Color(0,255,0), TileType.GRASS);
tileMap.put(new Color(250,255,0), TileType.SAND);
tileMap.put(new Color(135,135,135), TileType.ROCK);
tileMap.put(new Color(255,0,233), TileType.DIRT_PATH_SIDE);
then method determineObject would become:
private GameObject determineObject(HashMap<Color, GameObject> tileDict,
int x, int y) {
GameObject g = null;
for(Color c : tileDict.keySet()) {
if(c.getRGB() == img.getRGB(x, y)) {
TileType type = tileDict.get(c);
g = new Tile(x, y, type);
g.setXPos(x*g.getWidth());
g.setYPos(y*g.getHeight());
// BTW, how about a break here?
}
}
return g;
}
Or even:
private GameObject determineObject(HashMap<Color, GameObject> tileDict,
int x, int y) {
GameObject g = null;
Color c = new Color(img.getRGB(x, y));
TileType type = tileDict.get(c);
if (type != null) {
g = new Tile(x, y, type);
g.setXPos(x*g.getWidth());
g.setYPos(y*g.getHeight());
}
return g;
}
UPDATE
I forgot to multiply x and y by the tile width. With my approach, you cannot use g.getWidth() and g.getHeight(), but I think in your case their values are both 16. Ill will add constants:
private static final int TILE_WIDTH = 16;
private static final int TILE_HEIGHT = 16;
and the method determineObject becomes:
private GameObject determineObject(HashMap<Color, GameObject> tileDict,
int x, int y) {
GameObject g = null;
Color c = new Color(img.getRGB(x, y));
TileType type = tileDict.get(c);
if (type != null) {
g = new Tile(TILE_WIDTH, TILE_HEIGHT, type);
g.setXPos(x*TILE_WIDTH);
g.setYPos(y*TILE_HEIGHT);
}
return g;
}
Good morning,
I have one little problem.
I created one class named Map(). In this class there in one method that generate an Array. Then i created other two classes (Top and Bottom) that extend Map. Then I created 2 objects. One of Top and one of Bottom. I want to get the same array for the Top's object and for the Bottom's object. Here is the code Source:
public class Map{
public Map(){}
public int [] yTopValues()
{
int [] arrayTopY = new int[100];
for(int i=0;i<100;i++)
arrayTopY[i]=randomInt(-50,50);//it puts in i-th position an int between 50 and -50
return arrayTopY;
}
public int [] yBottomValues()
{
int [] arrayBottomY = yTopValues;
for(int i=0;i<100;i++)
arrayBottomY[i]=arrayBottomY[i]-250;
return arrayBottomY;
}
public int [] xValues()
{
int [] arrayX = new int[100];
for(int i=0;i<100;i++)
arrayX[i]=randomInt(0,50);//it puts in i-th position an int between 0 and 50
return arrayX;
}
//other stuff
}
public class TopMap extends Map{
public TopMap(){
this.area=new Area(new Polygon(
this.xValues,
this.yTopValues,
200)
);
}
public class BottomMap extends Map{
public BottomMap(){
this.area=new Area(new Polygon(
this.xValues,
this.yBottomValues,
200)
);
}
In the View class I created two objects one of TopMap and one of BottomMap then I drew the areas with g2.draw(topMap.area) and g2.draw(bottomMap.area)
I need the 2 polygons to be similar, but both of them are different because the method is executed twice. What should I do?
Thank you very much!!
The class Map does not hold the array. It is local only to the xValues() method. If you want the other classes to get that exact array do this:
/*
* Since this is a variable in the CLASS field, this object will
* be accessible to the child class.
*/
private int[] arrayX = new int[100];
public Map(){
createArrayX(); // This makes sure that the array is created, or else
// every value inside of it will be 0.
}
public void createArrayX(){ // Exact same thing as xValues(), but without the return type
for(int i=0;i<100;i++){
arrayX[i]=randomInt(0,50);
}
}
public int[] getArrayX(){ // The method that gets the array.
return arrayX;
}
i have some trouble with deep copying.
I have this java project, chess, and I need to use the clone() method, because I need to try new configurations without changing the board.
Board scacchiera = new Board();
Initialization(scacchiera);
Board clone = scacchiera.clone();
System.out.println(scacchiera.toString());
System.out.println(clone.toString());
I create an object, scacchiera, then I clone it. I think I have done correctly a deep copy, but when I change something in scacchiera, clone changes too.
In object Board:
public class Board implements Cloneable{
//TODO
//rivedere se check e checkmate public o private;
//se private, costruire get e set;
public Pedine[][] board;
public boolean check;
public boolean checkmate;
//creating 2 lists for all the pieces; Neri=black, Bianchi=White
public ArrayList<Pedine> Neri;
public ArrayList<Pedine> Bianchi;
public Board(){
this.board = new Pedine [8][8];
this.check = false;
this.checkmate = false;
this.Neri = new ArrayList<Pedine>();
this.Bianchi = new ArrayList<Pedine>();
}
...
#Override
public Board clone() throws CloneNotSupportedException{
Board cloned = (Board) super.clone();
cloned.board = (Pedine[][]) board.clone();
return cloned;
}
I have this double array of Pedine, and I have to clone it too, so I do:
public class Pedine implements Cloneable{
private int x;
private int y;
private Piece pezzo;
private Colour colore;
...
#Override
public Pedine clone() throws CloneNotSupportedException{
return (Pedine) super.clone();
}
Why it doesn't work?
I tried this code too, but it doesn't work.
#Override
public Board clone() throws CloneNotSupportedException{
Board cloned = (Board) super.clone();
cloned.board = (Pedine[][]) board.clone();
for (int i=0; i<8; i++)
for(int j=0; j<8; j++){
cloned.board[i][j] = board[i][j].clone();
}
return cloned;
}
(Pedine extends Object)
The problem, as sharonbn indicates, is in the double-array. While you can clone it manually with a double-loop, your chess engine is going to suffer a performance penalty: you will be cloning a lot of boards, and you can benefit from making them a lot easier to copy around.
One option is to use a flat array and some clever addressing to speed things up:
private Piece[] board; // 64 Pieces in there
public Piece at(col, row) {
if (row < 0 || row >= 8 || col < 0 || col >= 8) return null;
return board[col + row*8];
}
Now, instead of accessing board[row][col] you use at(col, row). And copying and creating boards is a lot easier:
board = other.board.clone();
... should now work as expected.
I also strongly recommend having immutable pieces, with no state information whatsoever. Your current pieces have an x and y field, for example. What do they need those for? You should tell them their actual positions only while moving them; that way, you don't need to clone pieces at all -- because all pawns are exactly alike, and you can actually use the same "black pawn" for everything black-pawn related.
deep cloning of multi dimension arrays should be custom coded, as is explained here
I'm using a arraylist to add states(the board state for the 8 puzzle). My problem is when I get the children of the state it changes the values stored in my array list. I'm assuming this is because ArrayList just stores pointers to the objects and not the values themselves. In order to fix this I create a new object every time before I store it into the ArrayList but I'm still having the same problem.
I will also try to follow naming conventions more often thanks for the tip.
private ArrayList<int[][]>VisitedBoard;
if(RuleNumber ==2){
//Here is my problem. This will change what is stored in VistedBoards
NextState = new State(FireRule.Rule2(WM.get_Board()));//Fire Rule
for(int j=0;j<VisitedBoards.size();j++){
//Meaning this will always be true
if(Arrays.equals(VisitedBoards.get(j), NextState.get_Board())){
Loop =true; //Loop to previous state
}
if(j==VisitedBoards.size()-1 && Loop ==false){ //If the next state is not any previously visited
NotALoop =true;
VisitedBoards.add(NextState.get_Board());
WM.set_Board(NextState.get_Board());
}
}
}
public int[][] Rule2(int [][] Board){//The FireRule Class
Find_BlankLocation(Board);
int temp;
State NewState;
temp = Board[BlankLocation[0]-1][BlankLocation[1]];
Board[BlankLocation[0]-1][BlankLocation[1]] = 0;
Board[BlankLocation[0]][BlankLocation[1]] = temp;
NewState = new State(Board);
return Board;
}
public class State { //State class
private int[][] Board;
private int[][] Goal;
private Boolean GoalFound;
public State(int[][] Start, int[][] goal){
Board = Start;
Goal = goal;
GoalFound=false;
}
public State(int[][] NewState){
Board=NewState;
}
public int[][] get_Goal(){
return Goal;
}
public int[][] get_Board(){
return Board;
}
public void set_Board(int[][] board){
Board = board;
}
public Boolean get_GoalFound(){
return GoalFound;
}
}
Containers like ArrayList work the same in all languages: they are called data structures because they organize storage/retrieval of objects. Obviously they don't store the fields of the objects themselves.
Trying to interpret your problem, maybe you don't want to share the boards between the list of visitedBoards and WM (whatever it means...). Then simply implement get_Board() to return a copy of the array instead of the Board object itself:
public int[][] get_Board(int[][] src) {
int[][] dst = new int[src.length][src[0].length];
for (int i = 0; i < src.length; i++) {
System.arraycopy(src[i], 0, dst[i], 0, src[i].length);
}
return dst;return dst;
}
Beside this, as others already told you, you'd really better to adopt the standard Java naming conventions, use meaningful names, and encapsulate your x, y and int[][] in real application classes.
Presumably, the new State object contains a pointer to the same arrayList as before. You'll want to manually copy the array out to a new one (a "deep clone" or "deep copy" as it is called). You might find this useful: Deep cloning multidimensional arrays in Java...?
Every time you create a new instance of State, you pass it the same array (whatever is returned by WM.get_Board()).
You then add that same array to VisitedBoards when you call VisitedBoards.add().
The fact that you're creating new State objects is irrelevant, because only the return value of NextState.get_Board() gets added to the list.
As a result, the list VisitedBoards always contains several references to the exact same array.
As Raffaele has suggested, you'll be fine if you make sure get_Board() returns a copy of the array in stead of a reference to the original (assuming that doesn't mess up logic that exists elsewhere).
The main thing I learned from this question is how important it is to follow naming conventions.
Your unconventional capitalization has made me dizzy!
Following these rules will make it much easier for others to understand your Java code:
class names should be capitalized (ie PascalCase)
variable names should be lowercase (ie camelCase)
do not use underscores in method names, class names, or variable names (they should only be used for constants)
always use meaningful names when possible
My advice is to create your own container object for their 2D array and implement deep copying.
For example:
package netbeans;
import java.util.Arrays;
public class Container
implements Cloneable
{
private int [] _data;
private int _sx;
private int _sy;
public int get(int x, int y)
{
try { return this._data[y*this._sx+x]; }
catch (Exception e) { throw new ArrayIndexOutOfBoundsException(); }
}
public void set(int x, int y, int value)
{
try { this._data[y*this._sx+x] = value; }
catch (Exception e) { throw new ArrayIndexOutOfBoundsException(); }
}
public Object Clone() { return new Container(this); }
public Container(int sizeX, int sizeY, int [] data)
{
this._sx = sizeX;
this._sy = sizeY;
this._data = data;
}
public Container(Container cont)
{
this._data = Arrays.copyOf(cont._data, cont._data.length);
}
}