I want to animate a rectangle in a specific pattern. I was told to use a SwingTimer for animation instead of a Thread.
My plan was to animate a rectangle moving forward until it hits the end of the frame. Then it moves down by one unit(The height of the rectangle, so in my case 30), and then moves backwards; and when it hits the end, there it moves down again and so on.
Now the problem with the SwingTimer is that the whole operation is a continuous loop so the rectangle doesn´t move the way I want it to. In order for this to work, I guess I´ve to start and stop the loop of some methods which is complicated and I don´t know how to do it properly .
So how can I animate the rectangle the way I want it to? Is SwingTimer really the proper way to do such things or are other methods better?
Here´s the code I´ve got so far. I´m aware that it´s not much and that ActionPerformed does a completely different animation.
import javax.swing.JFrame;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class Test extends javax.swing.JPanel implements ActionListener{
private int x = 0;
private int y = 0;
Timer tm = new Timer(50, this);
public Test() {
initComponents();
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(new java.awt.Color(102, 102, 102));
g.fillRect(x, y, 30, 30);
tm.start();
}
public void moveForward() {
x = x + 30;
repaint();
System.out.println("(" + x + "|" + y + ")");
}
public void moveBackwards() {
x = x - 30;
repaint();
System.out.println("(" + x + "|" + y + ")");
}
public void moveDown() {
y = y + 30;
repaint();
System.out.println("(" + x + "|" + y + ")");
}
public void moveUp() {
y = y - 30;
repaint();
System.out.println("(" + x + "|" + y + ")");
}
public void actionPerformed(ActionEvent e) {
moveForward();
if (x >= 270){
moveDown();
}
}
public static void main(String[] args) {
Test t = new Test();
JFrame f = new JFrame();
f.setSize(300, 300);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(t);
f.setVisible(true);
}
What you have done so far looks pretty good. You only need your action method to work properly. For that i would use a class variable called direction:
private boolean direction = true;
Now in your action method you move the rectangle either forward or backwards, depending on direction. And if it hits the end you move the rectangle down and invert direction:
public void actionPerformed(ActionEvent e) {
if (direction){
moveForward();
}
else {
moveBackwards();
}
//Check if it is at the end
if(((x >= 270) && (direction)) || ((x <= 30) && (!direction))) {
moveDown();
direction = !direction;
}
}
The if clause is a little bit complicated, but you can split it up, if you want it to be more readable.
Related
I'm a newbie here. I have a code here from which I would like to change the text of a JLabel to that of the position of a moving - mouse. Here is my code.
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
public class Draw extends JFrame{
int x;
int y;
String positions = "Positions: " + x + ", " + y;
JLabel positionsOnFrame = new JLabel(positions);
public class AL implements MouseMotionListener {
public void mouseMoved(MouseEvent e) {
x = e.getX();
y = e.getY();
}
public void mouseDragged(MouseEvent e) {
positions += " dragged.";
}
}
//Constructor
public Draw() {
setTitle("Title");
setBackground(Color.BLACK);
setSize(300, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
addMouseMotionListener(new AL());
add(positionsOnFrame);
setVisible(true);
}
public static void main(String[] args) {
new Draw();
}
}
Side problem: The JFrame doesn't turn black as well even though I have set the color to be black from the constructor.
Any solution to the mouse problem? Nothing happens! The values are just set to 0! (I haven't initialized them, they're just automatically set to 0!).
Help would definitely be appreciated!
First, uninitialized integers (such as x and y) are given a default value of zero. But it's not good practice to rely on this; best to explicitly initialize their values even if still zero.
Next, your mouseMoved() callback is in-fact getting called. But it's not updating the text of your 'positionsOnFrame' label, it's only updating the x and y coordinates. Just because you created the label with a String (positions), doesn't mean the label's text will automatically change whenever that String is changed. You have to change the text of the label accordingly. So adding positionsOnFrame.setText("Positions: " + x + "," + y); inside your mouseMoved() callback will fix that part.
Finally, change the color of the frame's content pane instead of the frame directly: getContentPane().setBackground(Color.BLACK);
Hope that helps!
This should work
public void mouseMoved(MouseEvent e) {
x = e.getX();
y = e.getY();
positionsOnFrame.setText("Positions: " + x +", " + y);
System.out.println(x);
}
and for the background color this should work.
getContentPane().setBackground(Color.BLACK);
The String positions will not change each time the x and y change. The value will stay with what x and y were when you assigned it originally.
For example
String s = "hello";
String t = s;
System.out.println(t);
s = "bye";
System.out.println(t);
will print hello both times
Exercise1609: Write a program that draws line segments using the arrow keys. The line starts from the center of the frame and draws towards east,north, west, or south when the right-arrow key, up-arrow key, left-arrow key, or down-arrow key is pressed. In short, draw a maze. See comments below for a description of my question.
import java.awt.*;
import java.awt.event.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Exercise1609 extends JFrame {
private KeyboardPanel panel = new KeyboardPanel();
public Exercise1609() {
add(panel);
panel.setFocusable(true);
}
public static void main(String[] args) {
Exercise1609 frame = new Exercise1609();
frame.setTitle("Tegn med piltaster");
frame.setSize(600, 300);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
//The panel that listens for key and responds by drawing
public static class KeyboardPanel extends JPanel {
private int x,y,previousX,previousY;
private boolean firstTime = true;
public KeyboardPanel() {
/**
* why must x and y be initialized inside paintComponent?
* if I want to start drawing from the middle of the panel?
* If I remove the if-block inside paintComponent and instead
* place the initialization here, as shown with the two lines below:
* x = previousX = getWidth() / 2;
* y = previousY = getHeight() / 2;
* ...then the program will not start to draw from the middle,
* but upper left corner of the screen
*/
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
previousY = y;
previousX = x;
switch (e.getKeyCode()) {
case KeyEvent.VK_DOWN:
y++;
break;
case KeyEvent.VK_UP:
y--;
break;
case KeyEvent.VK_RIGHT:
x++;
break;
case KeyEvent.VK_LEFT:
x--;
break;
}
repaint();
}
});
}//end constructor
#Override
protected void paintComponent(Graphics g) {
super.paintComponents(g);
if(firstTime) {
//Why can't x and y be initialized outiside paintComponent?
//Why can't they be initialized inside the constructor of this class?
x = previousX = getWidth() / 2;
y = previousY = getHeight() / 2;
firstTime = false;
}
g.drawLine(previousX, previousY, x, y);
System.out.println(x + " " + y);
}
}
}
The last line System.out.println(x + " " + y); outputs 0,0 if I try to initialize x and y anywhere else
but paintComponent(). When initialized inside paintcomponent() the output is 292,131...which is what I want.
getWidth() and getHeight() are not set correctly until the UI elements have gone through a layout pass. This is guaranteed to happen before paintComponent() is called but probably not at other points where you have tried to call them.
See: getWidth() and getHeight() are 0 after calling setPreferredSize()
If you need to be notified when the width and height of the component is set/changed, check out ComponentListener: http://docs.oracle.com/javase/7/docs/api/java/awt/event/ComponentListener.html
I'm trying to make a game where you are an oval and you have 2 ovals following you. When you press 's' the 2 ovals following you circle around you. The problem is that I can't make the ovals do a 360 turn.
Code:
public class apples extends JFrame {
public static int x, y;
public static int userWIDTH = 15;
public static int userHEIGHT = 15;
public static int defenseWIDTH = 5;
public static int defenseHEIGHT = 5;
public static int defenseX;
public static int defenseY;
private Image dbImage;
private Graphics dbg;
public class AL extends KeyAdapter {
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode == e.VK_LEFT) {
if(!(x < 15)) {
x += -10;
}
}
else if(keyCode == e.VK_RIGHT) {
if(!(x > 810)) {
x += 10;
}
}
else if(keyCode == e.VK_S) {
//Not sure how to make the 2 ovals circle while following the player.
}
}
public void keyReleased(KeyEvent e) {
}
}
public apples() {
super("Dodgem");
setSize(840, 620);
setResizable(true);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addKeyListener(new AL());
x = (this.getWidth() - (userWIDTH + userHEIGHT)) / 2;
y = (this.getHeight() - (userWIDTH + userHEIGHT)) / 2;
}
public void paint(Graphics g) {
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
public void paintComponent(Graphics g) {
g.fillOval(x, y, userWIDTH, userHEIGHT);
defenseX = x;
defenseY = y;
g.fillOval(defenseX - 20, defenseY + 20, defenseWIDTH, defenseHEIGHT);
g.fillOval(defenseX + 20, defenseY - 20, defenseWIDTH, defenseHEIGHT);
repaint();
}
public static void main(String[] args) {
new apples();
}
Also, this is an example if it helps...
The two ovals have to "spin".
Sorry for my ignorance, and in advance, thank you.
In order to make something move in a cricle around a point you need to use the parametric equation for a circle. It is described fully on wikipedia: http://en.wikipedia.org/wiki/Circle
The equation can be written in parametric form using the trigonometric functions sine and cosine as:
x = a + r cos t
y = b + r sin t
where t is a parametric variable in the range 0 to 2π, interpreted geometrically as the angle that the ray from (a, b) to (x, y) makes with the x-axis.
In other words, if your target is at (a,b) then to circle around it with radius r you need to plug those variables into the equations above, with t being the angle between 0 and 2π that you want the chaser to be at.
If you want the chaser to transition between chasing and circling then you will need to determine the starting angle using elementary trigonometry.
I have two rectangles, r1 which is moving, and r2 which is a stationary tile. I need to know what side of r2 (or r1) is hit to determine which direction r1 should go. The collision detection works with the shape.intersects(otherShape), unfortunately this means that r1 will "Sink" a few pixels inside of r2. This is very problematic when dealing with the corners of the rectangles since this will cause two sides of each rectangle to intersect, thus making figuring out what side was hit by checking what side intersects which to be ineffective.
What we know:
Positions and Center positions of r1 and r2
Velocities and speeds of r1 and r2
So given that information, i need an algorithm that is able to get the side of collision.
A square is defined by four corners, the upper-left, upper-right, lower-left, lower-right. If your updates/collisiondetections are fast enough then the following will work. This takes into consideration the event that only one corner collides (if your rectangle rotates or moves in 2D).
import java.awt.Color;
import java.awt.Graphics;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class TestMovingRect extends JComponent {
JFrame frame;
Rectangle2D r1;
Rectangle2D r2;
int speedX, speedY;
int width = 20;
int height = 20;
public static void main(String[] args) {
new TestMovingRect();
}
public TestMovingRect() {
r1 = new Rectangle2D.Double(0, 0, width, height);
r2 = new Rectangle2D.Double(200, 0, width, height);
speedX = 1;
frame = new JFrame();
frame.setSize(500, 500);
frame.add(this);
frame.setVisible(true);
loop();
}
public void tick(){
System.out.println("Old r1: " + r1.getX() + "," + r1.getY());
double x = r1.getX();
double y = r1.getY();
r1.setRect(x + speedX, y + speedY, 10, 10);
System.out.println("New r1: " + r1.getX() + "," + r1.getY());
}
private void loop() {
while (true){
tick();
sleep();
checkIntersect();
frame.validate();
frame.repaint();
}
}
private void checkIntersect() {
Point2D upperLeft = new Point2D.Double(r1.getX(), r1.getY());
Point2D upperRight = new Point2D.Double(r1.getX() + r1.getWidth(),
r1.getY());
Point2D lowerLeft = new Point2D.Double(r1.getX(), r1.getY()
+ r1.getHeight());
Point2D lowerRight = new Point2D.Double(r1.getX() + r1.getWidth(),
r1.getY() + r1.getHeight());
if (r2.contains(upperRight)){
System.out.println("UpperRight hit");
//Do stuff
}
if (r2.contains(lowerRight)) {
System.out.println("lowerRight hit");
// Do stuff
}
if (r2.contains(lowerLeft)) {
System.out.println("LowerLeft hit");
// Do stuff
}
if (r2.contains(upperLeft)) {
System.out.println("UpperLeft hit");
// Do stuff
}
}
private void sleep() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void paintComponent(Graphics g) {
// TODO Auto-generated method stub
super.paintComponents(g);
g.setColor(Color.blue);
g.fillRect((int) r1.getX(), (int) r1.getY(), (int) r1.getWidth(),
(int) r1.getHeight());
g.setColor(Color.red);
g.fillRect((int) r2.getX(), (int) r2.getY(), (int) r2.getWidth(),
(int) r2.getHeight());
}
}
Another (far simpler) way is to interpolate the velocity of the rectangle. If it is moving to the right and it intersects then you know it must have hit the right side. But then if your rectangle is rotating or moving in 2D you will have added complexity and the above code would do just as fine.
Edit: To your comment
if (r2.contains(upperRight)){
if (speedX * speedX > speedY * speedY) {
System.out.println("I hit on the right side");
}
else if (speedY * speedY > speedX * speedX) {
System.out.println("I hit on the topside");
}
else if (speedX * speedX == speedY * speedY) {
System.out
.println("I hit on a 45 degree diagonal, side is ambigious, please decide for me");
}
}
I am somewhat new to java OO. Using the classic procedural aspects of Java are fairly straightforward, includingevent processing and even Swing. But I am having some trouble with objects.I have written a small program in Eclipsethat uses event processing for detecting mouse movement and clicks in an applet viewer. I even draw a face in the viewer on a mouse click. The face draw code is done in a method included in the program, which returns the drawn face as Graphics object 'g' passed as a parameter when calling the the 'drawFace()' method. The 'drawFace()' method returns a Graphics type and program works fine! I then try to make a separate class in Eclipse to create a new 'drawFace' object when there is a mouse click, just like the previous code, and instantiate it via 'new'. The face
is not drawn. I am sure I am not either defining the Face constructor class correctly or invoking it correctly. I am attaching first the working code using a method ('DrawFaceMethod'), and the non-working code using the main code and the second constructor class to draw to face ('DrawFaceObject'). Both codes are fairly short and similar. Any help appreciated.
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class AppletDrawFaceMethod extends Applet implements MouseListener ,
MouseMotionListener{
int mouseX = 0, mouseY = 30; // display area where coordinates of mouse displayed
int width = 0, height = 0; // size of applet viewing area
String msg = "";
boolean mouseclick = false; //need to test for mouse click on TRUE
Font font = new Font("Serif", Font.BOLD, 36);
public void init() {
width = getSize().width; //get applet viewing size
height = getSize().height;
System.out.println("Applet dimensions: " + width + " , " + height);
//addMouseListeners
addMouseListener(this);
addMouseMotionListener(this);
} // end init()
// paint method executed on every event
public void paint(Graphics g) {
//need to associate font with paint method
g.setFont(font);
//test mouseclick and set boolean
if (mouseclick == true){
//calls method 'drawFace', passes mouseclick x,y coordinates
// and Graphics object 'g'
//the 'drawFace' method returns a Graphic object of a face drawn
drawFace(mouseX, mouseY, g);
msg = "Face drawn at mouse click " + mouseX + ", " + mouseY;
//re-initialize variables
mouseclick = false;
mouseX = 0;
mouseY = 30;
} // end of 'if mouseclick == true' face drawing code
g.drawString(msg, mouseX, mouseY);
} // end of paint method
// Following methods are mouse 'Listener' methods to detect mouse events
// Handle mouse moved.
public void mouseMoved(MouseEvent me) {
// show status
msg = "Moving mouse at " + me.getX() + ", " + me.getY();
//showStatus("Moving mouse at " + me.getX() + ", " + me.getY());
repaint();
}
// Handle mouse clicked.
public void mouseClicked(MouseEvent me) {
mouseclick = true; //set boolean 'mouseclick' to TRUE
//save coordinates
mouseX = me.getX();
mouseY = me.getY();
repaint();
}
// Handle mouse entered.
public void mouseEntered(MouseEvent me) {
// save coordinates
//mouseX = 0;
//mouseY = 30;
msg = "Mouse entered.";
repaint();
}
// Handle mouse exited.
public void mouseExited(MouseEvent me) {
// save coordinates
//mouseX = 0;
//mouseY = 30;
msg = "Mouse exited applet viewer.";
repaint();
}
//Other method mouse event methods required even if not used
// Handle button pressed.
public void mousePressed(MouseEvent me) {}
// Handle button released.
public void mouseReleased(MouseEvent me) {}
// Handle mouse dragged.
public void mouseDragged(MouseEvent me) {}
///////////////////////////////////////////////////////////
//
// 'drawFace method' receive a Graphics object parameter g'
// it must return a Graphics object which the method draws
//
///////////////////////////////////////////////////////////
public Graphics drawFace(int xStart,int yStart, Graphics g) {
g.drawOval (mouseX, mouseY, 120, 150); // Head.
g.drawOval ((mouseX + 45), (mouseY + 60), 30, 30); // nose
g.fillArc((mouseX + 20), (mouseY + 85), 80, 40, 180, 180); //mouth.
g.drawOval ((mouseX + 17),(mouseY + 35), 30, 20); //Left eye.
g.drawOval ((mouseX + 70),(mouseY + 35), 30, 20); //Right eye.
g.fillOval ((mouseX + 28), (mouseY + 41), 10, 10); //Left pupil.
g.fillOval ((mouseX + 81), (mouseY + 41), 10, 10); //Right pupil.
g.drawOval ((mouseX - 15), (mouseY + 52), 15, 30); //Left ear.
g.drawOval ((mouseX + 120), (mouseY + 52), 15, 30); //Right ear.
g.drawArc ((mouseX + 15), (mouseY + 25),35,15,0,180);//Left brow.
g.drawArc ((mouseX + 67), (mouseY + 25), 35, 15, 0, 180);//Right.
return g; //returns pointer to drawn graphics face
} //end of drawFace method
} // End of class
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
//
// 'drawFaceObject' Applet code , followed by 'drawFace' constructor class
//
//
//////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class DrawFaceObject extends Applet implements MouseListener ,
MouseMotionListener{
int mouseX = 0, mouseY = 30; // display mouse coordinates
int width = 0, height = 0; // size of applet viewing area
String msg = "";
boolean mouseclick = false; //need to test for mouse click on TRUE
Font font = new Font("Serif", Font.BOLD, 36);
public void init() {
width = getSize().width; //get applet viewing size
height = getSize().height;
System.out.println("Applet dimensions: " + width + " , " + height);
//addMouseListeners
addMouseListener(this);
addMouseMotionListener(this);
} // end init()
// paint method executed on every event
public void paint(Graphics g) {
//need to associate font with paint method
g.setFont(font);
//test mouseclick and set boolean
if (mouseclick == true){
//creates object'drawFace', passes mouseclick x,y coordinates
// and Graphics object 'g'
Class_DrawFace face = new Class_DrawFace(g);
msg = "Face drawn at mouse click " + mouseX + ", " + mouseY;
//re-initialize variables
mouseclick = false;
mouseX = 0;
mouseY = 30;
} // end of 'if mouseclick == true' face drawing code
g.drawString(msg, mouseX, mouseY);
} // end of paint method
// Following are mouse 'Listener' methods to detect mouse events
// Handle mouse moved.
public void mouseMoved(MouseEvent me) {
// show status
msg = "Moving mouse at " + me.getX() + ", " + me.getY();
//showStatus("Moving mouse at " + me.getX() + ", " + me.getY());
repaint();
}
// Handle mouse clicked.
public void mouseClicked(MouseEvent me) {
mouseclick = true; //set boolean 'mouseclick' to TRUE
//save coordinates
mouseX = me.getX();
mouseY = me.getY();
repaint();
}
// Handle mouse entered.
public void mouseEntered(MouseEvent me) {
// save coordinates
//mouseX = 0;
//mouseY = 30;
msg = "Mouse entered.";
repaint();
}
// Handle mouse exited.
public void mouseExited(MouseEvent me) {
// save coordinates
//mouseX = 0;
//mouseY = 30;
msg = "Mouse exited applet viewer.";
repaint();
}
//Other method mouse event methods required even if not used
// Handle button pressed.
public void mousePressed(MouseEvent me) {}
// Handle button released.
public void mouseReleased(MouseEvent me) {}
// Handle mouse dragged.
public void mouseDragged(MouseEvent me) {}
} // End of class
/////////////////////////////////////////////////////////////
//
// 'drawFace' Constructor
////////////////////////////////////////////////////////////
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class Class_DrawFace extends Applet{
//instance variables
public Graphics g;
public int x, y;
Class_DrawFace(Graphics g) {
int x = 0;
int y = 0;
}
Class_DrawFace(int mouseX, int mouseY, Graphics g) {
int x = mouseX;
int y = mouseY;
}
public Graphics drawFace(int x, int y, Graphics g) {
g.drawOval (x, y, 120, 150); // Head.
g.drawOval ((x + 45), (y + 60), 30, 30); // nose
g.fillArc ((x + 20), (y + 85),80,40,180, 180);//mouth.
g.drawOval ((x + 17),(y + 35), 30, 20);//Left eye.
g.drawOval ((x + 70),(y + 35), 30, 20);//Right eye.
g.fillOval ((x + 28), (y + 41),10,10);//Left pupil.
g.fillOval ((x + 81), (y + 41),10,10);//Right pupil.
g.drawOval ((x - 15), (y + 52), 15, 30);//Left ear.
g.drawOval ((x + 120), (y + 52), 15, 30);//Right ear.
g.drawArc ((x + 15), (y + 25),35,15,0,180);//Left eyebrow.
g.drawArc ((x + 67), (y + 25),35,15,0,180);//Right eyebrow.
return g; //return drawnFace Graphics object
} //end of drawFace class constructor
}//end of class