用户:
蓝矮爱乐查看:4 回复:11 评论:4 创建时间:2022-06-26T09:57:49
(以下操作可能会变简单)
自认为简单的跑酷,都是知道路线的,只要跑酷难度在自己的能力之内。跑酷再简单,哪怕不知道路线,都不会跑()
假如一个跑酷很简单,路线很难,可是你又想和其他人比赛,别人不知道路线,怎么比?
那么,你要带路!可是带路只能带一次,别人看不到就看不到了,怎么弄个永久的带路系统?
啊,带路的系统可不是那么好屑的()
所以,这个跑酷要什么样的代码?首先,必须有存档点和计时器和SQL排行榜()
然后,带路系统就要有,带路原理就是系统持续记录你的位置,然后别人要看的时候从上往下依次读取
那么,持续记录位置的代码来咯!
db.sql`CREATE TABLE IF NOT EXISTS learnboard(
datas TEXT NOT NULL
)`;//因为带路要永久让别人看到你跑酷,所以要用SQL()
//下面这个之所以要用globalThis,因为要方便调用呗()
globalThis.seeWriterPlaying=/**
@param {Box3Entity} e//参数e的类型是Box3Entity
*/async function seeWriterPlaying(e){
//是异步函数,因为while循环就要用await才能不卡崩服务器,还有显示SQL数据就要用await
try{//尝试执行这些代码,如果作者没有录制,那么就找不到录制数据,就会报错
e.player.cameraMode='fixed';
//第三人称固定视角,这可以一直让视角跟随读取的数据视角
const d=JSON.parse((await db.sql`select*from learnboard`)[0].datas);
/*存进SQL数据类型要TEXT纯文本类型,其他类型存进去会报错
这里用了JSON.parse是因为存进去时是用JSON.stringify存进去的
SQL显示的都会是数组,所以要用[0]获取第一项,作者录取的数据是存进datas这个字段*/
var a=0;
//变量a用于切换动画的位置,连起来才会有带路的效果
e.et=world.createEntity({mesh:'mesh/互动机器人.vb',position:po,gravity:false,collides:false,fixed:true});//如果玩家用第三视角观看的话,那么就要用实体来表示位置
e.et.enableInteract=true;//让机器人允许互动,好让其他玩家知道有人开启了观战模式
e.et.interactHint=`观战模式的${e.player.name}`;//设置NPC的文字
while(true){//持续切换视角位置就是要用到while循环
var ad=JSON.parse(d[a%d.length].d);
//读取位置时,还要读取作者当时拍摄的时候的前进一个单位
var po=JSON.parse(d[a%d.length].p);
e.player.cameraPosition.copy(po);
//将玩家的视角位置切换到读取出来的位置
e.player.cameraTarget.copy(ad);
//让玩家面向作者当时录取时的位置前进一个单位,这样能让玩家视角跟随到作者的面向
if(e.player.seeWriterCameraMode=='follow')e.player.cameraPosition.subEq({x:(ad.x-po.x)*4,y:(ad.y-po.y)*4,z:(ad.z-po.z)*4});
//要单独拎出一个属性来表示视角模式,因为cameraMode已经是fixed了
await world.nextTick();//等到下一个tick触发
e.et.position.copy(po);//让实体来到读取的数据的位置
e.et.meshOrientation.copy(Quat.rotateY(Math.atan2(toVector(ad).sub(po).z, toVector(ad).sub(po).x)));
//让方向面向作者当时的方向
e.et.enableDamage=true;
e.et.maxHp=100;
e.et.hp=d[a%d.length].h;
//如果这个跑酷还要用到血量,那么就可以显示血量了
a++;//因为是从上依次往下读取,所以要加上1,这个变量a就是读取的项数
if(e.player.cameraMode!='fixed')break;//如果玩家取消了观看,就退出循环
}
}catch(error){
e.player.directMessage('作者未录制通关动画');
e.player.cameraMode='follow';//重新把视角调回默认视角
console.log(error)//这个调试出错误是因为方便修bug,如果是找不到录制数据而发生的错误,就不用修复了。可以删除
}
};
globalThis.Quat=new Box3Quaternion(0,0,0,1)//默认的旋转方向
function g(o) {
return new Box3Vector3(o.player.facingDirection.x,Math.sin(-o.player.cameraPitch),o.player.facingDirection.z);
//这个用函数来表示玩家摄像机xyz轴是因为要很麻烦,所以用函数来封装
}
function toVector(o) {return new Box3Vector3(o.x,o.y,o.z)}
//这个也比较麻烦,因为定义名要连续写3次,那如果定义名很长呢?
world.onPlayerJoin(({entity})=>{
e=world.querySelector('player')//可以删除,这是方便调试而用
entity.player.recording=function recording() {//录制通关的函数
entity.posJ=[];//这个数组用于存玩家的位置
entity.tickEvent=world.onTick(()=>{
entity.posJ.push({p:JSON.stringify(entity.position),d:JSON.stringify(entity.position.add(g(entity))),h:entity.hp});
//因为要做到动画效果,所以要持续往表格添加位置
})
};
entity.player.unRecording=async function unRecording(parameter) {
//取消录制,parameter这个参数如果是true的话,那么就会保存录制结果
entity.tickEvent.cancel();
if(parameter){
await db.sql`DELETE FROM learnboard`;//e,其实可以用更新数据的
await db.sql`INSERT INTO learnboard VALUES(${JSON.stringify(entity.posJ)})`
}
entity.posJ=undefined;
};
entity.player.seeWriterCameraMode='follow';
//另外用一个观看的变量,因为玩家观看的时候就要用fixed固定视角观看
entity.player.unseeing=function unseeing() {
//停止观看
entity.player.cameraMode='follow';//重新调回默认视角
entity.et.destroy();//销毁跟随观看视角的实体
}
})
这些代码写完了,总感觉漏了些什么?
哦!还有一些观看作者的操作:取消观看,切换观看视角,判断玩家是否观看等等
取消观看:entity.player.unseeing();
取消录制:entity.player.unRecording();
取消录制并保存:entity.player.unRecording(true);
判断玩家是否正在录制:Boolean(entity.posJ);
判断玩家是否观看:Boolean(world.querySelectorAll('*').filter(e=>e.interactHint==`观站模式的${entity.player.name}`).length);
切换观看第一视角:entity.player.seeingWriterCameraMode='fps';
切换观看第三视角:entity.player.seeingWriterCameraMode='follow';
开始录制:entity.player.recording();
开始观看:seeWriterPlaying(entity)
完结~
不要吞排版啊!()()