I am making a RPG-style program, but I have trouble to get my array of treasure objects to work. I want to save all treasures I find in the array, to be printed out later. Here is the code for the treasure class:
private static int x = 0;
Treasure treasureArray[] = new Treasure[20];
public void collectedTreasures(Treasure t){
treasureArray[x] = t;
x++;
}
And in the main program:
GoldTreasure t = new Coin();
hero1.setPoints(t.getCoin());
t.collectedTreasures(t);
The creation of the treasure object is within a switch within a infinite loop.
When i print out the array, with method
public void printTreasures(){
for (int y=0 ; y<x ; y++){
System.out.print(treasureArray[y] + ", ");
I only get "null" for as many treasures there should be in the array. If i print out the array after t.collectedTreasures(t), I see that only the last treasure is there, and the indexes before that object is null. What have I done wrong?
Yes I'm a newbie. Be nice.
This code is quite suspicious:
GoldTreasure t = new Coin();
hero1.setPoints(t.getCoin());
t.collectedTreasures(t);
It means you are:
creating a new treasure t;
calling collectedTreasures on that very instance.
You should assign the treasure array to the hero, not to the treasure itself.
Also note that x should not be a static variable because it will get shared among all instances; clearly not your intention, since the treasure array is per-instance.
The problem is that you collect the treasure in itself because you call the collect function - that belongs to a treasure - to collect itself.
Later on, when you call printTreasures in what object does it run? Do you create a new instance of treasure and ask for it to print what it has collected? If such, the results are according to the code and there is no issue with it, but the logic is faulty.
What you should do: the hero is the one collecting the treasures, therefore move the definition of the array of treasures, the counter and the 2 functions - collectedTreasures and printTreasures - in the hero class. Further more, make X not static, as its value will be shared among heroes. Maybe, even more ellegant, create an additional class to handle the treasures and compose you hero using different classes.
And may I suggest a renamig for the collectedTreasures(Treasure t) function to collectTreasure(Treasure t).
We would need to see your full code to give you a detailed answer, but I suspect what you are doing is creating lots of Treasure subclasses and calling collectedTreasure on each one. This is going to increment your global x counter each time, whereas each individual treasureArray only has one entry in it.
You can move the collectedTreasure method to the class corresponding to your hero1 object, at the same time, get rid of the static (global) x variable and replace your array of Treasure objects with a List implementation (e.g. ArrayList), they all keep track of their own sizes so you don't have to. Plus your code won't crash when you get more than 20 treasures!
Related
I am making a simple game which has an array of objects called beats which move along the screen towards a stationary player like a basic rhythm game, and I have decided that using a linked list is the best way to track the nearest beat to the player
Currently I am trying to add to the linked list, and have this as a starting point:
public static LinkedList<Beat> beatLinkedList = new LinkedList<Beat>();
The linked list is public and static as it needs to be accessed in a different class.
int startingPoint = 800;
//For loop 51 times
for(int i=0;i<=50;i++){
//modifier to start position to create differing gaps between beats
int startModifier = random.nextInt(50);
beatLinkedList.add(new Beat(startingPoint,300,ID.Beat));
System.out.println(beatLinkedList.get(0));
//redefines the starting point for each beat
startingPoint = startingPoint+50+startModifier;
}
}
When I want to render the objects however I need to use the handler class, to add the objects to a linked list of gameobjects which has the render method called on them which I would like to keep the same ideally meaning I need to use the handler classes addObject method:
public void addObject(GameObject object){
//linked list built in method to add an object
this.object.add(object);
}
For using an array this solution worked
But something similar for the linked list does not
handler.addObject(beatLinkedList.add(new Beat(startingPoint,300,ID.Beat)));
I should also add that when I get the element at position 0 it outputs all 51 objects which is also a problem.
With trying to use the handler like this I am given an exception saying "addoObject in Handler cannot be applied to boolean"on line 50:
handler.addObject(beatLinkedList.add(new Beat(startingPoint,300,ID.Beat)));
I'm not sure about this but it seems that I need to give a pointer to a location when using the add method and so I tried this:
beatLinkedList.addLast(new Beat(startingPoint,300,ID.Beat));
And this method still has the problem of adding all 51 objects to the same point in the list, which I imagine is something to do with being in a for loop still.
handler.addObject(beatLinkedList.addLast(new Beat(startingPoint,300,ID.Beat)));
Trying to utilise this with my handler class results in a different error from before saying that the 'void' type is not allowed as a parameter. I'm really not sure where to go from here.
beatLinkedList.addLast(new Beat(startingPoint,300,ID.Beat));
handler.addObject(beatLinkedList.getLast());
Solved thanks to Abra's comment, I decided to add the object to 2 seperate linked lists, one of just the beats, and one containing all the game objects, which allows them to be rendered properly, while also allowing beats to be identified and removed when necessary.
I was programming a plugin in Java and I wanted to set 4 different Location objects. Because in school(C++) they taught us to use [] and I like them (brackets), I decided to do that. Oh boy, I was wrong(or maybe it was just my mistake) I came up with this code:
Location[] pos = new Location[4]; //an array (I guess)
Location loc = e.getBlock().getLocation(); //to get the position of a block
and then I set it in a for loop to iterate trough them like this:
for(int i = 0; i < 4; i++){
pos[i] = loc;
}
But! When I wanted to change any of the pos[x] variables, all of them changed. Could this be related to pointers or something?
Anyways. I changed my code to do it like this
Location loc = e.getToBlock().getLocation();
Location loc1 = e.getToBlock().getLocation();
Location loc2 = e.getToBlock().getLocation();
Location loc3 = e.getToBlock().getLocation();
This code fortunately works, but how would I go with more variables, what if I wanted something like 200 of them? Or maybe a dinamic "array".
You might be wondering why I said "array" in quotes, but I really have no idea how to call pos[] other than an array, even tho I know that an Array exists and it's something completely different.
You have to create a new Location object at each iteration in the for loop.
Now you are using the same object in all the array slots. The 'loc' variable is a reference to the object in the heap, so changing it spreads the changes to all the array,
They all changed because you set them all to be the same object: the one you assigned to loc. If you had put the call to e.getToBlock().getLocation() inside the loop, your 4 array elements would have been different objects.
Right now your getLocation function is only being called once which creates a single object. Call it inside your for loop.
for (int i = 0; i < 4; i++) {
Location loc = e.getBlock().getLocation(); //to get the position of a block
pos[i] = loc;
}
When I wanted to change any of the pos[x] variables, all of them changed
It's because you assign each element of your pos to same object. You are from C++ background, so you should have a knowledge about pointers. What you are doing is assigining a "pointer" to same object in all positions of pos.
what if I wanted something like 200 of them?
I am not sure if I understand you right. You can use an ArrayList which allows you to add elements dynamically, so you don't have to know its size in advance. Look at the docs.
Did you intend to assign for all the array items the same object loc?
If yes, here we go. As others suggest, you should call the function e.getBlock().getLocation() once each time you go through your loop. This gives different objects with the same value.
Another workaround is to copy the object, rather than only assign the reference.
What I think about your problem is that you are mixing copying and assignment. When you assign loc to the array items in your loop
for(int i = 0; i < 4; i++){
pos[i] = loc;
}
you assign it by reference, as it an object and not a primitive data type.
This means that the array items, after you assigned loc, have a only a reference to a memory position, when you change its value via any reference, all other references will have the new value, expected behaviour.
If you intend to initiate all the items of your array to loc, you should deep/shallow copy it, i.e., not assign it by reference. See here for an explanation on difference between copy and assignment. Here is an answer for deep copy using serialization
public class example
{
public static void main(String[] args)
{
int[] MyArray = new int[10];
MyArray[1] = 5;
int[] NewArray = MyArray;
NewArray[1] = 10;
System.out.println(MyArray[1]);
}
}
Why does the system print out 10 instead of 5?
It seems like whatever changes we made to element in NewArray, MyArray will change along, why?
I copy this pattern to initiate like int, string variables but they don't behave like this above, why? thanks guy, I am new to CS programming.
It seems like whatever changes we made to element in NewArray, MyArray will change along, why?
You aren't changing NewArray. You're changing the array that the value of NewArray refers to. It's like this:
NewArray is a variable (an unconventionally named one, but hey)
The value of NewArray is a reference
The reference refers to an object
It's really, really important to differentiate between variables, references and objects. Don't feel worried that it didn't just come to you immediately - this is a stage a lot of people go through when they first encounter a language like Java.
The values of MyArray and NewArray both refer to the same array, so if you make changes to the array via one variable, you still see the change when you then look at the array via a different variable.
I copy this pattern to initiate like int, string variables but they don't behave like this above, why? thanks guy, I am new to CS programming.
For int, that's a value type - the value of an int variable is the number itself, not a reference to an object.
For String, I suspect you were changing the value of the variable to refer to a different String object - not changing the contents of the String object itself (which you can't - strings are immutable in Java). For example:
String x = "first";
String y = x;
x = "second"; // This doesn't change the value of `y`
I like to think of variables as pieces of paper. For value type variables, the value is just written on the piece of paper:
int i = 10;
is like having a piece of paper with the name i, and a value of 10 on it.
For classes and arrays (which are reference types) the value on the piece of paper isn't the object - it's a way of navigating to the object. A bit like having someone's home address written on a piece of paper.
Suppose you have two pieces of paper with the same address written on them. If you rub one of them out and write a different address, that doesn't change anything about what will happen if someone looks at the other piece of paper and goes to that house. That's like the String example above.
The array example, however, is more like this: I write my home address on two pieces of paper, and give them to Fred and Ginger. Fred reads the address, visits my home, and paints the front door red. (He's modifying the object - my house - without changing his piece of paper at all.) Now if Ginger reads the address on his piece of paper and visits my home, he'll see a red front door.
The reason this happens is because when you say int[] NewArray = MyArray; this is copying the reference of MyArray to NewArray.
This reason you are copying the reference is because you do not call the new operator to instantiate a new array.
So, when you say NewArray[x] it is pointing to the x position in memory of MyArray (and hence the value in memory of MyArray). No new memory is allocated when you do int[] NewArray = MyArray; since the new operator is not called.
It is beacuse when you do =, this makes the new obkect to point to the old one. So any changes made to the new one will reflect in the old one to, as they are the same technically.
You should array.clone to avoid this.
You are not copying it's value. You say:
Java create "MyArray".
Java creates a variable poiting at an object
Java create another array "NewArray" that is the same as MyArray
Java creates a variable poiting at the same object as MyArray
Java change the value of NewArray[1] to 10
Java changes the value on the object it is poiting at, not the variable itself.
Hope you get it.
As a side note, you should use [0] instead of [1]. Arrays start at 0, like everything in programming. So, the array with 10 items you created starts at 0 and ends at 9. Take note of that.
I am creating a game, and it requires an infinite number of Rectangles.
For example, let's say I name the variables car:
public Rectangle car1;
public Rectangle car2;
public Rectangle car3;
and so on,
Would there be an easier way? Like:
public int carNumber;
public Rectange car + carNumber;//if carNumber was one, it would be called car1
Also, I will need to test if the rectangles contain others. <-- I know how to do this.
You can't and shouldn't try to declare an infinite number of anything -- just doesn't make sense. Instead use a collection such as an ArrayList that can hold a variable number of object references. e.g.,
private List<Rectangle> carList = new ArrayList<>();
This won't work:
public Rectange car + carNumber;//if carNumber was one, it would be called car1
because variable names don't work that way, they can't be created by concatenating Strings. But don't worry about this, because the ArrayList will take care of this. The third item in the list would be obtainable easy enough: carList.get(2).
To see if any Rectangles in the list contain another Rectangle use a for loop and iterate through the collection:
for (Rectangle rect : carList) {
if (rect.contains(testRectangle) {
// this item contains the test Rectangle
}
}
You would use an ArrayList to do this
Arrays are static memory allocation. You always need to state the size of the array upon array creation, thus not possible to have an "infinite" array. What you are looking for is called dynamic memory allocation.
One example of using dynamic memory is ArrayList.
ArrayList allows you to expand it when elements are added and shrink it when elements are removed. You can expand the size of an ArrayList so called "infinitely" by keep on adding elements into it. However the limit for number of elements you can add to it depends on how much memory your system has.
Basically, dynamic memory allocation is what you are looking for. You may also consider using Vector.
Sorry You can't do it in JAVA. You can't create a variable name dynamically.
I am creating a game, and it requires an infinite number of Rectangles.
You will get OutOfMemory in case of infinite number of Rectangles. Please think about it again.
You can use a static array if the number of rectangles is already known.
Rectangle[] rec = new Rectangle[size];
//get the first Rectangle
Rectangle first = rec[0];
// get the total no of Rectangles
int length = rec.length();
in general code like:
car1 = "blue";
car2 = "red";
car3 = "green";
is 99% of the time better expressed as an array
cars = ["blue", "red", "green"]
In Java arrays are of fixed length when you initialize them, so you could just make a big one or you could use an ArrayList as an above commenter mentioned which is a list-structure that allows for one by one additions.
I am brand new to programming, as well as to this website, so forgive me if I screw anything up. I'm having a heck of a time figuring out how to properly post my code in here.
package tester;
import java.util.*;
public class Mainclass2 {
public static void main(String[] args) {
int y = 3;
int[] x = {1, 2, 3, 4};
editnumbersArray(x);
editnumbersNotArray(y);
System.out.println(x[2]); **//now this was changed from 3 to 9...**
System.out.println(y); //but this one went unchanged.
}
//this accepts 'x[]' into the 'a[]' parameter.
public static void editnumbersArray(int[] a){
a[2] = 9; **//<---why does this one CHANGE the actual x[2] instead of just a[2]?**
}
//this accepts 'y' into the 'a' parameter.
public static void editnumbersNotArray(int a){
a = 9; **//<--while this one only changes 'a' instead of 'y'?**
}
}
So my question is basically typed in there as comments. Why does the array that is passed into the method change the values of the original array (x[]) when the int that is passed into the other method doesnt change? I'm sure it's a simple answer, but when I did my research I couldn't figure out what to search. I don't know what this is called so everything I searched led me the wrong way. Thanks for any help!!
EDIT: Thanks for that analogy with the address! That is by far the best way you could have explained it to me. So basically when you pass an array into a parameter, its passing a reference, not the actual value? So when I make adjustments within my method, its changing whatever the array is referencing?
I noticed that this also happens with a list. So the list isnt actually passed by value? It seems as if the array/list itself is basically passed in for editing, no matter what I name it within my method (a[] in this case.)
EDIT http://javadude.com/articles/passbyvalue.htm this page really cleared it up. And sorry for posting a duplicate question. The problem was that I didn't know what I was trying to ask. I had never even heard these terms "pass-by-value/reference", so now I know
Changing the value of the parameter itself never affects the argument in Java, because all arguments are passed by value. However, look at this method:
public static void editnumbersArray(int[] a){
a[2] = 9;
}
That assignment doesn't change the value of the parameter. The value of a is still the same reference, to the same array - it just changes the contents of the array.
Imagine if I wrote my home address on a piece of paper for you. It wouldn't matter what you did to that piece of paper - that wouldn't change where I lived. However, if you visited the address and painted the front door green, without ever changing the piece of paper at all, I would see that change.
It's very important to differentiate between different concepts:
A variable is a named storage location; it holds a value, which is always either a primitive value (e.g. an int) or a reference. In my example above, the piece of paper was like the variable.
A reference is just a value which allows you to navigate to an object. It's not the object itself. It's like the address on the piece of paper.
An object contains other variables. There may be several variables which all have values which are references to the same object. It's like the house in my example: I can write my address on several pieces of paper, but there's only one house.
An array is an object which acts as a container for other variables. So the value of a is just a reference to the array.
Java uses pass by value (what you want to search for) for everything. Essentially that means it makes a copy of the parameter that it then passes to the method. That means that you cannot change what something points at by using the = operator.
That is why the (int a) version doesn't change a.
However, in the case of an Object or an array it doesn't make a copy of the Object or array, it makes a copy of the reference to the Object or the array. That means that you have two variables, the original on and the, in your example, (int[] a) one that both point to the same spot in memory. Changes to either variable will affect the other variable.
Pass by value, pass by reference, and pass reference by value are the types of things you want to search on for more information.