Слушатель движения мыши только в одном направлении

Я работал над обработчиком движений мыши в Java, но не смог разобраться в этом полностью, потому что я хочу, чтобы объект двигался в направлении, куда когда-либо на экране была указана мышь, но, к сожалению, когда мышь находится внутри окна апплета, объект движется только в одном направлении. Вот мой код ниже..

import java.awt.*;
import java.awt.geom.*;
import java.util.*;
import java.applet.*;
import java.awt.event.*;
import javax.swing.*;

public class MouseOver extends Applet implements KeyListener, MouseListener,
      MouseMotionListener {
   private int[] Xpoints = { 0, -5, 5 };
   private int[] Ypoints = { -10, -2, -2 };
   private double xpos, ypos;
   private Polygon poly;
   int polyrot = 0;
   private int width; // !! added
   private int height; // !! added

   public void init() {
      poly = new Polygon(Xpoints, Ypoints, Xpoints.length);
      addKeyListener(this);
      addMouseListener(this);
      addMouseMotionListener(this);
   }

   public void paint(Graphics g) {
      Graphics2D g2d = (Graphics2D) g;
      AffineTransform id = new AffineTransform();
      width = getSize().width;
      height = getSize().height;
      g2d.setColor(Color.BLACK);
      g2d.fillRect(0, 0, width, height);
      g2d.setColor(Color.RED);
      g2d.draw(poly);
      g2d.translate(width / 2, height / 2);
      g2d.rotate(Math.toRadians(polyrot));
      g2d.scale(5, 5);
   }

   public void keyReleased(KeyEvent k) {
   }

   public void keyTyped(KeyEvent k) {
   }

   public void keyPressed(KeyEvent k) {
      switch (k.getKeyCode()) {
      case KeyEvent.VK_LEFT:
         if (polyrot < 0) {
            polyrot = 359;
            polyrot++;
         }
         repaint();
         break;
      case KeyEvent.VK_RIGHT:
         if (polyrot > 360) {
            polyrot = 0;
            polyrot--;
         }
         repaint();
         break;
      }
   }

   public void mouseEntered(MouseEvent m) {
   }

   public void mouseExited(MouseEvent m) {
   }

   public void mouseReleased(MouseEvent m) {
   }

   public void mouseClicked(MouseEvent m) {
   }

   public void mousePressed(MouseEvent m) {
      switch (m.getButton()) {
      case MouseEvent.BUTTON1:
         if (polyrot < 0) {
            polyrot = 359;
            polyrot--;
         }
         repaint();
         break;
      case MouseEvent.BUTTON2:
         if (polyrot > 360) {
            polyrot = 0;
            polyrot++;
         }
         repaint();
         break;
      }
   }

   public void mouseMoved(MouseEvent e) {
      xpos = getX();
      if (xpos < 0) {
         polyrot--;
      } else if (xpos > 0) {
         polyrot++;
      }
      repaint();
      // !! break; // Doesn't belong here
   }

   @Override
   public void mouseDragged(MouseEvent e) {
      // You forgot this method
   }
}

4 ответа

Ваша проблема с этой строкой:

public void mouseMoved(MouseEvent e){
 xpos=getX(); // ******
 if(xpos<0){polyrot--;}
 else if(xpos>0){polyrot++;}
 repaint();
 break;
}

Это возвращает позицию апплета x, а не курсор мыши. Вам нужно использовать объект MouseEvent, e и вместо этого получить позицию мыши. Измените это на:

xpos = e.getX();

Пожалуйста, не игнорируйте мой комментарий к вашему вопросу. Пожалуйста, помните, что мы добровольцы, которые помогают в наше свободное время. Пожалуйста, не усложняйте, чем помогать вам.


Я пытался отредактировать ваш код так, чтобы он компилировался, и теперь с отступом. Подумайте о создании приложения Swing, а не приложения AWT, поскольку приложения Swing более гибкие, мощные и надежные.

