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;
}
}
}
Related
I am a new coder. I am having trouble adding a start and stop button for this piece of example code that i am working off. I'm sure i have to mess with with Thread.sleep(10); in the game class. This code starts the game when the program is run. is there a way i could add start button to start the thread. I have created j button already. Thanks.
Game Class
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class Game extends JPanel {
Ball ball = new Ball(this);
Racquet racquet = new Racquet(this);
public Game() {
addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
racquet.keyReleased(e);
}
#Override
public void keyPressed(KeyEvent e) {
racquet.keyPressed(e);
}
});
setFocusable(true);
}
private void move() {
ball.move();
racquet.move();
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
ball.paint(g2d);
racquet.paint(g2d);
}
public void gameOver() {
JOptionPane.showMessageDialog(this, "Game Over", "Game Over", JOptionPane.YES_NO_OPTION);
System.exit(ABORT);
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame("Mini Tennis");
Game game = new Game();
frame.add(game);
frame.setSize(300, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
while (true) {
game.move();
game.repaint();
Thread.sleep(10);
}
}
}
Ball Class
import java.awt.Graphics2D;
import java.awt.Rectangle;
public class Ball {
private static final int DIAMETER = 30;
int x = 0;
int y = 0;
int xa = 1;
int ya = 1;
private Game game;
public Ball(Game game) {
this.game= game;
}
void move() {
if (x + xa < 0)
xa = 1;
if (x + xa > game.getWidth() - DIAMETER)
xa = -1;
if (y + ya < 0)
ya = 1;
if (y + ya > game.getHeight() - DIAMETER)
game.gameOver();
if (collision()){
ya = -1;
y = game.racquet.getTopY() - DIAMETER;
}
x = x + xa;
y = y + ya;
}
private boolean collision() {
return game.racquet.getBounds().intersects(getBounds());
}
public void paint(Graphics2D g) {
g.fillOval(x, y, DIAMETER, DIAMETER);
}
public Rectangle getBounds() {
return new Rectangle(x, y, DIAMETER, DIAMETER);
}
}
Racquet Class
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
public class Racquet {
private static final int Y = 330;
private static final int WIDTH = 60;
private static final int HEIGHT = 10;
int x = 0;
int xa = 0;
private Game game;
public Racquet(Game game) {
this.game = game;
}
public void move() {
if (x + xa > 0 && x + xa < game.getWidth() - WIDTH)
x = x + xa;
}
public void paint(Graphics2D g) {
g.fillRect(x, Y, WIDTH, HEIGHT);
}
public void keyReleased(KeyEvent e) {
xa = 0;
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT)
xa = -1;
if (e.getKeyCode() == KeyEvent.VK_RIGHT)
xa = 1;
}
public Rectangle getBounds() {
return new Rectangle(x, Y, WIDTH, HEIGHT);
}
public int getTopY() {
return Y;
}
}
This is an mcve demonstrating the structure outlined in Hovercraft Full Of Eels comment :
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionListener;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class AnimationUsingTimer {
private Timer timer;
AnimationUsingTimer() {
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
AnimationPanel animationPanel = new AnimationPanel();
window.add(animationPanel);
JButton start = new JButton("Start");
start.addActionListener(e -> animationPanel.start());
window.add(start, BorderLayout.PAGE_START);
JButton stop = new JButton("Stop");
stop.addActionListener(e -> animationPanel.stop());
window.add(stop, BorderLayout.PAGE_END);
window.pack();
window.setVisible(true);
}
class AnimationPanel extends JPanel{
private BufferedImage img;
private Area ball, walls;
private final static int W = 450, H = 300, DIAMETER = 20;
private int x = W/2, y = H/2, xDelta = 3, yDelta = 2;
AnimationPanel() {
img = new BufferedImage(W, H, BufferedImage.TYPE_INT_RGB);
JLabel imageLabel = new JLabel(new ImageIcon(img));
add(imageLabel);
walls = new Area(new Rectangle(0,0,W,H));
ActionListener animate = e -> {
animate();
repaint();
};
timer = new Timer(50, animate);
}
public void animate() {
x+=xDelta; y+=yDelta;
ball = new Area(new Ellipse2D.Double(x, y, DIAMETER, DIAMETER));
if (checkCollision(ball,walls)) {
if ( x+DIAMETER>img.getWidth() || x<0 ) {
xDelta *= -1;
}
if(y+DIAMETER>img.getHeight() || y<0 ) {
yDelta *= -1;
}
}
}
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2D = img.createGraphics();
g2D.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2D.setColor(Color.CYAN);
g2D.fillRect(0, 0, img.getWidth(), img.getHeight());
if(ball != null){
g2D.setColor(Color.RED);
g2D.fill(ball);
}
g2D.dispose();
}
void start(){
timer.start();
}
void stop(){
timer.stop();
}
private boolean checkCollision(Area area1, Area area2) {
return area1.getBounds().intersects(area2.getBounds());
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new AnimationUsingTimer());
}
}
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
There is one Paraview user interface as follow attracted me.
I think this interface can be used to assign value into array. It works like this :
I want to implement this into a Java program but I found no Java API can support my idea. The closest design from me would be adding multiple JSlider like this :
But what if it is a 100 size array, I wouldn't want to add 100 JSliders. Do you have better solution for this ?
Okay, so this is a pretty basic example. It needs a lot more work and optimisation, but should get you moving in the right direction
Have a look at Painting in AWT and Swing, Performing Custom Painting, 2D Graphics and How to Write a Mouse Listener for more details
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.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
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 TestGraph {
public static void main(String[] args) {
new TestGraph();
}
public TestGraph() {
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 GraphPane(0, 100, new int[100]));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class GraphPane extends JPanel {
protected static final int COLUMN_WIDTH = 10;
protected static final int VERTICAL_INSETS = 10;
private int[] data;
private int minValue, maxValue;
private Path2D.Double graph;
private List<Shape> buttons;
private Point mousePoint;
public GraphPane(int minValue, int maxValue, int[] data) {
this.data = data;
this.minValue = minValue;
this.maxValue = maxValue;
buttons = new ArrayList<>(data == null ? 25 : data.length);
updateView();
MouseAdapter ma = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
updateData(e);
}
#Override
public void mouseDragged(MouseEvent e) {
updateData(e);
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
}
protected void updateData(MouseEvent e) {
// Which "column" was clicked on
int column = (int) Math.round(((double) e.getX() / (double) COLUMN_WIDTH)) - 1;
// Get the "height" of the clickable area
int clickRange = getHeight() - (VERTICAL_INSETS * 2);
// Adjust the y click point for the margins...
int yPos = e.getY() - VERTICAL_INSETS;
// Calculate the vertical position that was clicked
// this ensures that the range is between 0 and clickRange
// You could choose to ignore values out side of this range
int row = Math.min(Math.max(clickRange - yPos, 0), clickRange);
// Normalise the value between 0-1
double clickNormalised = row / (double) clickRange;
// Calculate the actual row value...
row = minValue + (int) (Math.round(clickNormalised * maxValue));
// Update the data
data[column] = row;
mousePoint = new Point(
COLUMN_WIDTH + (column * COLUMN_WIDTH),
getHeight() - (VERTICAL_INSETS + (int) Math.round((data[column] / 100d) * clickRange)));
updateView();
repaint();
}
#Override
public void invalidate() {
super.invalidate();
updateView();
}
protected Shape createButton(int xPos, int yPos) {
return new Ellipse2D.Double(xPos - COLUMN_WIDTH / 2, yPos - COLUMN_WIDTH / 2, COLUMN_WIDTH, COLUMN_WIDTH);
}
protected void updateView() {
graph = new Path2D.Double();
buttons.clear();
if (data != null && data.length > 0) {
int verticalRange = getHeight() - (VERTICAL_INSETS * 2);
int xPos = COLUMN_WIDTH;
int yPos = getHeight() - (VERTICAL_INSETS + (int) Math.round((data[0] / 100d) * verticalRange));
graph.moveTo(xPos, yPos);
if (data[0] > 0) {
buttons.add(createButton(xPos, yPos));
}
for (int index = 1; index < data.length; index++) {
xPos = (index * COLUMN_WIDTH) + COLUMN_WIDTH;
yPos = getHeight() - (VERTICAL_INSETS + (int) Math.round((data[index] / 100d) * verticalRange));
graph.lineTo(xPos, yPos);
if (data[index] > 0) {
buttons.add(createButton(xPos, yPos));
}
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(data == null ? 0 : (data.length + 1) * COLUMN_WIDTH, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (data != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(new Color(64, 64, 64, 32));
for (int index = 0; index < data.length; index++) {
int xPos = (index * COLUMN_WIDTH) + COLUMN_WIDTH;
g2d.drawLine(xPos, VERTICAL_INSETS, xPos, getHeight() - VERTICAL_INSETS);
}
g2d.setColor(Color.BLACK);
g2d.draw(graph);
for (Shape button : buttons) {
g2d.fill(button);
}
if (mousePoint != null) {
g2d.setColor(new Color(255, 192, 203));
Ellipse2D dot = new Ellipse2D.Double((mousePoint.x - COLUMN_WIDTH / 2) - 2, (mousePoint.y - COLUMN_WIDTH / 2) - 2, COLUMN_WIDTH + 4, COLUMN_WIDTH + 4);
g2d.draw(dot);
g2d.setColor(new Color(255, 192, 203, 128));
g2d.fill(dot);
}
g2d.dispose();
}
}
}
}
Before anyone says I didn't put the "fill" in, I deliberately used a Path2D to make it much simpler to achieve ;)
here is a small example how to create this using polygon class .i sorted x coordinate and use polygon class to make this.
GraphPane.class
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.util.ArrayList;
import java.util.Collections;
import javax.swing.JPanel;
public class GraphPane extends JPanel {
ArrayList<XYpoints> poinList = new ArrayList();
private int px;
private int py;
private XYpoints last;
private boolean drag;
private static Color graphColor=new Color(32, 178, 170);
public GraphPane() {
initComponents();
poinList.add(new XYpoints(50, 400));
poinList.add(new XYpoints(450, 50));
poinList.add(new XYpoints(600, 400));
}
private void initComponents() {
setBackground(new java.awt.Color(255, 255, 255));
addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
public void mouseDragged(java.awt.event.MouseEvent evt) {
System.out.println("drag");
if (drag) {
last.setY(evt.getY());
GraphPane.this.repaint();
}
}
});
addMouseListener(new java.awt.event.MouseAdapter() {
public void mousePressed(java.awt.event.MouseEvent evt) {
int x = evt.getX();
int y = evt.getY();
for (XYpoints poinList1 : poinList) {
px = poinList1.getpX();
py = poinList1.getpY();
if (x < px + 5 && x > px - 5 && y < py + 5 && y > py - 5) {
System.out.println("inter");
poinList1.setIntersect(true);
last = poinList1;
drag = true;
GraphPane.this.repaint();
return;
}
}
poinList.add(new XYpoints(x, y));
Collections.sort(poinList, new XComp());
GraphPane.this.repaint();
}
public void mouseReleased(java.awt.event.MouseEvent evt) {
if (drag) {
drag = false;
last.setIntersect(false);
GraphPane.this.repaint();
}
}
});
}
#Override
protected void paintComponent(Graphics gr) {
super.paintComponent(gr);
Graphics2D g = (Graphics2D) gr.create();
Polygon p = new Polygon();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for (XYpoints poinList1 : poinList) {
px = poinList1.getpX();
py = poinList1.getpY();
p.addPoint(px, py);
}
g.setColor(graphColor);
g.fillPolygon(p);
for (XYpoints poinList1 : poinList) {
px = poinList1.getpX();
py = poinList1.getpY();
g.setColor(Color.red);
if (poinList1.isIntersect()) {
g.setColor(Color.blue);
}
g.fillOval(px - 5, py - 5, 10, 10);
}
g.dispose();
}
}
XYpoints.class
import java.awt.Polygon;
import java.util.Comparator;
public class XYpoints extends Polygon {
private int x;
private int y;
private boolean inter;
public XYpoints(int x, int y) {
this.x = x;
this.y = y;
}
public void setIntersect(boolean state) {
inter = state;
}
public void setY(int y){
this.y=y;
}
public boolean isIntersect() {
return inter;
}
public int getpX() {
//System.out.println("send " + this.x);
return this.x;
}
public int getpY() {
return this.y;
}
}
XComp .class
class XComp implements Comparator<XYpoints> {
#Override
public int compare(XYpoints t, XYpoints t1) {
if (t.getpX() < t1.getpX()) {
return -1;
} else {
return 1;
}
}
}
myframe.class
import javax.swing.JFrame;
public class myframe extends JFrame {
public myframe() {
GraphPane pane = new GraphPane();
setContentPane(pane);
setSize(650, 500);
setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new myframe();
}
});
}
}
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'm trying to draw Images with Graphics2D on JFrame.
But this code only displays blank background.
How to do that?
Java Version: SE-1.6
IDE: Eclipse
My code looks like this:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferStrategy;
import java.awt.geom.Line2D;
import java.util.TimerTask;
import javax.swing.JFrame;
public class GraphicTest extends JFrame{
public static void main(String[] args) {
GraphicTest gt = new GraphicTest();
gt.start();
}
JFrame frame;
BufferStrategy strategy;
GraphicTest(){
int width = 320;
int height = 240;
this.frame = new JFrame("test");
this.frame.setSize(width, height);
this.frame.setLocationRelativeTo(null);
this.frame.setLocation(576, 336);
this.frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
this.frame.setUndecorated(true);
this.frame.setBackground(new Color(0, 0, 0, 50));
this.frame.setVisible(true);
this.frame.setIgnoreRepaint(true);
this.frame.createBufferStrategy(2);
this.strategy = this.frame.getBufferStrategy();
}
public void onExit(){
System.exit(0);
}
void start(){
java.util.Timer timer = new java.util.Timer();
timer.schedule(new RenderTask(), 0, 16);
}
class RenderTask extends TimerTask{
int count = 0;
#Override
public void run() {
GraphicTest.this.render();
}
}
void render() {
// Some moving images
Graphics2D g2 = (Graphics2D)this.strategy.getDrawGraphics();
g2.setStroke(new BasicStroke(5.0f));
Line2D line = new Line2D.Double(20, 40, 120, 140);
g2.draw(line);
this.strategy.show();
}
}
Thank you for any help you can provide.
BufferStrategy is normally associated with heavy weight components, which don't have any concept of transparency.
Transparent and translucent (per alpha pixeling) is not "officially" supported under Java 6
Making a window translucent effects anything else painted to it...this very annoying, regardless if you are using Java 6 or 7
The secret is to make the Window transparent to begin with, then overlay a transparent component that has a special "translucent" paint effect.
Under Java 6 (update 10 I think), there became available a private API called AWTUtilities which provide the ability to make a window transparent or translucent, the following example is based on that API.
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.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TransparentWindowAnimation {
public static void main(String[] args) {
new TransparentWindowAnimation();
}
public TransparentWindowAnimation() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
if (supportsPerAlphaPixel()) {
try {
JFrame frame = new JFrame("Testing");
frame.setUndecorated(true);
setOpaque(frame, false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new PaintPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (Exception exp) {
exp.printStackTrace();
}
} else {
System.err.println("Per pixel alphering is not supported");
}
}
});
}
public static boolean supportsPerAlphaPixel() {
boolean support = false;
try {
Class<?> awtUtilsClass = Class.forName("com.sun.awt.AWTUtilities");
support = true;
} catch (Exception exp) {
}
return support;
}
public static void setOpaque(Window window, boolean opaque) throws Exception {
try {
Class<?> awtUtilsClass = Class.forName("com.sun.awt.AWTUtilities");
if (awtUtilsClass != null) {
Method method = awtUtilsClass.getMethod("setWindowOpaque", Window.class, boolean.class);
method.invoke(null, window, opaque);
}
} catch (Exception exp) {
throw new Exception("Window opacity not supported");
}
}
public class PaintPane extends JPanel {
private BufferedImage img;
private int xPos, yPos = 100;
private int xDelta = 0;
private int yDelta = 0;
public PaintPane() {
while (xDelta == 0) {
xDelta = (int)((Math.random() * 8)) - 4;
}
while (yDelta == 0) {
yDelta = (int)((Math.random() * 8)) - 4;
}
setOpaque(false);
try {
img = ImageIO.read(new File("AngryBird.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
xPos += xDelta;
yPos += yDelta;
if (xPos - (img.getWidth() / 2) <= 0) {
xPos = img.getWidth() / 2;
xDelta *= -1;
}
if (xPos + (img.getWidth() / 2) >= getWidth()) {
xPos = getWidth() - (img.getWidth() / 2);
xDelta *= -1;
}
if (yPos - (img.getHeight() / 2) <= 0) {
yPos = img.getHeight() / 2;
yDelta *= -1;
}
if (yPos + (img.getHeight() / 2) >= getHeight()) {
yPos = getHeight() - (img.getHeight() / 2);
yDelta *= -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.setColor(new Color(128, 128, 128, 128));
g2d.fillRect(0, 0, getWidth(), getHeight());
int x = xPos - (img.getWidth() / 2);
int y = yPos - (img.getHeight()/ 2);
g2d.drawImage(img, x, y, this);
g2d.dispose();
}
}
}
Another way can be seen here. It can be accomplished by
frame.setBackground(new Color(0, 0, 0, 0));
....
setOpaque(false); //for the JPanel being painted on.