- 导读
- Location点的旋转
- 坐标系的修正与在玩家背部建立坐标系
- 制作简易翅膀
- 本教程需要读者有一定的空间想象能力(因为我也懒得画图了233)
- 本教程使用的 PaperSpigot1.12.2-R0.1-SNAPSHOT 核心
- 在阅读之前请确保你具有高中数学必修4和和Java基础的知识
- <To初中生>: 如果你是初中的话,别慌,你有趋向的概念就可以读懂本教程(应该吧...)
- <To高中生>: 如果你还未学到关于上面的那本书,别慌学到了再来看也行233 (雾
- <To大学生>: 没什么好说的...
Location点的旋转
首先我们引入平面上点围绕另一个点进行旋转的公式 (数学上) 平面中,一个点(x,y)绕任意点(x0,y0)逆时针旋转a度后的坐标
- dx = (x - x0)*cos(a) - (y - y0)*sin(a) + x0 ;
- dy = (x - x0)*sin(a) + (y - y0)*cos(a) + y0 ;
- /**
- * 在二维平面上利用给定的中心点逆时针旋转一个点
- *
- * @param location 待旋转的点
- * @param angle 旋转角度
- * @param point 中心点
- * [url=home.php?mod=space&uid=491268]@Return[/url] {[url=home.php?mod=space&uid=41191]@link[/url] Location}
- */
- public static Location rotateLocationAboutPoint(Location location, double angle, Location point) {
- double radians = Math.toRadians(angle);
- double dx = location.getX() - point.getX();
- double dz = location.getZ() - point.getZ();
- double newX = dx * Math.cos(radians) - dz * Math.sin(radians) + point.getX();
- double newZ = dz * Math.cos(radians) + dx * Math.sin(radians) + point.getZ();
- return new Location(location.getWorld(), newX, location.getY(), newZ);
- }
坐标系的修正与在玩家背部建立坐标系
在我们之前的教程中,我们都会发现,我们在做一些让特效出现在玩家面前时,会出现特效出现在另外一边,这其实就是我们没有经过玩家朝向的修正,而发生的情况,比如下面这一张图
那么我们可以重新建立一个修正过后的坐标系,用的方法就是利用Location点的旋转
- import org.bukkit.Location;
- /**
- * 自动修正在平面上的粒子朝向
- *
- * [url=home.php?mod=space&uid=1231151]@author[/url] Zoyn
- */
- public class PlayerFixedCoordinate {
- private Location zeroDot;
- private double rotateAngle;
- public PlayerFixedCoordinate(Location playerLocation) {
- // 旋转的角度
- rotateAngle = playerLocation.getYaw();
- zeroDot = playerLocation.clone();
- zeroDot.setPitch(0);
- // 重设仰俯角, 防止出现仰头后旋转角度不正确的问题
- }
- public Location getZeroDot() {
- return zeroDot;
- }
- public Location newLocation(double x, double z) {
- return rotateLocationAboutPoint(zeroDot.clone().add(-x, 0, z), rotateAngle, zeroDot);
- }
- /**
- * 在二维平面上利用给定的中心点逆时针旋转一个点
- *
- * @param location 待旋转的点
- * @param angle 旋转角度
- * @param point 中心点
- * @return {@link Location}
- */
- public static Location rotateLocationAboutPoint(Location location, double angle, Location point) {
- double radians = Math.toRadians(angle);
- double dx = location.getX() - point.getX();
- double dz = location.getZ() - point.getZ();
- double newX = dx * Math.cos(radians) - dz * Math.sin(radians) + point.getX();
- double newZ = dz * Math.cos(radians) + dx * Math.sin(radians) + point.getZ();
- return new Location(location.getWorld(), newX, location.getY(), newZ);
- }
- }
之后我们看newLocation这个方法,需要填入两个参数分别是 x, y (为了方便理解,我其实直接将其设计为数学上的平面直角坐标系(右手坐标系))
而我们在看
- zeroDot.clone().add(-x, 0, z)
比如说,zeroDot是(0, 0),方法填入3, 2, 那么add完之后就得到 (3, 2) 这个点
那么为什么是-x呢???
完整代码:
- Player player = ........
- PlayerFixedCoordinate coordinate = new PlayerFixedCoordinate(player.getLocation());
- double radius = 10;
- for (double t = -1; t <= 1; t += 0.001) {
- double x = radius * Math.sin(t) * Math.cos(t) * Math.log(Math.abs(t));
- double y = radius * Math.sqrt(Math.abs(t)) * Math.cos(t);
- Location loc = coordinate.newLocation(x, y);
- loc.getWorld().spawnParticle(Particle.FIREWORKS_SPARK, loc, 1, 0, 0, 0, 0);
- }
绘图思考可以参照这张图:
- import org.bukkit.Location;
- /**
- * 将玩家背后转换为一个平面直角坐标系
- *
- * @author Zoyn
- */
- public class PlayerBackCoordinate {
- private Location zeroDot;
- private double rotateAngle;
- public PlayerBackCoordinate(Location playerLocation) {
- // 旋转的角度
- rotateAngle = playerLocation.getYaw();
- zeroDot = playerLocation.clone();
- zeroDot.setPitch(0); // 重设仰俯角
- zeroDot.add(zeroDot.getDirection().multiply(-0.3)); // 使原点与玩家有一点点距离
- }
- public Location getZeroDot() {
- return zeroDot;
- }
- public Location newLocation(double x, double y) {
- return rotateLocationAboutPoint(zeroDot.clone().add(-x, y, 0), rotateAngle, zeroDot);
- }
- /**
- * 在二维平面上利用给定的中心点逆时针旋转一个点
- *
- * @param location 待旋转的点
- * @param angle 旋转角度
- * @param point 中心点
- * @return {@link Location}
- */
- public static Location rotateLocationAboutPoint(Location location, double angle, Location point) {
- double radians = Math.toRadians(angle);
- double dx = location.getX() - point.getX();
- double dz = location.getZ() - point.getZ();
- double newX = dx * Math.cos(radians) - dz * Math.sin(radians) + point.getX();
- double newZ = dz * Math.cos(radians) + dx * Math.sin(radians) + point.getZ();
- return new Location(location.getWorld(), newX, location.getY(), newZ);
- }
- }
- Player player = (Player) sender;
- PlayerBackCoordinate coordinate = new PlayerBackCoordinate(player.getLocation().add(0, 1.6D, 0));
- for (int angle = 0; angle < 360; angle++) {
- double radians = Math.toRadians(angle);
- double x = Math.cos(radians);
- double y = Math.sin(radians);
- Location loc = coordinate.newLocation(x, y);
- loc.getWorld().spawnParticle(Particle.FLAME, loc, 1, 0, 0, 0, 0);
- }
制作简易翅膀
不说这么多,直接上代码好吧,用的就是上面的代码
- Player player = (Player) sender;
- PlayerBackCoordinate coordinate = new PlayerBackCoordinate(player.getLocation().add(0, 1.5D, 0));
- for (double angle = 0; angle <= 135; angle++) {
- double x = Math.toRadians(angle);
- double y = Math.sin(2 * x);
- Location loc = coordinate.newLocation(x, y);
- loc.getWorld().spawnParticle(Particle.VILLAGER_HAPPY, loc, 1, 0, 0, 0, 0);
- }
- for (double angle = -135; angle <= 0; angle++) {
- double x = Math.toRadians(angle);
- double y = Math.cos((2 * x) + (Math.PI / 2));
- Location loc = coordinate.newLocation(x, y);
- loc.getWorld().spawnParticle(Particle.VILLAGER_HAPPY, loc, 1, 0, 0, 0, 0);
- }
- coordinate = new PlayerBackCoordinate(player.getLocation().add(0, 1, 0));
- double radius = 0;
- for (double angle = 0; angle <= 3 * 360; angle++) {
- double radians = Math.toRadians(angle);
- double x = radius * Math.cos(radians);
- double y = radius * Math.sin(radians);
- Location loc = coordinate.newLocation(x, y);
- loc.getWorld().spawnParticle(Particle.FIREWORKS_SPARK, loc, 1, 0, 0, 0, 0);
- radius += 0.001;
- }
结语
是的这个教程又开始更新了,就当做没事拿来玩玩的了,毕竟上了大学,还是可以拿线性代数来学以致用的嘛嘻嘻嘻。此外我想开一个ParticleLib的坑,专门来制作这类特效,希望各位看官可以多多支持
[groupid=1701]Complex Studio[/groupid]