Composite pattern in java - java

I'm working on a program right now that allows you to create shapes (square, rectangles and circles) you also have an option to create a compound shape by selecting already created shapes...I'm using two observers for the shapes. One for squares/rectangles and one for large circles and these observers list the reference points and sizes of the shapes. When a compound shape is created it should list the components in the square/rectangle frame if there are squares/rectangles in the compound shape.
I'm supposed to create the compound shape using composite pattern. So basically compound shapes and my circles, squares and rectangles need to be handled the same way
I have an array of objects called shapes, and compound shape is an object with an array of shapes in it.
My question is how can I check through the shapes array for an object of type compound shape and then check through the compound shapes array for an instance of rectangle or square?
Sorry for not including code but my program is somewhat large with a lot of classes
heres the methods I use to check for an instance of square or rectangle...these two methods are in two different classes. The shapes display in the right observer window when theyre just the simple shapes but the compound shapes dont display. If for example I had a shape list with 3 shapes...shape 1 is a large circle, shape 2 is a compound shape and shape 3 is a rectangle. And lets say the compound shape has 2 squares. Right now this would display the large circle and the rectangle but it wont display the compound shape components. I thought that once I got to the compoundShape, instanceof would look pick out an instanceof square or rectangle from the compundshape array
heres the compound shapes toString method
public String toString(){
String output="";
output += "Compound Shape: /n";
for (int i = 0; i< numShapes; i++){
output += shapes[i].toString();
}
return output;
}
heres the do method I use to look for an instance of square or rectangle
do {//squares rectangles
currentShape = shapes.getShape();
if (shapes.squareRectangleFinder())
outputString1 += currentShape.toString();
}while (shapes.next());
and heres the square finder method
public boolean squareRectangleFinder() {
if ((shapes[currentShape] instanceof Square)||(shapes[currentShape] instanceof Rectangle)){
return true;
}
return false;
}

I guess this is what "composite pattern" should do. Accordint to Wikipedia:
clients should ignore the difference between compositions of objects and individual objects
In my understanding it should be done like this (getters/setters, add/remove operations omitted):
interface Shape {
public int getLeftmostCoordinate();
}
class Rectangle implements Shape {
private int top;
private int left;
private int width;
private int height;
public int getLeftmostCoordinate() {
return left;
}
}
class Circle implements Shape {
private int x;
private int y;
private int r;
public int getLeftmostCoordinate() {
return x - r;
}
}
class CompoundShape implements Shape {
private Shape[] shapes;
public int getLeftmostCoordinate() {
int left = shapes[0].getLeftmostCoordinate();
for (int i=1; i<shapes.length; i++) {
int candidate = shapes[i].getLeftmostCoordinate();
if (candidate < left) {
left = candidate;
}
}
return left;
}
}

Related

My game collision system doesn't work on more than one tile

