如何在Java Swing中实现MouseMotionListener让对象列表跟随鼠标?
解决蠕虫身体跟随鼠标时汇聚的问题
嘿,我一眼就看出你代码里的问题了——你的tracker方法更新身体段位置的逻辑完全搞反了,这才导致所有身体段突然挤到同一个点上。咱们一步步来梳理修复方案:
问题根源分析
先看你当前的追踪逻辑:
public void tracker(ArrayList <Worm> TracktheWorm) { for(int i = 0; i < TracktheWorm.size()-1 ; i++) { TracktheWorm.get(i+1).xWorm = TracktheWorm.get(i).xWorm; TracktheWorm.get(i+1).yWorm = TracktheWorm.get(i).yWorm; } repaint(); }
你是从前往后更新位置:把头部的位置直接赋值给第二个身体段,然后第二个的新位置又被传给第三个……循环下来,所有身体段都会在一次迭代里变成头部的位置,自然就全部汇聚了。
正确的身体跟随逻辑
要实现类似火车联动的效果,核心是让每个身体段跟随前一个身体段的上一帧位置,而不是当前帧的新位置。这里有两种靠谱的实现方式:
方式一:给Worm类添加历史位置记录
给蠕虫类新增保存上一帧位置的字段,让身体段始终跟着前一个的“足迹”移动:
public class Worm { Random rd = new Random(); int xWorm; int yWorm; int prevX; // 新增:上一帧的X坐标 int prevY; // 新增:上一帧的Y坐标 int Speed = 100; int size = 10; // 构造函数初始化历史位置 public Worm() { xWorm = rd.nextInt(250); yWorm = rd.nextInt(250); prevX = xWorm; prevY = yWorm; } public Worm(int xNew, int yNew){ xWorm = xNew; yWorm = yNew; prevX = xNew; prevY = yNew; } // 修改move方法,先保存当前位置再移动 public void move (int dx, int dy) { prevX = xWorm; prevY = yWorm; xWorm += dx; yWorm += dy; } // 修改setPosition方法,同步保存历史位置 public void setPosition(int x,int y) { prevX = xWorm; prevY = yWorm; this.xWorm = x; this.yWorm = y; } // 新增历史位置的getter public int getPrevX() { return prevX; } public int getPrevY() { return prevY; } // 其余原有方法(getter、paint、iscollision等)保持不变 }
然后修改tracker方法,让每个身体段移动到前一个的历史位置:
public void tracker(ArrayList<Worm> TracktheWorm) { // 从第二个身体段开始,依次跟随前一个的上一帧位置 for (int i = 1; i < TracktheWorm.size(); i++) { Worm prevWorm = TracktheWorm.get(i-1); TracktheWorm.get(i).setPosition(prevWorm.getPrevX(), prevWorm.getPrevY()); } repaint(); }
方式二:临时保存所有身体段的当前位置
如果不想修改Worm类,可以在追踪时先保存所有身体段的当前位置,再批量更新:
public void tracker(ArrayList<Worm> TracktheWorm) { // 先保存所有身体段的当前位置 List<Point> lastPositions = new ArrayList<>(); for (Worm worm : TracktheWorm) { lastPositions.add(new Point(worm.getxWorm(), worm.getyWorm())); } // 从第二个身体段开始,设置为前一个的历史位置 for (int i = 1; i < TracktheWorm.size(); i++) { Point prevPos = lastPositions.get(i-1); TracktheWorm.get(i).setPosition(prevPos.x, prevPos.y); } repaint(); }
实现MouseMotionListener让头部跟随鼠标
最后,在你的Panel类里实现鼠标监听,让蠕虫头部跟随鼠标移动:
public class WormPanel extends JPanel implements MouseMotionListener { private ArrayList<Worm> wormBody; public WormPanel() { wormBody = new ArrayList<>(); wormBody.add(new Worm()); // 初始化头部 createlongworm(); // 创建身体段 addMouseMotionListener(this); setPreferredSize(new Dimension(500, 500)); } @Override public void mouseMoved(MouseEvent e) { Worm head = wormBody.get(0); // 平滑移动到鼠标位置(除以5控制移动速度,数值越小越平滑) int dx = (e.getX() - head.getxWorm()) / 5; int dy = (e.getY() - head.getyWorm()) / 5; head.move(dx, dy); // 更新身体跟随 tracker(wormBody); } @Override public void mouseDragged(MouseEvent e) { mouseMoved(e); // 拖拽时同样触发跟随逻辑 } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); for (Worm worm : wormBody) { worm.paint(g); } } // 你的createlongworm方法保持不变 public void createlongworm() { for(int i = 0; i < 100 ; i++) { wormBody.add(new Worm(wormBody.get(i).xWorm+10,wormBody.get(i).yWorm)); } } }
总结
核心就是一句话:不要让所有身体段同步复制头部的新位置,要让它们依次跟随前一个的旧位置,这样才能形成连贯的“火车联动”效果。
内容的提问来源于stack exchange,提问作者Türker Berke Yıldırım
相关产品推荐
相关产品推荐

