PlayCanvas(三)__进阶篇

发布于 2019-11-28  37 次阅读


前言

进阶篇主要讲一些新的知识,包括js语法。

正文

获取场景app

//表示的场景,创建的时候要添加进去。
var app = pc.Application.getApplication();
//一般情况下this.app 就可以拿到
this.app 

Entity操作

var entity = new pc.Entity();
//添加摄像机组件 组件是小写,至于参数,鼠标放界面上就可以显示出来
entity.addComponent("camera", {
  fov: 45,
  nearClip: 1,
  farClip: 10000
});
//类似unity的get组件
var lights = entity.findComponents("light"); 
//移除组件
entity.removeComponent("light");
//添加到场景里
app.root.addChild(entity);
//坐标
var p = entity.getPosition();
entity.setPosition(p.x + 10, p.y, p.z);
//角度
var e = entity.getLocalEulerAngles();
entity.setLocalEulerAngles(e.x, e.y + 90, e.z);
//克隆entity,并添加到同级。
var e = this.entity.clone(); 
this.entity.parent.addChild(e); 
//注册删除事件
entity.on("destroy", function (e) {
    console.log("删掉了");
});
//删除
this.entity.destroy();
//删除子物体
var child = this.entity.children[0];
this.entity.removeChild(child);
//查找物体
var path = this.entity.findByPath('child/another_child');
var animals = node.findByTag("animal");
var birdsAndMammals = node.findByTag("bird", "mammal");
var meatEatingMammals = node.findByTag([ "carnivore", "mammal" ]);
//返回的第一个名字为head的物体
var head = player.findOne(function(node) {
    return node.model && node.name === 'head';
});
//lookAt朝向
this.entity.lookAt(position); 

asset操作

//通过public获取asset
this.UIPlay.element.texture = this.asset.resource;
//name  type file(文件信息) data(json数据)
var asset = new pc.Asset("a texture", "texture", {
    url: "http://example.com/my/assets/here/texture.png"
}); 
//通过连接获取
var asset = app.assets.find("My Asset");
var asset = app.assets.getByUrl("../path/to/image.jpg");
app.assets.add(asset); //添加进去
//下好的回调
asset.ready(function (asset) {
  // 回调
});
//加载
app.assets.load(asset);
//卸载
app.assets.unload();
//加载并回调
app.assets.loadFromUrl("../path/to/texture.jpg", "texture", function (err, asset) {
    var texture = asset.resource;
});
//移除资源
app.assets.remove(asset);
//回调
app.assets.on("add", function (asset) {
    console.log("New asset added: " + asset.name);
});
app.assets.on("remove", function (aseet) {
    console.log("Asset removed: " + asset.name);
});
app.assets.on("error", function (err, asset) {
    console.error(err);
});
app.assets.on("load", function (asset) {
    console.log("asset loaded: " + asset.name);
});

新的UI方式

有些功能需要用html和css来实现UI的效果,比如说输入框~
其实也蛮好理解。就是写入html和css,然后通过js引入asset来调用。
也可以 直接 var e = "html" 然后再调用,我觉得还是分开好。

html

<div class='button'>BUTTON</div>
<div class='counterBox'>
    times clicked <span class='counter'>0</span>
</div>
<div class='text'>
    Hit the button to increment the counter<br />
</div>

css

.container {
    position: absolute;
    top: 16px;
    left: 16px;

    background-color: #222;
    color: #fff;
    font-weight: 100;
    padding: 8px;

    box-shadow: 0 0 16px rgba(0, 0, 0, .3);
}
.container > .counterBox {//类似于继承
    float: right;
}

js

var Ui = pc.createScript('ui');

Ui.attributes.add('css', {type: 'asset', assetType:'css', title: 'CSS Asset'});
Ui.attributes.add('html', {type: 'asset', assetType:'html', title: 'HTML Asset'});

Ui.prototype.initialize = function () {
    // create STYLE element
    var style = document.createElement('style');

    // append to head
    document.head.appendChild(style);
    style.innerHTML = this.css.resource || '';

    // Add the HTML
    this.div = document.createElement('div');
    this.div.classList.add('container');
    this.div.innerHTML = this.html.resource || '';

    // append to body
    // can be appended somewhere else
    // it is recommended to have some container element
    // to prevent iOS problems of overfloating elements off the screen
    document.body.appendChild(this.div);

    this.counter = 0;
    //添加事件
    this.bindEvents();
};
Ui.prototype.bindEvents = function() {
    var button = this.div.querySelector('.button'); //获取class
    var con = document.getElementById("button"); //获取Id
    var c = document.getElementById("Longitude").value; //获取输入框的值
    button.addEventListener('click', function() { //给Button添加事件

    });

};

物理引擎

启动物理功能,需要在setting中PHYSICE中下载。

