im trying to code a GUI for "Towers of Hanoi" with a Java JFrame.
I thought I can just make a array with all rectangles (I use rectangles to display the elements, that the player can move) and then use something like this "recList[1].move()"to move the rectangle on the canvas, but I don't finde a funktion, that can do this.
It would be grade, if somebody could say me how i can move a rectangle to specific coordinates.
Here is my code:
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
public class GUIBuilder extends JFrame {
//object classes
public static class Rectangle {
Rectangle2D.Double Rectangle;
public Rectangle(double x, double y, double w, double h) {
Rectangle = new Rectangle2D.Double(x, y, w, h);
}
public void draw(Graphics2D g) {
g.draw(Rectangle);
}
}
public static class Stick {
Line2D.Double stick;
public Stick(double x1, double y1, double x2, double y2) {
this.stick = new Line2D.Double(x1, y1, x2, y2);
}
public void draw(Graphics2D g) {
g.draw(stick);
}
}
//draw
static class DrawPane extends JPanel {
public void paintComponent(Graphics g) {
double s = 3; // s = amount of sticks
double n = 5; // n = amount of elements
//base
Rectangle rectangle = new Rectangle(300, 700, (int) s * 100 + 100, 50);
rectangle.draw((Graphics2D)g.create());
//s sticks
for (int i=0; i<s; i++) {
Stick stick = new Stick(400 + 100 * i, 700 - (25 * (n + 1)), 400 + 100 * i, 700);
stick.draw((Graphics2D)g.create());
}
//n elements
Rectangle[] recList = new Rectangle[(int)n]; //declaration a list for the rectangles
for (int i=0;i<n;i++) {
double w = 90/n*(n-i);
double x = 355+90/n/2*i;
double y = 675-25*i;
double h = 25;
recList[i] = new Rectangle(x, y, w, h);
recList[i].draw((Graphics2D)g.create());
}
}
}
//guibuilder
public GUIBuilder() {
JFrame frame = new JFrame("Towers of Hanoi by ByPander");
frame.setContentPane(new DrawPane());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 600);
frame.setVisible(true);
}
//calling the guibuilder
public static void main(String[] args){
//start the Guibuilder
new GUIBuilder();
}
}
Related
I tried to plot a circle using the java awt, what I get in output is just few small which are separated by much distance apart and doesn't look like a circle as a whole. Code is given below :
class DrawFrame extends JFrame {
int хс, yc, r, x, y;
float p;
DrawFrame(int rr, int c1, int c2) {
setSize(1000, 1000);
setTitle("circle drawing algo");
r = rr;
xc = c1;
yc = c2;
}
public void paint(Graphics g) {
Circl(g);
}
public void Circl(Graphics g) {
x = xc - r;
while (x <= (xc + r)) {
for (y = yc - r; y <= (yc + r); y++) {
p = x * x + y * y - r * r;
if (p == 0.0)
g.drawOval(x, y, 2, 2);
}
x++;
}
}
You should start by having a read of Performing Custom Painting and Painting in AWT and Swing to get a better understanding of how the painting system works and how you should work with it.
You shouldn't override the paint method of top level components, apart from not been double buffered, they are actually compound components. This means that they have a number of additional components laid out on top of them which provide the overall functionality of the window.
This means that it's possible for what you've painted to the surface of the frame to be ignored, as the content on top of it paints over it.
You're also ignoring the complexity of the painting process, unless you're prepared to take over the responsibility of the paint method yourself, you should always call its super method.
A better place to start is with a JPanel (which is simpler) and override its paintComponent method
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
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(100, 100, 100));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
int xc, yc, r;
public TestPane(int rr, int c1, int c2) {
r = rr;
xc = c1;
yc = c2;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(r * 2, r * 2);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
circle(g);
}
public void circle(Graphics g) {
// Credit to LAD for the algorithm updates
int x = xc - r;
while (x <= (xc + r)) {
for (int y = yc - r; y <= (yc + r); y++) {
float p = (x - xc) * (x - xc) + (y - yc) * (y - yc) - (r * r);
if (p <= 0.0f)
{
g.drawOval(x, y, 2, 2);
}
}
x++;
}
}
}
}
Credit to LAD for the algorithm updates
The first thing to change is to make JFrame visible by adding
setVisible(true); to its constructor.
It is recommended to use names that have a clear meaning to make the code more readable. Make the fields scope as limited as possible, in this case make them private:
private int сenterX, centerY, radius;
(x,y and p are method variables and do not need to be fields )
Avoid using magic numbers. Use constants instead:
private static final int W = 1000, H = 1000, DOT_SIZE =2 ;
Putting it together, using correct Java naming conventions and fixing the algorithm:
import java.awt.Graphics; //add imports to make tour code mcve
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
class DrawFrame extends JFrame {
private final int сenterX, centerY, radius;
private static final int W = 1000, H = 1000, DOT_SIZE =2 ;
DrawFrame(int radius, int centerX, int centerY) {
setSize(W, H);
setTitle("circle drawing algo");
this.radius = radius;
сenterX = centerX;
this.centerY = centerY;
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//make program stop when closing frame
setVisible(true); //make frame visible
}
#Override
public void paint(Graphics g) {
super.paint(g);
circl(g);
}
public void circl(Graphics g) {
int x, y;
x = сenterX - radius;
while (x <= сenterX + radius) {
//calculate x
y = (int)Math.sqrt(radius*radius - (сenterX -x)*(сenterX -x ));
g.drawOval(x, centerY-y, 2, 2); // 2 y values for every x
g.drawOval(x, centerY+y, 2, 2);
x++;
}
}
// add main to make your code mcve
public static void main(String[] args) {
SwingUtilities.invokeLater(()-> new DrawFrame(100, 400, 400));
}
}
The next improvement could be to refactor so the painting is done on a JPanel rather than on the JFrame itself, using Graphics.drawOval:
class DrawFrame extends JFrame {
DrawFrame(int radius, int centerX, int centerY) {
setTitle("circle drawing algo");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//make program stop when closing frame
add(new DrawingPane(radius, centerX, centerY));
pack();
setVisible(true); //make frame visible
}
// add main to make your code mcve
public static void main(String[] args) {
SwingUtilities.invokeLater(()-> new DrawFrame(100, 400, 400));
}
}
class DrawingPane extends JPanel{
private final int сenterX, centerY, radius;
private static final int W = 1000, H = 1000, DOT_SIZE =2 ;
DrawingPane(int radius, int centerX, int centerY) {
setPreferredSize(new Dimension(W, H));
this.radius = radius;
сenterX = centerX;
this.centerY = centerY;
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawOval(сenterX, centerY, radius, radius);
}
}
I edited your code a bit and changed the draw algorithm a little in order to completely draw the circle. Here is the refactored code:
class DrawFrame extends JFrame {
int xc, yc, r, x, y;
float p;
DrawFrame(int rr, int c1, int c2) {
setSize(1000, 1000);
setTitle("circle drawing algo");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Handles the window being closed
setVisible(true); // Makes the window visible
r = rr;
xc = c1;
yc = c2;
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
GradientPaint gp = new GradientPaint(0f,0f,Color.blue,0f,30f,Color.green); // Just sets a color for the paint
g2.setPaint(gp);
Circl(g2);
}
public void Circl(Graphics g) {
x = xc-r;
while (x <= (xc+r)) {
for (y = yc-r; y <= (yc+r); y++) {
p = (x-xc)*(x-xc)+(y-yc)*(y-yc)-(r*r); // Edited this line so that it’s now the correct circle formula
if (p <= 0.0f) // If the point is 0 or less, then the point is within the circle bounds
g.drawOval(x, y, 2, 2);
}
x++;
}
}
public static void main(String[] args) {
new DrawFrame(100, 500, 500);
}
}
The code is a bit slow, though, as the drawOval method seems to be quite slow when called a bunch of times. So, this code is mainly suited for the algorithm aspect, as you could easily fill out an oval by calling the following once:
g.drawOval(x, y, 200, 200);
g.fillOval(x, y, 200, 200);
You set initial value of x as x = xc - r, y as y = yc - r. And
converting Cartesian to Polar coordinate like p = x * x + y * y - r *
r . Assume that if xc=500, and yc=500, r=50, "p" will never be 0. So
I think you forgot to calculate xc, yc when you draw. I modified your
code little bit and attached the result.
package testProject;
import java.awt.*;
import javax.swing.*;
public class DrawFrame extends JPanel {
int xc=500, yc=500, r=150, x, y;
int real_x, real_y;
float p;
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("circle drawing algo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBackground(Color.white);
frame.setSize(1000, 1000);
DrawFrame panel = new DrawFrame();
frame.add(panel);
frame.setVisible(true);
}
public void paint(Graphics g) {
Circl(g);
}
public void Circl(Graphics g) {
x = -r;
while (x <= r) {
y = -r;
while (y <= r) {
p = x * x + y * y - r * r;
// here is the change
if (p>=0 && p<= xc) {
g.drawOval(x+xc, y+yc, 3, 3);
}
y++;
}
x++;
}
}
}
I'm having issues drawing some circles to my JFrame. I originally had it using the default layout and realized this was only adding the most recent circle, so I changed the layout to null, and now nothing gets drawn. I've also tried frame.setLayout(new FlowLayout()) which also doesn't draw anything. Any help would be appreciated!
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
/**
* #author Christopher Nielson
*
*/
public class Main {
private static JFrame frame;
private static Random rand;
private static Jiggler jiggler;
private static ArrayList<JComponent> circles;
private static int fps;
public static void main(String[] args) {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
frame.setBounds(100, 100, 450, 450);
rand = new Random();
circles = new ArrayList<JComponent>();
int x = frame.getWidth();
int y = frame.getHeight();
for (int i = 0; i < Integer.parseInt(args[0]); i++) {
circles.add(new Circle(rand.nextInt(frame.getWidth()), rand.nextInt(frame.getHeight()),
rand.nextInt(frame.getWidth() / 10) + 100, rand.nextInt(frame.getHeight() / 10) + 100, null));
}
circles.forEach(current -> {
frame.add(current);
});
frame.setVisible(true);
jiggler = new Jiggler(circles, new JLabel("FPS: ")); // TODO add fps
jiggler.run();
}
}
And this is one reason you'll see us recommending time and time again to avoid using null layouts like the plague.
Having said that, your main problem is a design problem, not a layout problem, and that problem being that your Circle class shouldn't extend JComponent or any component for that matter, since if you want to draw multiple circles, you should have only one component, probably a JPanel doing the drawing, and the Circles should be logical classes, classes that have a public void draw(Graphics g) method, not component classes. You would pass the List of Circles to your drawing JPanel, and it would draw the Circles in its paintComponent method by calling the draw(g) methods of each Circle in the list.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class DrawChit extends JPanel {
private static final int PREF_W = 900;
private static final int PREF_H = 700;
private static final int MAX_SHAPES = 30;
private List<MyShape> shapes = new ArrayList<>();
public DrawChit() {
setBackground(Color.WHITE);
for (int i = 0; i < MAX_SHAPES; i++) {
double x = (PREF_W - 100) * Math.random();
double y = (PREF_H - 100) * Math.random();
double w = 100 + (Math.random() * PREF_W) / 10;
double h = 100 + (Math.random() * PREF_H) / 10;
Ellipse2D ellipse = new Ellipse2D.Double(x, y, w, h);
float hue = (float) Math.random();
double delta = 0.3;
float saturation = (float) (Math.random() * delta + (1 - delta));
float brightness = (float) (Math.random() * delta + (1 - delta));
Color color = Color.getHSBColor(hue, saturation, brightness);
shapes.add(new MyShape(ellipse, color));
}
// we'll throw a black square in the middle!
int rectW = 200;
int rectX = (PREF_W - rectW) / 2;
int rectY = (PREF_H - rectW) / 2;
shapes.add(new MyShape(new Rectangle(rectX, rectY, rectW, rectW), Color.BLACK));
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// use anti-aliasing to make graphics smooth
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// iterate through the shapes list, filling all
for (MyShape shape : shapes) {
shape.fill(g2);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class MyMouse extends MouseAdapter {
private Point p0 = null;
private MyShape shape = null;
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
// iterate *backwards* so get top-most Shape
for (int i = shapes.size() - 1; i >= 0; i--) {
if (shapes.get(i).contains(e.getPoint())) {
p0 = e.getPoint();
shape = shapes.get(i);
// move selected shape to the top!
shapes.remove(shape);
shapes.add(shape);
repaint();
return;
}
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (p0 != null) {
moveShape(e.getPoint());
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (p0 != null) {
moveShape(e.getPoint());
p0 = null;
shape = null;
}
}
// translates the shape
private void moveShape(Point p1) {
int deltaX = p1.x - p0.x;
int deltaY = p1.y - p0.y;
shape.translate(deltaX, deltaY);
p0 = p1;
repaint();
}
}
private static void createAndShowGui() {
DrawChit mainPanel = new DrawChit();
JFrame frame = new JFrame("Draw Chit");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class MyShape {
private Path2D path = new Path2D.Double();
private Color color;
public MyShape(Shape shape, Color color) {
path.append(shape, true);
this.color = color;
}
public boolean contains(Point p) {
return path.contains(p);
}
public void draw(Graphics2D g2) {
g2.setColor(color);
g2.draw(path);
}
public void fill(Graphics2D g2) {
g2.setColor(color);
g2.fill(path);
}
public void translate(int deltaX, int deltaY) {
path.transform(AffineTransform.getTranslateInstance(deltaX, deltaY));
}
}
I'm new to java. I am like to create a simple animation with a ball moving from left to right and i wish to give it an circular frame illusion(i don't know how to phrase it) If part of the ball leave the border of the frame(right side), that part would reappear in the left side of my frame. I had no idea how to start. So far i only manage to get the ball move.
This is a part of my code
public class BallAnimation extends JFrame {
private JButton left,right,up,down;
private Balls ball = new Balls();
private Ellipse2D circle;
public BallAnimation()
{
add(ball);
}
public class Balls extends JPanel{
private double X=0,Y=0;
private int i=1;
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g.setColor(Color.CYAN);
g.fillRect(0, 0, getWidth(), (getHeight()));
if(X==0 && Y ==0)
{
X=getWidth()/2.1;
Y=getHeight()/2.3;
g.setColor(Color.RED);
circle= new Ellipse2D.Double(X,Y,50,50);
g2.fill(circle);
}
else
{
g.setColor(Color.RED);
circle= new Ellipse2D.Double(X,Y,50,50);
g2.fill(circle);
}
if(i==1)
{
X=X+10;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
repaint();
}
}
}
public static void main(String[] args)
{
BallAnimation test = new BallAnimation();
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
test.setSize(700,500);
test.setVisible(true);
}
}
I'd search around and didn't find anything, maybe the phrase im use is not right. Any help would be appreciated.
You can do a simple calculation to check if the ball has gone past the edge of the component.Eg.
Rectangle rect = circle.getBounds();
Rectangel bounds = getBounds();
if(rect.getX() + rect.getWidth()>bounds.getWidth()){
//draw an ellipse that is offset by the width of the component.
Ellipse2D c2 = new Ellipse2D.Double(circle.getX()-bounds.getWidth(), circle.getY(), circle.getWidth(), circle.getHeight());
g2.fill(c2);
}
There you go, if it is out of bounds on the right side it will be drawn on the left side.
Here is an example, instead of checking if the ball wraps. I just drew the ball 9 times so that when it is across the boundary it gets drawn.
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.lang.reflect.InvocationTargetException;
/**
* Created by matt on 11/30/15.
*/
public class BouncingBall {
int width = 600;
int height = 600;
double diameter = 100;
double v = 10;
double vx = 6;
double vy = 8;
Ellipse2D ball = new Ellipse2D.Double(width/4, height/4, diameter, diameter);
Ellipse2D post = new Ellipse2D.Double(width/2 - diameter, height/2 - diameter, 2*diameter, 2*diameter);
JPanel display;
void buildGui(){
JFrame frame = new JFrame("ball");
display = new JPanel(){
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.BLACK);
g2d.fill(post);
g2d.setColor(Color.RED);
AffineTransform original = g2d.getTransform();
for(int i = 0; i<3; i++){
for(int j = 0; j<3; j++){
AffineTransform wrapper = new AffineTransform(original);
wrapper.translate((i-1)*width, (j-1)*height);
g2d.setTransform(wrapper);
g2d.draw(ball);
}
}
g2d.setTransform(original);
}
};
display.setMinimumSize(new Dimension(width, height));
display.setPreferredSize(new Dimension(width, height));
display.setMaximumSize(new Dimension(width, height));
frame.setContentPane(display);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
void startSimulation(){
while (!Thread.interrupted()&&display.isVisible()) {
double x = ball.getX() + vx;
double y = ball.getY() + vy;
//wrap the ball around.
if(x>width) x = x-width;
if(x<0) x = x+width;
if(y>height) y = y-height;
if(y<0) y = y+height;
ball.setFrame(x, y, diameter, diameter);
//check for collision.
double dx = ball.getCenterX() - 0.5*width;
double dy = ball.getCenterY() - 0.5*height;
double distance = Math.sqrt(dx*dx + dy*dy);
if(distance < 1.5*diameter){
vx = v*dx/distance;
vy = v*dy/distance;
}
display.repaint();
try {
Thread.sleep(33);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public static void main(String[] args) throws Exception {
BouncingBall b = new BouncingBall();
EventQueue.invokeAndWait(b::buildGui);
b.startSimulation();
}
}
Alright, so I have a class called Ball, where I'm putting some arguments inside the constructor. Here I have intial position, size and speed, but I also need to be able to set the size of the window (the JFrame) in the argument, so that when I call e.g. ball(xpos,ypos,size,speed,windowx,windowy) it will set the size of the JFrame according to what I put in windowx and windowy.
Right now I'm just trying stuff like a headless chicken without really knowing what I'm doing :P, so if someone could point me in the right direction, I would be very grateful!
package com.company;
import javax.swing.*;
import java.awt.*;
import java.util.Random;
public class Main extends JPanel {
static Ball[] balls = new Ball[20];
Random rand = new Random();
Main() {
for(int i = 0; i<20;i++){
float r = rand.nextFloat();
float g = rand.nextFloat();
float b = rand.nextFloat();
Color randomColor = new Color(r, g, b);
balls[i] = new Ball(Ball.randInt(100, 500),Ball.randInt(100, 500),Ball.randInt(10, 50),rand.nextInt(6-1)+1,randomColor,600,600);
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for(int i=0;i<20;i++) {
balls[i].draw(g);
}
}
public static void main(String[] args) throws InterruptedException{
Main m = new Main();
JFrame frame = new JFrame("Title"); //create a new window and set title on window
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //set the window to close when the cross in the corner is pressed
frame.setSize(600,600);
frame.add(m); //add the content of the game object to the window
frame.setVisible(true); //make the window visible
while(true){
Thread.sleep(10);
for(int i= 0;i<balls.length;i++){
balls[i].update();
}
m.repaint();
}
}
}
Ball class:
package com.company;
import javax.swing.*;
import java.awt.*;
import java.util.Random;
/**
* Created by John on 25/02/2015.
*/
public class Ball extends JPanel{
float _speedX;
float _speedY;
int _size;
float _x;
float _y;
float _speed;
Color _color;
int _windowX;
int _windowY;
Ball(int x, int y, int sz, float speed, Color c, int windowX, int windowY){
_x = x;
_y = y;
_speed=speed;
_speedX = speed;
_speedY = speed;
_size = sz;
_color = c;
_windowX = windowX;
_windowY = windowY;
}
public void update(){
_x += _speedX;
_y += _speedY;
if (_x+_size<0 || _x+_size>_windowX-_size){
_speedX*=-1;
}
if (_y+_size<0 || _y+_size>_windowY-_size){
_speedY*=-1;
}
this.repaint();
}
public static int randInt(int min, int max) {
Random rand = new Random();
int randomNum = rand.nextInt((max - min) + 1) + min;
return randomNum;
}
public void draw(Graphics g) {
g.setColor(_color);
g.fillOval((int)_x,(int) _y, _size, _size);
}
public void setPreferredSize(int wX, int wY) {
_windowX=wX;
_windowY=wY;
setPreferredSize(new Dimension(_windowX,_windowY));
}
}
is it possible to simply make 360 degree movement in java(swing) without any game engine? all I have is this attempt:
public class Game extends JPanel implements Runnable {
int x = 300;
int y = 500;
float angle = 30;
Game game;
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.add(new Game());
frame.setSize(600, 600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public Game() {
setSize(600, 600);
Thread thread = new Thread(this);
thread.start();
}
#Override
public void paint(Graphics g) {
g.setColor(Color.WHITE);
g.drawRect(0, 0, 600, 600);
g.setColor(Color.CYAN);
g.fillOval(x, y, 10, 10);
g.dispose();
}
#Override
public void run() {
while(true) {
angle += -0.1;
x += Math.sin(angle);
y--;
repaint();
try {
Thread.sleep(50);
} catch (InterruptedException ex) {}
}
}
}
as you can see in following picture, I don't know how to handle movement rotating, this is the output:
image http://screenshot.cz/GOXE3/mvm.jpg
Actually, this is quite possible.
My preferred way is to actually take advantage of the Graphics transform so that you don't have to do any computation, it's all left to the Graphics
By the way:
since you did not create the Graphics object, don't ever dispose it.
override paintComponent() rather than paint()
It's always a good pattern to call super.paintComponent()
Small demo example:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.RoundRectangle2D;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class TestRotate {
public static class ShapeAndColor {
private final Shape shape;
private final Color color;
public ShapeAndColor(Shape shape, Color color) {
super();
this.shape = shape;
this.color = color;
}
public Shape getShape() {
return shape;
}
public Color getColor() {
return color;
}
}
public static class RotatingShapesPanel extends JComponent {
private List<ShapeAndColor> shapes;
private double rotation = 0.0;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
AffineTransform translate = AffineTransform.getTranslateInstance(-getWidth() / 2, -getHeight() / 2);
AffineTransform rotate = AffineTransform.getRotateInstance(rotation);
AffineTransform t = AffineTransform.getTranslateInstance(getWidth() / 2, getHeight() / 2);
t.concatenate(rotate);
t.concatenate(translate);
g2d.setTransform(t);
AffineTransform scale = AffineTransform.getScaleInstance(getWidth(), getHeight());
for (ShapeAndColor shape : shapes) {
Area area = new Area(shape.getShape());
g2d.setColor(shape.getColor());
area.transform(scale);
g2d.fill(area);
}
}
public void setShapes(List<ShapeAndColor> shapes) {
this.shapes = shapes;
repaint();
}
public double getRotation() {
return rotation;
}
public void setRotation(double rotation) {
this.rotation = rotation;
repaint();
}
}
protected void initUI(final boolean useBorderLayout) {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
List<ShapeAndColor> shapes = new ArrayList<>();
Random r = new Random();
for (int i = 0; i < 10; i++) {
double x = r.nextDouble();
double y = r.nextDouble();
double w = r.nextDouble();
double h = r.nextDouble();
w = Math.min(w, 1 - x) / 2;
h = Math.min(h, 1 - y) / 2;
double a = Math.min(w, h) / 10.0;
RoundRectangle2D.Double shape = new RoundRectangle2D.Double(x, y, w, h, a, a);
Color color = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256));
shapes.add(new ShapeAndColor(shape, color));
}
final RotatingShapesPanel panel = new RotatingShapesPanel();
panel.setShapes(shapes);
frame.add(panel);
frame.setSize(600, 600);
frame.setVisible(true);
Timer t = new Timer(0, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
double rotation = panel.getRotation() + 0.02;
if (rotation > Math.PI * 2) {
rotation -= Math.PI * 2;
}
panel.setRotation(rotation);
}
});
t.setRepeats(true);
t.setDelay(10);
t.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestRotate().initUI(true);
}
});
}
}
Change a few lines...
int basex = 300; // midpoint of the circle
int basey = 400;
int radius = 100; // radius
int x;
int y;
float angle = 0; // Angles in radians, NOT degrees!
public void run() {
while(true) {
angle += 0.01;
x = (int)(basex + radius*Math.cos(angle));
y = (int)(basey - radius*Math.sin(angle));
repaint();
try {
Thread.sleep(50);
} catch (InterruptedException ex) {}
}
}
Not sure what you were trying to code there, but this is the correct formula for a circular movement.
To calculate the rotation around a point, you need a center point for the rotation (cx, cy), the radius or distance of the point from the center, you need the angle (in radians, not degrees), and you need to use sine and cosine to calculate the offset of the point from the center as it rotates around it.
int cx, cy, radius; // I'll let you determine these
double theta = Math.toRadians(30);
double dtheta = Math.toRadians(-0.1);
double dx = Math.cos(theta) * radius;
double dy = Math.sin(theta) * radius;
int x = (int)(cx + dx);
int y = (int)(cy + dy);
repaint();
theta += dtheta; // step the angle
You program has some problems:
int x = 300;
int y = 500;
You should use a floating point data type like double to store the coordinates. You can cast them to int when you want to draw them. If you store them in int, you'll lose precision.
x += Math.sin(angle);
y--;
This doesn't work, since y is decremented instead of calculated using Math.sin(angle). (us Math.cos for x)
This is your fixed code (unchanged parts are omitted):
double x = 300;
double y = 500;
float angle = 30;
double radius = 10D; // new variable to increase the radius of the drawn circle
Game game;
// main method
// constructor
#Override
public void paint(Graphics g) {
// ... stuff omitted
g.fillOval((int)x, (int)y, 10, 10); // you can cast to int here
g.dispose();
}
#Override
public void run() {
while (true) {
angle -= 0.1; // is the same as `angle += -0.1`
x += radius * Math.cos(angle);
y += radius * Math.sin(angle);
repaint();
// ... try catch block
}
}
This currenlty draw the circle counter-clockwise. If you want to draw it clockwise, then change angle to:
angle += 0.1;