简体   繁体   English

以固定速度将方块从起点移动到鼠标单击的位置

[英]Moving a square from a starting point to the position of a mouse click at a fixed speed

I'm trying to move a square from it's original position to the coordinates of my mouse when I click.当我点击时,我试图将一个正方形从它的原始位置移动到我的鼠标坐标。 The code I have somewhat works, but the square does not go directly to the mouse click.我的代码有些工作,但方块不会直接点击鼠标。 It goes diagonally a bit off, then it goes to the mouse click, as shown in the picture.它稍微倾斜一点,然后转到鼠标单击,如图所示。 I tried to make it a straight movement path but I could not think of a way to do so.我试图使它成为一条直线运动路径,但我想不出这样做的方法。 I'm pretty sure the error is something to do with the 1st method below.我很确定该错误与下面的第一种方法有关。

           ________X ← the mouse click
          /        
         /   ↑
        / ←  = movement path
       /
      /
_____/
|   | ← character
|___|

Here are the 3 methods involved so far (pls dont criticize my code too much)以下是目前涉及的 3 种方法(请不要过多批评我的代码)

 //int x and int y are the positions of the mouse, champion = the character

public static Champion calculateChampionMovement(int x, int y, Champion champion) {

    if (x != champion.x || y != champion.y) {

         //x and y dist = the distance between the character and the cursor
        int xDist = x - champion.x;
        int yDist = y - champion.y;

         //the angle
        plrAngle = Math.atan2(yDist, xDist) * 180 / Math.PI;

         //the speed of the character on the x and y axis
         //(character diagonally moves at the speed of "champion.speed")
        plrXSpeed = champion.speed * Math.cos(plrAngle * Math.PI / 180);
        plrYSpeed = champion.speed * Math.sin(plrAngle * Math.PI / 180);

         //calls the method below that actually moves the character
        playerMain.champion = (Champion) Entity.moveChampions(x, y, champion, champion.speed, plrXSpeed, plrYSpeed);

        champion.moving = true;
    }
    return playerMain.champion;
}

And the 2nd one...还有第二个……

 //called by the method above
public static Entity moveChampions(int x, int y, Champion champion, float speed, double xSpeed, double ySpeed) {

     //if the distance between the character on the x and y axis is not
     //exactly divisible by "speed", then this helps the character stop.
    if (Math.abs(x - champion.x) <= speed) {
        champion.x = x;
    }
    if (Math.abs(y - champion.y) <= speed) {
        champion.y = y;
    }
     //stops the character
    if (x == champion.x && y == champion.y) {
        champion.moving = false;
    }
     //moves the character
    if (champion.moving) {
        champion.x += xSpeed;
        champion.y += ySpeed;
    }
    return champion;
}

The last method calls "calculateChampionMovement" and "moveChampions", and it moves the character while "moving" is true最后一个方法调用“calculateChampionMovement”和“moveChampions”,当“moving”为真时它移动角色

public static void buttonTest() {
    if (RIGHTCLICK == true) {

         //mouse x and y positions
        cursorClickX = (int) (mapX + MOUSE_X);
        cursorClickY = (int) (mapY + MOUSE_Y);

         //first method (setup the x and y speed)
        playerMain.champion = PlayerMain.testMainChampionMove(cursorClickX, cursorClickY, playerMain.champion);

     // if character is already moving
    } else if (playerMain.champion.moving == true) {
         //move the character
        playerMain.champion = (Champion) Entity.moveChampions(cursorClickX, cursorClickY, playerMain.champion, champAsdf.speed, plrXSpeed, plrYSpeed);
    }
}

hi riot games pls dont sue me im too young anyways嗨,防暴游戏请不要告我我太年轻了

When faced with a problem, I tend to go back to basics, what do I know how to do?当遇到问题时,我倾向于回归基础,我知道该怎么做?

I know I can:我知道我可以:

  • Calculate the distance between two points计算两点之间的距离
  • Move an object a long a line over a given duration.在给定的持续时间内将对象移动很长的一行。

So we know:所以我们知道:

  • Start point起点
  • End point终点

From this we can calculate the distance between the two points.由此我们可以计算出两点之间的距离。

double distance = Math.sqrt(
                    (startX - targetX) * (startX - targetX)
                    + (startY - targetY) * (startY - targetY));

With this, we can calculate the time needed to travel between the two points based on the desired speed有了这个,我们可以根据所需的速度计算在两点之间行驶所需的时间

time = distance / speed

where speed is a constant ( 0.1 in my example, make it smaller to make it slower)其中speed是一个常数(在我的例子中0.1 ,让它变小使其变慢)

