PlayCanvas(五)__商业项目篇

发布于 2019-10-29  304 次阅读


前言

这段时间完成了playcanvas简单的展示功能,重构完成之后,我才拿过来记录一下。

正文

重构的内容主要是 讲摄像机逻辑、事件逻辑、模型逻辑、UI逻辑、工具方法。

脚本

Globals.js

全局类似于单例,并引入GameMain

var Globals = pc.createScript('globals');

//当前的步骤
Globals.attributes.add("CurrentStep",{
    type:"number",
    "default":-1
});
//当前的内容
Globals.attributes.add("CruuentGeneral",{
    type:"number",
    "default":1
});

//总共步骤
Globals.attributes.add("TotalSteps",{
    type:"number",
    "default":6
});
//换模型事件
Globals.attributes.add("Evt_GeneralEvent", {
        type: "string",
        "default": "GeneralEvent"
});
//步骤UI切换好像是
Globals.attributes.add("Evt_StepChange", {
    type: "string",
    "default": "StepChangeEvent"
});
//爆炸
Globals.attributes.add("Evt_StartBoom", {
    type: "string",
    "default": "StartBoom"
});
//返回
Globals.attributes.add("Evt_ReturnBoom", {
    type: "string",
    "default": "ReturnBoom"
});
//内容事件
Globals.attributes.add("Evt_Content",{
    type:"string",
    "default":"ContentEvent"
}); 
//事件转换器
Globals.attributes.add("EvtMgr", {
    type: "entity"
});
//摄像机
Globals.attributes.add("MainCamera", {
    type: "entity"
});
Globals.attributes.add("Model",{
    type:"entity"
});
Globals.attributes.add("UI",{
    type:"entity"
});
//步骤json
Globals.attributes.add("StepJsonData",{
    type:"asset",
    assetType: 'json'
});
var icanvas;
var iwidth;
var iheight;
var iproportion;
Globals.prototype.initialize = function() {
    window.GameMain = this;
    this.DebugCam = this.MainCamera.script.orbitCamera;
    this.ModelControl = this.Model.script.modelControl;
    this.UIControl = this.UI.script.uicontrol;  

    //获取设备的canvas 其实可以写在初始化
    icanvas = this.app.graphicsDevice.canvas;
    iwidth = icanvas.offsetWidth ;
    iheight = icanvas.offsetHeight ;
    iproportion = iheight / 1280; 
    this.point = new pc.Vec3();
    //加载Json
    this.AnimationStepData = this.StepJsonData.resources; 
}; 
// update code called every frame
Globals.prototype.update = function(dt) {
    //this.printCam();        //打印信息
    this.UIFollowModel();   //跟随信息
}; 
Globals.prototype.calcShortRot = function(y) {
    return y < -360 || y > 360 ? y % 360 : y;
};
Globals.prototype.printCam = function() {
    console.log("Cam yaw Y轴 " + this.DebugCam.yaw + 
                "\nCam Cam pitch X轴 " + this.DebugCam.pitch + 
                "\nCam distance 距离 " + this.DebugCam.distance );  
};
Globals.prototype.UIFollowModel = function()
{
    //让UI跟随模型
    for (var a = 0; a < GameMain.ModelControl.ArrayModel.length; a++)
    {
        this.MainCamera.camera.worldToScreen(GameMain.ModelControl.ArrayModel[a].getPosition(),this.point); 
        GameMain.UIControl.ArrayPointUI[a].setLocalPosition(
            (this.point.x - iwidth / 2 ) / iproportion,
            (-this.point.y + iheight / 2 ) / iproportion,
            0);
    }  
};

GlobalEventMgr.js

事件id处理器

var GlobalEventMgr = pc.createScript('globalEventMgr');

// initialize code called once per entity
GlobalEventMgr.prototype.initialize = function()
{
    this.entity.on(GameMain.Evt_GeneralEvent, this.onGeneral, this);
    this.entity.on(GameMain.Evt_StepChange,this.onStepChange, this);
}; 
GlobalEventMgr.prototype.update = function(dt) 
{ 
};
GlobalEventMgr.prototype.onStepChange = function(t) 
{//本来也在这里改的,有点条件
    //GameMain.CurrentStep += t;
    //console.log(" globals.CurrentStep" +  globals.CurrentStep); 
};
GlobalEventMgr.prototype.onGeneral =  function(t)
{//改值
    GameMain.CruuentGeneral = t;
    console.log(" GlobalEventMgr:GameMain.CruuentGeneral" +  GameMain.CruuentGeneral); 
};

CameraHandle.js

摄像机角度处理,此处只要是根据id调用json数据

var CameraHandle = pc.createScript('cameraHandle');

