Mouse coordinate issues in Slick2D - java

For development purposes of my game, I want to display the coordinates of the mouse in my window. I am having a couple of issues with this. First, the axis appears to start in the bottom left. I would like it to start in the upper left because that is what I am used to. I am currently compensating for this by subtracting the Y coordinate from the height of the window. I would prefer to not have to do this. The other issue is that my Y coordinate appears to be offset by 141 pixels and the X coordinate always stays at -1. How can I fix these issues?
int posX = Mouse.getX();
int posY = HEIGHT - Mouse.getY();
g.setColor(Color.black);
g.fillRect(0, HEIGHT - 50, 125, 30);
g.setColor(Color.white);
g.drawString(posX + "," + posY, 10, HEIGHT - 45);

Related

Java Game Dev - How do I create a vertical health bar?

I need some assistance fixing my vertical health bar. It tracks health correctly and updates, but because of how Java draws (from the top left corner, i.e. (0,0)), the bar appears to be upside down. I would like to flip the health bar so it would appear correctly but I am unsure how to do so.
The division in the codes x and y is just to place the bar in the correct position on the canvas. The multiplier is to scale up the health bar to fit a graphical overlay I made for it.
private void drawHealthBar(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.red);
g2.fillRect(WIDTH - (WIDTH / 50), HEIGHT / 2, 10, ships.get(0).getHealth() * 6);
}
Setup the coordinate system how you want, using transform() and translate(). So:
you want the origin to be at (0, height); bottom left.
then you want to flip the Y axis.
Example code:
AffineTransform tform = AffineTransform.getTranslateInstance( 0, height);
tform.scale( 1, -1);
g2.setTransform( tform);
you need to shift bar depending on amount of health left, like this:
private void drawHealthBar(Graphics g) {
final Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.red);
final int w = 10;
final int h = ships.get(0).getHealth() * 6; // calculate height first
final int x = WIDTH - (WIDTH / 50);
final int y = HEIGHT / 2 + (MAX_HEIGHT - h); // shift by height of whitespace
g2.fillRect(x, y, w, h);
}

Finding pixels covered by an oval in Java Canvas

I'm creating a graphical display to show whether a user is approaching a danger zone. For this i'm using a display similar to that of an archery board. The idea is to start in the center, but as the user gets closer to the danger zone enter the orange zone. And once the user breaks the 'safety threshold' enter the red zone. My idea is to draw a point on the board depending on what value the user gives me.
To draw this board I do the following.
Graphics2D g2d = (Graphics2D) bs.getDrawGraphics();
g2d.setColor(Color.white);
g2d.fillRect(0, 0, 800, 600); //set screen to white
g2d.setColor(Color.red);
g2d.fillOval(250, 250, 175, 175); //draw outerlayer of board as red
g2d.setColor(Color.black);
g2d.drawOval(250, 250, 175, 175);//give this red an outline
g2d.setColor(Color.orange);
g2d.fillOval(275, 275, 125, 125); //draw innerlayer as orange
g2d.setColor(Color.black);
g2d.drawOval(275, 275, 125, 125);//give this orange an outline
g2d.setColor(Color.green);
g2d.fillOval(300, 300, 75, 75); //draw innermost layer as green
g2d.setColor(Color.black);
g2d.drawOval(300, 300, 75, 75); //give the green an outline
First of all I could probably improve this, but that's not the main issue for now.
Instead my issue is finding exactly the pixels covered by each part of the board.
I've been using x+(width/2), y+(height/2) to get the center point
Thus using:
g2d.drawString(String.valueOf("X"), 338, 338);
To draw the center point of my green oval. This doesn't seem overly accurate but anyway.
I thought I would be able to simply give the outer edge as the x,y co-ords and the inner edge as the x+height, y+width co-ords as so:
g2d.drawOval(500, 500, 75, 75);
g2d.drawString(String.valueOf("X"), 537, 537); //centre???
g2d.drawString(String.valueOf("X"), 575, 575); //inneredge?x+width, y+height
g2d.drawString(String.valueOf("X"), 500, 500); //outer edge x+y co-ords
However, I think due to the oval shape this doesn't work.
I would be very grateful if someone could show me how to find the pixel range that each oval covers.
EDIT: Below is the board that i'm using, is it possible to find the pixel range for each color(Red,Orange,Green)?
Understanding a bit more what you wanted, here is the trick (using trigonometry):
int force = ...; // from 0 to 250
int radius = ...; // radius of the target (50 for example)
int centerX = ...; // X-coordinate of the center of the target
int centerY = ...; // Y-coordinate of the center of the target
double direction = Math.toRadians(Math.random() * 360); // a random angle between 0° and 360°
double x = (force * radius / 250.0d) * Math.cos(direction) + centerX; // X-coordinate of the new point
double y = (force * radius / 250.0d) * Math.sin(direction) + centerY; // Y-coordinate of the new point
Point2D point = new Point2D.Double(x,y); // Then you can plot this point on your target
All of your ovals appear to be circles. So, let's create a Circle model class.
You would call the draw method from a JPanel paintComponent method.
You would call the contains method when you want to see if a point is inside or on the edge of a circle.
You would keep track of all of the circles in a List, so you can maintain the order of the circles.
package com.ggl.testing;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
public class Circle {
private final int radius;
private final Color color;
private final Point location;
public Circle(int x, int y, int radius, Color color) {
this.location = new Point(x, y);
this.radius = radius;
this.color = color;
}
public boolean contains(int x, int y) {
double distance = Point.distance(x, y, location.x, location.y);
double radiusD = radius;
if (radiusD >= distance) {
return true;
} else {
return false;
}
}
public void draw(Graphics g) {
g.setColor(color);
g.fillOval(location.x - radius, location.y - radius, radius + radius,
radius + radius);
}
}
Use a concrete Ellipse2D for each zone. Then you can use g2d.fill() to draw the zone. Since an Ellipse2D is also a Shape, you can use the contains(Point2D p) method to check if a point is in bounds. Since the circles overlap, you'll have to check them in front-to-back order.

