I've been researching for the past hour or so and I can't seem to render an isometric map. I want to achieve something like this.
But I am getting this.... I am storing my map as tiles in a 1 dimensional array like so:
private final int width, height;
private final int tileWidth, length;
private int[] tiles;
public Level(int width, int height) {
this.width = width;
this.height = height;
tiles = new int[width * height];
tileWidth = 68;
length = 48;
}
I am passing through 10, 10 as the parameters for width and height. And I render the map like so:
public void render(Graphics g) {
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
g.setColor(Color.red);
if (x % 2 == 0)
g.drawRect(x * tileWidth, y * length / 2, tileWidth, length);
else
g.fillRect((x * tileWidth) + (tileWidth / 2), (y * length / 2), width, length);
}
}
}
Any help would be really appreciated, I've wanted to learn to make isometric games but have been stuck with flat 2D for a while.
For just tiles, you could use a shear transform:
Graphics2D g2d = (Graphics2D) g;
AffineTransform at = AffineTransform.getShearInstance(1, 0);
g2d.transform(at);
// rest of your drawing code here
You may also want to set the shear anchor point:
double sa_x = 100, sa_y = 100; // or whatever
AffineTransform at = new AffineTransform();
// S3: Move back to original origin
at.translate(sa_x, sa_y);
// S2: Shear
at.shear(1, 0);
// S1: Set origin
at.translate(-sa_x, -sa_y);
You can vary the shear factor 1 to get different amounts of shear.
Instead of drawing rects, you need to draw lines at isometric angles.
The angles in isometric geometry are 30 degrees, 90 degrees, 150 degrees, 210 degrees and 270 degrees (in radians: pi/6, pi/2, 5pi/6, 7pi/6, 3pi/2, 11pi/6.).
cos(pi/6) is sqrt(3)/2 or 0.866... and sin(pi/6) is 1/2 or 0.5. (This is meaningful because of http://en.wikipedia.org/wiki/File:Sin-cos-defn-I.png )
This means that if you want to draw a line at the angle pi/6 that is D pixels long starting at x1,y1:
x2 = x1+cos(pi/6)*D e.g. x1+D*sqrt(3)/2
y2 = y1+sin(pi/6)*D e.g. y1+D/2
and draw from x1,y1 to x2,y2.
All the other angles are either reflections of this (one dimension or both are made negative) or straight up and down (trivial to draw).
To calculate where on the screen to draw an isometric object, consider that isometric geometry has three dimensions: X, Y, Z. Movement by Z will just make you draw D higher or D lower. Movement by X or Y will move you in one isometric angled direction or the other, by the same x and y as the distance of drawing one tile line in that direction (so similar formula to the above).
Related
I'm drawing arrows using Java and I can draw them straight but now I need to have the arrows pointing in different directions.
In my current code, I draw a triangle and then a square.
Is there a way to group the two after they've been drawn and then rotate them at a random angle?
Right now I'm only able to rotate the triangle and square separately, causing some messy thing.
void setup() {
size(400, 400);
}
void draw() {
float r = random(24, 64);
background(255);
drawArrow(r);
//drawPlus(r);
saveFrame("dataArrow/plus####.png");
if (frameCount == 100) {
exit();
}
}
void drawArrow(float r){
float base = r * 2;
float xStart = random(1, width-base - 1);
float xEnd = xStart + base;
float k = 0.5 * base;
float y = random(k, width-k);
float middleBase = base/2 + xStart;
float rectSide = 0.5 * base;
float rectX1 = middleBase - rectSide/2;
float rectX2 = middleBase + rectSide/2;
fill(0);
triangle(xStart, y, xEnd, y, middleBase, y - k);
rect(rectX1, y, rectSide, rectSide);
}
not sure if this exactly what you mean but here is how to move things around
push and pop matrix allows you to organize things that should have the same translations
https://processing.org/reference/pushMatrix_.html
https://processing.org/reference/rotate_.html
https://processing.org/reference/translate_.html
basic example
pushMatrix();//start of new translation and rotation things
translate(xAmount,yAmount);//this moves the origin
rotate(angle);//this rotates around origin
//drawing around the point of rotation 0,0 here
//drawing...
popMatrix();//reset all translations and rotations to before
I hope I'm asking this concisely enough. I'm wanting to run a script that will predict where a rectangle will end up when doing a rotation, before the rotation actually starts. So, if you're given a rectangle which is located on coordinates (40, 40) and you want the angle to change by 20 degrees, how would you predict or estimate the x y values of where that rectangle would end up? I'm wanting to do this estimation first, then store it in an array, and then compare it when the real rotation happens. For the prediction, I'd have thought it would be something like this...
void setup(){
size(825, 825);
background(255);
smooth();
PShape Shape = createShape(GROUP);
PShape rectangle = createShape(RECT, 40, 40, 120, 230); // with 40 and 40 being the x and y
// extra point just to show where the x and y of the rectangle are //
strokeWeight(5);
stroke(0, 255, 0);
PShape point = createShape(POINT, 40, 40);
Shape.addChild(rectangle);
Shape.addChild(point);
int rectangleX = 40;
int rectangleY = 40;
int translationModifierX = 200;
int translationModifierY = 200;
// so this here would be the theoretical estimate on what the new x and y coordinates would be for the translation, before moving onto the rotation. This one's easy to predict, of course. //
int newX = rectangleX + translationModifierX;
int newY = rectangleY + translationModifierY;
// And here is where I'd be trying to estimate what the new x and y coordinates would be after rotated. //
float rotatedX = newX*cos(20) - newY*sin(20);
float rotatedY = newX*sin(20) + newY*cos(20);
println("Final X Coordinate Prediction:", rotatedX);
println("Final Y Coordinate Prediction:", rotatedY);
pushMatrix();
Shape.translate(newX, newY);
Shape.rotate(radians(20));
popMatrix();
shape(Shape);
}
This printed prediction, though, is not that close to where the x y actually ends up. It actually ends up around 263, 292, but the print puts the x value as ~-121, and its y value at ~317. What I'm really needing to do is get this prediction's x and y coordinates to be the same as it would be when I run rectangle.rotate(radians(20)). I just want to be able to see where this rectangle would go before it actually goes there. I feel like it's a math problem. I'm obviously new, so I'd appreciate any assistance.
You need to use the relative (rectangleX/rectangleY), not the absolute (newX/newY) coordinates.
float rotatedX = newX + rectangleX*cos(radians(20)) - rectangleY*sin(radians(20));
float rotatedY = newY + rectangleX*sin(radians(20)) + rectangleY*cos(radians(20));
I am trying to make a program where there are lines in a grid pointing towards the mouse like magnets. I am a beginner in Processing, can someone point me towards a tutorial on how to do that or give me some code and explain what it does?
int x1 = 0;
int x2 = 0;
int y1 = 0;
int y2 = 0;
void setup() {
size(200, 200);
}
void draw() {
background(255, 255, 0);
x1 = (mouseX + 100) / 2;
y1 = (mouseY + 100) / 2;
x2 = -1 * x1 + 200;
y2 = -1 * y1 + 200;
line(x1, y1, x2, y2);
}
There's plenty of solutions for this project. One of the easiest is to use Processing's PVector class.
The PVector class can be used for two or three dimensional vectors. A vector is an entity that has both magnitude and direction. The PVector class, however, stores the components of the vector (x,y for 2D, and x,y,z for 3D). The magnitude and direction are calculated from the components and can be accessed via the methods mag() and heading().
A two dimensional vector in Processing is defined through x and y components:
PVector v = new PVector(xComponent, yComponent);
With some mathematical formulae, you can determine magnitude and direction using the x- and y-components. But we don't need to determine these.
Below, I've attached completed solution code. Most of it should make sense to you. But it's worth understanding what is going on with PVector.
A nested for loop within void draw() contains x and y variables that represent the coordinates of each grid vertex.
We first define PVector v as a vector given by an x-component of mouseX - x, or the difference between the x-positions of the mouse and each grid point. Similarly, the y-component given by mouseY - y has the same difference.
Creating a variable PVector u initialized from v.setMag(15) holds a PVector that has the same direction as v, but with a length of just 15.
Now to draw the lines. Vectors represent an offset, not a position (in this case), so drawing a line from a grid point to an offset of a grid point is key.
Hence line(x, y, x + u.x, y + u.y), where u.x and u.y are the x- and y-components of the vector u.
void setup() {
size(600, 600); // Set the size of the canvas to 600x600.
}
void draw() {
background(255);
stroke(200); // Set the stroke color to black
int distVertLine = width / 10; // This variable defines the distance between each subsequent vertical line.
for(int i = 0; i < width; i += distVertLine) {
line(i, 0, i, height); // Draw a line at x=i starting at the top of the canvas (y=0) and going to the bottom (y=height)
}
int distHorizLine = height / 10; // This variable defines the distance between each subsequent vertical line.
for(int i = 0; i < width; i += distHorizLine) {
line(0, i, width, i); // Draw a line at y=i starting at the left of the canvas (x=0) and going to the right (x=width)
}
stroke(0); // Set the stroke to black.
// Use a nested for loop to iterate through all grid vertices.
for(int x = 0; x <= width; x += width/10) {
for(int y = 0; y <= height; y += height/10) {
PVector v = new PVector(mouseX - x, mouseY - y); // Define a vector that points in the direction of the mouse from each grid point.
PVector u = v.setMag(15); // Make the vector have a length of 15 units.
line(x, y, x + u.x, y + u.y); // Draw a line from the grid vertex to the terminal point given by the vector.
}
}
}
The answer already given by Ben Myers is excellent! The code below has a few small modifications:
the two for loops for the grid lines have been combined (since width and height are equal);
the construction of the vector is combined with setting the magnitude;
some minor changes to colors and comments.
Modified code:
void setup() {
// Set the size of the canvas to 600x600 pixels.
size(600, 600);
}
void draw() {
// There are 10x10 grid cells that each have a size of 60x60 pixels.
int gridSize = width / 10;
// Set the background color to anthracite and the stroke color to orange.
background(56, 62, 66);
stroke(235, 113, 52);
// Draw vertical and horizontal grid lines.
for (int lineIndex = 0; lineIndex < gridSize; lineIndex++) {
line(lineIndex * gridSize, 0, lineIndex * gridSize, height);
line(0, lineIndex * gridSize, width, lineIndex * gridSize);
}
// Set the stroke color to blue.
stroke(0, 139, 225);
// Use a nested for loop to iterate through all grid cells.
for (int x = 0; x <= width; x += gridSize) {
for (int y = 0; y <= height; y += gridSize) {
// Define a vector that points in the direction of the mouse from
// each grid point and set the vector length to 15 units.
PVector vector = new PVector(mouseX - x, mouseY - y).setMag(15);
// Draw a line from the grid point to the end point using the vector.
line(x, y, x + vector.x, y + vector.y);
}
}
}
I have a Java swing application where I can draw hot spots. I am allowing user to draw Rectangle , Polygon and Circle.
For Circle I am using Ellipse2D
Ellipse2D.Double ellipseDouble = new Ellipse2D.Double(x,y,width,height);
g.draw(ellipseDouble);
Above works fine and it does draw an ellipse/circle.
Now the problems when I want the region to be used in HTML Image map.
Html Image map doesn't support Ellipse so I was thinking to use polygon for Ellipse2D but really don't know how would I convert it.
Does anyone know how would I go about it converting an Ellipse2D to Polygon ponits?
Use FlatteningPathIterator.
See e.g. http://java-sl.com/tip_flatteningpathiterator_moving_shape.html where point moves following custom Shape.
You can get list of Points and create Polygon.
Maybe someone will find this one useful: this is pdfbox ellipse or circle (width=height) draw function inside rectangle, it make ellipse as polygon initially to draw.
Code based on math function of ellipse at poin [0 , 0]: x^2/a^2 + y^2/b^2 = 1
private PdfBoxPoligon draw_Ellipse_or_Circle_as_poligon_with_PDFBOX (
PDPageContentStream content, float bottomLeftX, float bottomLeftY,
float width, float height, boolean draw) throws IOException {
PdfBoxPoligon result = new PdfBoxPoligon();
float a = width/2;
float b = height/2;
int points = (int) (a*b/20);
if (DEBUG) {
System.out.println("points=" + points);
}
//top arc
for (float x = -a; x < a; x = x + a / points) {
result.x.add(bottomLeftX + a + x);
float y = (float) Math.sqrt((1-(x*x)/(a*a))*(b*b));
result.y.add(bottomLeftY+b+y);
}
//bottom arc
for (float x = a; x >= -a; x = x - a / points) {
result.x.add(bottomLeftX + a + x);
float y = -(float) Math.sqrt((1-(x*x)/(a*a))*(b*b));
result.y.add(bottomLeftY+b+y);
}
result.x.add(result.x.get(0));
result.y.add(result.y.get(0));
if (draw) {
for (int i=1; i < result.x.size(); i++) {
content.addLine(result.x.get(i-1), result.y.get(i-1), result.x.get(i), result.y.get(i));
}
}
return result;
}
I am working on creating graphs with vertices and edges. The graph is directed, so the edges are represented as arrows. My problem is getting the correct coordinates for the arrows.
A Vertex has a Coordinate (see class below), while an Edge goes from a Vertex to another Vertex. The challenge is that a vertex is drawn with a fixed radius (see picture below). I'm having problems getting the arrow pointing to the correct place on the circles circumference. It seems like with the code I currently have, the arrow points to the top-left corner, not the closest point.
I have the following method for drawing the arrows:
public static void drawArrow(Graphics g, Color color, int size,
Coordinate from, Coordinate to, Coordinate offset) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setColor(color);
double dx = to.x - from.x, dy = to.y - from.y;
double angle = Math.atan2(dy, dx);
int len = (int) Math.sqrt(dx*dx + dy*dy);
AffineTransform at = AffineTransform.getTranslateInstance(from.x + offset.x, from.y + offset.y);
at.concatenate(AffineTransform.getRotateInstance(angle));
g2.transform(at);
// Draw horizontal arrow starting in (0, 0)
g2.drawLine(0, 0, len, 0);
g2.fillPolygon(new int[] {len, len-size, len-size, len},
new int[] {0, -size, size, 0}, 4);
}
I got the essentials of the arrow code from an answer by aioobe, here.
I this method by overriding Edge's paintComponent function:
#Override
public void paintComponent(Graphics g) {
double radius = this.from.getRadius();
Coordinate vector = this.from.getPosition().clone();
vector.normalize();
vector.x = vector.x * radius; vector.y = vector.y * radius;
Coordinate to = new Coordinate(this.to.getPosition().x - vector.x,
this.to.getPosition().y - vector.y);
GraphicsUtils.drawArrow(g, this.color, ARROW_SIZE,
this.from.getPosition(), to,
new Coordinate(radius, radius));
}
As the drawArrow method does what it's supposed to, it draws an arrow from a to b, I want to change the way that I am calling it in the above method. For example, by using the offset parameter for the drawArrow method or something alike.
The Coordinate class:
public class Coordinate {
public double x;
public double y;
...
public void normalize() {
double length = Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2));
this.x = this.x / length;
this.y = this.y / length;
}
...
}
A screenshot of my current output:
Note there are both arrows from D to E and E to D. The latter is not showing because the arrow head is behind D's circle.
Now to be clear, the problem is:
In the paintComponent-method, I am taking the radius of the circle and multiplying it with the normalized (see method) vector. This would give me a point of the circle's circumference, but it seems that always results in the top-left corner, which I don't get. I want to calculate the point on the circumference closest to the source vertex.
Like so:
Any suggestions?
You can calculate the arrow endpoints from the coordinates of the vertex centers and the vertex image radius. If (xa, ya) and (xb, yb) are the centers of two vertices a and b, and the vertices are drawn with radius r, then the directed line from a to be can be represented as
x = xa + t*(xb - xa)
y = ya + t*(yb - ya)
for a parameter t that varies from 0 to 1. Since t == 1 corresponds to a distance of d = sqrt((xb - xa)2 + (yb - ya)2), you just need to evaluate the above for t = r / d and t = (d-r) / d. (No trig required.)