CameraHandle.self = null;
// initialize code called once per entity
CameraHandle.prototype.initialize = function()
{ 
    CameraHandle.self = this;
    GameMain.EvtMgr.on(GameMain.Evt_StepChange, this.StepChangeClick, this); 
    this.StepChange(GameMain.CurrentStep);
}; 
CameraHandle.prototype.StepChangeClick = function(a)
{ 
    setTimeout(function(){
          CameraHandle.self.StepChange(GameMain.CurrentStep);
    },1); 
};
CameraHandle.prototype.StepChange = function(stepid)
{
    console.log("CameraHandle.CurrentStep" + GameMain.CurrentStep);
    this.dis = parseFloat(GameMain.AnimationStepData[stepid].Distance);
    this.yaw = parseFloat(GameMain.AnimationStepData[stepid].Yaw);
    this.pitch = parseFloat(GameMain.AnimationStepData[stepid].Pitch);        
    this.posX = parseFloat(GameMain.AnimationStepData[stepid].PosX);
    this.posY = parseFloat(GameMain.AnimationStepData[stepid].PosY);
    this.posZ = parseFloat(GameMain.AnimationStepData[stepid].PosZ);  
    GameMain.DebugCam.setMoveRot(this.yaw,this.pitch,this.dis ,new pc.Vec3(this.posX ,this.posY ,this.posZ)); 
};

Commont.js

全局工具类

var Commont = pc.createScript('commont');  
 //Static function 虽然js并不支持重载
Commont.ActiveGo = function(go,b)
{
    go.enabled = b;
};
Commont.ActiveGos = function(a,array,b)
{ 
    for (var e = a; e < array.length; e++)
    {
       this.ActiveGo(array[e],b);   
    }
};
Commont.ActiveGosIndex = function(a,array,index,b)
{ 
    for (var e = a; e < array.length; e++)
    {
        var isAct = (e=== index) ? b : !b;  
        this.ActiveGo(array[e],isAct);  
    }
};
Commont.Wait = function(func,time)
{
    setTimeout(function () {
      func(); 
    }, time);
};  
//UI调用部分 
Commont.onChangeUI = function(t, a) {
    for (var e = 0; e < t.length; e++)
    {
        if(e === a )
        {
           t[e].enabled = true;
        }
        else
        {
           t[e].enabled = false;
        }  
    }
}; 

ModelControl.js

模型处理

var ModelControl = pc.createScript('modelControl');
ModelControl.attributes.add("ModelTotal",{
    type: "entity"
}); 
//动画播放时间 毫秒单位
ModelControl.attributes.add("AnimationTime",{
    type:"number",
    "default":1
});
ModelControl.attributes.add("OutAnimationName", {
    type: "string",
    max:15,
    array:!0
});
ModelControl.attributes.add("InAnimationName", {
    type: "string",
    max:15,
    array:!0
});
ModelControl.attributes.add("ArrayModel",{//模型部件
    type:"entity",
    max:15,
    array:!0
});   
// initialize code called once per entity
ModelControl.prototype.initialize = function() { 
    Commont.ActiveGos(0,this.ArrayModel,false); 
};
ModelControl.prototype.PlayAnimation = function(name)
{
    this.ModelTotal.animation.play(name); 
};
ModelControl.prototype.OnReset = function(b)
{
    Commont.ActiveGo(this.ModelTotal,!b);
    Commont.ActiveGo(this.ArrayModel[GameMain.CruuentGeneral],b); 
};
ModelControl.prototype.SelectAnimationName = function(num,a)
{
     return a<0? this.InAnimationName[num]:this.OutAnimationName[num];
};
// update code called every frame
ModelControl.prototype.update = function(dt) {

};

UIControl.js

UI处理

var Uicontrol = pc.createScript('uicontrol');
Uicontrol.attributes.add("BtnPlay", {
    type: "entity"
});
Uicontrol.attributes.add("BtnReturn", {
    type: "entity"
});
Uicontrol.attributes.add("BtnLast",{
    type:"entity"
});
Uicontrol.attributes.add("BtnNext",{
    type:"entity"
});
Uicontrol.attributes.add("BtnContentIntroduceUI",{
    type:"entity"
}); 
Uicontrol.attributes.add("ArrayPointUI",{
    type:"entity",
    max:15,
    array:!0
});
Uicontrol.attributes.add("ArrayTitleUI",{
    type:"entity",
    max:15,
    array:!0
}); 
Uicontrol.attributes.add("ArrayContentUI",{
    type:"entity",
    max:15,
    array:!0
}); 
Uicontrol.attributes.add("ArrayPlayUIAssetUI",{
    type:"asset",
    max:2,
    array:!0
}); 

