I want a line to be drawn till the edge of the screen when I provide to it 2 points and an angle (for the direction). For example if the first mouse point is 4,4 and the next mouse point is 6,6 so from those points you know that the line has a North-East direction, then a line should be drawn from 4,4 till the end of the screen and passing through 6,6. Note: after the mouse gets to 6,6 the line should be drawn till the edge of the screen while the mouse is still at 6,6.
Also this should be done in MouseMoved with no clicks preferably, this means that both mouse points are obtained from MouseMoved. I tried for a whole day to get an output but no use.
You need to break you problem down...
First, you need to be able to calculate the angle between two points
double angle = Math.atan2(toY - fromY, toX - fromX);
wow, that was kind of easy (thank you Internet)
Next, we need to be able to calculate a point on the radius of circle (okay, this might sound weird, but it's the easiest solution I could think off...and I know I can solve it, thank you Internet)
toX = (int) (Math.round(fromX + (radius * Math.cos(angle))));
toY = (int) (Math.round(fromY + (radius * Math.sin(angle))));
What we're going to do is, create a circle so large that it expands beyond the visible frame boundaries and draw our line out to! Easy!
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Point from;
private Point clickTo;
private Point to;
public TestPane() {
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (to != null) {
to = null;
clickTo = null;
from = null;
}
if (from != null) {
to = e.getPoint();
clickTo = new Point(to);
double angle = Math.atan2(to.y - from.y, to.x - from.x);
int radius = Math.max(getWidth(), getHeight()) * 2;
to.x = (int) (Math.round(from.x + (radius * Math.cos(angle))));
to.y = (int) (Math.round(from.y + (radius * Math.sin(angle))));
} else {
from = e.getPoint();
}
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (from != null) {
g2d.setColor(Color.RED);
g2d.fillOval(from.x - 4, from.y - 4, 8, 8);
if (to != null) {
g2d.setColor(Color.GREEN);
g2d.fillOval(clickTo.x - 4, clickTo.y - 4, 8, 8);
g2d.setColor(Color.BLUE);
g2d.drawLine(from.x, from.y, to.x, to.y);
}
}
g2d.dispose();
}
}
}
With center anchor point....
and MouseMotionListener support
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Point from;
private Point clickTo;
private Point to;
public TestPane() {
addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
from = new Point(getWidth() / 2, getHeight() / 2);
to = e.getPoint();
clickTo = new Point(to);
double angle = Math.atan2(to.y - from.y, to.x - from.x);
int radius = Math.max(getWidth(), getHeight()) * 2;
to.x = (int) (Math.round(from.x + (radius * Math.cos(angle))));
to.y = (int) (Math.round(from.y + (radius * Math.sin(angle))));
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (from != null) {
g2d.setColor(Color.RED);
g2d.fillOval(from.x - 4, from.y - 4, 8, 8);
if (to != null) {
g2d.setColor(Color.GREEN);
g2d.fillOval(clickTo.x - 4, clickTo.y - 4, 8, 8);
g2d.setColor(Color.BLUE);
g2d.drawLine(from.x, from.y, to.x, to.y);
}
}
g2d.dispose();
}
}
}
One more small thing, i need the line to have a flexible length, by that i mean it should be within the screen, and since this is a rectangle then the width and height will differ, and having a fixed length will make problems because it will be long at some parts and short at others, any idea ?
So, you need to know where the line collides with the boundaries of the rectangle, which basically boils down to line collision detection (because a rectangle is just four lines)
So, Internet to the rescue
I took the idea slightly further and made a method which took a Rectangle and a Line2D and returned either a Point2D where the collision point occurs or null if no collision occurred (in this case, we should be 99.9% guaranteed of a collision)
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Point from;
private Point clickTo;
private Point to;
public TestPane() {
addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
from = new Point(getWidth() / 2, getHeight() / 2);
to = e.getPoint();
clickTo = new Point(to);
double angle = Math.atan2(to.y - from.y, to.x - from.x);
int radius = Math.max(getWidth(), getHeight()) * 2;
to.x = (int) (Math.round(from.x + (radius * Math.cos(angle))));
to.y = (int) (Math.round(from.y + (radius * Math.sin(angle))));
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public Point2D getIntersectionPoint(Line2D line1, Line2D line2) {
if (!line1.intersectsLine(line2)) {
return null;
}
double px = line1.getX1(),
py = line1.getY1(),
rx = line1.getX2() - px,
ry = line1.getY2() - py;
double qx = line2.getX1(),
qy = line2.getY1(),
sx = line2.getX2() - qx,
sy = line2.getY2() - qy;
double det = sx * ry - sy * rx;
if (det == 0) {
return null;
} else {
double z = (sx * (qy - py) + sy * (px - qx)) / det;
if (z == 0 || z == 1) {
return null; // intersection at end point!
}
return new Point2D.Float(
(float) (px + z * rx), (float) (py + z * ry));
}
} // end intersection line-line
public Point2D getIntersectionPoint(Line2D line, Rectangle bounds) {
Point2D top = getIntersectionPoint(line, new Line2D.Double(bounds.x, bounds.y, bounds.x + bounds.width, bounds.y));
Point2D bottom = getIntersectionPoint(line, new Line2D.Double(bounds.x, bounds.y + bounds.height, bounds.x + bounds.width, bounds.y + bounds.height));
Point2D left = getIntersectionPoint(line, new Line2D.Double(bounds.x, bounds.y, bounds.x, bounds.y + bounds.height));
Point2D right = getIntersectionPoint(line, new Line2D.Double(bounds.x + bounds.width, bounds.y, bounds.x + bounds.width, bounds.y + bounds.height));
return top != null ? top
: bottom != null ? bottom
: left != null ? left
: right != null ? right
: null;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Rectangle bounds = new Rectangle(50, 50, getWidth() - 100, getHeight() - 100);
g2d.draw(bounds);
if (from != null) {
g2d.setColor(Color.RED);
g2d.fillOval(from.x - 4, from.y - 4, 8, 8);
if (to != null) {
g2d.setColor(Color.GREEN);
g2d.fillOval(clickTo.x - 4, clickTo.y - 4, 8, 8);
Line2D line = new Line2D.Double(from, to);
g2d.setColor(Color.BLUE);
g2d.draw(line);
Point2D intersectPoint = getIntersectionPoint(line, bounds);
g2d.setColor(Color.MAGENTA);
g2d.fill(new Ellipse2D.Double(intersectPoint.getX() - 4, intersectPoint.getY() - 4, 8, 8));
g2d.draw(new Line2D.Double(from, intersectPoint));
}
}
g2d.dispose();
}
}
}
So, know you have a projection of the line beyond the visible boundaries of the component (which would helpful in your other question) and know where the line interests the inner boundaries
Related
BEFORE YOU MARK IT AS DUPLICATE
I have searched a lot in the internet for that and tried every solution, but no one does it the same way I do it. In my case the rotation is in a sperate class.
I have created a java class that inherits JLabel class, in my class I have an arrow BufferedImage which I draw using the paintComponent(Graphics g) method.
I am trying to make the arrow point to a specific point (which I get from a different method) but something goes wrong and the arrow rotates to the wrong direction.
I THINK: it doesn't calculate correctly because the imageLocation is relative to the label.
Here is my code:
package pkg1;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.*;
public final class ImageLabel extends JLabel {
private float angle = 0.0f; // in radians
private Point imageLocation = new Point();
private File imageFile = null;
private Dimension imageSize = new Dimension(50, 50);
private BufferedImage bi;
private BufferedImage resizeImage(BufferedImage originalImage, int img_width, int img_height) {
int type = originalImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : originalImage.getType();
BufferedImage resizedImage = new BufferedImage(img_width, img_height, type);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, img_width, img_height, null);
g.dispose();
return resizedImage;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (bi == null) {
return;
}
imageLocation = new Point(getWidth() / 2 - bi.getWidth() / 2, getHeight() / 2 - bi.getHeight() / 2);
Graphics2D g2 = (Graphics2D) g;
g2.rotate(angle, imageLocation.x + bi.getWidth() / 2, imageLocation.y + bi.getHeight() / 2);
g2.drawImage(bi, imageLocation.x, imageLocation.y, null);
}
public void rotateImage(float angle) { // rotate the image to specific angle
this.angle = (float) Math.toRadians(angle);
repaint();
}
public void pointImageToPoint(Point target) {
calculateAngle(target);
repaint();
}
private void calculateAngle(Point target) {
// calculate the angle from the center of the image
float deltaY = target.y - (imageLocation.y + bi.getHeight() / 2);
float deltaX = target.x - (imageLocation.x + bi.getWidth() / 2);
angle = (float) Math.atan2(deltaY, deltaX);
if (angle < 0) {
angle += (Math.PI * 2);
}
}
}
Okay, so two things jump out at me...
If you take a Point from outside the context of the label, you will have to translate the point into the components coordinate context
The calculateAngle seems wrong
So starting with...
private void calculateAngle(Point target) {
// calculate the angle from the center of the image
float deltaY = target.y - (imageLocation.y + bi.getHeight() / 2);
float deltaX = target.x - (imageLocation.x + bi.getWidth() / 2);
angle = (float) Math.atan2(deltaY, deltaX);
if (angle < 0) {
angle += (Math.PI * 2);
}
}
angle = (float) Math.atan2(deltaY, deltaX); should be angle = (float) Math.atan2(deltaX, deltaY); (swap the deltas)
You will find that you need to adjust the result by 180 degrees in order to get the image to point in the right direction
angle = Math.toRadians(Math.toDegrees(angle) + 180.0);
Okay, I'm an idiot, but it works :P
I'd also make use of a AffineTransform to translate and rotate the image - personally, I find it easier to deal with.
In the example, I've cheated a little. I set the translation of the AffineTransform to the centre of the component, I then rotate the context around the new origin point (0x0). I then paint the image offset by half it's height/width, thus making it appear as the if the image is been rotated about it's centre - It's late, I'm tired, it works :P
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private ImageLabel label;
public TestPane() {
setLayout(new GridBagLayout());
label = new ImageLabel();
add(label);
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
label.pointImageToPoint(e.getPoint(), TestPane.this);
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public final class ImageLabel extends JLabel {
private double angle = 0;
private Point imageLocation = new Point();
private File imageFile = null;
private Dimension imageSize = new Dimension(50, 50);
private BufferedImage bi;
public ImageLabel() {
setBorder(new LineBorder(Color.BLUE));
bi = new BufferedImage(50, 50, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bi.createGraphics();
g2d.setColor(Color.RED);
g2d.drawLine(25, 0, 25, 50);
g2d.drawLine(25, 0, 0, 12);
g2d.drawLine(25, 0, 50, 12);
g2d.dispose();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(bi.getWidth(), bi.getHeight());
}
protected Point centerPoint() {
return new Point(getWidth() / 2, getHeight() / 2);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (bi == null) {
return;
}
Graphics2D g2d = (Graphics2D) g.create();
AffineTransform at = g2d.getTransform();
Point center = centerPoint();
at.translate(center.x, center.y);
at.rotate(angle, 0, 0);
g2d.setTransform(at);
g2d.drawImage(bi, -bi.getWidth() / 2, -bi.getHeight() / 2, this);
g2d.dispose();
}
public void rotateImage(float angle) { // rotate the image to specific angle
this.angle = (float) Math.toRadians(angle);
repaint();
}
public void pointImageToPoint(Point target, JComponent fromContext) {
calculateAngle(target, fromContext);
repaint();
}
private void calculateAngle(Point target, JComponent fromContext) {
// calculate the angle from the center of the image
target = SwingUtilities.convertPoint(fromContext, target, this);
Point center = centerPoint();
float deltaY = target.y - center.y;
float deltaX = target.x - center.x;
angle = (float) -Math.atan2(deltaX, deltaY);
angle = Math.toRadians(Math.toDegrees(angle) + 180.0);
repaint();
}
}
}
I just want to add that using a JLabel for this purpose is overkill, a simple JPanel or JComponent would do the same job and carry a lot less overhead with it, just saying
I would like to rotate a rectangle when e.g. y position achieve specified position. I would like to behave a rectangle as a car on a junction - just turn e.g. right. I prefer just rotate and continue.
A draft code looks like that:
Graphics2D g2d = (Graphics2D) g.create();
g2d.setPaint(new Color(150, 150, 0));
//1. when rectangle achieve 500 on y dimension just rotate left/right
if(y==500) {
_rotate = true;
g2d.rotate(Math.toRadians(90.));
}
if(_rotate) { //if rotate, continue way on x dimension
++x ;
g2d.fillRect(x, y, 20, 40);
} else { //else go to the north
--y;
g2d.fillRect(x, y, 20, 40);
}
There is a lot of information which is missing from your question.
In order to be able to rotate a shape, you need to know a few things, you need to know it's current position and it's next target position, then you can simply calculate the angle between these two points.
The question then becomes, how do you calculate these positions. There are plenty of ways you might achieve this, the following is a simple path following process.
First, we generate a path which we need to follow, we use the Shape API to calculate the points along the path. We use a simple time based animation (rather the looping through the points, we calculate the progress along the path by calculating amount of time the animation has been playing divided by the amount of time we want it to take) and picking the point which best matches our current progress.
We use a AffineTransform to rotate the player shape and the translate the resulting Shape to the required position. Ease
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class PathFollow {
public static void main(String[] args) {
new PathFollow();
}
public PathFollow() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Shape pathShape;
private List<Point2D> points;
private Shape car;
private double angle;
private Point2D pos;
private int index;
protected static final double PLAY_TIME = 5000; // 5 seconds...
private Long startTime;
public TestPane() {
Path2D path = new Path2D.Double();
path.moveTo(0, 200);
path.curveTo(100, 200, 0, 100, 100, 100);
path.curveTo(200, 100, 0, 0, 200, 0);
pathShape = path;
car = new Rectangle(0, 0, 10, 10);
points = new ArrayList<>(25);
PathIterator pi = pathShape.getPathIterator(null, 0.01);
while (!pi.isDone()) {
double[] coords = new double[6];
switch (pi.currentSegment(coords)) {
case PathIterator.SEG_MOVETO:
case PathIterator.SEG_LINETO:
points.add(new Point2D.Double(coords[0], coords[1]));
break;
}
pi.next();
}
// System.out.println(points.size());
// pos = points.get(0);
// index = 1;
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (startTime == null) {
startTime = System.currentTimeMillis();
}
long playTime = System.currentTimeMillis() - startTime;
double progress = playTime / PLAY_TIME;
if (progress >= 1.0) {
progress = 1d;
((Timer) e.getSource()).stop();
}
int index = Math.min(Math.max(0, (int) (points.size() * progress)), points.size() - 1);
pos = points.get(index);
if (index < points.size() - 1) {
angle = angleTo(pos, points.get(index + 1));
}
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.draw(pathShape);
AffineTransform at = new AffineTransform();
if (pos != null) {
Rectangle bounds = car.getBounds();
at.rotate(angle, (bounds.width / 2), (bounds.width / 2));
Path2D player = new Path2D.Double(car, at);
g2d.translate(pos.getX() - (bounds.width / 2), pos.getY() - (bounds.height / 2));
g2d.draw(player);
}
g2d.dispose();
}
// In radians...
protected double angleTo(Point2D from, Point2D to) {
double angle = Math.atan2(to.getY() - from.getY(), to.getX() - from.getX());
return angle;
}
}
}
I'm fairly new to programming with graphics and I'm attempting to code a side scrolling 2D game. At the moment, I'm trying to figure out how to approach redrawing a scrolling image as it appears in the JFrame. I'm using 8x8 pixel blocks as images. One possible issue I thought about concerns moving a sprite just 1 or 2 pixels and still rendering each image as it appears pixel by pixel on/off of the screen. How do I go about rendering the image/blocks pixel by pixel instead of whole images should the sprite barely move? Any feedback is much appreciated!
This is a proof of concept only! I randomly generate the tiles that get painted, I hope you have some kind of virtual map setup so you know which tiles to paint at any given virtual point!
Basically, what this does, is when the screen is moved left or right, it shifts the "master" image left or right and stitches new tiles onto new edge
My test was using a style sheet of 31x31 cells (don't ask, I just grab it off the net)
This is VERY scaled down example of the output, it was running at 1100x700+
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Scroll {
public static void main(String[] args) {
new Scroll();
}
public Scroll() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage screen;
private BufferedImage styleSheet;
public TestPane() {
try {
styleSheet = ImageIO.read(getClass().getResource("/StyleSheet.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "right");
ActionMap am = getActionMap();
am.put("left", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
stitch(-31);
}
});
am.put("right", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
stitch(31);
}
});
}
#Override
public void invalidate() {
screen = null;
super.invalidate();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void stitch(int direction) {
if (screen == null) {
prepareScreen();
}
Random r = new Random();
BufferedImage update = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = update.createGraphics();
g2d.drawImage(screen, direction, 0, this);
int gap = direction < 0 ? (direction * -1) : direction;
int xOffset = 0;
if (direction < 0) {
xOffset = getWidth() - gap;
}
for (int x = 0; x < gap; x += 31) {
for (int y = 0; y < getHeight(); y += 31) {
xOffset += x;
int cellx = 2;
int celly = 2;
if (r.nextBoolean()) {
cellx = 7;
celly = 5;
}
BufferedImage tile = styleSheet.getSubimage((cellx * 33) + 1, (celly * 33) + 1, 31, 31);
g2d.drawImage(tile, xOffset, y, this);
}
}
g2d.dispose();
screen = update;
repaint();
}
protected void prepareScreen() {
if (screen == null) {
screen = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
}
Random r = new Random();
Graphics2D g2d = screen.createGraphics();
for (int x = 0; x < getWidth(); x += 31) {
for (int y = 0; y < getHeight(); y += 31) {
int cellx = 2;
int celly = 2;
if (r.nextBoolean()) {
cellx = 7;
celly = 5;
}
BufferedImage tile = styleSheet.getSubimage((cellx * 33) + 1, (celly * 33) + 1, 31, 31);
g2d.drawImage(tile, x, y, this);
}
}
g2d.dispose();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (screen == null) {
prepareScreen();
}
g2d.drawImage(screen, 0, 0, this);
g2d.dispose();
}
}
}
I am currently working on a simple top down shooter. The object is a ball that slides around the screen, and I am trying to make a sort of wet-dragging affect.
I am using Java Swing and just the default Graphics2d lib inside.
This is what I have:
and this is my goal:
I need to know how I can make a curved line that has the ability to change alpha at the trailing end. I have searched online but I can only find non-dynamic solutions. (The tail needs to update as the player moves across the screen.)
A simple solution might be to simple add each point to a List of Points which before the player is moved.
You would simply then need to iterate this list and either simple use something like Graphics#drawLine or even GeneralPath to render the "drag" line, for example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Drag {
public static void main(String[] args) {
new Drag();
}
public Drag() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private List<Point> points;
private Point pos;
private int diametere = 10;
public TestPane() {
points = new ArrayList<>(25);
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "right");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "up");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "down");
ActionMap am = getActionMap();
am.put("left", new MoveAction(-5, 0));
am.put("right", new MoveAction(5, 0));
am.put("up", new MoveAction(0, -5));
am.put("down", new MoveAction(0, 5));
pos = new Point(100 - (diametere / 2), 100 - (diametere / 2));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (points.size() > 1) {
g2d.setColor(Color.RED);
GeneralPath path = new GeneralPath();
boolean started = false;
System.out.println("----");
for (Point p : points) {
if (started) {
System.out.println(p);
path.lineTo(p.x, p.y);
} else {
path.moveTo(p.x, p.y);
started = true;
}
}
g2d.draw(path);
}
int radius = (int) (diametere / 2d);
g2d.setColor(Color.GREEN);
g2d.draw(new Ellipse2D.Double(pos.x - radius, pos.y - radius, diametere, diametere));
g2d.dispose();
}
protected void moveBy(int xDelta, int yDelta) {
if (pos.x + xDelta < 0) {
xDelta = 0;
pos.x = 0;
} else if (pos.x + xDelta + diametere > getWidth()) {
xDelta = 0;
pos.x = getWidth() - diametere;
}
if (pos.y + yDelta < 0) {
yDelta = 0;
pos.y = 0;
} else if (pos.y + yDelta + diametere > getHeight()) {
yDelta = 0;
pos.y = getWidth() - diametere;
}
points.add(new Point(pos));
pos.x += xDelta;
pos.y += yDelta;
repaint();
}
public class MoveAction extends AbstractAction {
private int xDelta;
private int yDelta;
public MoveAction(int xDelta, int yDelta) {
this.xDelta = xDelta;
this.yDelta = yDelta;
}
#Override
public void actionPerformed(ActionEvent e) {
moveBy(xDelta, yDelta);
}
}
}
}
Hmm.. maybe you need something like this:
public class BallArea extends JComponent {
static final int MAX_SIZE = 63;
static final BasicStroke stroke = new BasicStroke(5);
final Queue<Point> points = new LinkedList();
public BallArea() {
setSize(400, 400);
setBackground(Color.BLACK);
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
if (points.size() >= MAX_SIZE) {
points.poll();
}
points.add(e.getPoint());
repaint();
}
});
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(stroke);
int i = 1;
Point prev = null;
for (Point p : points) {
if (prev == null) {
prev = p;
continue;
}
g2.setColor(new Color(255, 0, 0, i*4));
g.drawLine(prev.x, prev.y, p.x, p.y);
i++;
prev = p;
}
}
}
I made a mini code that draw oval and link each other , now i try to move the oval(Circle) but I have a problem (in coding)
// Panneau.java
public class Panneau extends JPanel {
private int R = 20;
private boolean isDrag = false;
String text = "stack";
int x = 250, y = 200;
int height = 50, width = 50;
Random Rnd = new Random();
int rand=Rnd.nextInt();
int r=Math.abs(rand%250);
int r2=Math.abs(rand%250);
public Panneau() {
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if ((x<=e.getX() && x+R>=e.getX()) && ( y<=e.getY() && y+R>=e.getY())) {
moveVertex(e.getX(),e.getY());
isDrag = true;
}
}
#Override
public void mouseReleased(MouseEvent e) {
isDrag = false;
}
});
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
if (isDrag) moveVertex(e.getX(),e.getY());
}
});
}
private void moveVertex(int x1, int y1) {
if ((x!=x1) || (y!=y1)) {
x=x1-10;
y=y1-10;
repaint();
}
}
#Override
protected void paintComponent(Graphics g){
// declaration
super.paintComponent(g);
g.setColor(Color.black);
g.drawLine(x,y,x+r,y+r2);
g.setColor(Color.yellow);
g.fillOval(x-height/2, y-width/2,width, height);
g.fillOval((x-height/2)+r, (y-width/2)+r2,width, height);
FontMetrics fm = g.getFontMetrics();
double textWidth = fm.getStringBounds(text, g).getWidth();
g.setColor(Color.blue);
g.drawString(text, (int) (x - textWidth/2),(int) (y + fm.getMaxAscent() / 2));
g.drawString(text, (int) (x - textWidth/2)+r,(int) (y + fm.getMaxAscent() / 2)+r2);
}
}
I must move the two circles and the line must not move(Graph node)
please help me and thanks :)
After the update ( thanks to MadProgrammer) now I can move all the figure ( but if I clicked in the red circle only) , I want to move just circles thanks :)
Basically, because instead of using reapint(int, int) you could use repaint()
private void moveVertex(int x1, int y1) {
int OFFSET = 1;
if ((x != x1) || (y != y1)) {
x = x1 - 10;
y = y1 - 10;
repaint();
}
}
This will ensure that the entire component is repainted.
While I wouldn't discount the use of repaint(int, int), because your painting process is relatively simple, it's not going to provide you with a great deal of benefit at this stage
Updated with additional example
IF I understand, you want to be able to move a single node and have the line remain joined.
While it might be possible to implement within the code you have available, a simpler soltution would be to take advantage of the 2D Graphics Shape API, this provides a number of really useful functions, including determining of points fall within a given shape.
It also means you don't need to keep track of a large number of parameters, but instead, get a self contained object that just knows how it should be painted...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestGraphNode {
public static void main(String[] args) {
new TestGraphNode();
}
public TestGraphNode() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Panneau());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class Panneau extends JPanel {
private int radius = 50;
private String text = "stack";
private List<Ellipse2D> nodes;
private Ellipse2D dragged;
private Point offset;
public Panneau() {
nodes = new ArrayList<>(25);
nodes.add(new Ellipse2D.Float(50 - (radius / 2), 100 - (radius / 2), radius, radius));
nodes.add(new Ellipse2D.Float(350 - (radius / 2), 100 - (radius / 2), radius, radius));
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
for (Ellipse2D node : nodes) {
if (node.contains(e.getPoint())) {
System.out.println("Clicked...");
dragged = node;
// Adjust for the different between the top/left corner of the
// node and the point it was clicked...
offset = new Point(node.getBounds().x - e.getX(), node.getBounds().y - e.getY());
// Highlight the clicked node
repaint();
break;
}
}
}
#Override
public void mouseReleased(MouseEvent e) {
// Erase the "click" highlight
if (dragged != null) {
repaint();
}
dragged = null;
offset = null;
}
});
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
if (dragged != null && offset != null) {
// Adjust the position of the drag point to allow for the
// click point offset
Point to = e.getPoint();
to.x += offset.x;
to.y += offset.y;
// Modify the position of the node...
Rectangle bounds = dragged.getBounds();
bounds.setLocation(to);
dragged.setFrame(bounds);
// repaint...
repaint();
}
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
// declaration
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
// Draw the connecting lines first
// This ensures that the lines are under the nodes...
Point p = null;
for (Ellipse2D node : nodes) {
g2d.setColor(Color.BLACK);
Point to = node.getBounds().getLocation();
to.x += radius / 2;
to.y += radius / 2;
if (p != null) {
g2d.draw(new Line2D.Float(p, to));
}
p = to;
}
// Draw the nodes...
for (Ellipse2D node : nodes) {
g2d.setColor(Color.yellow);
g2d.fill(node);
if (node == dragged) {
g2d.setColor(Color.BLUE);
g2d.draw(node);
}
g2d.setColor(Color.BLUE);
FontMetrics fm = g.getFontMetrics();
int textWidth = fm.stringWidth(text);
int x = node.getBounds().x;
int y = node.getBounds().y;
int width = node.getBounds().width;
int height = node.getBounds().height;
g.drawString(text,
x + ((width - textWidth)) / 2,
y + ((height - fm.getHeight()) / 2) + fm.getAscent());
}
g2d.dispose();
}
}
}