Есть несколько вещей...

В вашем keyPressed а также mousePressed события, которые только когда-либо обрабатывают вне пределов условий, например...

if (polyrot < 0) {
    polyrot = 359;
    polyrot++;
}
//...
if (polyrot > 360) {
    polyrot = 0;
    polyrot--;
}

Но вы никогда не обрабатываете то, что должно делать, когда оно находится в допустимых пределах (0-359)...

Вместо этого вы можете просто добавить или вычесть сумму из polyrot и позволить API справиться с этим (к удивлению, он способен работать с углами < 0 и> 359), например...

public void mousePressed(MouseEvent m) {
    switch (m.getButton()) {
        case MouseEvent.BUTTON1:
            polyrot--;
            repaint();
            break;
        case MouseEvent.BUTTON2:
            polyrot++;
            repaint();
            break;
    }
}

Теперь, я не уверен, что вы подразумеваете под "объектом для перемещения в направлении, где когда-либо на экране указана мышь". Означает ли это, что объект должен фактически изменить свои координаты x/y или он должен просто "смотреть" на курсор мыши...

Исходя из того факта, что у вас фактически нет кода движения, и вы в основном закрашиваете объект в фиксированном месте, я предполагаю "посмотреть"...

По сути, вам нужно знать, где находится мышь и где находится объект, а затем определить угол между ними...

public void mouseMoved(MouseEvent e) {
    int x = width / 2;
    int y = height / 2;

    Point mousePoint = e.getPoint();

    int deltaX = mousePoint.x - x;
    int deltaY = mousePoint.y - y;

    polyrot = -Math.atan2(deltaX, deltaY);
    polyrot = Math.toDegrees(polyrot) + 180;

    repaint();
}

Вы должны заметить, что я изменил 'polyrot' на 'double'

Ваш paint Метод тоже неверен. По сути, вы рисуете свой объект, прежде чем вы изменили его, вместо этого вы должны использовать что-то более похожее на...

g2d.translate(width / 2, height / 2);
g2d.rotate(Math.toRadians(polyrot));
g2d.draw(poly);

Вы также должны звонить super.paint(g) прежде чем применить свою собственную картину...

Как примечание стороны, вы должны избегать переопределения paint контейнеров верхнего уровня, таких как JApplet, но вместо этого создайте пользовательский компонент, расширяющийся от чего-то вроде JPanel и переопределить это paintComponent метод, выполняя вашу собственную картину там (не забудьте позвонить super.paintComponent). Посмотрите на Выполнение Custom Painting для более подробной информации

Вы также должны избегать использования KeyListener и вместо этого используйте API связывания ключей, поскольку он не страдает от тех же проблем фокуса, которые KeyListener делает...

Обновлен на работающем примере

Итак, я поиграл с кодом и создал этот простой пример...

введите описание изображения здесь

В основном я выбросил Polygon в пользу Path2Dв основном потому, что он обеспечивает гораздо большую функциональность и с ним легко иметь дело при масштабировании;)

import java.applet.Applet;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;