Uicontrol.self = null;
// initialize code called once per entity
Uicontrol.prototype.initialize = function() {

    Uicontrol.self = this; 
    //初始化事件 
    GameMain.EvtMgr.on(GameMain.Evt_StepChange, this.StepChangeClick, this);
    GameMain.EvtMgr.on(GameMain.Evt_GeneralEvent, this.GeneralClick, this);
    GameMain.EvtMgr.on(GameMain.Evt_StartBoom, this.StartBoomClick, this);
    GameMain.EvtMgr.on(GameMain.Evt_ReturnBoom,this.ReturnBoomClick, this);
    GameMain.EvtMgr.on(GameMain.Evt_Content,this.ContentClick,this);
    //初始化操作
    Commont.ActiveGo(this.BtnReturn,false);
    Commont.ActiveGo(this.BtnContentIntroduceUI,false);
    Commont.ActiveGo(this.BtnLast,true);  
    Commont.ActiveGo(this.BtnNext,true);
    Commont.ActiveGo(this.BtnPlay,true);

    Commont.ActiveGos(0,this.ArrayPointUI,false);
    Commont.ActiveGos(0,this.ArrayTitleUI,false);
    Commont.ActiveGos(0,this.ArrayContentUI,false);
    //初始化播放UI
    this.BtnPlay.element.texture = this.ArrayPlayUIAssetUI[0].resource;

    this.isPut = true;
    this.isPlay = false;  
    this.isPlayContent = false; 
}; 

Uicontrol.isStep = true;
Uicontrol.isPlayAnimation = true;
Uicontrol.prototype.StepChangeClick = function(a) 
{//播放步骤动画  
    if(Uicontrol.isStep && this.isPut){
        this.OnStepChange(a);
    } 
};
Uicontrol.prototype.OnStepChange = function(a){
    GameMain.CurrentStep += a;
    console.log("Uicontrol.CurrentStep" + GameMain.CurrentStep);
    if(GameMain.CurrentStep <0)
    {
        GameMain.CurrentStep = 0;
        return;
    }
    else if(GameMain.CurrentStep>GameMain.TotalSteps)
    {
        GameMain.CurrentStep = GameMain.TotalSteps;
        return;
    } 
    Uicontrol.isStep = false;
    //  下一步 0 1 2 3   上一步 0 1 2 3 globals.CurrentStep 1 2 3 4 
    var isActive = a<0? false: true;   //判断显隐
    var currentNum = a<0? GameMain.CurrentStep :GameMain.CurrentStep-1; //判断iD
    var animationName = GameMain.ModelControl.SelectAnimationName(currentNum,a); //判断动画名字  
    var time = isActive ? GameMain.ModelControl.AnimationTime:0; 
    GameMain.ModelControl.PlayAnimation(animationName); //调用模型播放动画的事件
    setTimeout(function () {   
        if(currentNum==(GameMain.TotalSteps-1))
        {
            Commont.ActiveGos(currentNum,Uicontrol.self.ArrayPointUI,isActive); 
        }
        Commont.ActiveGo(Uicontrol.self.ArrayPointUI[currentNum], isActive);  
    }, time);  
    setTimeout(function () {  
        Uicontrol.isStep = true;  
    }, GameMain.ModelControl.AnimationTime);
};
Uicontrol.prototype.StartBoomClick = function()
{//点击播放爆炸动画 
    if(this.isPut &&Uicontrol.isStep)
    {
        Uicontrol.isPlayAnimation = !Uicontrol.isPlayAnimation;
        this.isPut = !this.isPut;
        this.isPlay = !this.isPlay;  
        var num = this.isPlay ? GameMain.TotalSteps :0; 
        GameMain.MainCamera.script.cameraHandle.StepChange(num); //旋转和中心点都做完了 
        this.BtnPlay.element.texture =this.isPlay ? 
            this.ArrayPlayUIAssetUI[1].resource:this.ArrayPlayUIAssetUI[0].resource;//变换播放按钮  
        var offset =  this.isPlay? 1: -1 ;  
        this.OnStepChange(offset);
        var a = setInterval(function(){
           if((Uicontrol.self.isPlay&& GameMain.CurrentStep >=GameMain.TotalSteps) ||( GameMain.CurrentStep <=0 &&!Uicontrol.self.isPlay) )
            {
                Uicontrol.isPlayAnimation = true;
                Uicontrol.self.isPut = true; 
                Uicontrol.isStep = true;
                clearInterval(a); 
            } 
            Uicontrol.self.OnStepChange(offset);
        },GameMain.ModelControl.AnimationTime); 
    } 
};  