How to draw a circle within a circle?

I'm trying to get a bunch of small circles that have varying shades of green to be drawn within a big circle to get a "bush" look, but I can't figure out how to get all the small circles within the shape of a big circle. I can only figure out how to get it within a rectangle.
public void paintComponent(Graphics g)
{
super.paintComponent(g);
for(int i = 0; i < 1000; i++){
int redV = (int) ((Math.random() * 100) + 27);
g.setColor(new Color(red, red + 31, red - 15));
int x = (int) ((Math.random() * 400) + 150);
int y = (int) ((Math.random() * 500) + 200);
g.fillOval(x, y, 50, 50);
}
}
I guess you have to do some geometry here, and verify whether the x and y coordinates generated randomly are within your circle. As you said, within a rectangle is easy (because you just check that x > left, x+50 < right, y > top, y+50 < bottom), however for a circle you have to use the equation of a circle and check that (x,y) and (x+50,y+50) are within it before actually doing the fillOval().
I think you have a simple way out by using the Java 2D Shape.contains(), which is implemented by Ellipse2D. So essentially you create an instance of Ellipse2D.Double or Ellipse2D.Float for the greater circle, and then just call contains() each time you generate the coordinates to check they are within it before drawing them.
I think you can just change the Color slightly, and increment/decrement x, y, width, and height slightly to get them to be within the older circle. The new oval should be painted over the old one.
Choose the point that should be the center of the big circle, and draw the big circle relative to that (e.g. using java.awt.geom.Ellipse2D).
You can then use the center of the big circle and its radius to position the other smaller circles relative to that also, inside the circumference.

Is there any easy way to draw a circle onto a JPanel?

I'm having trouble using the drawOval(x,y,width,height) method, which assumes that the x and y values represent the coordinates of the "upper left corner of the oval to be drawn" (javadoc)
I want the x and y values to represent the center-point of a circle. How do I do this? Thanks
A simple solution, if you have the width/height declared in advance, would be to use the drawOval method as follows:
drawOval( x - (width/2), y - (height/2), width, height);
This will ensure that (x, y) is at the center of the oval.
Why?
Let's say (x, y) is (10, 10) and you want to draw an oval of (height, width) = (10, 10).
drawOval(x, y, height width);
would then draw the top-right of the oval at (10, 10), and the bottom-left would be at (10 + 10, 10 + 10) = (20, 20).
On the other hand, if you use
drawOval( x - (width/2), y - (height/2), height, width);
the top-right of the oval would be drawn at ( 10 - (10/2), 10 - (10/2) ) = (5, 5) and the bottom would be drawn at (5 + 10, 5 + 10) = (15, 15). The center would then be (10, 10) :)