创建地面物体

  • 添加Collision组件,并设置宽高
  • 添加RigidBody组件,并设置静态,物体则不是静态

添加力与脉冲

this.entity.rigidbody.applyForce(10, 0, 0);
this.entity.rigidbody.applyImpulse(10, 10, 0);

设置触发器

触发器添加Collision,不添加刚体。

TriggerVolume.prototype.initialize = function() {
    this.entity.collision.on('triggerenter', function (entity) {
        console.log(entity.name + ' has entered trigger volume.');
    });
    this.entity.collision.on('triggerleave', function (entity) {
        console.log(entity.name + ' has left trigger volume.');
    });
};

检测射线

var Raycast = pc.createScript('raycast');

// initialize code called once per entity
Raycast.prototype.initialize = function() {
    if (!this.entity.camera) {
        console.error('This script must be applied to an entity with a camera component.');
        return;
    }

    // Add a mousedown event handler
    this.app.mouse.on(pc.EVENT_MOUSEDOWN, this.mouseDown, this);

    // Add touch event only if touch is available
    if (this.app.touch) {
        this.app.touch.on(pc.EVENT_TOUCHSTART, this.touchStart, this);
    }
};

Raycast.prototype.mouseDown = function (e) {
    this.doRaycast(e.x, e.y);
};

Raycast.prototype.touchStart = function (e) {
    // Only perform the raycast if there is one finger on the screen
    if (e.touches.length === 1) {
        this.doRaycast(e.touches[0].x, e.touches[0].y);
    }
    e.event.preventDefault();
};

Raycast.prototype.doRaycast = function (screenX, screenY) {
    // The pc.Vec3 to raycast from (the position of the camera)
    var from = this.entity.getPosition();

    // The pc.Vec3 to raycast to (the click position projected onto the camera's far clip plane)
    var to = this.entity.camera.screenToWorld(screenX, screenY, this.entity.camera.farClip);

    // Raycast between the two points and return the closest hit result
    var result = this.app.systems.rigidbody.raycastFirst(from, to);

    // If there was a hit, store the entity
    if (result) {
        var hitEntity = result.entity;
        console.log('You selected ' + hitEntity.name);
    }    
};

批处理

  • 静批:将静态几何体组合到一个网格实例或多个大型实例中,以减少绘制调用,但仍支持摄影机剔除。

  • 动批:将动态几何图形组合到一个具有在GPU上应用的动态属性的网格实例中。

  • 创建批次组:在setting中的BatchGroups创建组。

    • Name:批次组的名字
    • Dynamic 动批启用,静批禁用。
    • MaxAABB 最大网格的尺寸
  • 在模型身上添加Batch Group

  • 合并批次的规则

    • 具有相同的批次组ID
    • 具有相同的材料
    • 具有相同的着色器参数
    • 放在边界框内,且边长不得超过最大AABB大小
    • 在同一层
    • 每批次的最大顶点数为65535
    • 对于动态批次,最大数量为可移动的网格实例。此硬件相关,但最大为1024

优化资源

  • jpg比png更优。
  • 降低图的质量,比如用512代替1024
  • 不要预加载可以异步加载的资产。
  • 天空盒生成后,原图可以删掉
  • 确保导入的模型仅具有所需的顶点属性。
  • 使用Chrome开发工具。
  • 用不到内置物理引擎就不要下载。

开启VR模式

  • setting中的Rendering 下开启Enable VR
  • 进入VR
  • 退出VR
  • 没有设备中打开VR窗口
  • 默认不会进入VR模式,需要按钮调用
    //进入VR
    this.entity.camera.enterVr(function (err)) {
    if (err) {
        console.error(err); // could not enter VR
    } else {
        // in VR!
    }
    });
    //退出VR
    this.entity.camera.exitVr(function (err) {
    if (err) {
        console.error(err); // could not exit VR
    } else {
        // not in VR!
    }
    });
    //开启VR窗口
    if (this.app.vr.display) {
    this.entity.camera.vrDisplay = this.app.vr.display;
    }

数据结构

Array

数组

var array = new Array(); //创建数组
array.push(1); //添加元素
array.splice(0,array.length);//清除元素
delete array[0]; //删除元素,但是这个元素占位还在
array.remove(1); //移除元素

Map

map类似C#中的Dictionary

var myMap = new Map(); 
myMap.set(GameManager.SweetsType.EMPTY,this.Stone);//添加
myMap.set(GameManager.SweetsType.NORMAL,this.Stone); 
console.log(myMap); //2个长度
myMap.get(GameManager.SweetsType.NORMAL); //获取this.Stone
myMap.delete(GameManager.SweetsType.NORMAL); //删除
console.log(myMap.size);//长度
myMap.clear(); //清除

随机

Math.floor(Math.random() *X); //随机0到x的数
Math.floor(Math.random() *X) + y; //随机y到x的数

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