|
还没有账号?赶快去注册吧!
您需要 登录 才可以下载或查看,没有账号?立即注册
×
本帖最后由 Harlotte 于 2024-5-12 21:06 编辑
首先感谢zbx1425的技术支持!
通过一段时间的研究和钻研,我终于完成了对列车js代码的开发与实验,现除了声音部分由于nte函数问题(?)还无法实现,其他均已实现。
写在前面,JS一定会对流畅度有影响,这十分正常,请有心理准备。目前这种大杂烩的做法会使延迟异常的高,不建议直接搬走使用,尽量将其分为不同JS。(各功能分开的我过两天整理好了会发,可以再等等)。
- var rms = ModelManager.loadPartedRawModel(Resources.manager(), Resources.idRelative("df5g.obj"), null);//抄的
- var models = uploadPartedModels(rms);//抄的
- var yanrawModels = Array.from(ModelManager.loadPartedRawModel(Resources.manager(), Resources.idRelative("df5g_yan.obj"), null).values());
- var suo = 1;//初始化缩放
- var yanclass = 30;//烟大小等级数量
- var yanmaxscale = 4;//烟最大缩放
- var yanarrayrms = yanrawModels[0].copy();//存储烟模型
- var yanarray = new Array();//烟模型文件(加载后
- for (let i = 0; i < yanclass; i++) {//缩放并上传不同大小的烟模型
- yanarray[i] = {model:new Array()};//向这个元素其添加一个数组
- for(let j=0;j<4;j++){//这里我的df5g_yan中含有4种烟,所以为j<4
- yanarrayrms = yanrawModels[j].copy();//复制到临时rawmodel
- yanarrayrms.applyScale(suo,suo,suo);//进行缩放
- yanarrayrms.applyUVMirror(false, true);//UV翻转(取决于模型文件)
- yanarrayrms.sourceLocation = null;//可以理解为断开原数据连接,否则多个缩放大小会指向统一份数据
- yanarray[i].model[j] = ModelManager.uploadVertArrays(yanarrayrms)//添加数据到数组中的数组 大的为缩放值 小的为模型类型
- }
- suo = suo +yanmaxscale/yanclass;//缩放大小更新
- }
- var r=0;//初始化摇晃幅度
- var pid=1.12; //轮子直径
- var d=-0.446434+0.01; //轮子距原点纵轴距离
- var s1=3.1358; //轮子距原点横距离1
- var s2=1.80722; //轮子距原点横距离2
- var pit = 1;//初始化音高(速度)
- var yao=0.1;//摇晃幅度限制
- var yao1=0.01;//车速对摇晃幅度的影响幅度
- var yc = new Vector3f(0.336062 , 3.49877 + 0.15 , 6.31814 );//烟囱位置
- var yantimelimit = 6;//烟囱持续时间限制
- var yanverticalspeedlimit = 1;//烟囱上升速度系数 m/s
- var yanshuatimelimit = 0.08;//烟刷新时间
- var yannumlimit = 0 ;//初始化烟数量限制
- var kongzu =0.5; //空气阻力系数m/s
- function create(ctx, state, train) {
- yannumlimit = yantimelimit * (1 / yanshuatimelimit) + 20;//烟数量限制
- state.r = 0.0;//初始化轮子旋转角度
- state.speed = 0;//初始化列车速度
- state.number = new Array();//声音下一次播放时间记录
- state.yan = new Array();//烟数据
- state.ynum = 0;//烟现在数量
- state.time = 0;//初始化时间
- state.yantime = 0;//初始化烟刷新时间
- for (let j = 0; j < yannumlimit; j++) {//初始化烟数据
- state.yan[j] = {zhe:0,runing:0,time:0,speed:train.speed(),model:1,lastpos:new Vector3f(0,0,0),lastrot:new Vector3f(0,0,0),vect:new Vector3f(0,0,0),rot:new Vector3f(0,0,0)};
- }
- }
- function render(ctx, state, train) {
- //ctx.setDebugInfo("yanm=",yanarray[0].model[Math.floor(grnn(0,5))-1]);
- pit = 1.0 + train.speed() / 2;//更新音高(速度)
- if(r==0&&grnn(0,800)-train.speed()/10<5&&train.speed()>0){//当抖动归零且随机数为目标以内且列车在运动时:
- r=grn(0,yao+train.speed()*yao1);//随机抖动幅度
- }else if(r>0.1){//当角度为正且它在归零范围外时
- r=r-Math.abs(grnn(0,0.15));//减少随机数
- }else if(r<-0.1){//当角度为负且它在归零范围外时
- r=r+Math.abs(grnn(0,0.15));//增加随机数
- }else{//当他在归零范围内时
- r=0;//归零
- };
- if(train.speed()-state.speed>=0){//如果列车加速或保持速度则车轮转动
- if(train.isReversed()){//如果它是倒车的
- state.r = state.r - train.speed() / ( pid * Math.PI ) * 360 * Timing.delta() * 20; //轮子角度向后转
- }else{//否则如果它前进
- state.r = state.r + train.speed() / ( pid * Math.PI ) * 360 * Timing.delta() * 20;//向前转
- }
- }else{//否则如果其减速
- state.r = state.r;//保持不动
- sound(ctx,"mtr:df5g/shache",i,0,0,0,pit,state.number[1],16,0.05);//播放刹车声
- };
- let mat = new Matrices();//创建矩阵
- let mat2 = new Matrices();//创建矩阵
- mat.rotateZ(dtrd(r));//第一个矩阵应用全部抖动
- mat2.rotateZ(dtrd(r)/5);//第二个应用部分抖动
- for (let i = 0; i < train.trainCars(); i++) {//重复加载车辆
- ctx.drawCarModel(models["bogie_frame"], i, mat2);//转向架 应用部分抖动
- ctx.drawCarModel(models["bogie_frame_1"], i, mat2);//同上
- ctx.drawCarModel(models["coupler"], i, mat);//其余应用全部抖动
- ctx.drawCarModel(models["decorations"], i, mat);
- ctx.drawCarModel(models["doors"], i, mat);
- ctx.drawCarModel(models["frame"], i, mat);
- ctx.drawCarModel(models["shell"], i, mat);
- if(train.isOnRoute()){//如果它已经出库
- if(train.isReversed()){//如果它前进
- ctx.drawCarModel(models["light_2"], i, mat);//后退组灯灭
- ctx.drawCarModel(models["light_11"], i, mat);//前进组灯亮
- }else{//否则它后退
- ctx.drawCarModel(models["light_1"], i, mat);//前进组灯亮
- ctx.drawCarModel(models["light_21"], i, mat);//后退组灯灭
- };
- }else{//否则它没出库
- ctx.drawCarModel(models["light_1"], i, mat);//前进组灯灭
- ctx.drawCarModel(models["light_2"], i, mat);//后退组灯灭
- }
- };
- for (let i = 0; i < train.trainCars(); i++) {//加载轮子
- let mat33 = new Matrices();
- mat33.translate(0,d,0);//向下平移
- mat33.translate(0,0,s1);//向前平移
- mat33.pushPose();//存储平移
- mat33.rotateX(dtrd(state.r));//旋转
- ctx.drawCarModel(models["wheel"], i, mat33);//绘制
- mat33.popPose();//还原平移
- mat33.translate(0,0,s2);//继续向前
- mat33.pushPose();//。。。。。。
- mat33.rotateX(dtrd(state.r));
- ctx.drawCarModel(models["wheel"], i, mat33);
- mat33.popPose();
- mat33.translate(0,0,s2);
- mat33.pushPose();
- mat33.rotateX(dtrd(state.r));
- ctx.drawCarModel(models["wheel"], i, mat33);
- mat33 = new Matrices();
- mat33.translate(0,d,0);
- mat33.translate(0,0,-s1);
- mat33.pushPose();
- mat33.rotateX(dtrd(state.r));
- ctx.drawCarModel(models["wheel"], i, mat33);
- mat33.popPose();
- mat33.translate(0,0,-s2);
- mat33.pushPose();
- mat33.rotateX(dtrd(state.r));
- ctx.drawCarModel(models["wheel"], i, mat33);
- mat33.popPose();
- mat33.translate(0,0,-s2);
- mat33.pushPose();
- mat33.rotateX(dtrd(state.r));
- ctx.drawCarModel(models["wheel"], i, mat33);
- };
- ctx.setDebugInfo("r=",state.r);
- ctx.setDebugInfo("dtrd(r)=",dtrd(state.r));
- let gmk = getCurrentTrackModelKey(ctx,state,train);//获取当前轨道的自定义轨道名称
- if(train.isOnRoute()){//如果工作
- for (let i = 0; i < train.trainCars(); i++) {
- sound(ctx,"mtr:df5g_engine2",i,0,0,0,pit,state.number[1],16,1);//播放常见的声音,最后一个是轮播时常,单位是秒,推荐是音频的一半左右
- sound(ctx,"mtr:df5g_engine",i,0,0,0,pit,state.number[2],16,1);//同上
- if(gmk.indexOf("horn")){
- sound(ctx,"mtr:df5g_horn",i,0,0,0,pit,state.number[3],16,5);//播放鸣笛声,单位是秒,推荐是5秒左右,可以根据需要调整 我这里是因为音频不合适循环播放,实际音频在1s左右
- }
- }
- }
- //yanshuatimelimit = (yannumlimit - 20)/yantimelimit;
- for(i = 0; i < train.trainCars(); i++){
- if(train.isOnRoute()){//是否出库
- if(state.yantime < state.time){//是否到达刷新时间
- state.yan[state.ynum].runing = 1;//是否显示
- state.yan[state.ynum].time = 0;//记录时间
- state.yan[state.ynum].speed = train.speed();//记录速度
- state.yan[state.ynum].lastpos = train.lastCarPosition[i];//记录位置
- state.yan[state.ynum].lastrot = train.lastCarRotation[i];//记录旋转
- state.yan[state.ynum].vect = getWorldPositionFromTrainLocalPosition(yc,train.lastCarPosition[i],train.lastCarRotation[i]);//记录世界位置
- state.yan[state.ynum].rot = new Vector3f(grn(0,2*Math.PI),grn(0,2*Math.PI),grn(0,2*Math.PI));//随机旋转
- state.yan[state.ynum].model = Math.floor(grnn(0,4));//随机模型
- if(train.isReversed()){//记录向前向后惯性方向
- state.yan[state.ynum].zhe = 1;
- }else{
- state.yan[state.ynum].zhe = 0;
- }
- state.yantime = state.yantime + yanshuatimelimit;//增加刷新时间
- state.ynum = state.ynum + 1;//计数器加一
- if(state.ynum >= yannumlimit){//如果超限(前面20个已经显示完毕) 计数器归零
- state.ynum = 0;
- }
- }
- }
- for (let j = 0; j < yannumlimit; j++) {
- //以下判断烟是否显示
- if(state.yan[j].runing == 0){//如果不显示 跳过
- continue;
- }
- if(state.yan[j].time > yantimelimit){//如果超过时间 将其改为不显示并跳过
- runing = 0;
- continue;
- }
- //以下绘制烟
- let mat9 = new Matrices();//一个临时刷新矩阵
- let mat10 = getTrainLocalPositionFromWorldPosition(state.yan[j].vect,train.lastCarPosition[i],train.lastCarRotation[i]);//将渲染位置转换为列车坐标系
- let mat11 = vectadd(state.yan[j].rot , vectMirrorFlip(train.lastCarRotation[i]));//计算旋转
- mat9.translate(mat10.x(),mat10.y(),mat10.z());//移动
- mat9.rotateX(mat11.x());//旋转
- mat9.rotateY(mat11.y());
- mat9.rotateZ(mat11.z());
- let yansuo1 = positive(Math.floor(state.yan[j].time / yantimelimit * yanclass +grn(0,0.1)) -1);//计算烟的大小模型
- ctx.drawCarModel(yanarray[yansuo1].model[state.yan[j].model], i, mat9);//绘制烟
- //以下为烟添加变换
- state.yan[j].rot = vectadd(state.yan[j].rot,new Vector3f(grn(0,2*Math.PI),grn(0,2*Math.PI),grn(0,2*Math.PI)));//增加随机旋转
- let vectyy = new Vector3f(0,yanverticalspeedlimit * Timing.delta(),0);//垂直坐标增加量
- let vectzz = new Vector3f(0,0,0);//初始化水平(列车z轴)增加量
- state.yan[j].speed = positive(state.yan[j].speed - kongzu * Timing.delta());//速度(惯性)减少空气阻力
- if(state.yan[j].zhe == 1){//如果已经折返 则惯性为-速度
- vectzz = new Vector3f(0,0,-state.yan[j].speed * 20 * Timing.delta());
- }else{//否则为+速度
- vectzz = new Vector3f(0,0,state.yan[j].speed * 20 * Timing.delta());
- }
- state.yan[j].vect = vectadd(state.yan[j].vect,vectadd(vectyy,getWorldPositionFromTrainLocalPositionOnly(vectzz,state.yan[j].lastpos,state.yan[j].lastrot)));//增加位置
- state.yan[j].time = state.yan[j].time + Timing.delta();//增加时间
- }
- }
- state.speed = train.speed();//更新速度
- state.time = state.time + Timing.delta();//更新时间
- }
- function uploadPartedModels(rawModels) {//直接搬过来的,上传模型
- let result = {};
- for (it = rawModels.entrySet().iterator(); it.hasNext(); ) {
- entry = it.next();
- entry.getValue().applyUVMirror(false, true);
- result[entry.getKey()] = ModelManager.uploadVertArrays(entry.getValue());
- }
- return result;
- }
- function grn(min, max) {//随机小数正负
- if(Math.random()>=0.5){
- return Math.random()*(max-min)+min;
- }else{
- return 0-Math.random()*(max-min)+min;
- }
- }
- function grnn(min, max) {//随机小数
- return Math.random()*(max-min)+min;
- }
- function getCurrentTrackModelKey(ctx, state, train) {//获取当前轨道的自定义轨道名称,让ai写的
- // 获取列车从车库开出的距离
- let railProgress = train.railProgress();
- // 获取当前轨道的索引
- let currentRailIndex = train.getRailIndex(railProgress, true);
- // 检查当前轨道索引是否有效
- if (currentRailIndex >= 0 && currentRailIndex < train.path().size()) {
- // 获取当前路径数据对象
- let currentPathData = train.path().get(currentRailIndex);
- // 获取当前轨道使用的自定义轨道名称
- let trackModelKey = currentPathData.rail.getModelKey();
- return trackModelKey;
- }
- return null; // 或者是一个默认值
- }
- function dtrd(degrees) {//角度转弧度
- return degrees * Math.PI / 180;
- }
- function rdtd(radians) { // 弧度转角度
- return radians * 180 / Math.PI;
- }
- function sound(ctx,name2,i,xx,yy,zz,pit,nu,ll,long){//播放声音pit是音高(速度) nu是一个数组,用来记录播放时间,ll是音频响度,long是循环播放时间
- if(Timing.elapsed()>nu){//如果时间超过了播放时间
- ctx.playCarSound(Resources.id(name2) , i , xx , yy , zz , ll , pit);//播放
- nu = Timing.elapsed()+long; //更新播放时间
- }
- }
- function getWorldPositionFromTrainLocalPosition(localPosition , wordpost , wordrotate){//转换列车局部坐标到世界坐标
- let mat = new Matrix4f();//新建一个临时矩阵,将它想想为一个原点位于列车位置,xyz轴与世界标系相等的坐标系
- mat.rotateX(wordrotate.x());//可以理解为旋转这个平行于世界坐标系的坐标系,让它与列车的xyz坐标平行,与其重叠
- mat.rotateY(wordrotate.y());
- mat.rotateZ(wordrotate.z());
- mat.translate(localPosition.x(),localPosition.y(),localPosition.z());//在列车坐标系中移动
-
- return vectadd(wordpost,mat.getTranslationPart())//计算还原到原来的世界坐标系的位置并于世界坐标相加
- }
- function getWorldPositionFromTrainLocalPositionOnly(localPosition , wordpost , wordrotate){//转换列车局部坐标到世界坐标
- let mat = new Matrix4f();
- mat.rotateX(wordrotate.x());
- mat.rotateY(wordrotate.y());
- mat.rotateZ(wordrotate.z());
- mat.translate(localPosition.x(),localPosition.y(),localPosition.z());
-
- return mat.getTranslationPart();//以上于上一个函数相同 但没有增加世界坐标
- }
- function getTrainLocalPositionFromWorldPosition(localPosition , wordpost , wordrotate){//转换世界坐标到列车局部坐标
- let mat = new Matrix4f();//新建一个临时矩阵,将它想想为一个位于列车原点位置、xyz轴与列车坐标系相等的坐标系
- mat.rotateX(-wordrotate.x());//旋转世界坐标将其与列车坐标xyz轴平行
- mat.rotateY(-wordrotate.y());
- mat.rotateZ(-wordrotate.z());
- mat.translate(vectsub(localPosition,wordpost));//移动列车相对于世界坐标的位置 两坐标相减即可看作一个带有方向的距离
-
- return mat.getTranslationPart();
- }
- function vectMirrorFlip(vect){//镜像翻转
- return new Vector3f(-vect.x(),-vect.y(),-vect.z());
- }
- function vectadd(v1,v2){//向量相加
- return new Vector3f(v1.x()+v2.x(),v1.y()+v2.y(),v1.z()+v2.z());
- }
- function vectsub(v1,v2){//向量相减
- return new Vector3f(v1.x()-v2.x(),v1.y()-v2.y(),v1.z()-v2.z());
- }
- function positive(num){//一个简单的取整函数
- if(num>0){//如果大于0
- return num;//返回原值
- }else{//否则小于0
- return 0;//返回0
- }
- }
复制代码
无偿分享!还请多多支持!!有什么问题请不吝赐教!!!
Aphrodite
2024年5月12日
|
评分
-
查看全部评分
|