Animating Separate Objects

2019-09-07 08:45发布

问题:

I've been working on an "elevator simulator" where I have to animate "elevators". I was able to create different elevator objects, which I did by having each Elevator Object have the parameters of width, height, and coordinates. I then stored them all into an array and used a for loop to draw them into my frame using JPanel's PaintComponent method.

Can you guys suggest a way or give me advice to animate them separately from each other, like say move them up and down independently? I was able to make it move when I only had ONE elevator, but when I tried to apply it to multiple elevators, it did not work.

My previous attempt involved an ActionListener (that listens to a button press to "start" the animation) that simply changes the x and y coordinates of the SINGLE elevator. So How do I go and do that with several elevators (the number of elevators is arbitrary to the user). Do I have to make as many ActionListeners as there are elevators, so it can listen to them independently?

Here's the ActionListener that worked when there's only ONE elevator. It only moves up so far.

  private ActionListener timerActionUp = new ActionListener()
{
    private int iterator = 0;
    private int top = 0;
    public void actionPerformed(ActionEvent e)
    {
      if(top<floorQueue.length){
      if(iterator<floorQueue[top]){ //floorQueue is so that the elevator knows where to stop
        if(movefloorup<VERTICALFLOORDISTANCE*6){ //this is when the elevator reaches the "top" floor that can fit into the screen, and moves to the next column representing the floors further up
            repaint();
            movefloorup = movefloorup + VERTICALFLOORDISTANCE;
            System.out.println(movefloorup);
            iterator++;
        }
        else{
            //timer.stop();
            repaint();
            switchmarker = 1; //makes elevator moves to the next column
            movefloorup = 0;
            iterator++;

        }
      }
      else
      {
          System.out.println("Picking up passengers...");
          elevatorCapacity = elevatorCapacity + peopleQueue[floorQueue[top]];
          System.out.println("Passengers in elevator: "+elevatorCapacity);
          peopleQueue[floorQueue[top]] = 0; //Updates the number of people in the elevator
          top++;
          if(elevatorCapacity >= 5)
          {
              System.out.println("WARNING!  ELEVATOR FULL!");
              elevfull = 1;
          }
          //timer.stop();
      }

      }
      else
      {
          System.out.println("Done picking up passengers.");
          timer.stop();
      }



    }
};

Thank you very much!

回答1:

"Do I have to make as many ActionListeners as there are elevators, so it can listen to them independently?"

No, that would require multiple Timers. Avoid doing this whenever you can.

"Can you guys suggest a way or give me advice to animate them separately from each other, like say move them up and down independently?"

What you should do is try and implement the business logic in methods within your Elevator class and just call the those methods while looping through all the Elevators in your array.

Two make the Elevators to appear to move independently, you can have flags, say in your move method, like

public void move() {
    if (move) {
        // do something
    }
}

What ever is your reason for making the elevator move, that will be the reason the raise the flag. And vice versa. Maybe something like if (onFloor) { elevator.move = false }, maybe for a duration of 20 timer "iterations", and keep a count in the elevator class, that will reset back to 0 when the count hits 20, then move will be back at true.


Here's an example you can play with. I was working on it for about 20 minutes then gave up. The logic is a bit off, but it basically points out the ideas i mentioned. Maybe you'll have better luck with it. You can also see a good working example of moving different object here

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 javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class ElevatorAnimate extends JPanel {

    private static final int D_W = 300;

    private static final int FLOORS = 6;
    private static final int FLOOR_HEIGHT = 100;
    private static final int BUILDING_HEIGHT = FLOORS * FLOOR_HEIGHT;
    private static final int D_H = BUILDING_HEIGHT;
    private static final int BUILDING_BASE = BUILDING_HEIGHT;
    private static final int ELEVATOR_HEIGHT = 60;
    private static final int ELEVATOR_WIDTH = 30;

    private final List<Elevator> elevators;

    public ElevatorAnimate() {
        elevators = createElevators();

        Timer timer = new Timer(50, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                for (Elevator el : elevators) {
                    el.move();
                }
                repaint();
            }
        });
        timer.start();
    }

    private List<Elevator> createElevators() {
        List<Elevator> list = new ArrayList<>();
        list.add(new Elevator(6, 30));
        list.add(new Elevator(4, 90));
        list.add(new Elevator(2, 150));
        return list;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        drawFloors(g);
        for (Elevator el : elevators) {
            el.drawElevator(g);
        }
    }

    private void drawFloors(Graphics g) {
        for (int i = 1; i <= FLOORS; i++) {
            g.drawLine(0, FLOOR_HEIGHT * i, D_W, FLOOR_HEIGHT * i);
        }
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(D_W, D_H);
    }

    public class Elevator {

        int floor, x, y;
        boolean move = false;
        boolean up = true;
        int stopCount = 0;

        public Elevator(int floor, int x) {
            this.floor = floor;
            y = BUILDING_HEIGHT - (floor * FLOOR_HEIGHT);
            this.x = x;
        }

        public void drawElevator(Graphics g) {
            g.fillRect(x, y, ELEVATOR_WIDTH, ELEVATOR_HEIGHT);
        }

        public void move() {
            if (y <= 0) {
                up = false;
            } else if (y >= BUILDING_BASE + ELEVATOR_HEIGHT) {
                up = true;
            }

            if (isOnFloor()) {
                move = false;
            }

            if (move) {
                if (up) {
                    y -= 2;
                } else {
                    y += 2;
                }
            } else {
                if (stopCount >= 20) {
                    move = true;
                    stopCount = 0;
                } else {
                    stopCount++;
                }
            }
        }

        private boolean isOnFloor() {
            return y / FLOOR_HEIGHT == 100;
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new ElevatorAnimate());
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}


回答2:

Starting from this related Subway simulation, the following variation adds two independent panels, each of which contains its own view and control panel.

// Common initialization for either JApplet or JFrame
private static void initContainer(Container container) {
    container.add(createPanel(), BorderLayout.NORTH);
    container.add(createPanel(), BorderLayout.SOUTH);
}

private static JPanel createPanel() {
    JPanel panel = new JPanel(new BorderLayout());
    ButtonPanel control = new ButtonPanel();
    SubwayPanel subway = new SubwayPanel(control);
    panel.add(subway, BorderLayout.NORTH);
    panel.add(control, BorderLayout.SOUTH);
    subway.beginOperation();
    return panel;
}