I'm working on a collision system for my game, however I can't get it to work, if I add more than one wall (which is the object I'm rendering) the collision system doesn't work and I can get through the block.
However if I leave only one wall the collision works correctly, or if at the end of the loop I add a break;
the collision works but only on the first wall of the map, the others don't get the collision.
Would anyone know how to solve this? I've been trying to solve it for 2 days and I couldn't.
public boolean checkCollisionWall(int xnext, int ynext){
int[] xpoints1 = {xnext+3,xnext+3,xnext+4,xnext+3,xnext+3,xnext+4,xnext+10,xnext+11,xnext+11,xnext+10,xnext+11,xnext+11};
int[] ypoints1 = {ynext+0,ynext+8,ynext+9,ynext+11,ynext+12,ynext+15,ynext+15,ynext+12,ynext+11,ynext+9,ynext+8,ynext+0};
int npoints1 = 12;
Polygon player = new Polygon(xpoints1,ypoints1,npoints1);
Area area = new Area(player);
for(int i = 0; i < Game.walls.size(); i++){
Wall atual = Game.walls.get(i);
int[] xpoints2 = {atual.getX(),atual.getX(),atual.getX()+16,atual.getX()+16};
int[] ypoints2 = {atual.getY(),atual.getY()+16,atual.getY()+16,atual.getY()};
int npoints2 = 4;
Polygon Wall = new Polygon(xpoints2,ypoints2,npoints2);
area.intersect(new Area(Wall));
if(area.isEmpty()){
return true;
}
}
return false;
}
I'm pretty sure the problem is this call:
area.intersect(new Area(Wall));
Here's the JavaDoc for that method:
public void intersect(Area rhs)
Sets the shape of this Area to the intersection of its current shape
and the shape of the specified Area. The resulting shape of this Area
will include only areas that were contained in both this Area and also
in the specified Area.
So area, which represents the shape of your player, is going to be modified by each test with a wall, which is why it's only working with one wall.
You could fix the issue by simply making the player Area the argument of the call, as in:
Area wallArea = new Area(Wall);
wallArea.intersect(area);
if(wallArea.isEmpty()){
return true;
}
By the way, this logic is reversed isn't it. Don't you want to check that the resulting area is not empty, i.e. there was an overlap between the player and the wall?
The other option, if each Wall is actually a rectangle, would be to use the this Area method instead:
public boolean intersects(double x,
double y,
double w,
double h)
Tests if the interior of the Shape intersects the interior of a
specified rectangular area. The rectangular area is considered to
intersect the Shape if any point is contained in both the interior of
the Shape and the specified rectangular area.
Something like this:
if(area.intersects(atual.getX(), atual.getY(), 16, 16)) {
return true;
}
As this avoids the creation of an Area object for each wall, and the intersection test is going to be much simpler, and faster.

Object oriented design - Shapes

So, after many years of OOP, I got a pretty simple homework assignment from one of my university courses to implement a simple object-oriented structure.
The requested design:
Implement an objected oriented solution for creating the following shapes:
Ellipse, Circle, Square, Rectangle, Triangle, Parallelogram.
Each shape created must have the following parameters : unique id, color.
And following functions: color change, move, area, circumference, is inside, copy.
No validity tests are needed (not in the classes and not from user input).
My design:
Overall a pretty simple approach, shape_class / non-circular are abstract, and rectangle/square are combined into one class since they contain exactly the same parameters and no validity tests are needed (no reason to split them into two).
Shape class - implements a static id (unique id), and an init function dealing with the color name.
public abstract class shape_class {
static int STATIC_ID;
int id;
String color_name;
public shape_class(String color_name_input) {
this.id = STATIC_ID;
shape_class.STATIC_ID+=1;
if (Arrays.asList(toycad_globals.ALLOWED_COLORS).contains(color_name_input))
{
this.color_name = color_name_input;
}
}
public void change_color(String color_name_input) {
if (Arrays.asList(toycad_globals.ALLOWED_COLORS).contains(color_name_input)) {
this.color_name = color_name_input;
}
}
public abstract shape_class return_copy();
public abstract void move(double x, double y);
public abstract double area();
public abstract double circumference();
public abstract boolean is_inside(double x, double y);
}
** Non-circular** - Receives an array of points (Which define the object) and implements almost all required functions.
public abstract class non_circullar extends shape_class {
List<line> line_list = new ArrayList<line>();
List<point> point_list = new ArrayList<point>();
non_circullar(String color_name, point...input_point_list) {
super(color_name);
this.point_list = Arrays.asList(input_point_list);
for (int current_index =0; current_index< (input_point_list.length); current_index++) {
point current_first_point = input_point_list[current_index];
point current_second_point = input_point_list[(current_index+1)%input_point_list.length];
this.line_list.add(new line(current_first_point, current_second_point));
}
}
public point[] get_point_list_copy() {
int index = 0;
point [] new_array = new point[this.point_list.size()];
for (point current_point:this.point_list) {
new_array[index] = current_point.return_copy();
index+=1;
}
return new_array;
}
public double circumference() {
double sum = 0;
for (line current_line :this.line_list) {
sum += current_line.get_length();
}
return sum;
}
public void move(double x, double y) {
for (point current_point :this.point_list) {
current_point.move(x, y);
}
}
public boolean is_inside(double x, double y) {
int i;
int j;
boolean result = false;
for (i = 0, j = this.point_list.size() - 1; i < this.point_list.size(); j = i++) {
if ((this.point_list.get(i).y > y) != (this.point_list.get(j).y > y) &&
(x < (this.point_list.get(j).x - this.point_list.get(i).x) * (y - this.point_list.get(i).y) /
(this.point_list.get(j).y-this.point_list.get(i).y) + this.point_list.get(i).x))
{
result = !result;
}
}
return result;
}
int get_top_left_line_index() {
int top_left_line_index = 0;
int index = 0;
point best_point = this.line_list.get(0).get_average_point();
point current_point;
for (line current_line :this.line_list) {
current_point = current_line.get_average_point();
if (current_point.x < best_point.x) {
best_point = current_point;
top_left_line_index = index;
} else if (current_point.x == best_point.x && current_point.y > best_point.y) {
best_point = current_point;
top_left_line_index = index;
}
index +=1;
}
return top_left_line_index;
}
}
The problem:
For this assignment 40 points were reduced for design issues:
1) Circle is an ellipse and thus needs to inherit from it (Even though they share no parameters).
2) Rectangle / Square are two different entities even though in this implementation they are exactly the same (no validity tests).
I would be happy to get some inputs from the community regarding this design, are the design issues 'legit' or not, and what could have been done better?
Edit 1:
An ellipse is expressed by : two points and d (For a point to be on the ellipse the distance between it and the two points must be equal to d).
A circle is expressed by : center and radius.
I find it very hard to understand how they can share common params.
I suggest you follow this scheme:
You need to categorize shapes by the number of the edges first and then by the common characteristics. Then you have to recognize the following facts:
circle is just a special type of ellipse
square is just a special type of rectangle
both rectangle and parallelogram have 4 edges
unlikeparallelogram, rectangle have all the angles of 90°.
This is a simplified scheme according to your needs:
Ellipse, Circle, Square, Rectangle, Triangle, Parallelogram
Edit: Note that there exists the following hierarchy as well. Both rectangle and parallelogram have the opposite edges of the same length. Finally, it depends on the preferred interpretation and on what suits your situation better (thanks to #Federico klez Culloca):
Quadrilateral <- Parallelogram <- Rectangle <- Square
Make it scalable: In case of more complex shapes of elementary geometry included, I'd put probably place polygon below shape and then differentiate the descendants by the convexity and non-convexity first.
The design you have used is not idea (IMHO).
First, rename non-circular into Polygon (Also, us uppercase for the first letter).
Based on the implementation, a Circle is a specific Ellipse so I would have used inheritance here
Shape < -- Circular < -- Ellipse < -- Circle
< -- Polygon < -- Triangle < -- Equilateral
< -- ... //don't know the english names of those triangles
< -- Quadrilateral < -- Square
< -- Rectangle
< -- ...
< -- Hexagon
< -- ...
Each subclass of Polygon are abstract, those are used for the validation of the number of corners.
In general, I would have linked Square and Rectangle based on the geometry rule (same width and heigth) ( Square extends Rectangle) but based on your implementation using Point and Line, this is not required.
But using two classes would still allows some validation in the future ( every Line for a Square need to have the same length, ...).
This shows that a design depends mostly on the requirement, not only on the subject.
About Ellipse and Circle. An Ellipse is form of two points, if those point are the same, this is a Circle, this can be a link ;)