Uicontrol.prototype.GeneralClick = function()
{//点击UI直接传参 globals.CurrentStep  
    if(Uicontrol.isPlayAnimation){
        this.OnReset(true); 
        Commont.ActiveGos(0,this.ArrayPointUI, false); 
        GameMain.DebugCam.focusEntity = GameMain.ModelControl.ArrayModel[GameMain.CruuentGeneral];  
    }
}; 
Uicontrol.prototype.ReturnBoomClick = function()
{
    this.OnReset(false); 
    for (var e = 0; e < GameMain.CurrentStep; e++)
    {
        Commont.ActiveGo(this.ArrayPointUI[e],true);   
    }
    if(GameMain.CurrentStep==GameMain.TotalSteps)
    {
        Commont.ActiveGos(GameMain.TotalSteps,this.ArrayPointUI,true); 
    }
    GameMain.DebugCam.focusEntity = GameMain.ModelControl.ModelTotal;
    GameMain.MainCamera.script.cameraHandle.StepChange(GameMain.TotalSteps); //旋转和中心点都做完了  
};
Uicontrol.prototype.OnReset = function(b)
{ 
    Commont.ActiveGo(this.BtnReturn,b);
    Commont.ActiveGo(this.BtnPlay,!b); 
    Commont.ActiveGo(this.BtnContentIntroduceUI,b);
    Commont.ActiveGo(this.BtnLast,!b);  
    Commont.ActiveGo(this.BtnNext,!b); 
    Commont.ActiveGo(this.ArrayTitleUI[GameMain.CruuentGeneral],b); 
    GameMain.ModelControl.OnReset(b); //模型
}; 
Uicontrol.prototype.ContentClick = function(a)
{
    if(GameMain.CruuentGeneral ==1){return;}
    this.isPlayContent = !this.isPlayContent;
    Commont.ActiveGo(this.ArrayContentUI[GameMain.CruuentGeneral],this.isPlayContent);  
};

StepUIClick.js

按钮事件

var StepUiclick = pc.createScript('stepUiclick');
StepUiclick.attributes.add("eventName",{
    type:"string",
    "default":"name_EventName"
});
//不知道有啥用
StepUiclick.attributes.add("eventType",{
  type: "number",
        "default": 0,
        "enum": [{
            StepChangeEvent : 0
        },{
            GeneralEvent:1,
        },{
            StartBoom : 2,
        },{
            ReturnBoom :3
        },{
            ContentEvent:4,
        }]
});
StepUiclick.attributes.add("eventIndex_listen", {
    type: "number",
    "default": 0
});
// initialize code called once per entity
StepUiclick.prototype.initialize = function() {
     this.entity.element.on('touchstart', this.onStateChange, this); 
};

StepUiclick.prototype.onStateChange = function(t)
{
    console.log("点击到UI "+this.eventName +" " +this.eventIndex_listen);
    GameMain.EvtMgr.fire(this.eventName, this.eventIndex_listen);
}; 

读解摄像机

OrbitCamera.js

外部参数

  • DistanceMax 最大距离
  • DistanceMin 最小距离
  • PitchAngleMax 最大角度(仰视)
  • PitchAngleMin 最小角度(俯视)
  • inertiaFactor 平滑阻尼,建议0.3左右,表示滑动完之后的一个平滑过程。
  • FocusEntity 焦点模型,外部直接调用替换就可以更换模型。
  • FrameonStart 好像是预加载的意思。
  • CamCenter 中心点(如果有更换中心点的需求)。

内部参数

  • distance(属性) 距离。
  • pitch(属性) X轴的角度。
  • yaw(属性) Y轴的角度。
  • pivotPoint(属性) 中心点的位置。
  • setMoveRot(方法) 自己加的,用来设置距离、角度和中心点。(floatY,floatX,floatDistance,Vec3)
  • 处理了旋转角度的问题。

// yaw是Y轴 paich是X轴 distance是距离 center是中心点。
OrbitCamera.prototype.setMoveRot = function(yaw, pitch, distance,center)
{  
    var y = this.calShortRotate( yaw,this._targetYaw ); 
    this._targetYaw  =  y; 
    this._targetPitch = pitch;
    this._targetDistance = distance;
    this.pivotPoint = center;
};

OrbitCamera.prototype.calShortRotate = function( t, e) 
{  
    if((0 > e) || (e > 360))
    {
        var a = (e - e % 360) + parseFloat(t);//t是目标值,读的json所以要转一下。
        return a;
    } 
    return t;  
}; 

MouseInput.js

MouseInput 没做修改。相对Touch来说比较简单容易理解,Down Up Move Wheel 四个事件单逻辑就够了。
Down的时候开启Move监听,Up的时候关闭Move监听,Move对 pitch 和 yaw 进行更改。
Wheel 对 distance 进行更改。

TouchInput.js

TouchInput也没做修改也是四个事件 TOUCHSTART TOUCHEND TOUCHCANCEL TOUCHMOVE。
主要Move事件,分为单点和多点。单点和鼠标逻辑一样。
多点分为 两个Touch距离是变化还是不变,变化的话更改距离,不变的话就是改中心点。


不积跬步,无以至千里;不积小流,无以成江海。