I am currently making a terrain generator, everything works fine in one class but I am going to be expanding my application.
Currently I have a JFrame class which holds everything, generating the terrain, painting the terrain, finding locations etc.
I want to add another class that will generate the terrain but when I create this class I need to access fields from the main JFrame class and when I do I get a stack overflow error - here is my code.
public class Simulator extends Applet
{
//fields
public Simulator()
{
grid = new int[100][100];
inhabGrid = new boolean[grid.length][grid.length];
gridSize = grid.length - 1;
dist = grid.length;
TerrainGenerator gen = new TerrainGenerator();
setSize(dist,dist);
seedGrid();
findInhabLocation();
printGridToConsole();
}
public void paint(Graphics g)
{
//panting the grid
}
public void seedGrid()
{
//seeding
}
public boolean generateTerrain(int x1,int y1, int x2, int y2)
{
//terrain generator
}
public boolean mouseUp(Event evt, int x, int y)
{
seedGrid(); //Create a new map
findInhabLocation();
repaint();
printGridToConsole();
return true;
}
public boolean keyEvents(Event evt, int x, int y)
{
seedGrid(); //Create a new map
findInhabLocation();
repaint();
printGridToConsole();
return true;
}
public void findInhabLocation()
{
//find best inhabitant location
}
public int locateWater(int x, int y)
{
//finding closest water
}
public int locateJungle(int x, int y)
{
//finding closest jungle
}
}
}
That works fine in its own class but when I create a class for example:
public class TerrainGenerator
{
Simulator sim = new Simulator();
}
I know this has something to do with the constructor and it's something silly I am doing, what would be the best way of splitting up this app into classes, for example terrain generator, inhabitants etc
For example I want to be able to call a method from the 'TerrainGenerator' class and call i.e. terrainGenerator.generateTerrain
Your TerrainGenerator creates a Simulator object and vice versa, hence you'll end up with infinitely many objects (but at some point the stack is full and a stack overflow exception is thrown instead...)
Instead of creating a new Simulator in your TerrainGenerator, you should pass a reference to your current Simulator (well, actually, that is not a great design either, but I'm not gonna confuse you with the problems of circular references).
Heuster answer is correct, furthermore, I think you could take look at MVC to help you organize your classes.
Depending which should be the parent, you can pass in the instantiated class to the other, ie;
private final TerrainGenerator gen; //if you need to save this.
public Simulator(TerrainGenerator terrainGenerator)
{
this.gen = terrainGenerator;
....etc
}
public class TerrainGenerator
{
Simulator sim = new Simulator(this);
}
or
private final TerrainGenerator gen; //if you need to save this.
public Simulator()
{
this.gen = new TerrainGenerator(this);
....etc
}
private final Simulator sim; //If you need to save it.
public class TerrainGenerator
{
public TerrainGenerator(Simulator simulator) {
this.sim = simulator;
}
}
Related
I intend to write a program that simulates particles collisions in one or more dimension. For the 2D case, I would also like to make a GUI that shows the particles.
I have a main class, ParticleCollider, which contains an inner class, Particle, an array of said Particlesas well as some methods for updating the positions and velocities of the particles. The class roughly looks like this:
class ParticleCollider {
class Particle {
private double mass;
private double[] pos;
//plus some other private class variables
public Particle(double mass, double[] pos) {
this.mass = mass;
this.pos = pos;
}
}
private Particle[] pArray;
//Details of constructor are irrelevant
public ParticleCollider() {
}
//Do stuff to particles in pArray, i.e. change their positions and velocitites
public void update() {
//For example
pArray[0].pos[0] = 0;
}
}
In the graphics class, I want to be able to access the Particles so that I can find their positions and radii for drawing purposes. One way would of course be to add a method getParticlesin ParticleColliderto return the array of Particles, pArray. My question is now if this would be considered a violation of encapsulation. Because the Particleclass has no setters, I cannot change the Particles. Also, because an array hase fixed length, I cannot add any Particles. The only thing I could do, which I guess is pretty bad, is take some Particleand assign it the value of null.
EDIT
It has been suggested that I use a List instead of an array and provide an iterator to said List. It would seem to me that this would not solve the encapsulation problem. Regardless, I'm relucant to abandon the array because I need to be able to select a random Particle in the collection of Particles and then iterate it cyclically.
How about using this pattern:
public class Particle {
// Particle code
}
public class Particles implements Iterable<Particle> {
ArrayList<Particle> myParticles = new ArrayList<Particle>();
public void add(Particle particle) { myParticles.add(particle); }
public Iterator<Particle> iterator() {
return myParticles.iterator();
}
// more code on particles
}
void bla() {
Particles particles = new Particles();
particles.add(new Particle());
particles.add(new Particle());
for (Particle particle : particles) {
System.out.println("P="+particle);
}
}
If you want to inhibit the remove() on this iterator you might use this pattern:
public static class Particles implements Iterable<Particle> {
ArrayList<Particle> myParticles = new ArrayList<Particle>();
public void add(Particle particle) { myParticles.add(particle); }
public Iterator<Particle> iterator() {
return new Iterator<Particle>() {
Iterator<Particle> listIterator = myParticles.iterator();
#Override
public boolean hasNext() {
return listIterator.hasNext();
}
#Override
public Particle next() {
return listIterator.next();
}
#Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
Let us say we have a class called World. Which contains a class called Data. We also have a third class called Input. If Input.clicked(Event event, int x, int y) were to be called I would not be able to access World which means I can't access Data. How do you go about resolving this?
Another way to ask this might be: How can you access something in a method from another class that can't be changed when what you need to access is not final?
Sorry, I am having a hard time explaining this.
Update bit: The world class already exists, can't create a new one. It would be inside the Game class.
Here is a code example, not working code. More pseudo.
public class World {
Data data = new Data();
Input input = new Input();
public void update(float delta) {
input.getInput();
input.makeChangesBasedOnInput();
}
public void render(float delta) {
}
}
public class Data {
public int importantNumber; // Static is not an option
// For me I have to get a user name... but same idea here
public Data() {
Random ran = new Random();
importantNumber = ran.nextInt(1000);
}
}
public class Input {
Button button = new Button();
public Input() { // passing the World class does not work, ex. public Input(World world) {
button.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) { // I can't add world here...
// HERE IS ISSUE
System.out.println(World.Data.importantNumber);
}
}
}
public void getInput() {
// MAGIC
}
public void makeChangesBasedOnInput() {
// MAGIC
}
}
Update 2: Here is another example of what I am trying to do with TextButton & ClickListener from libgdx.
statsButton is a TextButton() from libgdx.
You say passing the World class does not work, well that is probably because you tried to acces a local variable from anonymous function, example:
public Input(World world) {
button.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
// error: world is not final
System.out.println(world.data.importantNumber);
}
}
}
this is what probably happened (if not, please let me know). In Java 8, world would be effectivly final, but in Java 7 or earlier, you would have to declare it final explicitly, like
public Input(final World world) { ... }
Also a common approach is to store your world inside a field:
private World world;
public Input(World world) {
this.world = world;
...
}
I have:
public class HFSim extends ApplicationTemplate
{
private static class AppFrame extends ApplicationTemplate.AppFrame
{
void setBuoy()
{
//code
Position buoypos=Position.fromDegrees(buoylat, buoylon);
}
void setVehicle()
{
//code
Position vehiclepos=Position.fromDegrees(lat, lon, elev);
}
double findDistance()
{
//find distance between marker (vehicle) and a buoy
Earth earth= new Earth();
double radius = earth.getEquatorialRadius();
double distancebetween=LatLon.ellipsoidalDistance(buoypos, vehiclepos, radius, 6356752.3);
return distancebetween;
}
How can I use the objects buoypos and vehiclepos in the setBuoy and setVehicle methods in the findDistance() method?
You have two clearcut options here:
Make buoypos and vehiclepos instance variables, or..
Provide more descriptive names for setVehicle() and give it a Position return type.
Option 1 would look like this:
...classname...
{
private Position vehiclePosition;
private Position bouyPosition;
public void setVehiclePosition()
{
this.vehiclePosition = ....
}
}
Option 2 would look like this:
...classname...
{
public Position createVehiclePosition()
{
vehiclePosition = ....
return vehiclePosition.
}
}
Finally, you would use them as either:
...classname...
{
public double findDistance()
{
...this.vehiclePosition...
or
Position vehiclePos = this.createVehiclePosition();
}
}
The option you choose is highly dependent on how the class is supposed to behave.
Use variables with the class scope. This essentially means
///outside of a method but within the class you'll want to set:
private this.bouypos = new Position;
private this vehiclepos = new Position;
//method1 {
Position this.buoypos=Position.fromDegrees(buoylat, buoylon);
//method2 {
Position this.vehiclepos=Position.fromDegrees(lat, lon, elev);
//method3 calls things set in method1 & 2
findDistance(){
//code
double distancebetween=LatLon.ellipsoidalDistance(this.buoypos, this.vehiclepos, radius, 6356752.3);
}
Make the findDistance method take two Positions as parameters
double findDistance(Position buoypos, Position vehiclepos){
}
I want a Animations class that can be reused through different projects. The problem is how I let the class change another object's members (such as position). Here is a very simplified version of how it would operate and what it can do.
public class Animation() {
private float currValue, targetValue, duration;
public Animation(currValue, targetValue, duration) {
this.currValue = currValue;
this.targetValue = targetValue;
this.duration = duration;
}
public void update() {
// Here I would update its currValue based on duration and target
}
}
So when I want to animate let's say a rectangle's position I would do:
class Rectangle {
private float x, y;
private Animation a;
public Rectangle (x, y) {
this.x = x;
this.y = y;
this.a = new Animation(x, 100, 1000); // Duration in ms
}
public void update() {
a.update(); // Update animation
}
}
Obviously this does not work, because Animation does not update Rectangle's x value. Only one solution comes to mind, and that is passing in the instance of Rectangle and the field name "x" and then use the Reflection API to update the value. But that seems like a pretty poor solution.
Any suggestions? Should I design my code differently?
Reflection is not necessarily a poor solution in this case. In fact, it's a very general solution that allows elegant code on the client side. But of course, one should be aware of the caveats of using reflection in general.
A very pragmatic approach of such an animation would be to "factor out" what the animation actually does: Namely changing some float value, in your case. So one way of separating the "client" code and the implementation could be the following:
interface FloatSetter {
void setFloat(float f);
}
public class Animation
{
private float currValue, targetValue, duration;
private FloatSetter floatSetter;
public Animation(
float currValue, float targetValue, float duration,
FloatSetter floatSetter)
{
this.currValue = currValue;
this.targetValue = targetValue;
this.duration = duration;
this.floatSetter = floatSetter;
}
public void update()
{
...
floatSetter.setFloat(currValue);
}
}
Then you can pass an appropriate implementation of FloatSetter to your Animation - probably via an anonymous inner class:
class Rectangle
{
private float x, y;
private Animation a;
public Rectangle(float fx, float fy) {
this.x = fx;
this.y = fy;
FloatSetter floatSetter = new FloatSetter()
{
#Override
public void setFloat(float f)
{
this.x = f;
}
});
this.a = new Animation(x, 100, 1000, floatSetter);
}
public void update() {
a.update(); // Update animation
}
}
BTW: Depending on what you are going to achieve, I'd recommend to not put the Animation instance into the Rectangle. But I assume that this is just a sketch to show your intention.
Important : You should definitiely have a look at the "Timing Framework": https://java.net/projects/timingframework . It is the accompanying code for chapters of the book "Filthy Rich Clients" ( http://filthyrichclients.org/ ) by Chet Haase and Romain Guy, and they certainly know their stuff. The library is a very sophisticated and flexible implementation of what you obviously want to achieve there. (They also support a generic "PropertySetter" that uses reflection (https://java.net/projects/timingframework/sources/svn/content/trunk/timingframework-core/src/main/java/org/jdesktop/core/animation/timing/PropertySetter.java?rev=423 ), but this is just one helper class to define a general "TimingTarget", which is the sophisticated version of the "FloatSetter" that I sketched above).
I'm currently working on a game written in Java.
At the moment I'm stuck finding an easy way to store my GameObjects (Player, Enemies, and so on...) so that I can access them by their coordinates while still being able to move them easily.
I already tried Multidimensional Arrays, which is nice, but won't let me move my Objects easily. I'd have to physically move the Object in the array every time it moves.
Then I tried "normal" Arrays, which lets you move things easily, just increase the objects x, y or z value, but won't allow me to access Objects by coordinates without iterating through the whole array.
Right now, i'm trying to find a compromise that allows me to have both.
Thanks in advance,
//265
The simple solution is to use both forms at the same time. Store the coordinates in your GameObject instances, but also simultaneously cache them in your 3D array. The array should preferably be encapsulated in an object that provides method to update and query it. Something like this:
public class GameObjectDatabase implements LocationChangeListener {
private int [] [] [] data;
private Set<GameObjects> objects;
...
public GameObject gameObjectAt(int x, int y, int z) {
return data[x][y][z];
}
#Override
public void positionUpdated(GameObject obj, int oldX, int oldY, int oldZ) {
....
}
}
Why the listener and the overridden method? Because it's not really your GameObject's job to update this data - it's the responsibility of the GameObjectDatabase. So, ideally, your GameObject should allow to register listeners in a Set and call their positionUpdated methods every time its location changes.
All game objects that have a position (player, enemies etc) should have an internal reference to their position eg;
class Position {
int x;
int y;
}
interface Positionable {
Position getPosition();
void setPosition(int x, int y, GameArea area);
}
class Player implements Positionable {
//stuff
}
class Enemy implements Positionable {
//stuff
}
You can then have a class representing your game area;
class GameArea {
Positionable[][] grid;
List<Positionable> gameObjects;
public Positionable getByLocation(int x, int y) {
return grid[x][y];
}
public void setAtLocation(int x, int y, Positionable p) {
grid[x][y] = p;
}
public List<Positionable> getAll() {
return gameObjects;
}
}
This allows you to access by position and iterate over all objects. When a game object moves it needs to update its position internally and explicitly update the GameArea, as shown in the below example setPosition() implementation.
void setPosition(int x, int y, GameArea area) {
area.setAtLocation(this.x, this.y, null);
area.setAtLocation(x, y, this);
this.x = x;
this.y = y;
}