如何在不移动其他子类的情况下 move/animate 跨屏幕的单个子类对象?

How to move/animate a single subclass object across the screen without moving the other subclasses?

对于我在 Java 中的最后一个作业,我必须对一些 'monsters' 进行建模并使其中一个在屏幕上移动。为此,我需要使用已经实现的计时器,(timer = new Timer (50, monsterPanel) 使子类 'MovingMonster'(父类 'Monster')的 X 坐标移动到屏幕右侧。同时其他子类,只有“SeeingMonster" 现在,不要在屏幕上移动。

我的猜测是必须更改 MovingMonster 的 void draw(Graphics g) 方法中的 x 坐标,但我不确定如何将其 link 更改为 public void actionPerformed (ActionEvent e)class MonsterPanel 中,如果它甚至应该在同一个侦听器中。

如有任何帮助,我们将不胜感激。以下是该项目的完整代码,可在任何 IDE.

中运行
import java.util.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.Timer;
import java.awt.event.*;

class MonsterMania {
    MonsterPanel monsterPanel = new MonsterPanel();
    Timer timer;

    void createGUI() {
        // create the GUI on the event thread.
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                final JFrame frame = new JFrame("Monster Mania");
                frame.add(monsterPanel, BorderLayout.CENTER);
                frame.setSize( 600, 400 );
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);

                monsterPanel.setBackground( Color.DARK_GRAY );
                monsterPanel.addMonsters();

                timer = new Timer( 50, monsterPanel);
                timer.start();
            }
        });
    }

    public static void main( String[] a ) {
        new MonsterMania().createGUI();
    }
}

class MonsterPanel extends JPanel implements ActionListener {
    ArrayList<Monster> monsters = new ArrayList<Monster>();  // the list of monsters on the screen

    void addMonsters() {
        monsters.add( new Monster( 50, 40 ));
        monsters.add( new Monster (150, 200 ));
        monsters.add( new Monster (300, 300 ));
        monsters.add (new SeeingMonster (150, 50, Color.GREEN));
        monsters.add (new MovingMonster (400, 150));
    }

    public void paintComponent( Graphics g ) {
        super.paintComponent( g );
        for (Monster monster : monsters) {
            monster.draw( g );
        }
    }

    public void actionPerformed( ActionEvent e ) {
        for (Monster monster : monsters) {
            monster.step( this );
        }

        repaint();
    }  
}

class Monster {
    int size = 50;
    int arcSize = 10;  // size of arc that defines roundedness of rounded rectangle
    int locx = 0; // x coordinate center (pixel coordinates)
    int locy = 0; // y coordinate center (pixel coordinates)
    Color fill = Color.YELLOW;  // inner color
    Color line = Color.BLACK;   // color of border
    int phase = 0; // phase in the animation, a counter of time steps

    Monster( int x, int y ) {
        locx = x;
        locy = y;
    }

    // update the monster because a time step has passed
    // the parameter monsterPanel can be used for getting information about the panel, e.g., the size
    void step( MonsterPanel monsterPanel ) {
        phase++;
    }

    void draw( Graphics g ) {
        // draw body
        g.setColor( fill );
        g.fillRoundRect( locx - size/2, locy - size/2, size, size, arcSize, arcSize );
        g.setColor( line );
        g.drawRoundRect( locx - size/2, locy -size/2, size, size, arcSize, arcSize );
        // draw mouth
        // every 5 time steps, mouth is changed
        if ( phase % 20 < 10 ) {
            int s = size/5; // size of closed mouth
            g.drawOval( locx - s/2, locy + size/6, s, s );
        } else {
            int s = size/3; // size of open mouth
            g.fillOval( locx - s/2, locy + size/6, size/3, size/3 );
        }
    }
}

class SeeingMonster extends Monster{
  Color eyecolor;


  public SeeingMonster ( int x, int y , Color color){
    super( x, y);
    locx = x;
    locy = y;
    eyecolor = color;
  }

  void draw( Graphics g ) {
    super.draw(g);
    int s = size/7;
    g.setColor(eyecolor);
    g.fillOval ( locx + 10, locy - 15 , size/5, size/5 );
    g.fillOval ( locx + -15 , locy - 15 , size/5, size/5 );
}
}

class MovingMonster extends Monster{


  MovingMonster( int x, int y){
    super(x,y);
    locx = x;
    locy = y;
  }
  public int getLocationX() {
    return locx;
  }




  void draw (Graphics g ) {
    super.draw(g);




  }
}

另一种方法是覆盖 SeeingMonster class 中的 step 方法,让它什么都不做。

class SeeingMonster {
    @Override
    void step( MonsterPanel monsterPanel ) {}
}

一个更好的方法是使用方法 step.

创建接口 Movable
public interface Movable {
    void step(MonsterPanel monsterPanel);
}

现在您可以将此接口实现到 MovingMonster class 中,您现在可以在其中实现此方法。

class MovingMonster extends Monster implements Movable {
    @Override
    void step( MonsterPanel monsterPanel ) {
        ++phase;
    }
}

现在您可以单独为 Movable

的实例保留 List
List<Movable> monsters = new ArrayList<Movable>();

您可以创建一个单独的函数来获取一个 Monster 作为参数,如果该 Monster 确实实现了该接口,那么您可以将这个 Monster 添加到您单独的 List.

private List<Movable> movables = new ArrayList<Movable>();
private List<Monster> monsters = new ArrayList<Monster>();
private void add(Monster monster) {
    monsters.add(monster);
    if (monster instanceof Movable) {
        movables.add((Movable)monster);
    }
}

现在你可以让你的 addMonster 方法看起来像这样。

void addMonsters() {
    add( new Monster( 50, 40 ));
    add( new Monster (150, 200 ));
    add( new Monster (300, 300 ));
    add (new SeeingMonster (150, 50, Color.GREEN));
    add (new MovingMonster (400, 150));
}

最后,您的 actionsPerformed 方法将只能循环遍历 Movable 个实例,这些实例实际上 Monster 可以移动。

public void actionPerformed( ActionEvent e ) {
    for (Movable movable : movables) {
        movable.step(this);
    }
    repaint();
}