Bukkit球面坐标问题

时间:2016-01-13 19:13:49

标签: java minecraft bukkit

此代码使用bukkit api for minecraft。但是,此问题不需要bukkit知识或经验。我引用的“粒子”是使用属于“位置”(bukkit类)的x,y和z值生成的。这个位置可以被认为是3d空间中的一个坐标。 player.getDirection()是玩家正在寻找的单位向量。我意识到这可以使用3d中的圆的参数方程来完成。但是,我希望能够在3d中移动其他对象。注意:在Minecraft中,y轴是数学中通常称为z轴的轴。 (y轴是直线向上)

它的假设: 粒子效应应该像激光一样,但不是发送一行粒子,而是发送一个垂直于player.getDirection()的粒子圈。经过数小时的数学理论,我能够确定要做到这一点,我需要创建一个关于x轴的圆。然后,我需要将坐标从传统的cortesian坐标转换为极坐标。这是必要的,这样我就可以移动圆圈中的所有点来生成垂直于玩家方向的圆圈。然后,就像激光一样朝着那个方向前进。

它在做什么。 当玩家方向矢量位于xz平面时,粒子效果完美地起作用。在这个平面内部,它射出垂直于玩家方向的圆圈。然而,当玩家增加或减少他或她的方向的y分量时,圆圈开始变形。如果玩家创造直接向下看的效果,它会产生一个完美的数字8.直视,该方法什么都不做。这很可能是由于域之一对三角函数之一的限制,最终应该很容易解决。如果玩家看起来几乎笔直,它也会生成一个图8.在平行于xz平面和y轴之间,形状介于图8和圆之间。 没有堆栈跟踪。 这是我的方法代码和一些存储数据的内部类:

