Calculate x y of Point after increasing distance - java

I am trying to get the x and y value of a point after increasing the distance r. Perhaps there is a better way of calculate the angle phi too, so that I don't need to check in which quadrant the point is. The 0-point is at the half of the width and height of the window. Here is my attempt:
package test;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
public final class Laser extends java.applet.Applet implements Runnable{
private static final long serialVersionUID = -7566644836595581327L;
Thread runner;
int width = 800;
int height = 600;
Point point = new Point(405,100);
Point point1 = new Point(405,100);
public void calc(){
int x = getWidth()/2;
int y = getHeight()/2;
int px = point.x;
int py = point.y;
int px1 = point1.x;
int py1 = point1.y;
double r = 0;
double phi = 0;
// Point is in:
// Quadrant 1
if(px > x && py < y){
r = Math.hypot(px1-x, y-py1);
phi = Math.acos((px1-x)/r)*(180/Math.PI);
}/*
// Quadrant 2
else if(px < x && py < y){
r = Math.hypot(x-px, y-py);
phi = Math.acos((px-x)/r)*(180/Math.PI);
}
// Quadrant 3
else if(px < x && py > y){
r = Math.hypot(x-px, py-y);
phi = Math.acos((px-x)/r)*(180/Math.PI)+180;
}
// Quadrant 4
else if(px > x && py > y){
r = Math.hypot(px-x, py-y);
phi = Math.acos((px-x)/r)*(180/Math.PI)+180;
}*/
r += 1;
point1.x = (int) (r*Math.cos(phi));
point1.y = (int) (r*Math.sin(phi));
System.out.println(r+";"+point1.x+";"+point1.y);
}
public void paint(Graphics g) {
g.setColor(Color.ORANGE);
calc();
g.drawLine(point.x, point.y, point1.x, point1.y);
int h = getHeight();
int w = getWidth();
g.setColor(Color.GREEN);
g.drawLine(0, h/2, w, h/2);
g.drawLine(w/2, 0, w/2, h);
}
/*
public void initPoints(){
for(int i = 0; i < pointsStart.length; i++){
int x = (int)(Math.random()*getWidth());
int y = (int)(Math.random()*getHeight());
pointsStart[i] = pointsEnd[i] = new Point(x,y);
}
}
*/
public void start() {
if (runner == null) {
runner = new Thread(this);
setBackground(Color.black);
setSize(width, height);
//initPoints();
runner.start();
}
}
#SuppressWarnings("deprecation")
public void stop() {
if (runner != null) {
runner.stop();
runner = null;
}
}
public void run() {
while (true) {
repaint();
try { Thread.sleep(700); }
catch (InterruptedException e) { }
}
}
public void update(Graphics g) {
paint(g);
}
}

You are changing (x,y) to be r from some other point, when it had previously been some distance r' from that point, correct? So why not avoid the trigonometry, and just scale each of the components from that point by r/r'?
Edit: ok, iterate over the pixels along whichever component (x or y) is longer (let's assume it's y); for each xi in (0..x), yi = xi*(y/x), and you plot (xi,yi).

Keep it simple! And use double variables for such computations, I changed it for you.
package test;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.geom.Point2D;
public final class Laser extends java.applet.Applet implements Runnable {
private static final long serialVersionUID = -7566644836595581327L;
Thread runner;
int width = 800;
int height = 600;
Point2D.Double point = new Point2D.Double(400, 100);
Point2D.Double point1 = new Point2D.Double(405, 102);
public void calc() {
double px = point.x;
double py = point.y;
double px1 = point1.x;
double py1 = point1.y;
double dx = px1 - px;
double dy = py1 - py;
double len = Math.hypot(dx, dy);
double newlen = len+2;
double coeff = Math.abs((newlen-len)/len);
point1.x += dx * coeff;
point1.y += dy * coeff;
System.out.println(len+";"+point1.x+";"+point1.y);
}
public void paint(Graphics g) {
g.setColor(Color.ORANGE);
calc();
g.drawLine((int)point.x, (int)point.y, (int)point1.x, (int)point1.y);
int h = getHeight();
int w = getWidth();
g.setColor(Color.GREEN);
g.drawLine(0, h / 2, w, h / 2);
g.drawLine(w / 2, 0, w / 2, h);
}
/*
* public void initPoints(){
*
* for(double i = 0; i < pointsStart.length; i++){ double x =
* (double)(Math.random()*getWidth()); double y =
* (double)(Math.random()*getHeight()); pointsStart[i] = pointsEnd[i] = new
* Point(x,y); }
*
* }
*/
public void start() {
if (runner == null) {
runner = new Thread(this);
setBackground(Color.black);
setSize(width, height);
// initPoints();
runner.start();
}
}
#SuppressWarnings("deprecation")
public void stop() {
if (runner != null) {
runner.stop();
runner = null;
}
}
public void run() {
while (true) {
repaint();
try {
Thread.sleep(700);
}
catch (InterruptedException e) {
}
}
}
public void update(Graphics g) {
paint(g);
}
}

Related

Detect and count how many times a swing shape passes through a rectangle inside an environment