Extracting the Silhouettes Coordinates

From the image I posted up there, I have all the coordinates from those rectangles in the Figure C saved in an array of the class Figure.
Figure:
public abstract class Figure {
private int left, right, height;
protected Coordinates[] coords;
public Figure() {
}
public Figure(int left, int right, int height, Coordinates[] coords) {
this.left = left;
this.right = right;
this.height = height;
this.coords = coords;
}
public int getRight() {
return right;
}
public int getLeft() {
return left;
}
public int getHeight() {
return height;
}
public Coordinates[] getCoords() {
return coords;
}
public abstract void setCoordinates();
public abstract void showCoordinates();
}
Coordinates:
public class Coordinates {
private float x, y;
public Coordinates() {
}
public Coordinates(float x, float y) {
this.x = x;
this.y = y;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
}
Thing is, I have to find the coordinates of the silhouette from the whole graph the way it is in Figure D (see the image) using the coordinates from the array already mentioned.
Example (See the Image Reference):
1st Rectangle Coordinates are: (1,0)(1,11)(5,11)(5,0)
2nd Rectangle Coordinates are: (2,0)(2,6)(7,6)(7,0)
3rd Rectangle Coordinates are: (3,0)(3,13)(9,13)(9,0)
4th Rectangle Coordinates are: (12,0)(12,7)(16,7)(7,0)
5th Rectangle Coordinates are: (14,0)(14,3)(25,3)(25,0)
6th Rectangle Coordinates are: (19,0)(19,18)(22,18)(22,0)
7th Rectangle Coordinates are: (23,0)(23,13)(29,13)(29,0)
8th Rectangle Coordinates are: (24,0)(24,4)(28,4)(28,0)
The Coordinates of the Silhouettes from all those rectangles should be:
(1,11)(3,13)(9,0)(12,7)(16,3)(19,18)(22,3)(23,13)(29,0)
This is where I'm stuck thinking how I'll get these coordinates.
I'm not asking someone to do it for me or something like that, I just want to think from where to start cause all I've tried failed so far, so any tips or ideas would come in handy! thank you so much in advance! Good nite.
It looks like you are attempting to obtain the union of each cluster of overlapping rectangles. Java's java.awt.geom.Rectangle class has a createUnion(Rectangle2D) method that will 'absorb' a second rectangle into the first (via a 'union'). However, this doesn't solve your clustering problem.
If the the number of rectangles you are trying to process is relatively small and clustering is only needed in one dimension (i.e. horizontally), the most straight-forward way would be to keep a list of rectangles that haven't already been clustered, loop through each unclustered rectangle, remove the first rectangle into its own new 'cluster' and then perform an intersect with all other unclustered rectangles to determine if the pair should be clustered. The java.awt.geom.Rectangle2D.intersects(Rectangle) method is perfectly suitable for this. If they intersect then the rectangle that intersects should be removed from the list of unclustered rectangles and added to the current cluster.
The Rectangle2D class doesn't quite match your storage of coordinates, but a mapping will be reasonably straight forward.
Once you have your sets of clustered rectangles, you still need to find the path of each Polygon that bounds all rectangles in a given cluster. If your sample picture is indicative of all rectangles such that they all have their bottom edge at the same 'height' and none of your rectangles have different rotations, this will be a lot easier.

Inheritance of Square method in java

I have a class Rectangle laid out like this:
package Inheritance;
/**
*
* #author Jacob
*/
public class Rectangle {
final private int length;
final private int width;
public Rectangle (int l, int w)
{
length = l;
width = w;
}
public int getLength ()
{
return length;
}
public int getWidth ()
{
return width;
}
#Override
public String toString ()
{
return String.format ("Rectangle (%dX%d)", length, width);
}
}
I then need to create class square in the following way:
ad Square:
Square extends Rectangle /
No fields are declared in class Square /
It has a parameterized constructor with (only) one parameter /
The parameter is used to initialize both fields of Rectangle /
It has a method called getSide to expose the side-length of the square /
Override the toString method so that it will return a String of the following form: / Square(side) e.g. Square(4)
The values for the sides are going to be hard coded. Rectangle is going to have a width of 4. In order to get the side of the square to be 4 do I create an instance of rectangle and call the method getWidth and set that as the side length. Thats how I would think to do it but in that case I would only be using one of the fields so, My question is how do I initialize both fields? Can I call Rectangle and make length and width equal or is there some other way I should do it?
Here is the code for my Square class:
public class Square {
public Square (int side)
{
super(side, side);
}
public int getSide ()
{
return side;
}
#Override
public String toString ()
{
return String.format ("Square (%d)", side);
}
}
For the line super(side, side) I get the error constructor Object in class Object cannot be applied to given types. Required no arguments, found int, int. For my return statements I get that it cannot find the variable side.
The values for the sides are going to be hard coded.
I assume that you mean that you will hardcode the values for the width and length when you create a Rectangle and Square object (for example in main()). These values should absolutely not be hardcoded any where in the Rectangle and Square classes.
Rectangle is going to have a width of 4. In order to get the side of the square to be 4 do I create an instance of rectangle and call the method getWidth and set that as the side length.
Not at all. Rather, Square should have its own constructor which calls the Rectangle constructor with the same value for both the width and length:
public Square(int side) {
super(side, side); // Set the width and length to the same value.
}

SWT - Drawing a Moving Image Over Tiles

I've been experimenting with different ways of moving a image over a grid of tiles for a game, but I've been unable to get a working implementation.
First I tried using a grid layout to hold a bunch of Tiles that extended Canvas and drew themselves. This drew the tiles nicely, however it seems that I am unable to draw my Player object on top of them. Originally, the Player also extended Canvas and I intended to have the widget on top of the tiles. It seems like this is impossible.
I then tried to have the Tile simply extend nothing, and just hold the image. I then hold each Tile in a 2D array and draw each Tile by a nested for loop, using the int from the for loop, multiplied by the image size, to draw Tile's Image. I put this code in a PaintListener inside of my constructor for my Map class that extended Canvas and dropped my Map onto my Shell in a Fill layout, but the PaintListener never gets called (I tested with a print statement).
What implementation could I use to draw the Tiles at the start of the game, then allow me to control the movement of my Player image?
I did something similar.
Using a PaintListener I get the calls when the Widget needs to be repainted. In my paint function, I loop over a tile array (wrapped in a World class) and draw all tiles. Afterwards I use the same technique with a worldObjects array/class:
public class WorldWidget extends Canvas {
WorldWidget() {
addPaintListener(new PaintListener() {
#Override
public void paintControl(PaintEvent e) {
WorldWidget.this.paintControl(e);
}
});
}
protected void paintControl(PaintEvent e) {
GC gc = e.gc;
for (short y = 0; y < world.getHeight(); y++) {
for (short x = 0; x < world.getWidth(); x++) {
final ITile tile = world.getTile(x, y);
final Image image = ImageCache.getImage(tile);
gc.drawImage(image, x * tileSize, y * tileSize);
}
}
// Here is used a similar loop, to draw world objects
}
}
This is obviously a condensed code example, as the class is part of an editor and reacts on mouse clicks and movement amongst other things.
When I did a tile based simulation while ago I did it this way:
I had 2 layers of the tile map - one for the terrain and second for the units.
The map itself was represented by a JPanel.
So roughly you got this for the JPanel:
public void paintComponent(Graphics graphics) {
// create an offscreen buffer to render the map
if (buffer == null) {
buffer = new BufferedImage(SimulationMap.MAP_WIDTH, SimulationMap.MAP_HEIGHT, BufferedImage.TYPE_INT_ARGB);
}
Graphics g = buffer.getGraphics();
g.clearRect(0, 0, SimulationMap.MAP_WIDTH, SimulationMap.MAP_HEIGHT);
// cycle through the tiles in the map drawing the appropriate
// image for the terrain and units where appropriate
for (int x = 0; x < map.getWidthInTiles(); x++) {
for (int y = 0; y < map.getHeightInTiles(); y++) {
if (map.getTerrain(x, y) != null) {
g.drawImage(tiles[map.getTerrain(x, y).getType()], x * map.getTILE_WIDTH(), y * map.getTILE_HEIGHT(), null);
}
}
}
if (map.getSimulationUnits() != null) {
for (Unit unit : map.getSimulationUnits()) {
g.drawImage(tiles[unit.getUnitType()], (int) Math.round(unit.getActualXCor() * map.getTILE_WIDTH()), (int) Math.round(unit.getActualYCor() * map.getTILE_HEIGHT()),
null);
}
}
// ...
// draw the buffer
graphics.drawImage(buffer, 0, 0, null);
}
Logic:
private Terrain[][] terrain = new Terrain[WIDTH][HEIGHT];
/** The unit in each tile of the map */
private Unit[][] units = new Unit[WIDTH][HEIGHT];
Then you have your game loop where you update the position of the units and other things, basically render() and update() the game. Check the links I've provided below.
NOTE
Since you are making a simple game this post about making game loops will be definitely useful for you. This hopefully also answer your question about moving the object on the map.
This site will be also very helpful since you will probably need to detect collision at some point too.

Categories

Resources