I'm creating a 2D game in Java using the Java2D library for drawing, and I really need a float-precision Polygon object that I can use both to draw game objects and to do collision detection on them. Unfortunately, Java's Polygon object comes in int precision only, and there is no equivalent Polygon2D like there is with Rectangle and Rectangle2D. I've already done enough research to see that I have a few options, but none of them seem very good.
Use Path2D. According to a Java developer posting in this forum, the lack of Polygon2D was an oversight, but its suggested replacement is Path2D. Unfortunately, Path2D doesn't provide a way to access its individual vertices or edges, which I need in order to do collision detection (specifically I need to get a vector orthogonal to each edge).
Implement my own Polygon2D that implements the Shape interface so that I can still pass it to Graphics2D.draw(Shape). This looks like it would be pretty difficult. The Shape interface requires tricky-to-implement methods like contains(Rectangle2D) and getPathIterator(AffineTransform). For getPathIterator in particular, it seems that in order to implement it I'd need to return an object of type PathIterator, but there are no concrete implementations of the PathIterator interface available in the public AWT packages.
Wrap Path2D in an object that "remembers" the individual vertices and provides them to the client. This worked for me when I needed an Area that remembered its component shapes: I wrapped it in a CompoundShape class that implemented the Shape interface and forwarded all the Shape methods to Area's implementation of them, while keeping track of each Shape that was added to the Area in an ArrayList. The problem with this is that if I keep track of the individual vertices in two arrays of floats, there is no way to expose them to the user without the possibility of the user changing the vertices - and since that would happen by direct array access, the internal Path2D wouldn't get notified of the changes.
Copy Polygon.java. The actual source code of Java's Polygon class is available on grepcode.com, and I could simply replace the vertex-related ints with floats throughout to get a Polygon2D. Unfortunately, when I tried this, the line import sun.awt.geom.Crossings; threw a compiler error saying "The type Crossings is not accessible due to restriction on required library C:\Program Files\Java\jre7\lib\rt.jar." According to this question that happens because Sun's license agreement prevents you from replacing core Java classes with your own, but Polygon doesn't try to do that - it simply creates an object of type sun.awt.geom.Crossings, no replacing or extending happens, and I made sure to put my copy of Polygon in a package not called "java".
What's the best way to proceed with this? I'd appreciate either suggestions for how make one of these options work or an idea for another option that doesn't have the problems these encounter.
I would also recommend Path2D. GeneralPath is a legacy class; don't use it.
Path2D does provide access to the vertex values, albeit it a roundabout fashion. You need to use a PathIterator:
PathIterator pi = path.getPathIterator(null);
float[] value = new float[6];
float x = 0, y = 0;
while (!pi.isDone()) {
int type = pi.currentSegment(values);
if (type == PathIterator.SEG_LINETO) {
x = values[0];
y = values[1];
}
else if (type == PathIterator.SEG_CLOSE) {
x = 0;
y = 0;
}
else {
// SEG_MOVETO, SEG_QUADTO, SEG_CUBICTO
}
pi.next();
}
When you're ready to get fancy, you can expand that else to support the quadratic and cubic curves.
I assume you don't need those at this time as you're talking about polygons.
Also, Path2D has some handy static methods for testing whether the path intersects a rectangle and whether the path contains a rectangle or point. Sadly, there are no methods for testing for a path intersecting or containing another path.
Perhaps have the internals of the polygon at a different scale?
Multiply by a large number and typecast to int when writing to it, divide by the same large number when reading?
Can you use a 3rd party library? If so, might I suggest to use the Slick 2D Polygon class. What I would do is internally, use this class for your actual Polygon to check intersection with contains and then when you need to draw, just cast the float values to int and draw the Java2D Polygon.
I know this might not be the optimal solution, but it might work for what you're doing.
Related
I am creating an Android app that draws to the canvas. For this, I have defined rectangular screenareas that I want to draw to the canvas. As I am always drawing a fixed set of screenareas, I was thinking of using Enum (as Enum is designed for fixed sets).
Here is my enum:
public enum LayoutEnum {
FULLSCREEN(
new ScreenArea(
new Rect(
0,
0,
MainActivity.getDevice().getWidth(),
MainActivity.getDevice().getHeight()),
Attributes.BG_PAINT)),
LOGO_AREA(
new ScreenArea (
new Rect(
(int) (0.3 * FULLSCREEN.getScreenArea().getArea().width()),
(int) (0.3 * FULLSCREEN.getScreenArea().getArea().width()),
(int) (FULLSCREEN.getScreenArea().getArea().width() - 0.3 * FULLSCREEN.getScreenArea().getArea().width()),
(int) (0.7 * FULLSCREEN.getScreenArea().getArea().width())),
Attributes.BG_PAINT)
);
private ScreenArea screenArea;
LayoutEnum(ScreenArea screenArea) {
this.screenArea = screenArea;
}
public ScreenArea getScreenArea() {
return screenArea;
}
}
ScreenArea is a simple class that holds a Rect and a Paint and contains a draw method (and some getters and setters).
The question I have, is: is this a good approach?
On one hand I am working with a fixed set of variables. On the other hand, these variables are mutable and I can change their attributes (e.g., using the getters and setters). For example, I can call FULLSCREEN.getScreenArea().getPaint().setColor(Color.BLUE)
When you look at Enum it says it is
a special data type that enables for a variable to be a set of
predefined constant
So I do have a fixed set, it is predefined, but not necessarily constant.
My original approach was to define a class called Layout which contained a HashMap of Screenarea's. In that case, I was using e.g., Layout.get("fullscreen").draw(canvas) to draw the screenarea to the canvas. In this new approach I am using e.g., FULLSCREEN.getScreenArea().draw(canvas).
One of the reasons I would like to switch is to introduce a typesafe solution. Of course, it would also be possible to switch from a HashMap to an EnumMap and store the names of my screenareas in an Enum.
Hope you can point me in the right direction: a direction that not only works (the above is already working) but is also acceptable and doesn't smell.
I want to create a game which has for example 20x30 fields,my first thought was that each field would be a list(becouse sometimes some field contains more than one object),but after reading a few questions about the array of generic lists,I've realised it's not a good solution.
The game is going to be a very simple version of Raft,playing it in console with commands like "left" so the character moves one field left.
So can you recommend a good container or something to design the fields?
An illustration of the game:
http://imgur.com/a/8YpeA
If you are implementing a fixed-sized rectangular "playing surface", then I would recommend a Cell[][] where the Cell type is a custom class that represents the state of a cell on the surface.
There is no need to use generics here ... unless you are trying to implement an abstraction that can be used in many games.
Also, there is no need for list-like functionality. You don't remove or add cells to the board. You move pieces / players / whatever from one cell to another.
(If your board is not based on discreet cells, the you will need to use some other approach. But any 2D playing surface with a bounded number of discrete cells can be mapped to a Java array, one way or another.)
So can you recommend a good container or something to design the fields?
Recommendations for libraries and tools are OFF-TOPIC.
There are two ways you can create generic arrays:
Create private static inner class of a type:
transient Node<K, V>[] table;
public MyHashMap(int limit) {
this.limit = limit;
table = (Node<K, V>[]) new Node[limit];
}
Use Array.newInstance(class, size)
moreover using generics for custom implementations is not a good choice.
I'm trying to recreate a board game. This board game has a 4x4 dimension which can be represented by a 2D arraylist. However, what i'm having difficulty doing is deciding what would be the best method of implementing a 4x4 board game where each row and column can hold 4 items(In the fashion of a stack where the top item is the greatest int). Would a 2D arraylist of stacks be the most efficient in this case, or would a 3D arraylist be the way to go. Similarly, how would I initialize a 3D arraylist of integers? Thanks!
Efficiency is going to be fine either way, do whatever is easiest for the kinds of things you need to do with the squares. Will you be referencing things by their X,Y coordinates? Then you might want to just use a 2-d array of tiles, so you can reference things as
tile = board[x][y]
This assumes that the origin is at the top-left of the board. It's also very efficient, if that were actually an issue.
You asked "...what would be the best method of implementing a 4x4 board game...". But it seems like you should not care about the implementation right now. It sounds like you should care about the interface. Define an interface that precisely mirrors what you want to would like to represent:
interface Board {
int getNumRows();
int getNumCols();
int getStackHeight(int r, int c);
int getStackValue(int r, int c, int h);
}
As it was mentioned before, efficiency should hardly be an issue, and IF it becomes an issue, you'll probably be glad when you can change your implementation without affecting anything else in your game.
I would rather not use any third party JARs or AWT as part of this solution. I am doing everything in my power to keep my project dependency-free. And, if the JRE ships with any classes that solve this for me, I'm still interested in a custom solution here so that I can really understand the mathematics and not just blindly make a few API calls.
I have the following POJO structure for various shapes:
public class Coordinate {
private Double xVal;
private Double yVal;
// Constructors, getters/setters, etc.
public static Double distance(Coordinate c1, Coordinate c2) {
// Calculates the Cartesian distance between c1 and c2 using the standard
// distance formula.
}
}
public abstract class Shape {
// Some properties inherent to all 2D shapes.
public abstract Double calcArea();
public abstract Double calcPerimeter();
}
public class Rectangle extends Shape {
private Coordinate upperLeft;
private Coordinate upperRight;
private Coordinate lowerLeft;
private Coordinate lowerRight;
// Constructors, overrides, getters/setters, etc.
}
public class Circle extends Shape {
private Coordinate center;
private Double radius;
// Constructors, overrides, getters/setters, etc.
}
Now then, I will be given a List<Shape> (mixed set containing 0+ Rectangles and 0+ Circles). I need to determine if any of the shapes in this list intersect with each other (true or false):
public boolean intersectionsExist(List<Shape> shapes) {
// ???
}
I'd like to implement best practices here, so I don't know if there is already any algorithm to do this with (potentially) dozens of shapes. All the "intersection detection" code snippets I've found on SO and on the web have been between exactly 2 shapes. But what if I have 3 rectangles and 7 circles in the list?!?
My thinking is to iterate through each Shape in the list, and compare it with every other Shape (hence a quadratic solution, which I'm not thrilled about). But that way, I could return true the instant I find a Shape that intersects with another.
As for detecting the actual intersection, I am wondering if there is anything I can do that treats these shapes like a Venn diagram. Meaning, somehow determine if one shape is overlapping another. But as to how I could determine "overlap", I have no idea.
So several questions:
Are there any standard algorithms out there for detecting intersections among 3+ shapes? If so, can someone please give me some links/info on them?
If the answer to #1 above is "no", then is my quadratic solution above the best way to go (double-nested for-loops comparing each Shape to every other, and returning true when one intersection is found)? Or is there a better/more efficient way?
Most importantly: how to detect the actual intersections? Are there standard algorithms to accomplish this (links?)? Can someone provide a code example (using my POJOs above), or even give a simple pseudo-code example of what I could do here?
Your problem is commonly called Constructive Solid Geometry. Lookup Wikipedia and or a standard book about computer graphics but please don't expect working code about this complex stuff as a ready-to-use answer.
There are varying solutions for collision detection. You can handle detection within a huge array of objects, as with modern games and their thousands of models, but you are only ever comparing collision for two items at a time
The fastest and simplest-to-code option is to use circles that encompass your objects(very easy if your object is circular) and use a distance-between test. If the distance between the two circles' center points is less than their combined radii, then they are colliding.
This option has some drawbacks, such as a circle on a rectangular object will either collide in some areas where the rectangle isn't drawn(if the circle is larger than the rect) or won't collide at some times it should(if the circle is smaller than the rect).
Some other things you can look at are Axis-Aligned Bounding Boxes or n-DOP collision, both of which are somewhat more mathematically intensive. Here's a good general collisions tutorial
If you want to get extremely complicated and mathy, here is a method known as SAT(Separating Axis Theorem) http://www.metanetsoftware.com/technique/tutorialA.html
If you're interested in the theory of intersections, there is an analysis of the problem in a paper by Chazelle and Dobkin of Princeton†. The paper is too long to summarize here, but it provides a lengthy step-by-step algorithm with proofs. You would still need to code the algorithm yourself. However, the OP did ask for links and/or references.
†Chazelle, B., and Daniel P. Dobkin. Intersection of Convex Objects in Two and Three Dimensions. Princeton, NJ: Princeton U, Dept. of Computer Science, 1986. Web.
Let's say for example a vector is composed of some objects, one of type rectangle, some of type triangle, and then circles.
v = [rectangle, triangle, triangle, circle, circle]
The vector's size can change. I can add another circle as so:
v.addElement(circle);
and..
v = [rectangle, triangle, triangle, circle, circle, circle]
but each object type is clustered together like above. It can't be like:
v = [rectangle, circle, circle, triangle, circle, triangle] //<-- can't be.
I know I explained it pretty horrible but hopefully, it's enough to understand my scenario. Now, I want to randomly choose, for example, an object of type circle.
My thought process is to make a separate method that 1, finds the beginning index and 2, find the ending index and then use random functions off of that. Is there a more elegant way to solve this problem of only choosing randomly off of circles?
Use the Collections API:
Collections.shuffle(v);
Object random = v.get(0);
You should use a hashmap and map the object class as the key and a corresponding array of objects of that class. You can yse reflection to get the class name and set as the key, then add the object to the array as the value.
Otherwise you can't group similar objects in the array and choose a random object from a set of similar objects in an array of different classes like you asked... Unless you framed your question incorrectly
This sounds like a fairly simple random pick problem. All you need to do is generate a random number and get that element -
v.get(Random.nextInt(v.size()));
You can potentially use the implements keyword to check if an object is of a type (or a subtype of that type), but this is not a very pretty solution.
The best solution would likely be to control read and write access to this vector; basically, if you have specific methods for inserting the different shapes, you can stay in control and always ensure that things are inserted to the right place. At that point, just store two ints or such to know where the second and third sections start when choosing.
Although personally, I would just use three separate vectors, if that's possible.