Moving objects and timers
"I want the object to randomly pop up from the bottom of the screen reach a certain ascent and then fall back down"
See the runnable example below. What I do is pass a radomDelayedStart
to the Shape
. Every tick of the timer, the randomDelayedStart
decreases til it reaches 0, that's when the flag to be drawn in raised. Most of the logic is in the Shape
class methods, which are called in the Timer
s Actionlistener
. Everything is done in one Timer
. For the ascent, I just used a hard coded 50, but you can also pass a random ascent to the Shape
. Let me know if you have any questions. I tried to made the code as clear as possible.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class RandomShape extends JPanel {
private static final int D_HEIGHT = 500;
private static final int D_WIDTH = 400;
private static final int INCREMENT = 8;
private List<Shape> shapes;
private List<Color> colors;
private Timer timer = null;
public RandomShape() {
colors = createColorList();
shapes = createShapeList();
timer = new Timer(30, new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (Shape shape : shapes) {
shape.move();
shape.decreaseDelay();
repaint();
}
}
});
JButton start = new JButton("Start");
start.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
timer.start();
}
});
JButton reset = new JButton("Reset");
reset.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
shapes = createShapeList();
timer.restart();
}
});
JPanel panel = new JPanel();
panel.add(start);
panel.add(reset);
setLayout(new BorderLayout());
add(panel, BorderLayout.PAGE_START);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Shape shape : shapes) {
shape.drawShape(g);
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(D_WIDTH, D_HEIGHT);
}
private List<Color> createColorList() {
List<Color> list = new ArrayList<>();
list.add(Color.BLUE);
list.add(Color.GREEN);
list.add(Color.ORANGE);
list.add(Color.MAGENTA);
list.add(Color.CYAN);
list.add(Color.PINK);
return list;
}
private List<Shape> createShapeList() {
List<Shape> list = new ArrayList<>();
Random random = new Random();
for (int i = 0; i < 20; i++) {
int randXLoc = random.nextInt(D_WIDTH);
int randomDelayedStart = random.nextInt(100);
int colorIndex = random.nextInt(colors.size());
Color color = colors.get(colorIndex);
list.add(new Shape(randXLoc, randomDelayedStart, color));
}
return list;
}
class Shape {
int randXLoc;
int y = D_HEIGHT;
int randomDelayedStart;
boolean draw = false;
boolean down = false;
Color color;
public Shape(int randXLoc, int randomDelayedStart, Color color) {
this.randXLoc = randXLoc;
this.randomDelayedStart = randomDelayedStart;
this.color = color;
}
public void drawShape(Graphics g) {
if (draw) {
g.setColor(color);
g.fillOval(randXLoc, y, 30, 30);
}
}
public void move() {
if (draw) {
if (y <= 50) {
down = true;
}
if (down) {
y += INCREMENT;
} else {
y -= INCREMENT;
}
}
}
public void decreaseDelay() {
if (randomDelayedStart <= 0) {
draw = true;
} else {
randomDelayedStart -= 1;
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.add(new RandomShape());
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
When is a timer needed for moving objects in GUI?
As long as you're only
- directly reacting to one event
- and only update the display once
... it's completely OK to do that without timers.
The cases where you can/should use timers is
- if you have an ongoing animation
- if you're not directly reacting to a UI event, but call that "changes" from another thread.
Why use timers then?
- Swing (that you're using) is not thread safe, so changing some UI elements from a Thread other than the EDT (Event Dispatch Thread) might bring disorder and chaos (really strange behaviour) into your UI.
- If you have ongoing animations - which usually require a loop of some kind - an do all that inside the EDT, the UI will NOT be able to react to any input or even update itself properly.
So you use a timer which automatically:
- runs in its own thread, so UI does not block
- and calls the EDT for updates to the UI to keep things thread safe and clean
How do I move an object using a timer and the key press event (Like snake)
1: You are creating variable 'x' every time means locally in player_keyDown event so create it globally.
2: you are using while loop it, not needed as you are already using timer_tick.
3: Instead of Top, Left use Location property of button it gives you X, Y co-ordinate
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
timer1.Interval = 1000;
timer1.Start();
}
string x = "right";
private void Player_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.W)
{
x = "up";
}
else if (e.KeyCode == Keys.S)
{
x = "down";
}
else if (e.KeyCode == Keys.D)
{
x = "right";
}
else if (e.KeyCode == Keys.A)
{
x = "left";
}
}
private void timer1_Tick(object sender, EventArgs e)
{
if (x == "up")
{
Player.Location = new System.Drawing.Point(Player.Location.X, Player.Location.Y - 10);
}
if (x == "down")
{
Player.Location = new System.Drawing.Point(Player.Location.X, Player.Location.Y + 10);
}
if (x == "right")
{
Player.Location = new System.Drawing.Point(Player.Location.X + 10, Player.Location.Y);
}
if (x == "left")
{
Player.Location = new System.Drawing.Point(Player.Location.X - 10, Player.Location.Y);
}
}
}
C# timers for moving objects
Remove While loop from timer1_Tick method.
This method runs every 400 ms, but in your case at first launch it waits until one dog wins.
Also you should stop the timer after one of dogs win.
private void timer1_Tick(object sender, EventArgs e)
{
for (i = 0; i < Dogs.Length; i++) // there are four dogs
{
if (Dogs[i].Run()) // Run() returns true if full racetrack is covered by this dog
{
Winner = i + 1;
isWon = true;
timer1.Stop();
MessageBox.Show("We have a winner! Dog #" + Winner);
break;
}
}
}
Moving Object along a path: How to call actionPerformed only after previous actionPerformed has finished?
for (int i = controller.getPath().size()-1; i >= 0; i--){
Square target = controller.getPath().get(i);
canvas.startTimer(moving, target);
}
In your code above you iterate through the loop setting the Square position. The square position is set to the end before the Timer even has a chance to fire, so you only ever see the square painted in the last position.
When you use a Timer you don't need to use a loop. The Timer replaces the loop. You simply start the Timer. Then when the Timer fires you do something.
So, your logic would be something like:
- Add the Square objects to the ArrayList
- Start the Timer
- When the ActionListener is invoked you a) get the first Square from the ArrayList b) move the object to the square c) remove the Square from the ArrayList
- When the ArrayList is empty you stop the Timer.
Moving an array of shape object using timer and a start button - Java
You have a number of problems...
First, you use your ButtonListener
with your javax.swing.Timer
, but in the listener, you do nothing to actually update the position of the buttons when the timer ticks. So instead of...
timer = new Timer(DELAY, buttonListener);
You should be doing something more like...
timer = new Timer(DELAY, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
for (Shape shape : shapes) {
shape.move();
}
}
});
Second, you don't actually register the ButtonListener
with the start
or stop
buttons, for example...
start.addActionListener(buttonListener);
stop.addActionListener(buttonListener);
Thirdly, you are calling repaint
within the paintComponent
method, this is a very bad idea, painting should paint the current state and should do nothing that might otherwise cause a repaint of any kind to trigger, otherwise you will end up in an infinite loop, which consume your CPU until nothing will run...
Take a look at How to use Swing Timers for more details
Related Topics
How to Troubleshoot "Inconsistency Detected: Dl-Lookup.C: 111" (Java Result 127) Error
Aes Java Encoding, Ruby Decoding
Convert Existing Eclipse Project to Maven Project
Executing a Java Application in a Separate Process
Java Datetimeformatterbuilder Fails on Testtime
Loading a Properties File from Java Package
Wrong Ordering in Generated Table in JPA
How to Flatten a Struct in a Spark Dataframe
The Issue of * in Command Line Argument
How to View Visual Gc in Visualvm
Access Restriction: the Type 'Application' Is Not API (Restriction on Required Library Rt.Jar)
Calling One Jframe from Another Using Timer Without Any Buttons
Singleton Design Pattern VS Singleton Beans in Spring Container