此代码使用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
答案 0 :(得分:1)
另一种可能的方法是使用线性代数来获取2D对象(技术上是平面上的3D对象)并相应地旋转它。 [https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations]
你的圆可以有坐标(x,y,0)然后你可以使用Matrix-vector multiplication相应地用旋转矩阵转录它,其中向量是对象的坐标(x,y,0)和矩阵是旋转矩阵。注意:然后,另一个旋转矩阵可以从第一个旋转矩阵旋转结果矢量。旋转量(theta)将来自玩家的偏航和俯仰。