With this information, we know how long we must travel for and we can calculate the progress along the line/path based on the difference between when we started (when the mouse was clicked) and now.有了这些信息,我们就知道必须行驶多长时间,并且我们可以根据开始时间(单击鼠标时)和现在之间的差异计算沿线/路径的进度。

Assuming the startTime is the time that we started moving, runningTime is the amount of time we need to run for in order to maintain a constant speed假设startTime是我们开始移动的时间, runningTime是我们需要运行以保持恒定速度的时间

Then we can calculate our current progress using something like...然后我们可以使用类似的东西来计算我们当前的进度......

long duration = System.currentTimeMillis() - startTime;
double progress = duration / runTime;

From this we can calculate the position along the line based on the current duration...由此我们可以根据当前持续时间计算沿线的位置......

double x = (int) (startX + ((targetX - startX) * progress));
double y = (int) (startY + ((targetY - startY) * progress));

沿线移动

As a proof of concept.作为概念证明。 Sorry, you didn't mention what framework your were using ;)抱歉,您没有提到您使用的是什么框架;)

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestMove {

    public static void main(String[] args) {
        new TestMove();
    }

    public TestMove() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private Rectangle champion;
        private Line2D path;

        private double speed = 0.1;

        private Timer timer;
        private Long startTime;

        private double targetX, targetY;
        private double startX, startY;
        private double runTime;

        public TestPane() {
            champion = new Rectangle(95, 95, 10, 10);

            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    timer.stop();
                    calculateChampionMovement(e.getX(), e.getY(), champion);
                    startTime = System.currentTimeMillis();
                    timer.start();
                }
            });

            timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (targetX == champion.getCenterX() && targetY == champion.getCenterY()) {
                        System.out.println("Stopped as same");
                        timer.stop();
                    }

                    long duration = System.currentTimeMillis() - startTime;
                    double progress = duration / runTime;

                    if (progress >= 1.0) {
                        System.out.println("Stopped out of time");
                        progress = 1.0;
                        timer.stop();
                    }

                    double x = (int) (startX + ((targetX - startX) * progress));
                    double y = (int) (startY + ((targetY - startY) * progress));

                    // x/y are the center points, need to adjust them so the shape
                    // moves about the center point
                    champion.setRect(x - 5, y - 5, 10, 10);

                    repaint();
                }
            });
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.draw(champion);
            if (path != null) {
                g2d.setColor(Color.RED);
                g2d.draw(path);
            }
            g2d.dispose();
        }

        public void calculateChampionMovement(double x, double y, Rectangle champion) {

            if (x != champion.getCenterX() || y != champion.getCenterY()) {

                targetX = x;
                targetY = y;

                startX = champion.getCenterX();
                startY = champion.getCenterY();

                path = new Line2D.Double(
                                champion.getCenterX(),
                                champion.getCenterY(),
                                x, y);

                double distance = Math.sqrt(
                                (startX - targetX) * (startX - targetX)
                                + (startY - targetY) * (startY - targetY));

                runTime = distance / (double)speed;

            }
        }
    }

}

Using the pythagorian theorem we can calculate the distance D ie sqrt((targetx-startx)^2+(target-starty)^2).使用勾股定理,我们可以计算距离 D 即 sqrt((targetx-startx)^2+(target-starty)^2)。

Using your velocity variable (ill call it V)we can calculate a time variable T as D/V ie distance over velocity.使用您的速度变量(我称之为 V),我们可以将时间变量 T 计算为 D/V,即速度上的距离。

We can then get the separate x and y velocity as xdistance/T and ydistance/T or (targetx-startx)/T and (targety-startat)/T (Note that an exception for if T == 0 must be implementerad to avoid errors)然后我们可以得到单独的 x 和 y 速度作为 xdistance/T 和 ydistance/T 或 (targetx-startx)/T 和 (targety-startat)/T(注意,必须实现 if T == 0 的异常以避免错误)

Using time fragments to calculate the x and y velocity so that the total velocity remains the same is computationally unnecessary with the only upside being that we avoid dividing by zero but then again that is easily fixable with a single if statement(if(T != 0.0)).使用时间片段来计算 x 和 y 速度以使总速度保持不变在计算上是不必要的,唯一的好处是我们避免除以零,但再次使用单个 if 语句(if(T != 0.0))。

Using this or similar methods will make your program run faster as less computations are needed.使用这种或类似的方法将使您的程序运行得更快,因为需要的计算更少。 The time save is too small to be noticeable with modern computers but it keeps the code cleaner.节省的时间太小,现代计算机无法注意到,但它使代码更清晰。 Good luck with your project.祝你的项目好运。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM