切换风格

默认晚霞 雪山 粉色心情 伦敦 花卉 绿野仙踪 加州 白云 星空 薰衣草 城市 简约黑色 龙珠
回复 1

20

主题

36

帖子

588

积分

萌新

Ko no Hueihuea da!!!!!!!!!!!!!

Rank: 10Rank: 10Rank: 10

积分
588
人气
29 点
钻石粒
78 粒
贡献
10 点
论坛币
92 个
爱心
0 点

论坛审核会员论坛注册会员

QQ
[1.12.2][ECMA]播放木偶动画——宽带在燃烧[复制链接]
发表于 2019-4-12 17:34:27 | 显示全部楼层 |阅读模式
脚本例子
脚本版本: 1.0
适用版本: 1.12.2 
编写语言: ECMA
最后更新: 2019-04-21
代码版权: 强版权

请注册论坛会员,已便查看高清图片!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
屁话不多说 直接上代码

/**
 * @author Hueihuea(mchhui)
 * @description 请把本代码段至于引用之前。
 */

/**
 * @description 动画列表
 * @description 警告 线程不安全 请勿在运行后修改
 */
function MovementList() {
  var LinkedList = Java.type("java.util.LinkedList");
  this.lastFrame = 0;
  this.movements = new LinkedList();
  /**
   * @description 添加一帧动画
   * @param {"int"} frame 动画在第几帧
   * @param {"int"} part 运动那一部分 0:头 1:左手 2:右手 3:身体 4:左腿 5:右腿
   * @param {"int"} yaw X轴旋转
   * @param {"int"} pitch Y轴旋转
   * @param {"int"} rool Z轴旋转
   * @param {boolean} update 是否更新 默认false
   * @return {"MovementList"} this 返回自己
   */
  this.add = function (frame, part, yaw, pitch, rool, update) {
    if (update == null) {
      update = false;
    }
    if (frame < this.lastFrame) {
      throw "动画必须是有序的";
    }
    yaw%=360;
    if(yaw<0){
      yaw+=360;
    }
    pitch%=360;
    if(pitch<0){
      pitch+=360;
    }
    rool%=360;
    if(rool<0){
      rool+=360;
    }
    this.lastFrame = frame;
    this.movements.add(new Movement(frame, part, yaw, pitch, rool, update));
    return this;
  }

  /**
   * @description 添加一系列动画
   * @param {"ChainMovement"} chainMovement 
   * @return {"MovementList"} this 返回自己
   */
  this.addChainMovement = function (chainMovement) {
    var frameLine = chainMovement.endFrame - chainMovement.startFrame;
    var yawLine = chainMovement.endYaw - chainMovement.startYaw;
    var pitchLine = chainMovement.endPitch - chainMovement.startPitch;
    var roolLine = chainMovement.endRool - chainMovement.startRool;
    var yawVelocityCurveFunction = chainMovement.yawVelocityCurveFunction;
    var pitchVelocityCurveFunction = chainMovement.pitchVelocityCurveFunction;
    var roolVelocityCurveFunction = chainMovement.roolVelocityCurveFunction;
    for (var frame = chainMovement.startFrame; frame <= chainMovement.endFrame; frame += chainMovement.spacing) {
      this.add(frame, chainMovement.part,
        chainMovement.startYaw + yawLine * yawVelocityCurveFunction((frame - chainMovement.startFrame) / frameLine),
        chainMovement.startPitch + pitchLine * pitchVelocityCurveFunction((frame - chainMovement.startFrame) / frameLine),
        chainMovement.startRool + roolLine * roolVelocityCurveFunction((frame - chainMovement.startFrame) / frameLine), true);
    }
  }
}

/**
 * @description 一帧动画 你不应该调用本函数
 */
function Movement(frame, part, yaw, pitch, rool, update) {
  this.frame = frame;
  this.part = part;
  this.yaw = yaw;
  this.pitch = pitch;
  this.rool = rool;
  this.update = update;
}
Movement.HEAD = 0;
Movement.LEFTARM = 1;
Movement.RIGHTARM = 2;
Movement.BODY = 3;
Movement.LEFTLEG = 4;
Movement.RIGHTLEG = 5;

/**
 *@description 一系列动画
 */
function ChainMovement() {
  this.startFrame;
  this.endFrame;
  this.spacing = 1;
  this.part;
  this.startYaw;
  this.startPitch;
  this.startRool;
  this.endYaw;
  this.endPitch;
  this.endRool;
  this.yawVelocityCurveFunction = function (x) { return x };
  this.pitchVelocityCurveFunction = function (x) { return x };
  this.roolVelocityCurveFunction = function (x) { return x };
  /**
   * @description 设置开始帧和结束帧
   * @param {"int"} startFrame 开始帧
   * @param {"int"} endFrame 结束帧
   * @return {"ChainMovement"} this 返回自己
   */
  this.setFrames = function (startFrame, endFrame) {
    this.startFrame = startFrame;
    this.endFrame = endFrame;
    return this;
  }

  /**
   * @description 设置每帧间距 默认是1
   * @param {*} spacing 间距
   * @return {"ChainMovement"} this 返回自己
   */
  this.setSpacing = function (spacing) {
    this.spacing = spacing;
    return this;
  }
  /**
   * @description 设置动画
   * @param {"int"} part 运动那一部分 0:头 1:左手 2:右手 3:身体 4:左腿 5:右腿
   * @param {"int"} startYaw 开始yaw
   * @param {"int"} startPitch 开始pitch
   * @param {"int"} startRool 开始rool
   * @param {"int"} endYaw 结束yaw
   * @param {"int"} endPitch 结束pitch
   * @param {"int"} endRool 结束rool
   * @return {"ChainMovement"} this 返回自己
   */
  this.setMovements = function (part, startYaw, startPitch, startRool, endYaw, endPitch, endRool) {
    this.part = part;
    this.startYaw = startYaw;
    this.startPitch = startPitch;
    this.startRool = startRool;
    this.endYaw = endYaw;
    this.endPitch = endPitch;
    this.endRool = endRool;
    return this;
  }
  /**
   * @description 设置yaw速度曲线 应该接受x 返回y
   * @description y=f(x) 
   * @description x是0-1的数 表示时间 0是开始 1是结束 
   * @description y是0-1的数 表示动画完成进度 0是开始 1是结束
   * @param {"Function"} func 速度曲线函数
   * @return {"ChainMovement"} 返回自己
   */
  this.setYawVelocityCurveFunction = function (func) {
    this.yawVelocityCurveFunction = func;
    return this;
  }

  /**
   * @description 设置pitch速度曲线 应该接受x 返回y
   * @description y=f(x) 
   * @description x是0-1的数 表示时间 0是开始 1是结束 
   * @description y是0-1的数 表示动画完成进度 0是开始 1是结束
   * @param {"Function"} func 速度曲线函数
   * @return {"ChainMovement"} 返回自己
   */
  this.setPitchVelocityCurveFunction = function (func) {
    this.pitchVelocityCurveFunction = func;
    return this;
  }

  /**
   * @description 设置rool速度曲线 应该接受x 返回y
   * @description y=f(x) 
   * @description x是0-1的数 表示时间 0是开始 1是结束 
   * @description y是0-1的数 表示动画完成进度 0是开始 1是结束
   * @param {"Function"} func 速度曲线函数
   * @return {"ChainMovement"} 返回自己
   */
  this.setRoolVelocityCurveFunction = function (func) {
    this.roolVelocityCurveFunction = func;
    return this;
  }
}

/**
 * @description 动画播放器
 * @param {"NpcEvent"} event npc的事件
 * @param {"MovementList"} movementList 动画列表
 * @param {"int"} fps FPS
 */
function MovementPlayer(event, movementList, fps) {
  var isStop = false;
  var instance = this;
  /**
   * @description 开始播放动画
   */
  this.start = function () {
    if (event.npc != null) {
      var typePuppet = 9;
      if (event.npc.job.getType() != typePuppet) {
        return;
      }
    } else {
      return;
    }

    var Thread = Java.type("java.lang.Thread");
    var MyRun = Java.extend(Java.type("java.lang.Runnable"), {
      run: function () {
        var frames = movementList.movements;
        var npc = event.npc;
        var FPS = (fps != null) ? fps : 50;
        var callbackFunction = instance.callback;
        var iterator = frames.iterator();
        var frame;
        var amplifier = 1;
        var lastFrame;
        var flag = true;
        var FMLCommonHandler = Java.type("net.minecraftforge.fml.common.FMLCommonHandler");
        while (iterator.hasNext() && !isStop) {
          while (FMLCommonHandler.instance().getSide().isClient()) {
            var Minecraft = Java.type("net.minecraft.client.Minecraft");
            if (!Minecraft.func_71410_x().func_147113_T()) {
              break;
            }
          }
          if (frame != null) {
            lastFrame = frame.frame;
          }
          frame = iterator.next();
          if (flag) {
            flag = false;
          } else {
            amplifier = frame.frame - lastFrame;
            if (amplifier < 0) {
              amplifier = 0;
            }
          }
          npc.job.getPart(frame.part).setRotation(
            frame.yaw,
            frame.pitch,
            frame.rool);
          if (frame.update) {
            npc.updateClient();
          }
          if (iterator.hasNext()) {
            Thread.sleep(1000 / FPS * amplifier);
          }
        }
        callbackFunction(isStop, npc);
        isStop = false;
      }
    });
    new Thread(new MyRun()).start()
  }
  /**
   * @description 回调函数
   * @param {boolean} isStop 动画是否被强制终止
   * @param {"ICustomNpc"} npc 执行动画的npc
   * @return {void}
   */
  this.callback = function (isStop, npc) {
    
  }
  /**
   * @description 强制终止动画
   * @return {void}
   */
  this.stop = function () {
    isStop = true;
  }
}


/**
*@description 执行木偶动画
*@param CustomNPCsEvent event:事件对象
*@param String[] movements:动画配置
*@param int fps:一秒播放多少帧
*@description 动画配置示例:"0.head,0,0,0,true" "帧.部位,yaw,pitch,roll,是否更新(可选)"
*/
function playMovements_old(event, movements, fps) {
  var isStop = false;
  this.start = function () {
    if (event.npc != null) {
      var typePuppet = 9;
      if (event.npc.job.getType() != typePuppet) {
        return;
      }
    } else {
      return;
    }
    var str;
    for (var x in movements) {
      str = movements[x];
      str = str.replace("head", 0);
      str = str.replace("leftarm", 1);
      str = str.replace("rightarm", 2);
      str = str.replace("body", 3);
      str = str.replace("leftleg", 4);
      str = str.replace("rightleg", 5);
      if (str.search(/[A-Za-z]+/) >= 0) {
        throw "An error in line " + x + "."
      }
      movements[x] = str;
    }

    var Thread = Java.type("java.lang.Thread");
    var MyRun = Java.extend(Java.type("java.lang.Runnable"), {
      run: function () {
        var frames = movements;
        var npc = event.npc;
        var parameterFrame = 0;
        var parameterValue = 1;
        var parameterValuePart = 0;
        var parameterValuePitch = 1;
        var parameterValueYaw = 2;
        var parameterValueRoll = 3;
        var parameterValueRefresh = 4;
        var FPS = (fps != null) ? fps : 50;
        this.getParameters = (
          function (str) {
            var parameters = str.split(".");
            parameters[parameterValue] = parameters[parameterValue].split(",");
            parameters[parameterFrame] = parseInt(parameters[parameterFrame]);
            parameters[parameterValueRefresh] = (parameters[parameterValueRefresh] != null) ? parameters[parameterValueRefresh] : true;

            for (var x in parameters[parameterValue]) {
              parameters[parameterValue][x] = parseInt(parameters[parameterValue][x]);
            }
            return parameters;
          }
        );
        for (var frame = 0; frames.length > 0; frame++) {
          if (isStop) {
            return;
          }
          var parameters = this.getParameters(frames[0])
          if (parameters[parameterFrame] == frame) {
            frames.shift();
            npc.job.getPart(parameters[parameterValue][parameterValuePart]).setRotation(
              parameters[parameterValue][parameterValueYaw],
              parameters[parameterValue][parameterValuePitch],
              parameters[parameterValue][parameterValueRoll]);
            if (parameters[parameterValueRefresh] != 0) {
              npc.updateClient();
            }
          }
          Thread.sleep(1000 / FPS);//50fps(0.02*1000)
        }
      }
    });
    new Thread(new MyRun()).start()
  }

  this.stop = function () {
    isStop = true;
  }
  /*
  *执行木偶动画
  *CustomNPCsEvent event:事件对象
  *String[] movements:动画配置
  *int fps:一秒播放多少帧
  *动画配置示例:"0.head,0,0,0,true" "帧.部位,yaw,pitch,roll,是否更新(可选)"
  */
}

//使用示例:

function setTimeout(fn, millis) {
  var Thread = Java.type("java.lang.Thread");
  var MyRun = Java.extend(Java.type("java.lang.Runnable"), {
    run: function () {
      Thread.sleep(millis)
      try {
        fn.apply();
      } catch (err) { throw err; }
    }
  });
  new Thread(new MyRun()).start()
  //延迟millis毫秒执行fn
  /*
  *function fn:要运行的function对象
  *int millis:延迟的毫秒
  */
}

//一个例子

var waveRight = new MovementList();
var waveLeft = new MovementList();
//自动补充动画
waveRight.addChainMovement(new ChainMovement().setFrames(0, 10).setMovements(Movement.RIGHTARM, 0, 0, 170, 0, 0, 140));
waveRight.addChainMovement(new ChainMovement().setFrames(10, 20).setMovements(Movement.RIGHTARM, 0, 0, 140, 0, 0, 170));
waveRight.addChainMovement(new ChainMovement().setFrames(20, 30).setMovements(Movement.RIGHTARM, 0, 0, 170, 0, 0, 140));
waveRight.addChainMovement(new ChainMovement().setFrames(30, 40).setMovements(Movement.RIGHTARM, 0, 0, 140, 0, 0, 170));
waveRight.addChainMovement(new ChainMovement().setFrames(40, 50).setMovements(Movement.RIGHTARM, 0, 0, 170, 0, 0, 140));
waveRight.addChainMovement(new ChainMovement().setFrames(50, 60).setMovements(Movement.RIGHTARM, 0, 0, 140, 0, 0, 170));
waveRight.addChainMovement(new ChainMovement().setFrames(60, 80).setMovements(Movement.RIGHTARM, 0, 0, 170, 0, 0, 0)
  .setRoolVelocityCurveFunction(function (x) {
    return Math.sqrt(x);
  }));
waveLeft.addChainMovement(new ChainMovement().setFrames(0, 10).setMovements(Movement.LEFTARM, 0, 0, 360 - 170, 0, 0, 360 - 140));
waveLeft.addChainMovement(new ChainMovement().setFrames(10, 20).setMovements(Movement.LEFTARM, 0, 0, 360 - 140, 0, 0, 360 - 170));
waveLeft.addChainMovement(new ChainMovement().setFrames(20, 30).setMovements(Movement.LEFTARM, 0, 0, 360 - 170, 0, 0, 360 - 140));
waveLeft.addChainMovement(new ChainMovement().setFrames(30, 40).setMovements(Movement.LEFTARM, 0, 0, 360 - 140, 0, 0, 360 - 170));
waveLeft.addChainMovement(new ChainMovement().setFrames(40, 50).setMovements(Movement.LEFTARM, 0, 0, 360 - 170, 0, 0, 360 - 140));
waveLeft.addChainMovement(new ChainMovement().setFrames(50, 60).setMovements(Movement.LEFTARM, 0, 0, 360 - 140, 0, 0, 360 - 170));
waveLeft.addChainMovement(new ChainMovement().setFrames(60, 80).setMovements(Movement.LEFTARM, 0, 0, 360 - 170, 0, 0, 360 - 0)
  .setRoolVelocityCurveFunction(function (x) {
    return Math.sqrt(x);
  }));
function interact(event) {
  var mmPlayer = new MovementPlayer(event, waveRight, 30);
  mmPlayer.start();
  mmPlayer = new MovementPlayer(event, waveLeft, 30);
  mmPlayer.start();
}


温馨提示:
默认50fps
在服务器玩太高fps可能会导致网卡?(不确定 反正服务器别飘就完事了)
服务器最好低一点 5fps?
你不一定每帧都写 可以跳着写的
fps只是速度 不代表动画帧数上限
也就是说50fps你动画可以有500帧 甚至更多你可以在配置的最后一项选择该帧是否更新
更新会向本地发包 这会消耗网络资源
(本方法默认每帧更新 mc默认0.5s更新一次)


效果:

                               
登录/注册后可看大图


版权声明:
1.您不能转载本帖
2.您不能声称作者是自己


评分

参与人数 1人气 +2 收起 理由
咸鱼羊 + 2 tql,就是转头有点瘆人

查看全部评分

回复

使用道具 举报

0

主题

3

帖子

29

积分

论坛萌新

Rank: 1

积分
29
人气
0 点
钻石粒
34 粒
贡献
0 点
论坛币
8 个
爱心
0 点
发表于 2019-6-4 11:22:32 | 显示全部楼层
灰灰快更plus版
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|自定义NPC脚本中文论坛 ( 蜀ICP备17005795号-3 )

GMT+8, 2020-9-20 01:44 , Processed in 0.077035 second(s), 31 queries .

Powered by Discuz! X3.4

© 2001-2013 Comsenz Inc.

返回顶部