public class MouseOver extends Applet implements KeyListener, MouseListener,
                MouseMotionListener {

    private double xpos, ypos;
    private Path2D poly;
    private double polyrot = 0;
    private int width; // !! added
    private int height; // !! added

    public void init() {
        poly = new Path2D.Double();
        poly.moveTo(0, 10);
        poly.lineTo(5, 0);
        poly.lineTo(10, 10);
        poly.lineTo(0, 10);
        poly.closePath();
        addKeyListener(this);
        addMouseListener(this);
        addMouseMotionListener(this);
    }

    public void paint(Graphics g) {
        super.paint(g);;

        Graphics2D g2d = (Graphics2D) g;
        AffineTransform id = new AffineTransform();
        width = getSize().width;
        height = getSize().height;
        g2d.setColor(Color.BLACK);
        g2d.fillRect(0, 0, width, height);
        g2d.setColor(Color.RED);

        id.scale(5, 5);
        Shape scaled = poly.createTransformedShape(id);

        Rectangle bounds = scaled.getBounds();        
        g2d.translate((width - bounds.width) / 2, (height - bounds.height) / 2);
        g2d.rotate(Math.toRadians(polyrot), bounds.width / 2, bounds.height / 2);

        g2d.setStroke(new BasicStroke(5f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));

        g2d.draw(scaled);
    }

    public void keyReleased(KeyEvent k) {
    }

    public void keyTyped(KeyEvent k) {
    }

    public void keyPressed(KeyEvent k) {
        switch (k.getKeyCode()) {
            case KeyEvent.VK_LEFT:
                polyrot++;
                repaint();
                break;
            case KeyEvent.VK_RIGHT:
                polyrot--;
                repaint();
                break;
        }
    }

    public void mouseEntered(MouseEvent m) {
    }

    public void mouseExited(MouseEvent m) {
    }

    public void mouseReleased(MouseEvent m) {
    }

    public void mouseClicked(MouseEvent m) {
    }

    public void mousePressed(MouseEvent m) {
        switch (m.getButton()) {
            case MouseEvent.BUTTON1:
                polyrot--;
                repaint();
                break;
            case MouseEvent.BUTTON2:
                polyrot++;
                repaint();
                break;
        }
    }

    public void mouseMoved(MouseEvent e) {
        int x = width / 2;
        int y = height / 2;

        Point mousePoint = e.getPoint();

        int deltaX = mousePoint.x - x;
        int deltaY = mousePoint.y - y;

        polyrot = -Math.atan2(deltaX, deltaY);
        polyrot = Math.toDegrees(polyrot) + 180;

        repaint();
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        // You forgot this method
    }
}

Это:

  if (xpos < 0) {

означает "если курсор находится за пределами панели".

Это:

  xpos = getX();

не получает координаты мыши.

Измените ваше событие на что-то вроде этого:

public void mouseMoved(MouseEvent e) {
    xpos = e.getX();
    if (xpos < getWidth() / 2) {
        polyrot--;
    } else {
        polyrot++;
    }
    repaint();
}

Теперь он вращается против часовой стрелки, если курсор находится на левой стороне панели, и по часовой стрелке, если курсор находится на правой стороне.

Это:

  g2d.draw(poly);
  g2d.translate(width / 2, height / 2);
  g2d.rotate(Math.toRadians(polyrot));
  g2d.scale(5, 5);

не будет ничего делать, чтобы изменить изображение, потому что вы делаете свое преобразование после его рисования.

Это:

  Graphics2D g2d = (Graphics2D) g;

это плохая идея, потому что вы применяете преобразования к глобальному графическому контексту, который будет применяться к последующим перерисовкам других компонентов.

Измените свою краску на что-то вроде этого:

public void paint(Graphics g) {
    super.paint(g);
    Graphics2D g2d = (Graphics2D) g.create();
    width = getSize().width;
    height = getSize().height;
    g2d.setColor(Color.BLACK);
    g2d.fillRect(0, 0, width, height);
    g2d.translate(width / 2, height / 2);
    g2d.rotate(Math.toRadians(polyrot));
    g2d.scale(5, 5);
    g2d.setColor(Color.RED);
    g2d.draw(poly);
    g2d.dispose();
}

Дальнейшее чтение:

Отсюда:

public void mouseMoved(MouseEvent e){
 xpos=getX();
 if(xpos<0){polyrot--;}
 else if(xpos>0){polyrot++;}
 repaint();
 break;
}

Кажется, вы обновляете только xpos. Вам следует также обновить переменную ypos. Возможно, вы захотите сделать это с чем-то вроде этого:

ypos=e.getY();
if (this.ypos<0){
 this.polyrot--;
}else if (this.ypos>0) {
 this.polyrot++;
}
this.repaint();
Другие вопросы по тегам