OK so I am new am stuck on coming up with a good way of solving this problem. So I am creating an RPG top down survival game in Java using the slick2d. I have a problem when It comes to spawning items in the game. What is the best way to manage having hundreds of items... An example; I have a sub class of items called PickUpItems. For instance when a tree is destroyed by the player it spawns a PickUpItem which is just an Image with a Rectangle box for collision. What would be the best way to chose what Item to spawn without having to make hundreds of classes for each Interactive Item(Tree, bush, farming stuff etc). Should I have a item manager class? Given a name It will search a text file to get the parameters needed and create an Object then?
public void spawnPickUpItem(String type, int x, int y)
{
PickUpItem pickUpItem = null;
switch(type)
{
case"Log":
pickUpItem = new PickUpItem(type,logImage,x,y,this);
break;
case"Flint":
pickUpItem = new PickUpItem(type,flintImage,x,y,this);
break;
case"Rock":
pickUpItem = new PickUpItem(type,rockImage,x,y,this);
break;
}
This is my current attempt which works it spawns the necessary item but imagine running a switch statement with hundreds of cases each item you need an Item spawned in the game. I am sure some one can help.. THank you
You can follow the Factory Method pattern
Map<String, Image> imageRepository = new HashMap<>(); // to be filled
PickUpItem createItem(String type, int x, int y) {
Image itemImage = imageRepository.getOrDefault(type, yourDefaultImg);
return new PickUpItem(itemImage, x, y);
}
public void spawnPickUpItem(String type, int x, int y) {
PickUpItem pickUpItem = createItem(String type, int x, int y);
// further logic . . .
}
Related
Is there a way to create a listener (JavaFX) for any changes made to any of an object's field?
I have a coordinate object:
public class Coord {
public int x;
public int y;
public Coord(int aX, int aY) {
x = aX;
y = aY;
}
}
I have a component that creates a coordinate object when the mouse enters and destroys it when it exits. I've attached an invalidation listener:
this.setOnMouseEntered(event -> {
_hoverCoord = new SimpleObjectProperty<Coord>(getCoord(event.getX(), event.getY()));
_hoverCoord.addListener(redraw);
});
this.setOnMouseExited(event -> {
_hoverCoord = null;
});
When the mouse moves, I've been creating a new coordinate. Great, the invalidation fires because I'm replacing the coordinate. But this creates a whole bunch of these short-lived objects. I've resolved this by just calling the code I want directly in the mouse move, but it raised the following questions:
My first question is: Is that kind of rapid-fire object creation/destruction worth worrying about, generally? (I know that's a hard question to answer but I'm thinking in terms of garbage collection when creating tens of thousands of objects in a short time.)
My second question is: Is there a "listener" that just watches a POJO like Coord for field level changes?
My third question is: If not, is there a way to preserve Coord as a simple object and yet listen for specific field changes (without adding methods or changing the x and y from int)? I mean, no accessors for the fields.
My fourth question is: If not, how would I put in the accessors in Coord?
First, transform your Coord in a JavaFX Bean:
public class Coord{
private final IntegerProperty x = new SimpleIntegerProperty(this, "x");
private final IntegerProperty y = new SimpleIntegerProperty(this, "y");
public final void setX(int x){ this.x.set(x); }
public final int getX(){ return x.get(); }
public final IntegerProperty xProperty(){ return this.x; }
//Repeat for y.
}
Then, you may add an invalidation or change listener to the x property:
myCoordinate.xProperty().addListener(redraw);
myCoordinate.yProperty().addListener(redraw);
Now, there's a question: why do you need to listen the coordinates? If you need to compute something, you may use the helper Bindings, for instance, if you want to compute x*y each time the cursor moves, then you may use:
productProperty.bind(Bindings.createIntegerBinding(
()->coordinate.getX() * coordinate.getY(), //Compute x*y
coordinate.xProperty(), //dependency on x property
coordinate.yProperty()//dependency on y property
));
Or you may create your readonly property:
private final ReadOnlyIntegerWrapper product = new ReadOnlyIntegerWrapper(this, "product");
public Coord(){
init();
}
private void init(){
product.bind(Bindings.createIntegerBinding(
()->coordinate.getX() * coordinate.getY(), //Compute x*y
coordinate.xProperty(), //dependency on x property
coordinate.yProperty()//dependency on y property
));
}
public final int getProduct(){
return product.get();
}
public final ReadOnlyIntegerProperty productProperty(){
return product.getReadOnlyProperty();
}
Im working on a game in which multiple "notes" (sprites) are generated.
The notes are created at random. Each of them has a random velocity and are created in a different thread. The Notes class is a child of the sprite class. It has 2 properties and 1 method:
vel - a Velocity2 object holding the x and y component on the
velocity of the note object
pos - a Vector2 object holding the x and y coordinates of the note object.
changepos() - a method that changes the position based on the velocity of the object
(I cannot post the code of that class due to privacy reasons)
I currently have a static class "NoteStack", which can hold up to 64 references to Notes objects.
public class NoteStack {
public Notes[] note_array;
public int stack_len;
public NoteStack(){
note_array = new Notes[64];
stack_len = 0;
}
public void push(Notes n){
if(stack_len<64){
note_array[stack_len] = n;
stack_len++;
Gdx.app.log("push", "pushed");
}
}
public void delete_note(int pos){
if(note_array[pos] != null){
note_array[pos] = null;
for(int i = pos; i<stack_len; i++){
note_array[pos] = note_array[pos+1];
}
note_array[stack_len] = null;
stack_len = stack_len - 1;
}
}
}
Here's the code for my "update" function
public void update(float d, SpriteBatch b){
core.draw(b);
for(int i = 0; i< noteStack.stack_len; i++){
Gdx.app.log("update", "Update function running" + i);
noteStack.note_array[i].changePos(d);
noteStack.note_array[i].draw(b);
// scr_w - screen width , scr_h - screen height
if(noteStack.note_array[i].pos.x > scr_w || noteStack.note_array[i].pos.x < 0 || noteStack.note_array[i].pos.y > scr_h || noteStack.note_array[i].pos.y < 0){
noteStack.delete_note(i);
}
}
}
The issue (as you may see) is that whenever a note object from NoteStack gets removed (i.e. the delete_note method is called), other Notes objects in the array are affected.
Hence my question: What is the best way to reference multiple sprite (note) objects in LibGDX?
Generally speaking in programming, you should never implement own "classic" datastructures, only if it's really necessary and you can't use or extend a collection type, because the standard implementations are well programmed and tested, so those are safer to use.
In your case, I would use libGDX Array. That class has add, get, size methods, and if you really want to, you can extend the Array class to have an update function.
But in short, if you replace public Notes[] note_array; with public Array<Notes> note_array = new Array<>(true, 64); and use get and remove and size for iterating and managing the collection that should work.
In My game I created Multidimensional-Array from com.badlogic.gdx.utils.Array Class as the following:
private static final Array<Array<Actor>> ARRAY_COLS = new Array<Array<Actor>>();
Now, In touchDown method from InputListener, How can I get a specific actor from ARRAY_COLS AND it Index? which all I have the known actor event.getTarget(); as the following:
InputListener listener = new InputListener() {
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
return true;
});
EDIT: How Can I get index of this actor?
like that ARRAY_COLS.IndexOf(event.getTarget()); which the target is ARRAY_COLS.get(_col).get(_row); in the previous image case _col == 3; and _row == 4;
Um, event should return the specific actor that was clicked. If not, try setting actor's Touchable status. If it returns the Group actor that contains the one you need, you can always try using Actor#hit(float x, float y, boolean touchable), which takes local actor coordinates and should return an actor in the specific, clicked place. No need to store 2D array of actors, really.
Also, Actor has a setName method. Instead of a 2D array, you can use a ObjectMap<String, Actor> (also a lightweight LibGDX collection), give actors meaningful names and put the actors in the map during their initiation.
If you need a 2D array, you can use setUserObject to store the index values. I'm assuming you create the actor in nested for loops, so you can use a Vector2, Point or a simple class with two int variables storing the loop indexes. Then you can either serialize it to string and use as name or put as the user object and then retrieve it in the listener method.
For example:
public class IntPair { private final int x, y; /* Constructor, getters */ }
// Creation:
for(int x = 0; x < width; x++) {
for(int y = 0; y < height; y++) {
Actor actor = new Actor();
actor.setUserObject(new IntPair(x, y));
}
}
// Accessing index:
IntPair index = (IntPair) actor.getUserObject();
I am programming a probe that moves through a 2D board in Java. To do this, I have two ArrayLists of Integer that contain the path that the probe has followed. The first ArrayList contains the x-coordinate, and the second one, the y-coordinate. What I would like to do is check whether the next tile of the movement has been visited or not, this is, whether the new x-coord and the new y-coord are in the corresponding ArrayList and share the same position.That way, if the new tile has been visited, I wouldn't move there. How could I possibly do this? I have tried with indexOf and lastIndexOf, but it doesn't work as each coordinate can be repeated an indefinite number of times. I also tried .contains but it didn't work either as I need that it is contained in both arrays in a specific position.
Any help would be appreciated.
First of all Java is object oriented so you should use objects. Why are you storing a coordinate in two separate arrays?
You can define your own type:
class Position implements Comparable<Position> {
public final int x;
public final int y;
Position(int x, int y) { this.x = x; this.y; }
#Override public int compareTo(Position other) { ... }
#Override public boolean equals(Object other) { ... }
#Override public int hashCode() { ... }
}
Then with this you can do whatever you want, for example
Set<Position> visited = new HashSet<Position>();
Map<Position, Integer> visitedWithSpecificPositionInPath = new HashMap<Position, Integer();
and so on.
A pretty messy approach would be to find all indexes of matching x-coordinates and for each index found check whether the y-coordinate for the given index is equal to the y in question.
So given coordinates x, y and array lists visitedX and visitedY you could do something like this:
public static boolean isVisited(int x, int y){
for(int i = 0; i < visitedX.size(), i++){
if(visitedX.get(i) == x){
if(visitedY.get(i) == y){
return true;
}
}
}
return false;
}
But as Jack has mentioned you should reconsider your data structure as looping over the complete x-coordinates list is not very efficient (though you could reduce limits of outer for loop with usage of visitedX.indexOf(x) and visitedX.lastIndexOf(x) ).
Hey I am new java so forgive me if what I am about to ask is obvious, but I will try to explain as best as I can.
Its just a project that has been set for university so its not in a serious manner.
I have a class called MarsRoom which holds the attributes say for all the dimensions of the room like the totalheight and width of the walls in order to calculate the heat loss that the room will suffer in order to adjust the amount of solar energy that is needed to keep the room at the room temperature set.
The problem I am having is what is better practice or solution, to pass the attributes of the size of the room in a constructor(but this could get quite long in size, as the ones below are not only the ones that I may need) or create a whole different class specifically for that room like ROOM TYPE U? and set the attributes in there.
As it stands I can create a whole new room just by instantiating the room with the new values, but its going to get a little long, whereas I would rather not create a whole new class for a different room which may only differ from another room by a few meters on one of the walls!.
So what I am really trying to get at it, is is it ok to pass that many attributes to the constructor on instantiation?
//the instantiation in the runnable
MarsRoom room1 = new MarsRoom("RoomU", 40, 40, 20, 20, 8, 2, 4);
//the constructor in the MarsRoom class
public MarsRoom(String roomname, int windowsH, int windowsW, int wallsH, int wallsW, int windowC, int heaters, int lights){
name = roomname;
TotalWindowHeight = windowsH;
TotalWindowWidth = windowsW;
TotalWallHeight = wallsH;
TotalWallWidth = wallsW;
windowCeiling = windowC;
numheaters = heaters;
numlights = lights;
roomheaters = new Heaters[numheaters];
}
I'd say that you should be adding factory methods here.
Basically, keep your constructor, but add methods like
static Room createLaundryRoom(laundryRoomParameters) {
return new Room(...laundry room parameters plus defaults
common to all laundry rooms...);
}
One of the great benefits object oriented programming is the possibility of not repeating yourself in code. Hence objects, which define data (members) and functionality (methods), and no requirement to create instances of these "prototypes" with hard values until run-time. To create a new class for each room when it
may only differ from another room by a few meters on one of the walls
would be to deny OOP (and Java) by gross repetition. I'd stick with the constructors, and if similar kinds of rooms end up emerging, try one of the static factory methods suggested, or break up common functionality using inheritanceOracle.
Create a map with the keys being
Map<String, Integer> map = new HashMap();
map.put("TotalWindowHeight", new Integer(10));
map.put("TotalWindowWidth", new Integer(5));
...
map.put("NumberOfHeaters", new Integer(3));
MarsRoom room1 = new MarsRoom("RoomU", map);
Constructor will be like:
public MarsRoom(String roomname, HashMap<String, Integer> params) {
name = roomname;
TotalWindowHeight = map.get("TotalWindowHeight").intValue();
TotalWindowWidth = map.get("TotalWindowWidth").intValue;
...
roomheaters = new Heaters[map.get("NumberOfHeaters").intValue()];
}
this is not good OO however, but it seems like you are looking for something quick. If you want good OO you need to create an object for Window and in it you have hieght and width, another for ceiling, and you should not have number of something as a field, you should have an array to store the heater objects, and so and so forth, but this is quick and meets your requirement.
While technically legal, constructors with very long argument lists may be inconvenient to use. It also depends on whether you this the list may grow in the future or in subclasses.
If you have many parameters, but they have defaults and sometimes only a few need to be changed, you may find the Builder pattern useful. The idea is to replace constructor arguments with function calls, and allow them to be chained, for example:
public MarsRoom() {
//empty or just basic stuff set here
}
public MarsRoom setTotalWindowHeight(int TotalWindowHeight) {
this.TotalWindowHeight = TotalWindowHeight;
return this;
}
public MarsRoom setTotalWindowWidth(int TotalWindowWidth) {
this.TotalWindowWidth = TotalWindowWidth;
return this;
}
...
then, you can call:
MarsRoom room1 = new MarsRoom()
.setTotalWindowHeight(20)
.setTotalWindowWidth(40);
Of course, if you wanted to set all parameters this way, it's longer (thou maybe more readable) than the single constructor. But if you only set 2 parameters out of 10, it will usually be more convenient.
You don't show what the fields of MarsRoom are, but for each feature, I would have a Collection of sub-objects. A MarsRoom has-a List of Windows. A MarsRoom has-a List of Walls. etc... Then have setters and getters for each and methods to add new instances of these features.
Since this is for school, I'm only including a little bit of pseudo code.
public class MarsWindow {
int height;
int length;
// Setters & Getters
// standard getters & setters go here
int getArea() {
return this.height * this.width;
}
}
public class MarsRoom {
List<MarsWindow> windows;
List<MarsWall> walls;
List<MarsLight> lights;
List<MarsHeater> heaters;
public List<MarsWindow> addWindow(MarsWindow window) {
// Add a window to the "windows" list here
}
public List<MarsWall> addWall(MarsWall wall) {
// Add a wall to the "walls" list here
}
// Do this for the other fields
int getTotalWindowArea() {
int area = 0;
// Iterate over all windows
for(MarsWindow window : windows) {
area += window.getArea();
}
return area;
}
// Add other calculation methods here
}
If what you're trying to do is simply not duplicate the parameters you're passing the constructor, you can simply put them in a separate static method, like so:
public static MarsRoom newRoomU() {
return new MarsRoom("RoomU", 40, 40, 20, 20, 8, 2, 4);
}
You could also use some polymorphism or have different types of rooms or something similar to this and then have a superclass with the common values that all rooms will have.
You can also have more than one constructor and have different ones for values you wish to set depending on the room type etc.
Its always better to work with objects rather than primitives, you could use factory to create objects.
//the constructor in the MarsRoom class
public MarsRoom(String roomname, WindowDimension windowDimension, WallsDimensions wallDimension, RoomAmbience ambience){
}
public class WindowDimension{
private int height; //int windowsH
private int width; //int windowsW
private int circumference; //assumed windowC is circumference
}
public class WallsDimension{
private int height; //int wallsH
private int width; //int wallsW
}
public class RoomAmbience{
private int heaters;
private int lights;
}