The program spawns a flock of triangles that 'fly' through an environment. In this environment, there is a rectangle and sometimes the flock will fly through the rectangle. The flock itself is comprised of 20 triangles - what I want to know is how many of these triangles pass through the rectangle each time the flock flys through the environment (once the flock disappears outside of the environment it respawns).
At the moment, my attempt at implementing this is the "hasFoundFood" method where I attempt to detect whether, for each of the boids, they have come into contact with the bounds of the rectangle but the value for noSuccessful is always 20.
Is there a way to detect whether any or all of the triangles have come into contact with the boundaries of rectangle and then count how many times this has occurred?
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.*;
import static java.lang.Math.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
import javax.swing.Timer;
import java.util.Random;
import javax.swing.JButton;
public class Boids extends JPanel {
Flock flock;
Flock flock2;
final int w, h;
int noSuccessful;
public Area food = new Area(new Rectangle(600,250,200,200));
int[] xTriangle = {33,36,34};
int[] yTriangle = {30,30,20};
public Area triangle = new Area(new Polygon(xTriangle, yTriangle, 3));
public Boids() {
w = 1200;
h = 600;
setPreferredSize(new Dimension(w, h));
setBackground(Color.black);
spawnFlock();
flock.hasFoundFood(noSuccessful);
new Timer(17, (ActionEvent e) -> {
if (flock.hasLeftTheBuilding(w))
spawnFlock();
repaint();
}).start();
}
public void spawnFlock() {
Random rand = new Random();
int n = rand.nextInt(599) + 1;
flock = Flock.spawn(100, h - n, 20);
flock2 = Flock.spawn(100, h - n, 1);
}
#Override
public void paintComponent(Graphics gg) {
super.paintComponent(gg);
Graphics2D g = (Graphics2D) gg;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
flock.run(g, w, h);
g.draw(food);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setTitle("Simulator v0.6");
f.setResizable(false);
f.add(new Boids(), BorderLayout.CENTER);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}
class Boid {
static final Random r = new Random();
static final Vec migrate = new Vec(0.02, 0);
static final int size = 3;
/* static final Path2D shape = new Path2D.Double();
static {
shape.moveTo(0, -size * 2);
shape.lineTo(-size, size * 2);
shape.lineTo(size, size * 2);
shape.closePath();
}
*/
final double maxForce, maxSpeed;
Vec location, velocity, acceleration;
private boolean included = true;
Boid(double x, double y) {
acceleration = new Vec();
velocity = new Vec(r.nextInt(3) + 1, r.nextInt(3) - 1);
location = new Vec(x, y);
maxSpeed = 3.0;
maxForce = 0.05;
}
void update() {
velocity.add(acceleration);
velocity.limit(maxSpeed);
location.add(velocity);
acceleration.mult(0);
}
void applyForce(Vec force) {
acceleration.add(force);
}
Vec seek(Vec target) {
Vec steer = Vec.sub(target, location);
steer.normalize();
steer.mult(maxSpeed);
steer.sub(velocity);
steer.limit(maxForce);
return steer;
}
void flock(Graphics2D g, List<Boid> boids) {
view(g, boids);
Vec rule1 = separation(boids);
Vec rule2 = alignment(boids);
Vec rule3 = cohesion(boids);
rule1.mult(2.5);
rule2.mult(1.5);
rule3.mult(1.3);
applyForce(rule1);
applyForce(rule2);
applyForce(rule3);
applyForce(migrate);
}
public boolean doAreasCollide(Area area1, Area area2) {
boolean collide = false;
Area collide1 = new Area(area1);
collide1.subtract(area2);
if (!collide1.equals(area1)) {
collide = true;
}
Area collide2 = new Area(area2);
collide2.subtract(area1);
if (!collide2.equals(area2)) {
collide = true;
}
return collide;
}
void view(Graphics2D g, List<Boid> boids) {
double sightDistance = 100;
double peripheryAngle = PI * 0.85;
for (Boid b : boids) {
b.included = false;
if (b == this)
continue;
double d = Vec.dist(location, b.location);
if (d <= 0 || d > sightDistance)
continue;
Vec lineOfSight = Vec.sub(b.location, location);
double angle = Vec.angleBetween(lineOfSight, velocity);
if (angle < peripheryAngle)
b.included = true;
}
}
Vec separation(List<Boid> boids) {
double desiredSeparation = 25;
Vec steer = new Vec(0, 0);
int count = 0;
for (Boid b : boids) {
if (!b.included)
continue;
double d = Vec.dist(location, b.location);
if ((d > 0) && (d < desiredSeparation)) {
Vec diff = Vec.sub(location, b.location);
diff.normalize();
diff.div(d); // weight by distance
steer.add(diff);
count++;
}
}
if (count > 0) {
steer.div(count);
}
if (steer.mag() > 0) {
steer.normalize();
steer.mult(maxSpeed);
steer.sub(velocity);
steer.limit(maxForce);
return steer;
}
return new Vec(0, 0);
}
Vec alignment(List<Boid> boids) {
double preferredDist = 50;
Vec steer = new Vec(0, 0);
int count = 0;
for (Boid b : boids) {
if (!b.included)
continue;
double d = Vec.dist(location, b.location);
if ((d > 0) && (d < preferredDist)) {
steer.add(b.velocity);
count++;
}
}
if (count > 0) {
steer.div(count);
steer.normalize();
steer.mult(maxSpeed);
steer.sub(velocity);
steer.limit(maxForce);
}
return steer;
}
Vec cohesion(List<Boid> boids) {
double preferredDist = 50;
Vec target = new Vec(0, 0);
int count = 0;
for (Boid b : boids) {
if (!b.included)
continue;
double d = Vec.dist(location, b.location);
if ((d > 0) && (d < preferredDist)) {
target.add(b.location);
count++;
}
}
if (count > 0) {
target.div(count);
return seek(target);
}
return target;
}
void draw(Graphics2D g) {
AffineTransform save = g.getTransform();
int[] xTriangle = {33,36,34};
int[] yTriangle = {30,30,20};
Area triangle = new Area(new Polygon(xTriangle, yTriangle, 3));
g.translate(location.x, location.y);
g.rotate(velocity.heading() + PI / 2);
g.setColor(Color.green);
// g.fill(shape);
g.setColor(Color.green);
g.draw(triangle);
g.fill(triangle);
g.setTransform(save);
}
public void run(Graphics2D g, List<Boid> boids, int w, int h) { //similair method to run leader
flock(g, boids);
update();
draw(g);
}
}
class Flock {
List<Boid> boids;
Flock() {
boids = new ArrayList<>();
}
void run(Graphics2D g, int w, int h) {
for (Boid b : boids) {
b.run(g, boids, w, h);
}
}
boolean hasLeftTheBuilding(int w) {
int count = 0;
for (Boid b : boids) {
if (b.location.x + Boid.size > w) //will also be used to calculate votes based on whether boids is near food
count++;
}
return boids.size() == count;
}
void addBoid(Boid b) {
boids.add(b);
}
static Flock spawn(double w, double h, int numBoids) {
Flock flock = new Flock();
for (int i = 0; i < numBoids; i++)
flock.addBoid(new Boid(w, h));
return flock;
}
int hasFoundFood(int noSuccessful) {
Area food = new Area(new Rectangle(600,250,200,200));
int[] xTriangle = {33,36,34};
int[] yTriangle = {30,30,20};
Area triangle = new Area(new Polygon(xTriangle, yTriangle, 3));
noSuccessful = 0;
for (Boid b : boids) {
if(b.doAreasCollide(food, triangle)); {
noSuccessful++;
}
}
System.out.println(noSuccessful);
return noSuccessful;
}
}
class Vec {
double x, y;
Vec() {
}
Vec(double x, double y) {
this.x = x;
this.y = y;
}
void add(Vec v) {
x += v.x;
y += v.y;
}
void sub(Vec v) {
x -= v.x;
y -= v.y;
}
void div(double val) {
x /= val;
y /= val;
}
void mult(double val) {
x *= val;
y *= val;
}
double mag() {
return sqrt(pow(x, 2) + pow(y, 2));
}
double dot(Vec v) {
return x * v.x + y * v.y;
}
void normalize() {
double mag = mag();
if (mag != 0) {
x /= mag;
y /= mag;
}
}
void limit(double lim) {
double mag = mag();
if (mag != 0 && mag > lim) {
x *= lim / mag;
y *= lim / mag;
}
}
double heading() {
return atan2(y, x);
}
static Vec sub(Vec v, Vec v2) {
return new Vec(v.x - v2.x, v.y - v2.y);
}
static double dist(Vec v, Vec v2) {
return sqrt(pow(v.x - v2.x, 2) + pow(v.y - v2.y, 2));
}
static double angleBetween(Vec v, Vec v2) {
return acos(v.dot(v2) / (v.mag() * v2.mag()));
}
}
Update:
I have altered the code in line with Andrews code about collisions detection using Area's and it still wont work?! when I call hasFoundFood it still produces the value 20 which is incorrect as, at this point, it should be 0. I am pulling my hair out at this point and cannot for the life of me figure out what is wrong here?!

Pong Ball Leaving Padel

I am making Pong in Java right now using Eclipse. I am trying to get the balls to bounce off the padels proportionally to where they hit the padel. If they hit at the top or bottom, I would like them to bounce off at 75 degrees up at the top or 75 degrees down at the bottom. If they hit near the center, then I would like them to bounce off closer to horizontal.
I am calculating the angle in the ball class with this math:
double speed = getSpeed() + ballIncrease;
yPos = Math.abs(yPos);
double angle = multiplier * yPos;
double ratio = Math.tan(angle);
xSpeed = ratio * (speed/(ratio + 1));
ySpeed = Math.sqrt((speed * speed) - (xSpeed * xSpeed));
I think that it should be correct, but the balls don't behave like I expect them to. I was wondering if anyone can help me solve this problem.
package Pong;
/*Place cursor here to start
*
*/
//Import Libraries
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
#SuppressWarnings("serial")
public class Pong extends JPanel implements KeyListener{
//Create random instances
Random r2 =new Random();
public final static int padelStart = 150;
public final static int padelSpace = 10;
final static int BOX_WIDTH = 1200;
public final static int BOX_HEIGHT = 800;
double ballX = BOX_WIDTH/2;
double ballY = BOX_HEIGHT/2;
public static Padel padel1 = new Padel(padelSpace,padelStart,true);
public static Padel padel2 = new Padel(BOX_WIDTH-padelSpace-padel1.getWidth(),padelStart,false);
Ball ball1 = new Ball(ballX,ballY);
Ball ball2 = new Ball(300,300);
public static int padel1y1;
public static int padel1y2;
public static int padel2y1;
public static int padel2y2;
//Constants
public final static int UPDATE_RATE = 200;
//Main game class
public Pong () {
//Set window size
setPreferredSize(new Dimension(BOX_WIDTH,BOX_HEIGHT));
//Start game thread
Thread gameThread = new Thread() {
public void run(){
while(true){
//Draw objects
padel1y1 = padel1.getY();
padel1y2 = padel1.getY() + Padel.padelLength;
padel2y1 = padel2.getY();
padel2y2 = padel2.getY() + Padel.padelLength;
padel1.update();
padel2.update();
ball1.update();
ball2.update();
repaint();
//Wait
try {Thread.sleep(1000 / UPDATE_RATE);}
catch (InterruptedException ex) {}
}
}
};
gameThread.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.white);
g.fillRect(0,0,BOX_WIDTH,BOX_HEIGHT);
padel1.draw(g);
padel2.draw(g);
ball1.draw(g);
ball2.draw(g);
}
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_UP){padel2.setSpeed(-Padel.padelSpeed);}
if(e.getKeyCode() == KeyEvent.VK_DOWN){padel2.setSpeed(Padel.padelSpeed);}
if(e.getKeyCode() == KeyEvent.VK_W){padel1.setSpeed(-Padel.padelSpeed);}
if(e.getKeyCode() == KeyEvent.VK_S){padel1.setSpeed(Padel.padelSpeed);}
}
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_UP){padel2.setSpeed(0);}
if(e.getKeyCode() == KeyEvent.VK_DOWN){padel2.setSpeed(0);}
if(e.getKeyCode() == KeyEvent.VK_W){padel1.setSpeed(0);}
if(e.getKeyCode() == KeyEvent.VK_S){padel1.setSpeed(0);}
}
public void keyTyped(KeyEvent e) {}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
//Create Frame
JFrame frame = new JFrame("PONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONG");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Pong pong = new Pong();
frame.setContentPane(pong);
frame.setSize(BOX_WIDTH,BOX_HEIGHT);
frame.pack();
frame.addKeyListener(pong);
frame.setVisible(true);
}
});
}
}
Padel Class:
package Pong;
import java.awt.*;
import java.util.Random;
public class Padel {
public int y;
public int x;
public boolean ws;
public int speed = 0;
public final static int padelSpeed = 3;
public final static int padelWidth = 30;
public final static int padelLength = 200;
Random rng = new Random();
int r = rng.nextInt(256);
int g = rng.nextInt(256);
int b = rng.nextInt(256);
Color color = new Color(r,g,b);
public Padel(int xPos, int yPos, boolean wands){
y = yPos;
x = xPos;
ws = wands;
}
public void update(){
if(speed > 0 && y + padelLength < Pong.BOX_HEIGHT){
y = y + speed;
}
if(speed < 0 && y > 0){
y = y + speed;
}
}
public void draw(Graphics g) {
g.setColor(color);
g.fillRoundRect(x, y, padelWidth, padelLength, 25, 25);
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public int getWidth(){
return padelWidth;
}
public int getLength(){
return padelLength;
}
public int getSpeed(){
return speed;
}
public void setSpeed(int speed1){
speed = speed1;
}
public int getPadelSpeed(){
return padelSpeed;
}
}
Ball Class:
package Pong;
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
public class Ball {
Random rng = new Random();
int r = rng.nextInt(256);
int g = rng.nextInt(256);
int b = rng.nextInt(256);
Color color = new Color(r,g,b);
public final static double ballSpeedMin = -2.0;
public final static double ballSpeedMax = 2.0;
public final static double middleSpeedCutoff = 1.0;
public final static double ballIncrease = .2;
public final int ballRadiusMin = 10;
public final int ballRadiusMax = 40;
double x;
double y;
double xSpeed;
double ySpeed;
int ballRadius;
public Ball(double xPos,double yPos){
x = xPos;
y = yPos;
xSpeed = getRandomSpeed();
ySpeed = getRandomSpeed();
ballRadius = getRandomRadius();
}
public double getRandomSpeed(){
Random r =new Random();
return ballSpeedMin + (ballSpeedMax - ballSpeedMin) * r.nextDouble();
}
public int getRandomRadius(){
Random r = new Random();
return r.nextInt((ballRadiusMax - ballRadiusMin) + 1) + ballRadiusMin;
}
public void update(){
x = x + xSpeed;
y = y + ySpeed;
ySpeed = verticalBounce();
double multiplier = .75;
if(getLowX() < Pong.padelSpace + Padel.padelWidth){
if(y>=Pong.padel1y1 && y<=Pong.padel1y2){
double yPos = y - Pong.padel1y1 - (Padel.padelLength/2);
if(yPos<0){
double speed = getSpeed() + ballIncrease;
yPos = Math.abs(yPos);
double angle = multiplier * yPos;
double ratio = Math.tan(angle);
xSpeed = ratio * (speed/(ratio + 1));
ySpeed = -Math.sqrt((speed * speed) - (xSpeed * xSpeed));
}
else if(yPos>0){
double speed = getSpeed() + ballIncrease;
yPos = Math.abs(yPos);
double angle = multiplier * yPos;
double ratio = Math.tan(angle);
xSpeed = ratio * (speed/(ratio + 1));
ySpeed = Math.sqrt((speed * speed) - (xSpeed * xSpeed));
}
else{
double speed = getSpeed();
xSpeed = speed;
ySpeed = 0;
}
}
else{
System.exit(0);
}
}
if(getHighX() > Pong.BOX_WIDTH - Pong.padelSpace - Padel.padelWidth){
if(y>Pong.padel2y1 && y<Pong.padel2y2){
double yPos = y - Pong.padel2y1 - (Padel.padelLength/2);
if(yPos<0){
double speed = getSpeed() + ballIncrease;
yPos = Math.abs(yPos);
double angle = multiplier * yPos;
double ratio = Math.tan(angle);
xSpeed = - ratio * (speed/(ratio + 1));
ySpeed = -Math.sqrt((speed * speed) - (xSpeed * xSpeed));
}
else if(yPos>0){
double speed = getSpeed() + ballIncrease;
yPos = Math.abs(yPos);
double angle = multiplier * yPos;
double ratio = Math.tan(angle);
xSpeed = - ratio * (speed/(ratio + 1));
ySpeed = Math.sqrt((speed * speed) - (xSpeed * xSpeed));
}
else{
double speed = getSpeed();
xSpeed = -speed;
ySpeed = 0;
}
}
else{
System.exit(0);
}
}
}
public void draw(Graphics g) {
g.setColor(color);
int xPos = (int) Math.round(x) - ballRadius;
int yPos = (int) Math.round(y) - ballRadius;
g.fillOval(xPos,yPos,ballRadius*2,ballRadius*2);
}
public double verticalBounce(){
if(y - ballRadius<0 || y + ballRadius > Pong.BOX_HEIGHT){
return -ySpeed;
}
else{
return ySpeed;
}
}
public double getY(){
return y;
}
public double getX(){
return x;
}
public double getYSpeed(){
return ySpeed;
}
public double getXSpeed(){
return xSpeed;
}
public void setYSpeed(double y){
ySpeed = y;
}
public void setXSpeed(double x){
xSpeed = x;
}
public double getLowX(){
return x - ballRadius;
}
public double getLowY(){
return y - ballRadius;
}
public double getHighX(){
return x + ballRadius;
}
public double getHighY(){
return y + ballRadius;
}
public double getSpeed(){
return Math.sqrt((xSpeed*xSpeed)+(ySpeed*ySpeed));
}
}
double multiplier = .75;
//...
double yPos = y - Pong.padel1y1 - (Padel.padelLength/2);
//...
double angle = multiplier * yPos;
Are you aware that the angles you pass in trigonometric functions are expressed in radians?Assuming your paddle length is 20, with yPos varying between [-10, 10] your angle will vary between [-7.5, 7.5]. Translate this in radians and you'll see your angle rotates around the circle a bit more than 2 times. Is really this what you want?

How to add an image into a hexagon in a hexagonal grid?

I have a problem with a hexagonal grid. I found this code you can see below on Internet, so it's not mine. There are two public classes: hexgame which generates the grid and hexmech which draws and fills every single hexagon. What I'd like to do is basically insert an image into a specific hexagon, but I don't know how to code this and in which part of the classes I should put it. Am I thinking the wrong way?
Thank you very much for your help!
Hexgame
package hex;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class hexgame
{
private hexgame() {
initGame();
createAndShowGUI();
}
final static Color COLOURBACK = Color.WHITE;
final static Color COLOURCELL = Color.WHITE;
final static Color COLOURGRID = Color.BLACK;
final static Color COLOURONE = new Color(255,255,255,200);
final static Color COLOURONETXT = Color.BLUE;
final static Color COLOURTWO = new Color(0,0,0,200);
final static Color COLOURTWOTXT = new Color(255,100,255);
final static Color COLOURSAFE = Color.WHITE;
final static Color COLOURDANGEROUS = Color.LIGHT_GRAY;
final static int EMPTY = 0;
final static int UNKNOWN = -1;
final static int SAFE = 1;
final static int DANGEROUS = 2;
final static int CLICKED = 3;
final static int COLUMN_SIZE = 23;
final static int ROW_SIZE = 14;
final static int HEXSIZE = 45;
final static int BORDERS = 15;
int[][] board = new int[COLUMN_SIZE][ROW_SIZE];
void initGame(){
hexmech.setXYasVertex(false);
hexmech.setHeight(HEXSIZE);
hexmech.setBorders(BORDERS);
for (int i=0;i<COLUMN_SIZE;i++) {
for (int j=0;j<ROW_SIZE;j++) {
board[i][j]=EMPTY;
}
}
board[5][5] = SAFE;
board[5][6] = SAFE;
board[5][7] = SAFE;
board[6][5] = SAFE;
board [6][6] = SAFE;
board[4][4] = UNKNOWN;
}
private void createAndShowGUI()
{
DrawingPanel panel = new DrawingPanel();
JFrame frame = new JFrame("Hex Testing 4");
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
Container content = frame.getContentPane();
content.add(panel);
frame.setSize(825, 630);
frame.setResizable(true);
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
class DrawingPanel extends JPanel
{
public DrawingPanel()
{
setBackground(COLOURBACK);
MyMouseListener ml = new MyMouseListener();
addMouseListener(ml);
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setFont(new Font("TimesRoman", Font.PLAIN, 15));
super.paintComponent(g2);
for (int i=0;i<COLUMN_SIZE;i++) {
for (int j=0;j<ROW_SIZE;j++) {
if (board[i][j] != UNKNOWN)
hexmech.drawHex(i,j,g2);
}
}
for (int i=0;i<COLUMN_SIZE;i++) {
for (int j=0;j<ROW_SIZE;j++) {
if (board[i][j] != UNKNOWN)
hexmech.fillHex(i,j,board[i][j],g2);
}
}
}
class MyMouseListener extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
int x = e.getX();
int y = e.getY();
Point p = new Point( hexmech.pxtoHex(e.getX(),e.getY()) );
if (p.x < 0 || p.y < 0 || p.x >= COLUMN_SIZE || p.y >= ROW_SIZE) return;
board[p.x][p.y] = CLICKED;
repaint();
}
}
}
}
Hexmech
package hex;
import java.awt.*;
import javax.swing.*;
public class hexmech
{
#define HEXEAST 0
#define HEXSOUTHEAST 1
#define HEXSOUTHWEST 2
#define HEXWEST 3
#define HEXNORTHWEST 4
#define HEXNORTHEAST 5
public final static boolean orFLAT= true;
public final static boolean orPOINT= false;
public static boolean ORIENT= orFLAT;
public static boolean XYVertex=true;
private static int BORDERS=50
private static int s=0; // length of one side
private static int t=0; // short side of 30o triangle outside of each hex
private static int r=0; // radius of inscribed circle (centre to middle of each side). r= h/2
private static int h=0; // height. Distance between centres of two adjacent hexes. Distance between two opposite sides in a hex.
public static void setXYasVertex(boolean b) {
XYVertex=b;
}
public static void setBorders(int b){
BORDERS=b;
}
public static void setSide(int side) {
s=side;
t = (int) (s / 2); //t = s sin(30) = (int) CalculateH(s);
r = (int) (s * 0.8660254037844);
h=2*r;
}
public static void setHeight(int height) {
h = height;
r = h/2; // r = radius of inscribed circle
s = (int) (h / 1.73205); // s = (h/2)/cos(30)= (h/2) / (sqrt(3)/2) = h / sqrt(3)
t = (int) (r / 1.73205); // t = (h/2) tan30 = (h/2) 1/sqrt(3) = h / (2 sqrt(3)) = r / sqrt(3)
}
public static Polygon hex (int x0, int y0) {
int y = y0 + BORDERS;
int x = x0 + BORDERS;
if (s == 0 || h == 0) {
System.out.println("ERROR: size of hex has not been set");
return new Polygon();
}
int[] cx,cy;
if (XYVertex)
cx = new int[] {x,x+s,x+s+t,x+s,x,x-t}; //this is for the top left vertex being at x,y. Which means that some of the hex is cutoff.
else
cx = new int[] {x+t,x+s+t,x+s+t+t,x+s+t,x+t,x}; //this is for the whole hexagon to be below and to the right of this point
cy = new int[] {y,y,y+r,y+r+r,y+r+r,y+r};
return new Polygon(cx,cy,6);
}
public static void drawHex(int i, int j, Graphics2D g2) {
int x = i * (s+t);
int y = j * h + (i%2) * h/2;
Polygon poly = hex(x,y);
g2.setColor(hexgame.COLOURCELL);
//g2.fillPolygon(hexmech.hex(x,y));
g2.fillPolygon(poly);
g2.setColor(hexgame.COLOURGRID);
g2.drawString(String.format("%c;%d", 'A'+i, j+1), x+20, y+40);
g2.drawPolygon(poly);
}
public static void fillHex(int i, int j, int n, Graphics2D g2) {
char c='o';
int x = i * (s+t);
int y = j * h + (i%2) * h/2;
/*if (n < 0) {
g2.setColor(hexgame.COLOURONE);
g2.fillPolygon(hex(x,y));
g2.setColor(hexgame.COLOURONETXT);
c = (char)(-n);
g2.drawString(""+c, x+r+BORDERS, y+r+BORDERS+4); //FIXME: handle XYVertex
//g2.drawString(x+","+y, x+r+BORDERS, y+r+BORDERS+4);
}
if (n > 0) {
g2.setColor(hexgame.COLOURTWO);
g2.fillPolygon(hex(x,y));
g2.setColor(hexgame.COLOURTWOTXT);
c = (char)n;
if (n==3) {
g2.setColor(hexgame.COLOURTWO);
g2.fillPolygon(hex(x,y));
g2.setColor(hexgame.COLOURTWOTXT);
}
}
public static Point pxtoHex(int mx, int my) {
Point p = new Point(-1,-1);
//correction for BORDERS and XYVertex
mx -= BORDERS;
my -= BORDERS;
if (XYVertex) mx += t;
int x = (int) (mx / (s+t));
int y = (int) ((my - (x%2)*r)/h);
int dx = mx - x*(s+t);
int dy = my - y*h;
if (my - (x%2)*r < 0) return p; // prevent clicking in the open halfhexes at the top of the screen
//System.out.println("dx=" + dx + " dy=" + dy + " > " + dx*r/t + " <");
//even columns
if (x%2==0) {
if (dy > r) { //bottom half of hexes
if (dx * r /t < dy - r) {
x--;
}
}
if (dy < r) { //top half of hexes
if ((t - dx)*r/t > dy ) {
x--;
y--;
}
}
} else { // odd columns
if (dy > h) { //bottom half of hexes
if (dx * r/t < dy - h) {
x--;
y++;
}
}
if (dy < h) { //top half of hexes
//System.out.println("" + (t- dx)*r/t + " " + (dy - r));
if ((t - dx)*r/t > dy - r) {
x--;
}
}
}
p.x=x;
p.y=y;
return p;
}
In your implementation of paintComponent(), invoke setClip() with a suitable Shape, such as Polygon. You can size and translate the Polygon to match the destination hexagon using the createTransformedShape() method of AffineTransform. Use the coordinates of the polygon's boundary as the basis for the coordinates used in your call to drawImage(). A related example using Ellipse2D is shown here.

Screen Snake Collision Issue

I am a self taught programmer and I am coding Screen Snake for fun. I am using not using integers to store the position of the snake or apples, I am using doubles. I am having an issue when the snake goes through the apple. When the collide, the code does not register that it collided. I am assuming that this is because their X and Y values might be like .1 off. I have been trying to fix this for 2 weeks but have not been able to. Sorry if my code is a bit messy. I don't know exactly what you guys need from the code so I posted all of it. Also I really appreciate the help! Thanks!!
Main class:
Random random = new Random();
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double ScreenW = screenSize.getWidth();
double ScreenH = screenSize.getHeight();
int ScreenX = (int)Math.round(ScreenW);
int ScreenY = (int)Math.round(ScreenH);
JFrame frame = new JFrame();
double x = 1, y = 1;
int size = 5;
int ticks;
private int columnCount = 25;
private int rowCount = 15;
double a = (ScreenW / columnCount) - 1;
double b = (ScreenH / rowCount) - 1;
private Key key;
private List<Rectangle2D> cells;
private Point selectedCell;
boolean up = false;
boolean down = false;
boolean right = true;
boolean left = false;
boolean running = true;
private Thread thread;
private BodyP p;
private ArrayList<BodyP> snake;
private Apple apple;
private ArrayList<Apple> apples;
double width = screenSize.width;
double height = screenSize.height;
double cellWidth = width / columnCount;
double cellHeight = height / rowCount;
double xOffset = (width - (columnCount * cellWidth)) / 2;
double yOffset = (height - (rowCount * cellHeight)) / 2;
public Max_SnakeGame() throws IOException {
System.out.println(screenSize);
System.out.println(a + "," + b);
System.out.println(ScreenH + b);
System.out.println(ScreenW + a);
frame.getContentPane().add(new Screen());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setUndecorated(true);
frame.setBackground(new Color(0, 0, 0, 0));
frame.setLocationRelativeTo(null);
frame.setMaximumSize(screenSize);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
Image img = Toolkit
.getDefaultToolkit()
.getImage(
"C:/Users/Max/My Documents/High School/Sophomore year/Graphic Disign/People art/The Mods Who Tell Pointless Stories.jpg");
frame.setIconImage(img);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
new Max_SnakeGame();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
public class Screen extends JPanel implements Runnable {
private static final long serialVersionUID = 1L;
public Screen() {
key = new Key();
addKeyListener(key);
setMaximumSize(screenSize);
setOpaque(false);
setBackground(new Color(0, 0, 0, 0));
setFocusable(true);
snake = new ArrayList<BodyP>();
apples = new ArrayList<>();
start();
}
public void start() {
running = true;
thread = new Thread(this);
thread.start();
}
public void run() {
while (running) {
MoveUpdate();
repaint();
}
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
repaint();
Graphics2D g2d = (Graphics2D) g.create();
cells = new ArrayList<>(columnCount * rowCount);
if (cells.isEmpty()) {
for (int row = 0; row < rowCount; row++) {
for (int col = 0; col < columnCount; col++) {
Rectangle2D cell = new Rectangle2D.Double(xOffset
+ (col * cellWidth), yOffset
+ (row * cellHeight), cellWidth, cellHeight);
cells.add(cell);
}
}
}
g2d.setColor(Color.GRAY);
for (Rectangle2D cell : cells) {
g2d.draw(cell);
}
for (int i = 0; i < snake.size(); i++) {
snake.get(i).draw(g);
}
for (int i = 0; i < apples.size(); i++) {
apples.get(i).draw(g);
}
}
}
private class Key implements KeyListener {
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_RIGHT && !left) {
up = false;
down = false;
right = true;
}
if (keyCode == KeyEvent.VK_LEFT && !right) {
up = false;
down = false;
left = true;
}
if (keyCode == KeyEvent.VK_UP && !down) {
left = false;
right = false;
up = true;
}
if (keyCode == KeyEvent.VK_DOWN && !up) {
left = false;
right = false;
down = true;
}
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
public void MoveUpdate() {
if (snake.size() == 0) {
p = new BodyP(x, y, a, b);
snake.add(p);
}
if (apples.size() == 0){
double x1 = random.nextInt(25);
double Ax = ((x1*a+x1+1)*10)/10;
double y1 = random.nextInt(15);
double Ay = ((y1*b+y1+1)*10)/10;
double Afx = Math.round(Ax);
double Afy = Math.round(Ay);
System.out.println("Ax:"+Afx);
System.out.println("Ay:"+Afy);
apple = new Apple(Ax, Ay, a, b);
apples.add(apple);
}
for(int i = 0; i < apples.size(); i++) {
if(Math.round(x)-1 == apples.get(i).getx() || Math.round(x) == apples.get(i).getx() && Math.round(y)== apples.get(i).gety() || Math.round(y)-1 == apples.get(i).gety()) {
size++;
apples.remove(i);
i--;
}
}
ticks++;
if (ticks > 2500000) {
if (up == true) {
if (y <= 2) {
y = ScreenH - b;
System.out.println("Y:" + y);
} else {
y -= b + 1;
System.out.println("Y:" + y);
}
}
// down loop
else if (down == true) {
if (y >= ScreenH - b) {
y = 1;
System.out.println("Y:" + y);
}
else {
y += b + 1;
System.out.println("Y:" + y);
}
}
// left loop
else if (left == true) {
if (x <= 1) {
x = ScreenW - a;
System.out.println("X:" + x);
}
else {
x -= a + 1;
System.out.println("X:" + x);
}
}
// right loop
else if (right == true) {
if (x >= ScreenW - a) {
x = 1;
System.out.println("X:" + x);
}
else {
x += a + 1;
System.out.println("X:" + x);
}
}
ticks = 0;
p = new BodyP(x, y, a, b);
snake.add(p);
// rect.setFrame(x, y, a, b);
if (snake.size() > size) {
snake.remove(0);
}
}
}
}
Snake class:
public class BodyP {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double ScreenW = screenSize.getWidth();
double ScreenH = screen`enter code here`Size.getHeight();
double x = 1, y = 1;
private int columnCount = 25;
private int rowCount = 15;
double a = (ScreenW / columnCount) - 1;
double b = (ScreenH / rowCount) - 1;
public BodyP(double x, double y, double a, double b) {
this.x = x;
this.y = y;
this.a = a;
this.b = b;
}
public void MoveUpdate(){
}
public void draw(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Rectangle2D rect = new Rectangle2D.Double(x, y, a, b);
g.setColor(Color.BLACK);
g2.fill(rect);
}
public double getx() {
return x;
}
public void setx(double x) {
this.x = x;
}
public double gety() {
return y;
}
public void sety(double y) {
this.y = y;
}
}
Apple class:
public class Apple {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double ScreenW = screenSize.getWidth();
double ScreenH = screenSize.getHeight();
double x = 1, y = 1;
private int columnCount = 25;
private int rowCount = 15;
double a = (ScreenW / columnCount) - 1;
double b = (ScreenH / rowCount) - 1;
public Apple(double x, double y, double a, double b) {
this.x = x;
this.y = y;
this.a = a;
this.b = b;
}
public void MoveUpdate(){
}
public void draw(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Rectangle2D rect = new Rectangle2D.Double(x, y, a, b);
g.setColor(Color.RED);
g2.fill(rect);
}
public double getx() {
return x;
}
public void setx(double x) {
this.x = x;
}
public double gety() {
return y;
}
public void sety(double y) {
this.y = y;
}
}
If you think this is due rounding errors, use Euclidean distance and compare with the desired tolerance:
final double tolerance = 1.0; // or whatsoever
double dx = snake.x - apple.x;
double dy = snake.y - apple.y;
if ( dx*dx + dy*dy < tolearance * tolerance ) ...
I suggest to implement something like Point.distanceTo(Point) method to make this convenient.

Moving ball at an Angle

I am a newbie and trying to move a ball at a slope. Here is the code where I am giving coordinates (100,300,300,600) to move the ball in a slope but it's getting away from the the slope line. Here's the code: -
import javax.swing.*;
import java.awt.*;
public class AgentMotion extends JPanel implements Runnable
{
Color color = Color.red;
int dia = 0;
long delay = 40;
private double x;
private double y;
private double x1;
private double y1;
private int dx = 1;
private int dy = 1;
private int dv = 1;
private double direction;
double a;
double b;
double a1;
double b1;
public void abc(double x, double y, double x2, double y2) {
this.x = x;
this.y = y;
this.x1 = x2;
this.y1 = y2;
this.direction=Math.toRadians(Math.atan2(x1-x,y1-y));
System.out.println("segfewg"+direction);
this.a = x;
this.b = y;
this.a1 = x1;
this.b1 = y1;
}
protected void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(color);
//int x=100;
//int y=200;
int x3=(int)this.x;
int y3=(int)this.y;
g.fillOval(x3,y3,5,5); // adds color to circle
g.setColor(Color.black);
g2.drawOval(x3,y3,5,5); // draws circle
g2.drawLine(100, 300, 300, 600);
}
public void run() {
if(direction<0)
{
System.out.println("refregreg");
while(dy!=0) {
try {
Thread.sleep(delay);
} catch(InterruptedException e) {
System.out.println("interrupted");
}
move2();
repaint();
move();
repaint();
}
}
else
{
while(dx!=0) {
try {
Thread.sleep(delay);
} catch(InterruptedException e) {
System.out.println("interrupted");
}
move2();
repaint();
move();
repaint();
}
}
}
public void move() {
if(direction>0)
{
if(x + dv*Math.cos(direction) <a ||x + dia + dv * Math.cos(direction) >b) {
dx *= 0;
color = getColor();
}
x += dx;
}
else
{
System.out.println(x + dia + dv * Math.cos(direction));
if(x + dia + dv * Math.cos(direction) >b) {
dx *= 0;
color = getColor();
}
x -= dx;
}
}
public void move2() {
if(direction>0)
{
if(dv * Math.sin(direction) + y <a1 || dv * Math.sin(direction) + dia + y > b1) {
dy *= 0;
color = getColor();
}
y += dy;
}
else
{
System.out.println(dv * Math.sin(direction) + dia + y);
if(dv * Math.sin(direction) + y <a1 || dv * Math.sin(direction) + dia + y < b1) {
dy *= 0;
color = getColor();
}
y -= dy;
}
}
public Color getColor() {
int rval = (int)Math.floor(Math.random() * 256);
int gval = (int)Math.floor(Math.random() * 256);
int bval = (int)Math.floor(Math.random() * 256);
return new Color(rval, gval, bval);
}
public void start() {
while(dx==0) {
try {
System.out.println("jiuj");
Thread.sleep(25);
} catch(InterruptedException e) {
System.out.println("dwdwdwd");
}
}
Thread thread = new Thread(this);
thread.setPriority(Thread.NORM_PRIORITY);
thread.start();
}
}
A few suggestions
dx and dy should be double
atan is overkill as #Spektre says. What you want is much more simple to calculate direction.
this.direction = (y2 - y) / (x2 - x)
If we give (100,300,300,600) as the arguments to abc (which would presumably be a constructor for this class), the slope is 1.5. Therefore we could say:
dx = 1.0
dy = 1.5
and this would keep on the line perfectly. For the general case where you want to change the begin and the end point, you have to calculate the ratio. So you could set either dx or dy to 1.0 and then set the other one so that the ratio is maintained. Something like the following mathematical pseudocode:
dx = (x2 - x) / minimum(x2-x, y2-y)
dy = (y2 - y) / minimum(x2-x, y2-y)

Categories