public void lazerBeamCircle(Player _player, String _particleType, double interval) 
    {
        MyLogger.info("In lazerBeamCircle in Particles");
        Vector playerDirection = _player.getLocation().getDirection();
        final int increment = 16;
        final double radius = 1;
        if (LazerCircleTaskID.get(_player.getName()) == null)
        {
            LazerCircleTaskID.put(_player.getName(), 0);
        }
        else if ((LazerCircleTaskID.get(_player.getName()) != 0))
        {
            Bukkit.getServer().getScheduler().cancelTask((LazerCircleTaskID.get(_player.getName())));
        }
         MyLogger.info("Right before the task");
        LazerCircleTaskID.put(_player.getName(), Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(JavaPlugin.getProvidingPlugin(MinigameDriver.class), new Runnable() 
            {
                @Override
                public void run() 
                {  
                    //MyLogger.info("In the task after run");
                    taskLazerBeamCircle _lazerVarsCircle = new taskLazerBeamCircle();
                    _lazerVarsCircle.Loc = new Location[increment];
                    if (!PlayerLazerCircleBeam.containsKey(LazerCircleTaskID.get(_player.getName())))
                    {
                        //double changeTheta = Math.acos(playerDirection.getX() / (Math.sin(Math.acos((playerDirection.getY())))));
                        double changeTheta = Math.atan2(playerDirection.getZ(), playerDirection.getX());
                        //if (changeTheta < 0 )
                        //{
                        //  changeTheta += 2 * Math.PI;
                        /*if (playerDirection.getZ() < 0)
                        {
                            changeTheta = ( 2 * Math.PI) - changeTheta;
                        }*/
                        double changePhi = (Math.acos(playerDirection.getY()) - (Math.PI)/2);

                        double ro;
                        double theta;
                        double phi;
                        double thetaNew;
                        double phiNew;

                        for (int i = 1 ; i <= increment; i++)
                        {
                            MyLogger.info("In the for calculating coords i = " + i);
                            MyLogger.info("inverse sin test " + Math.asin(Math.sqrt(2) / 2));
                            Location locThrowAway = new Location(_player.getWorld(), 1, 0, 0);
                            //finding the coords of the circle on the x axis;
                            locThrowAway.setY(radius * Math.sin(((double) i / increment) * (2 * Math.PI)));
                            locThrowAway.setZ(radius * Math.cos(((double) i / increment) * (2 * Math.PI)));
                            MyLogger.info("after Finding the coords of the circle on the x axis" + locThrowAway.getX() + "  " + locThrowAway.getY() + "  " + locThrowAway.getZ());

                            //finding the coords in spherical coords
                            ro = Math.sqrt((locThrowAway.getX() * locThrowAway.getX()) +
                                    (locThrowAway.getY() * locThrowAway.getY()) +(locThrowAway.getZ() * locThrowAway.getZ()));

                            phi = Math.acos((locThrowAway.getY()) / ro);
                            theta = Math.asin(locThrowAway.getZ() / (ro * Math.sin(phi)));
                            if (theta < 0)
                            {
                                theta += 2 * Math.PI;
                            }

                            //adding the arcs to the spherical coords
                            thetaNew = (theta + changeTheta);
                            phiNew = (phi + changePhi);
                            //thetaNew = theta;
                            //phiNew = phi;
                            /*if (phiNew < 0)
                            {
                                phiNew = phiNew * -1;
                            }*/


                            //converting back to normal coords
                            //changeTheta is used as it is theta as well
                            locThrowAway.setX(Math.sin(phiNew) * Math.cos(thetaNew) * ro);
                            locThrowAway.setY(Math.cos(phiNew) * ro);
                            locThrowAway.setZ(Math.sin(phiNew) * Math.sin(thetaNew) * ro);
                            //locThrowAway.setX(locThrowAway.getX());
                            //locThrowAway.setY(locThrowAway.getY());
                            //locThrowAway.setZ(locThrowAway.getZ());
                            locThrowAway.setX(locThrowAway.getX() + _player.getLocation().getX());
                            locThrowAway.setY(locThrowAway.getY() + _player.getLocation().getY() + 2);
                            locThrowAway.setZ(locThrowAway.getZ() + _player.getLocation().getZ());
                            _lazerVarsCircle.Loc[i - 1] = locThrowAway;
                            //MyLogger.info("after converting back to normal coords" + locThrowAway.getX() + "  " + locThrowAway.getY() + "  " + locThrowAway.getZ());*/
                            /*Location center = _player.getLocation();
                            center.setX(center.getX() + center.getDirection().getX());
                            center.setY(center.getY() + center.getDirection().getY());
                            center.setZ(center.getZ() + center.getDirection().getZ());
                            double yaw = _player.getLocation().getYaw();
                            double pitch = _player.getLocation().getPitch();
                            yaw = Math.toRadians(yaw);
                            pitch = Math.toRadians(pitch);
                            Vector right = new Vector(Math.cos(yaw + (Math.PI/2.0)), 0, Math.sin(yaw + (Math.PI/2.0)));
                            Vector up = new Vector(Math.cos(yaw), Math.sin(pitch), Math.sin(yaw));
                            double a = 0;
                            Location[] DavidLocArray = new Location[16];
                            for (int j = 0; j < increment; j++) 
                            {
                                Location locThrowAway = new Location(_player.getWorld(), 1, 0, 0);
                                a = ((double) j / (double) increment) * (2 * Math.PI);
                                //MyLogger.info("a " + a);
                                locThrowAway.setX(center.getX() + (radius * Math.cos(a) * right.getX()) + (radius * Math.sin(a) * up.getX()));
                                locThrowAway.setY(center.getY() + (radius * Math.cos(a) * right.getY()) + (radius * Math.sin(a) * up.getY()));
                                locThrowAway.setZ(center.getZ() + (radius * Math.cos(a) * right.getZ()) + (radius * Math.sin(a) * up.getZ()));
                                //MyLogger.info("x,y,z " + locThrowAway.getX() + locThrowAway.getY() + locThrowAway.getZ());
                                int abc = _lazerVarsCircle.Loc.length;
                                //MyLogger.info("j = " + j);
                                Location throwAwayCopy = locThrowAway;
                                _lazerVarsCircle.Loc[j] = throwAwayCopy;
                                DavidLocArray[j] = locThrowAway;
                                //MyLogger.info("_lazerVarsCircle " + _lazerVarsCircle.Loc[j]);
                            }
                            //MyLogger.info("_lazerVarsCircle " + _lazerVarsCircle.Loc[14]);
                            for(int david = 0; david < increment; david++)
                            {
                                //MyLogger.info("_lazerVarsCircle[david] = " + DavidLocArray[david]);
                            }
                            */
                            //MyLogger.info("X , Y , Z after calculations " + locThrowAway.getX() + "  " + locThrowAway.getY() + "  " + locThrowAway.getZ());
                        }
                            PlayerLazerCircleBeam.put(LazerCircleTaskID.get(_player.getName()), _lazerVarsCircle);
                    }
                    else
                    {   
                        _lazerVarsCircle = PlayerLazerCircleBeam.get(LazerCircleTaskID.get(_player.getName()));
                        /*for (int i = 0; i < _lazerVarsCircle.Loc.length; i++)
                        {
                            _lazerVarsCircle.Loc[i].setX(_lazerVarsCircle.Loc[i].getX() + (playerDirection.getX() / interval));
                            _lazerVarsCircle.Loc[i].setY(_lazerVarsCircle.Loc[i].getY() + (playerDirection.getY() / interval));
                            _lazerVarsCircle.Loc[i].setZ(_lazerVarsCircle.Loc[i].getZ() + (playerDirection.getZ() / interval));
                            if (_lazerVarsCircle.Loc[i].getBlock().getType() != Material.AIR)
                            {
                                _lazerVarsCircle.Loc[i].getWorld().createExplosion(_lazerVarsCircle.Loc[i], 5);
                                Bukkit.getServer().getScheduler().cancelTask((LazerCircleTaskID.get(_player.getName())));
                            }
                        }
                        PlayerLazerCircleBeam.put(LazerCircleTaskID.get(_player.getName()), _lazerVarsCircle);*/
                    }
                    for (int h = 0; h < increment; h++)
                    {
                    //  MyLogger.info("sending packets to display particles");
                    //  MyLogger.info("X , Y , Z particle locations " + _lazerVarsCircle.Loc[j].getX() + _lazerVarsCircle.Loc[j].getY() + _lazerVarsCircle.Loc[j].getZ());
                    //  MyLogger.info("index-1 " + h);
                        //MyLogger.info("Index " + h + "x coord" +_lazerVarsCircle.Loc[h].getX());
                        PacketPlayOutWorldParticles _packet = new PacketPlayOutWorldParticles(EnumParticle.valueOf(_particleType), true,
                                (float) (_lazerVarsCircle.Loc[h].getX()), (float) (_lazerVarsCircle.Loc[h].getY()), (float) (_lazerVarsCircle.Loc[h].getZ()),(float) 0,(float) 0,(float) 0,(float) 0, 1);
                            for(Player _online : Bukkit.getOnlinePlayers()) 
                            {
                                ((CraftPlayer)_online).getHandle().playerConnection.sendPacket(_packet);
                            }
                    }
                  //  MyLogger.info("about to exit run");
                }
            },0L, 2L));

    }                   
// Class used to store local values for the helix particle effect (SEE createHelix for more info)
class taskPlayerVariablesHelix
{
    double X;
    double Y;
    double Z;
    boolean ParticleDirection;
    double NegativeY;
    Location Loc;
}
class taskLazerBeam
{
    double X;
    double Y;
    double Z;
    Location Loc;
}
class taskLazerBeamCircle
{
    //array of locations used to store the locations of the points of the circle
    Location[] Loc;
}

任何帮助将不胜感激! 谢谢。 编辑: 这是一个由于pokechu22发生的事情的视频 https://youtu.be/hU1uwZ9hiAI

1 个答案:

答案 0 :(得分:1)

另一种可能的方法是使用线性代数来获取2D对象(技术上是平面上的3D对象)并相应地旋转它。 Rotations in R3 [https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations]

你的圆可以有坐标(x,y,0)然后你可以使用Matrix-vector multiplication相应地用旋转矩阵转录它,其中向量是对象的坐标(x,y,0)和矩阵是旋转矩阵。注意:然后,另一个旋转矩阵可以从第一个旋转矩阵旋转结果矢量。旋转量(theta)将来自玩家的偏航和俯仰。