Isometric Projection - java

I'm working on a Java 2.5D game, but I'm having an issue with terrain tiles displaying properly. I've followed several tutorials, surfed StackOverflow, etc, but something still seems to be missing.
Each tile stores its coordinates in top-down 2D view, so that it originally looks like this:
When I try to project them isometrically, it looks like this (obviously incorrect):
Here is the relevant code:
static int getIsoX(int X, int Y)
{
return (X-Y) - xOrientation;
}
static int getIsoY(int X, int Y)
{
return ((X+Y)/2) - yOrientation;
}
static void rotateBuffer()
{
double axis = (double) GameWorld.GRID_SIZE/2;
AffineTransform transform = new AffineTransform();
transform.rotate(45 * Math.PI / 180.0, axis, axis);
op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
}
void draw(Graphics2D G)
{
int x = GameWorld.getIsoX(xCoord, yCoord);
int y = GameWorld.getIsoY(xCoord, yCoord);
G.drawImage(op.filter(sprite, null), x, y, null);
}
xOrientation and yOrientation refer to the coordinates of the camera. The final isometric view should appear such that the tiles are neatly up against one another:
What am I doing wrong?

Related

Is it possible to use BasicStrokes join types on a GeneralPath?

I have a polygon I've made with GeneralPath, and I've made a basic stroke with line thickness of 8 and set the join type to JOIN_MITER. When I try to paint this shape like so:
g2d.setStroke(stroke);
g2d.draw(generalPath);
It paints the shape with the correct line thickness, but it treats each line like it's own, giving it whatever type of cap end I define in the stroke. CAP_ROUND looks the best like this, but I would much prefer the if lines properly joined with JOIN_MITER. Can this be done? Am I using the right class when I use GeneralPath? Any help or advice would be much appreciated.
For context, here's the class stripped down to just the pertinent info. the paintComponent method is called from the paintComponent method of the JPanel which I'm drawing on, it has an arrayList of these which it iterates through and calls each their paintComponent methods at a time:
public class RShape extends RComponent{
GeneralPath linkedLines;
Stroke stroke;
public RShape(int x, int y, int sides, Stroke stroke, int defaultLineLength) {
this.stroke = stroke;
linkedLines = new GeneralPath();
double angle = ((double)360)/sides;//find what the angles would need to be to make a shape with that many sides
double dStartX = x;
double dStartY = y;
double nextAngle;
for(int i=0;i<sides;i++) {
nextAngle = angle*i;
nextAngle = nextAngle * Math.PI / 180;//convert to radians
double dEndX = dStartX + defaultLineLength * Math.sin(nextAngle);//find where the end of the line should be for the given angle and line length
double dEndY = dStartY + defaultLineLength * Math.cos(nextAngle);
int endX = (int) Math.round(dEndX);//round to the nearest int
int endY = (int) Math.round(dEndY);
int startX = (int) Math.round(dStartX);
int startY = (int) Math.round(dStartY);
linkedLines.moveTo(startX, startY);//add the next segment of the GeneralPath
linkedLines.lineTo(endX, endY);
dStartX = dEndX;//move the starting point to the end point so it's ready for the next loop
dStartY = dEndY;
}
linkedLines.closePath();//close the last gap.
}
public void paintComponent(Graphics2D g2d) {
g2d.setStroke(stroke);
g2d.draw(linkedLines);
}
}
This is called like this:
ComponentList components = new ArrayList<RComponent>();
components.add(new RShape(50,50,5,new BasicStroke(8,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER),60));

Libgdx intersection of polygons

I'm learning libgdx by adding some more features to the open source jumper game from Mario Zechner. I'm trying to make some platforms with an angle and run into the problem of collision detection of rotated rectangles.
I followed this solution and used Polygons along with my rectangle bounds.
For testing purposes I don't set an angle yet. I just want to verify that bob jumps correctly off the platforms. But for some reason this doesn't work. the bounds are either too far to the left, above the platform, or not there at all. Am I not setting the polygon correctly?
Would it be easier to use Box2d? I don't have any experience with that and I'm wondering if that's overkill for simple platforms.
public PlatformClient(int platformType, float x, float y) {
this.platformType = platformType;
float x1 = x - Platform.PLATFORM_WIDTH/2;
float y1 = y + Platform.PLATFORM_HEIGHT/2;
this.polyBounds = new Polygon(new float[]{x1, y1, x1+Platform.PLATFORM_WIDTH, y1, x1+Platform.PLATFORM_WIDTH, y1-Platform.PLATFORM_HEIGHT, x1, y1-Platform.PLATFORM_HEIGHT});
polyBounds.setPosition(x-Platform.PLATFORM_WIDTH/2, y-Platform.PLATFORM_HEIGHT/2);
}
class Platform {
public static final float PLATFORM_WIDTH = 2f;
public static final float PLATFORM_HEIGHT = 0.35f;
}
In Bob class update the polygon bounds when he moves:
public void update(float deltaTime) {
...
position.add(velocity.x * deltaTime, velocity.y * deltaTime);
bounds.x = position.x - BOB_WIDTH / 2;
bounds.y = position.y - BOB_HEIGHT / 2;
float newX = position.x - BOB_WIDTH / 2;
float newY = position.y - BOB_HEIGHT / 2;
polyBounds.setVertices(new float[]{
newX, newY,
newX+BOB_WIDTH, newY,
newX+BOB_WIDTH, newY-BOB_HEIGHT,
newX, newY-BOB_HEIGHT});
}
In World class:
private void checkPlatformCollisions () {
int len = platforms.size();
for (int i = 0; i < len; i++)
{
PlatformClient platform = platforms.get(i);
if (bob.position.y >= platform.position.y)
{
if(Intersector.overlapConvexPolygons(bob.polyBounds, platform.polyBounds))
{
System.out.println("it overlaps");
// jump off platform
}
}
}
}
EDIT
Thanks to the shape renderer, I was able to set the polygons correctly. I fixed some +,- issues in the code above. But the following code: Intersector.overlapConvexPolygons() still doesn't work (see image). He jumps before the polygons are making contact or he doesn't jump at all.
Any further ideas?
That's how I draw the polygon of Bob and the platforms that clearly overlap.
public void render() {
shapeRenderer.setProjectionMatrix(cam.combined);
shapeRenderer.begin(ShapeType.Line);
for(int i=0; i<world.platforms.size(); i++) {
shapeRenderer.setColor(1, 0, 0, 1);
shapeRenderer.polygon(world.platforms.get(i).polyBounds.getVertices());
shapeRenderer.polygon(world.bob.polyBounds.getVertices());
}
shapeRenderer.end();
}
ok, I solved it by removing
polyBounds.setPosition(x-Platform.PLATFORM_WIDTH/2, y-Platform.PLATFORM_HEIGHT/2);
from the constructor. Now the collision works correctly.

Code to draw a star