Java - Draw a ruler (line with tick marks at 90 degree angle)

I'm using Java AWT to draw lines on a panel (Line2D and Graphics2D.drawLine()) and I'm wondering how I can draw a line with tick marks, similar to:
|----|----|----|----|----|
I know the positions I'd like to draw the ticks at in advance.
The lines could be in any position, so the ticks must be drawn at an angle releative to the line itself.
My basic geometry & ability to apply it in Java is failing me. :)
I suggest you
implement a ruler-drawing-method that draws a simple horizontal ruler from left to right
Figure out the desired angle using Math.atan2.
Apply an AffineTransform with translation and rotation before invoking the ruler-drawing-method.
Here is a complete test-program. (The Graphics.create method is used to create a copy of the original graphics object, so we don't mess up the original transform.)
import java.awt.*;
public class RulerExample {
public static void main(String args[]) {
JFrame f = new JFrame();
f.add(new JComponent() {
private final double TICK_DIST = 20;
void drawRuler(Graphics g1, int x1, int y1, int x2, int y2) {
Graphics2D g = (Graphics2D) g1.create();
double dx = x2 - x1, dy = y2 - y1;
double len = Math.sqrt(dx*dx + dy*dy);
AffineTransform at = AffineTransform.getTranslateInstance(x1, y1);
at.concatenate(AffineTransform.getRotateInstance(Math.atan2(dy, dx)));
g.transform(at);
// Draw horizontal ruler starting in (0, 0)
g.drawLine(0, 0, (int) len, 0);
for (double i = 0; i < len; i += TICK_DIST)
g.drawLine((int) i, -3, (int) i, 3);
}
public void paintComponent(Graphics g) {
drawRuler(g, 10, 30, 300, 150);
drawRuler(g, 300, 150, 100, 100);
drawRuler(g, 100, 100, 120, 350);
drawRuler(g, 50, 350, 350, 50);
}
});
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(400, 400);
f.setVisible(true);
}
}
Note, that you could just as easily draw numbers above the ticks. The drawString-calls would go through the same transformation and get nicely "tilted" along the line.
Things that need noting:
A perpendicular line has a slope of -1/oldslope.
In order to support lines in any direction, you need to do it parametrically
Thus, you have dy and dx across the original line, which means that newdx=dy; newdy=-1*dx.
If you have it such that <dx, dy> is a unit vector (sqrt(dx*dx+dy+dy)==1, or dx==cos(theta); dy=sin(theta) for some theta), you then just need to know how far apart you want the tick marks.
sx, sy are your start x and y
length is the length of the line
seglength is the length of the dashes
dx, dy is the slopes of the original line
newdx, newdy are the (calculated above) slopes of the cross lines
Thus,
Draw a line from <sx,sy> (start x,y) to <sx+dx*length,sy+dy*length>
Draw a set of lines (for(i=0;i<=length;i+=interval) from <sx+dx*i-newdx*seglength/2,sy+dy*i-newdy*seglength/2> to <sx+dx*i+newdx*seglength/2,sy+dy*i+newdy*seglength/2>
I hope you know matrix multiplication. In order to rotate a line you need to multiple it by rotation matrix. (I coudln't draw a proper matrix but assume both line are not separated)
|x'| = |cos(an) -sin(an)| |x|
|y`| = |sin(an) cos(an)| |y|
The old points are x,y and the new is x',y'. Let us illustrate by an example, lets say you have a vertical line from (0,0) to (0,1), now you want to rotate it by 90 degrees. (0,0) will remain zero so lets just see what happens to (0,1)
|x'| = |cos(90) -sin(90)| |0|
|y`| = |sin(90) cos(90)| |1|
==
|1 0| |0|
|0 1| |1|
==
| 1*0 + 0*1|
| 0*0 + 1*1|
== |0|
|1|
you get to horizontal line (0,0),(0,1) like you would expect.
Hope it helps,
Roni

Categories

Resources