I looked up how to draw a star in Java, and I found the following code:
public void paint(Graphics g) {
drawStar(g,Color.BLACK,5,300,300,100,1…
drawStar(g,Color.RED,6,100,100,20,20);
drawStar(g,Color.BLUE,9,200,400,40,40)…
drawStar(g,Color.YELLOW,27,400,200,10,…
drawStar(g,Color.GREEN,400,300,300,250…
}
public double circleX(int sides, int angle) {
double coeff = (double)angle/(double)sides;
return Math.cos(2*coeff*Math.PI-halfPI);
}
public double circleY(int sides, int angle) {
double coeff = (double)angle/(double)sides;
return Math.sin(2*coeff*Math.PI-halfPI);
}
public void drawStar(Graphics g, Color c, int sides, int x, int y, int w, int h) {
Color colorSave = g.getColor();
g.setColor(c);
for(int i = 0; i < sides; i++) {
int x1 = (int)(circleX(sides,i) * (double)(w)) + x;
int y1 = (int)(circleY(sides,i) * (double)(h)) + y;
int x2 = (int)(circleX(sides,(i+2)%sides) * (double)(w)) + x;
int y2 = (int)(circleY(sides,(i+2)%sides) * (double)(h)) + y;
g.drawLine(x1,y1,x2,y2);
}
}
}
halfPI is defined as a private static variable outside the body
I don't quite get the logic behind these methods. Could someone offer an explanation?
You can follow the graphics object carefully line by line and see what happens to it. It looks like the writer's algorithm uses sine and cosine the evenly split the circle at the same sized angles depending on the number of sides. Then for each side, it draws the line. It is a good beginner program to test and make it work and don't worry if you can't make the basic math work, those are just rather easy trigonometric expressions depending on the arguments that are passed to the drawing method and the helper methods.

java.awt.Graphics.fillRect() misbehaving

Below I have a simple method for painting a set of objects onto an java.awt.applet.Applet. I thought this was very straightforward, but it ends up only painting the objects as a single pixel at the top-left corner of the applet. The idea is that the Display class takes in a set of fairly lightweight objects that extend GameObject and contain information about their location, size, and appearance on the screen, and then draws them pixel-by-pixel onto the applet, stretching and positioning them proportionally depending on the specified display height and width. In testing this, I set the width and height of the Display to 128, and pass two objects to the Display, which are both 32-pixel squares (both return 32 for getWidth() and getHeight()), one is red and returns 24 for getX() and getY(), and the other is blue and returns 16 for getX() and getY(). I put the Display in a javax.swing.JFrame and use a java.awt.BorderLayout to ensure it fills the frame (I use add(display, java.awt.BorderLayout.CENTER); within the aforementioned javax.swing.JFrame).
As far as I can tell, this should be paining a blue 32-pixel square that's 16 pixels from the top and left edges and a red 32-pixel square that is either obscured by or obscuring part of the other one. However, all I get is a single red or blue pixel in the top-left corner of the Display. This is consistent no matter how big or small the window is.
Code
public class Display extends java.awt.applet.Applet
{
private int w,h;
private ArrayPP<GameObject> gameObjects;//ArrayPP is my way of making a dynamically expanding array. It is similar to Vector, but has many more useful methods I use elsewhere.
public Display(int width, int height)
{
w = width;
h = height;
}
public void addGameObject(GameObject go)
{
gameObjects.add(go);
}
public void refresh(java.awt.Graphics g)
{
int x, y, w, h;
final int W = getWidth(), H = getHeight();
for (GameObject go : gameObjects)//Draw all objects
for (x = go.getX(), y = go.getY(), w = go.getWidth() + x, h = go.getHeight() + y; y < h; y++)//Draw all lines of the object
for (x = go.getX(); x < w; x++)//Draw all the pixels on this line of the object
{
g.setColor(go.getColorForPixel(x, y));
g.fillRect((x / this.w) * W, (y / this.h) * H, w/W, h/H);
}
}
}
public interface GameObject
{
public int getX();
public int getY();
public int getWidth();
public int hetHeight();
public java.awt.Color getColorForPixel(int x, int y);
}
Question
Why is java.awt.Graphics.fillRect(int x, int y, int width, int height) only painting the topleft corner of the applet?
Solution
The solution lies in the line that reads
g.fillRect((x / this.w) * W, (y / this.h) * H, w/W, h/H);
wherein integer calculations cause all values to be 0. The solution is as follows:
g.fillRect((int)(((float)x/(float)this.w) *W),
(int)(((float)y/(float)this.h) *H),
(int)((float)W/(float)w),
(int)((float)H/(float)h));
The problem lies with
(x / this.w) * W
If x and this.w are both integers and x
Convert one or more of x and w to float to force a floting point division.
(int)(((float)x/(float)this.w) *W)

How can I efficiently draw many pixels on a Canvas?

I'm making my first game using Java on Android. I need to draw a lot of pixels which together should create a line. My first approach was to make a large array of booleans, create a loop, and draw a pixel when the associated boolean was true.
It wasn't a good idea of course (the array is about 200x300). Now I remember only the position of the first pixel of the line, and every next pixel has to remember his follower. It works pretty well, but when the line gets longer (but still not very long), the efficiency is bad (<20 fps after 4000 frames).
This is the function that I use to draw a line (only one for now). Can anybody help me improve its efficiency?
public void drawLine(Canvas canvas, int beginx, int beginy) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.RED);
paint.setStrokeWidth(3);
int x = beginx;
int y = beginy;
while(C.mGrid[x][y].nx != -1) {
//canvas.drawLine(x, y, C.mGrid[x][y].nx, C.mGrid[x][y].ny, paint);
canvas.drawPoint(x, y, paint);
Grid temp = C.mGrid[x][y];
if ((C.mGrid[x][y].nx == x) && (C.mGrid[x][y].ny == y)) break;
x = temp.nx;
y = temp.ny;
}
}
and Grid.java:
package com.qwak.achtung;
public float x = 0,y = 0;
public int px = -1, py = -1, nx = -1, ny = -1;
public Grid(float x, float y) {
this.x = x;
this.y = y;
}
public void set(int px, int py, int nx, int ny) {
this.px = px;
this.py = py;
this.nx = nx;
this.ny = ny;
}
public void setp(int px, int py) {
this.px = px;
this.py = py;
}
public void setn(int nx, int ny) {
this.nx = nx;
this.ny = ny;
}
PS: It looks like this http://c.wrzuta.pl/wi10559/11f7d10b00110e504e25ebd3/0/andek 14 is fps (on my phone (samsung Spica) it run better - 40 but after a while it decreases to 20 and even less) and 983 is number of frames at all.
There is a drawLine method in the canvas object.
Use the example here: How to draw a line in android
canvas.drawLine(0, 0, 20, 20, paint);
If you want to draw a curve. Find the function of the curve. A Parabola for example is x=y^2. You can get points from the curve: 1 = 1, 2 = 4, 3 = 9, 4 = 16... etc.. If your drawing pixel by pixel you can plug in your x and get your y and draw it.
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.RED);
paint.setStrokeWidth(3);
for(int i = beginx; i < CanvasWidth; i++)
{
int x = i;
int y = i * i; //x=y^2
canvas.drawPoint(x, y, paint);
}
To keep a record of points that were visited you could do the following:
class Point
{
int x;
int y;
}
List<Point> points = new List<Point>();
onMove(int newX, int newY)
{
Point p = new Point();
p.x = newX;
p.y = newY;
points.add(p);
}
onDraw()
{
for(Point p : points)
{
canvas.drawPoint(p.x, p.y, paint);
}
}
You want to look into the bresenham algorithm. A bresenham algorithm is a method to draw or rasterize a line. It's a bit different from the subdivision of a grid in a certain angle for example a morton-curve. It's a bit like compute the scalar product for every angle like recall here Traversing a 2D array in an angle.

Categories