微软目前的开源项目:

  • 代码编辑器Visual Studio Code, 基于github的开源项目electron
  • Edge浏览器的JS引擎Chakra, 甚至被允许用于node.js, 以替换V8.
  • ANGLE, OpenGL ES到DirectX的翻译器
  • HoloJS, 微软增强现实眼镜Hololens的开发库
  • WinJS, 是的, 你可以用WinJS+HTML+JavaScript开发win10的UWP软件, 哦, 不过这和electron有什么区别?

cocos creator集electron, node.js, vue.js, 浏览器对象, canvas, webGL于一身, 哦看起来还是很强大的.

结构

/assets 根目录下面主要编辑的文件都在这儿
/library, /temp 可以认为都是临时文件, 貌似为了加速编辑器某些处理产生的, 和assets里的资源是匹配关系, 如果匹配出了问题, 这些都删掉, creator会自动再次生成.
/local 编辑器布局, 一般情况下并没有什么用, 貌似删了也没有关系
/settings 构建发布等相关配置, 蛮重要的,要保留.
package.json 也规定了一些重要的信息, 要保留.

运行后还会生成很多.meta文件, 是一个资源文件对应一个.meta, 里面主要是资源文件的uuid和其他一些信息.

assets资源

所以, 主要的编辑工作都是在assets里面. 再说说assets, 文件可以包括:
.fire 场景文件, 规定了场景中各个内容, 也就是creator中层级管理器里面显示的那些东东. 其实是一个json文件.
.js 脚本文件, 当然了, 是JavaScript, 这个后面专门说一下

资源文件:
图片 包括.png, jpg等, 这个不消说, 是在场景中添加到精灵里面的;
粒子 以.plist结尾. plist和json文件作用相同, 只不过是xml形式的. 粒子文件的粒子图片可以是独立图片, 也可以是内嵌在plist中的base64数据.独立图片的话, 需要和plist放在一个目录中. cocos支持的粒子文件在windows上可以用Particle Editor编辑.
字体 可以使用ttf字体或者是位图字体.fnt, windows下使用BMFont制作, MAC下使用glyph designer制作. windows下的制作方法查看这儿

动画 动画目前就我所知, 有三种形式:

  1. 通过creator编辑的动画, 以.anim结尾, 实际上也是json文件. 这个应该和项目是紧密耦合的, 因为在文件里面规定了frame帧引用的资源是uuid形式的, 而uuid是在项目中生成的.
  2. spine骨骼动画 是使用spine软件制作的骨骼动画, 收费才能使用, 恩, 因此我也不知道这个文件是什么样子的.
  3. DragonBones骨骼动画 是使用DragonBones软件制作的骨骼动画, 常被称为龙骨动画, 免费开源, 但似乎以前cocos不支持, 现在貌似也支持的吧太好, 我下载了一个动画加入, 发现骨头缺了一块...不厚道地揣测, 也许是因为龙骨软件的开发商是Egret, 也就是另一个游戏引擎白鹭的开发方, 白鹭引擎貌似现在发展的也不错, 在知乎上还能看到两个引擎的拥护者对喷, 是由于这种竞争关系导致的支持不好吗? 龙骨动画包括三个文件, xxx_ske.json, xxx_tex.json, _tex.png. 在creator中, 将xxx_ske.json拖进层级管理器, 再把_tex.png拖到Dragon Atlas Asset中即可.
  4. 音乐等其他文件, 目前暂未涉及.

js脚本与nodejs和浏览器js异同

js脚本很大程度上结合了node.js和浏览器环境, 然而又有所不同.

目前发现与nodejs一致的有:

  • 可以使用node.js的require加载自定义在assets中的任何js模块.
  • js中定义的所有变量var ,function 都只能在本js文件中引用.
  • 要让require的方式暴露本模块中的变量, 同nodejs一样,需要通过module.exports的方式.
  • 可以使用ES2015语法, 如let, const, 箭头函数等

不一致的有:

  • 不能使用node.js自带的模块, 如fs, path等.

与浏览器环境一致的有:

  • 包含一个全局变量window, 向window.xxx赋值,可以在任一js中访问. window其实本来是BOM(浏览器对象模型)的一部分, 然而可以在这儿使用.

据说还可以使用npm install安装第三方纯js库使用, 尚未试过.
另外根据帮助文档, cocos creator的项目中也有一个类似于electron的index.html文件, 目前暂未开放出来提前修改.

js脚本运行方式

  • 事实上, 在assets目录中的js脚本, 会在游戏一开始加载的时候全部运行一遍, 运行的顺序似乎并没有什么规律. 如果要控制运行顺序参考这儿
  • 所以, 在js正文中所书写的内容都会被运行.
  • 通过require('js文件名')可以直接引用任意目录下的js 文件, 所以js文件就算在不同的目录下也不能同名.

js脚本与其他资源文件的关联

  • 所有的资源是以节点树的方式组织, 有点类似于DOM树, 节点树的在'层级管理器'中显示.
  • 在js文件中定义一个cc.Class, 就可以与其他资源节点关联, 每个js文件最多只能有一个cc.Class
  • 这时把js拖到资源节点的属性面板中, 在cc.Class的properties中定义的内容可以显示在面板上,
  • 如果将内容定义为内置的类型, 则可以将节点拖放到属性面板的该类型上, 在程序中可以对此节点进行引用. 如
cc.Class({
    extends: cc.Component,
    properties: {
        label: cc.Label,
        }
    },
    accessLabel: function(){
        // 访问 this.label
    }
}
  • 通过几个父子方法, 从本节点可以到达任意其他节点. 如果本节点不是一个node,要获取node后才能使用.
    this.label.node.parent //父节点
    this.label.node.children // 子节点的array
    this.label.node.parent.children // 父节点的子节点array. 由于父节点是node,所以可以直接使用node下的元素children
    this.label.node.getParent() === this.label.node.parent // true. 目前暂不清楚get方法与直接访问元素是否可能有什么区别.
    this.label.node.getChildern() === this.label.node.children //true
    this.label.node.getChildByName('childname') // 按名字查找 
  • 通过修改某个节点的父节点来改变这个节点的位置.
    this.label.node.parent = another.node

js脚本对任一资源引用

通过cc.find()方法, 可以从根节点到达任意子节点

cc.find('Canvas/Label') //返回Canvas下的Label节点.

js对某个节点的及其组件component的操作

  • 获取到某个节点后, 你就可以对节点下面的属性直接操作.
this.label.node.x = 123  // 其他在属性检查器中看得到的都可以这样操作
  • 要操作节点上的某个组件, 使用getComponent和addComponent
this.label.getComponent(cc.Widget).top  = 123 // getComponent可以传入一个cc类型
this.label.getComponent('js_file_name') //可以传入字符串, 获取节点上附加的脚本组件
this.label.addComponent(cc.Layout) //也可以通过addComponent添加组件
  • 使用new cc.Node()创建新的节点, 还可以通过cc.instantiate克隆一个节点.
var newNode = new cc.Node('newNodeName') 
var clonedNode = cc.instantiate(anExistedNode)
  • 使用destory()删除一个节点
    somenode.destory()

节点生命周期

  • 附加在节点上的js组件,可以获得节点的生命周期变更通知, 并通过回调函数进行操作.生命周期的顺序是:
    onLoad
    onEnable
    start
    update, lastUpdate 依次循环
    onDisable
    onDestroy

  • 对节点的active赋值true/false, 将触发onEnable/onDisable事件

somenode.active = false // onDisable
somenode.active = true // onEnable
  • 对节点调用onDestroy, 触发onDisable, onDestory事件
    somenode.destroy() // onDisable, onDestory
  • 节点destory以后, 可以用isValid判断是否被destory了. 恩, 我认为这个名称按照上面的active命名方式, 应该叫valid..., 要么需要把active改为isActive以表明其boolean身份.
somenode.isValid  //true
somenode.destroy()
somenode.isValid  //false
  • 需要注意的是, 节点生命随着scene的load开始, scene关闭结束. 节点(node)的生命周期和js本身的只执行一次不同, 请注意区分.

js与被附属节点的关联

  • 通过this可以获取到当前的js脚本组件, 通过this.node可以获取js脚本所附属的节点.
  • 由于properties和自定义function都是通过this来引用的, 所以, 在cc.Class中定义properties和function的时候要注意了, 这两者都不要起一些creator保留的名字, 列了一下, 这样的保留字还是很多的:
__cid__
__classname__
__eventTargets
__instanceId
__onNodeActivated
__preload
__scriptAsset
__scriptUuid
_deserialize
_destroyImmediate
_destruct
_enabled
_getLocalBounds
_id
_instantiate
_isOnLoadCalled
_name
_objFlags
_onPreDestroy
addComponent
constructor
destroy
enabled
enabledInHierarchy
getComponent
getComponentInChildren
getComponents
getComponentsInChildren
isRunning
lateUpdate
name
node
onEnable
onFocusInEditor
onLoad
onLostFocusInEditor
onRestore
playJump
playRun
resetInEditor
schedule
scheduleOnce
start
unschedule
unscheduleAllCallbacks
update
uuid

场景切换与固定部分节点

  • 加载另一个场景

    cc.director.loadScene('anotherScene', callSomeFunctionWhenLoaded)

  • 预加载另一个场景

    cc.director.preLoadScene('anotherScene', callSomeFunctionWhenPreloaded)

  • 保留一个场景中的节点到下一个场景.

    cc.game.addPersistRootNode('nodeName')

  • 取消保留节点

    cc.game.removePersistRootNode('nodeName')

排列节点树中的节点

  • 前面说过了, 把一个节点下挂到其他节点下,只需要继续改这个节点的parent属性就行了
somenode.parent = someNewParentNode
  • 然而, 与兄弟节点间的排序, 该怎么做呢? 可以用父节点的addChild()和removeChild(), 每次addChild()以后, 被增加的节点都会自动加到父节点树的最后面, 也就是场景的最顶端.
var pa = somenode.parent
pa.removeChild(somenode)
pa.addChild(somenode)  // 将somenode移动到了父节点树的最后面.

值得注意的是, 虽然可以用pa.children直接访问到children的array, 然而此array做pop/push/shift/unshift等操作, 似乎并不会对节点树有任何影响. 因此还是乖乖用addChild和removeChild吧!
* 还可以在本级使用setSiblingIndex(index), 可以调整自己在本级中的位置为index

somenode.getSiblingIndex() // 例如, 0, 是在最低端
somenode.setSiblingIndex(2) // 例如, 2, 上移两层.

发射和监听事件

  • 只能从节点上发送和监听事件
  • 通过在本节点上使用emit发射的事件, 只能被本节点接收到.
  • 通过在本节点上dispatchEvent发射的事件, 通过冒泡的方式逐层被上级节点接收到.

英文原文写得好,在这儿

这儿介绍使用nodejs的方式运行, 当然你要装好了nodejs.

以mac版为例, 打开sublime, 选择"Tools->Build System->New Build System...", sublime将打开一个"untitled.sublime-build"文件, 里面有一些json内容, 删掉这些内容, 替换为:

{
"cmd": ["node", "$file"],
"selector": "source.js"
}

保存文件, 取名为"node".
打开一个js文件, 按"command+B"(windows下是ctrl+B)试试, 看console界面有没有输出.
如果输出提示找不到node, 需要修改上面文件的地址为绝对路径.
在mac下打开终端, 输入

which node

我的mac上显示的是

/usr/local/bin/node

将显示node的绝对路径, 复制到上面的文件中, 修改为:

{
"cmd": ["/usr/local/bin/node", "$file"],
"selector": "source.js"
}

再试试!

以下在windows系统中测试过.
默认vim编辑完一个文件后, 要生成一个以~为结尾的备份文件.
不需要该文件, 则需要在用户的根目录如/user/name/下设置 _vimrc 文件.

加入

set nobackup

也可以指定一个其备份的地方:

set backupdir=D:/Program/ Files/Vim /tmp

有时,为了设计美观的关系, 需要字体留一定空隙, 使用css属性letter-spacing, 如下代码:

<div style="text-align: center;">
    <div style="font-size: 88px;color: #f7517f;">loading</div>
    <div style="font-size: 28px;letter-spacing:45px;color:#806d92">&#x5450;&#x558A;Pro</div>
</div>

显示效果如下:

loading
呐喊Pro

然而, 却会发现, 下面的文字和上面的没有letter-spacing的文字对不齐.
用鼠标选择下面的文字, 你会发现letter-spacing的45px空间是加在每一个字符后面的, 这样字符都会靠左一点点.
怎么解决呢? 有的网友建议在前面加空格, 当然是转义的空格了:

&nbsp;

代码改为:

<div style="text-align: center;">
    <div style="font-size: 88px;color: #f7517f;">loading</div>
    <div style="font-size: 28px;letter-spacing:45px;color:#806d92">&nbsp;&#x5450;&#x558A;Pro</div>
</div>

显示效果如下:

loading
 呐喊Pro

然而加上空格你又会发现,由于空格还是占用了空间, 整体字符又会靠右一点点...

css的问题还是要回到css的方法上解决, 正确的姿势之一是增加text-indent, 如下:

<div style="text-align: center;">
    <div style="font-size: 88px;color: #f7517f;">loading</div>
    <div style="font-size: 28px;letter-spacing:45px;text-indent: 45px;color:#806d92">&#x5450;&#x558A;Pro</div>
</div>

显示效果如下:

loading
呐喊Pro

除了text-indent方案以外,应该还可以使用padding-left. 不过, 能在text的css属性内解决的, 就不要放到box的属性去解决, 所以text-indent的方式要更优雅一些吧

  • 正常情况下的一个function
    写法一

    f = function(){}

或者写法二

function f(){}
  • 为new以后的新对象提供属性的function
function F(){this.x = 1; this.obj_f = function(){}}
var o = new F()
o.x
o.obj_f()
  • 为所有new以后的新对象提供公共属性的function

写法1

function F(){F.prototype.pub_x = 1; F.prototype.pub_f = function(){} }
var o1 = new F()
var o2 = new F()
o1.pub_x === o2.pub_x
o1.pub_f === o2.pub_f

写法2

function F(){}
F.prototype = {pub_x : 1, pub_f : function(){} }
var o1 = new F()
var o2 = new F()
o1.pub_x === o2.pub_x
o1.pub_f === o2.pub_f
  • 不需要new直接使用的function
function F(){}
F.F_pub_f = function(){}
  • 综上所述的F, 自己既是一个function, 又是一个object, 又能给别人new. 可以为new的对象提供单独的属性, 公共的属性, 以及不需要new也能使用的属性.
function F(){} //F是一个函数
function F(){this.x = 1; this.obj_f = function(){}}  //F可以给别人new了. 提供单独的属性x, obj_f. 如 var f = new F()
F.prototype = {pub_x : 1, pub_f : function(){} }  // F可以给new出来的对象提供公共的属性pub_x, pub_f
F.F_pub_x = 1
F.F_pub_f = function(){}  //不需要new也能直接访问的F的属性F_pub_x, F_pub_f.

获取dom元素的实际宽高,而不是style里面设置的宽高, 使用offsetWidth/offsetHeight.例如:

<div id="element">test</div>
<script>
console.log(element.offsetWidth, element.offsetHeight)
</script>

首先安装android studio
下载安卓的几个插件包,sdk,ndk等等.
被Wall了? 找个hosts. 我发现223.255.227.170作为developer.android.com, 74.125.28.121作为tools.android.com似乎速度还不错.
最后的ant属于单独安装的. 里面的ant.cmd在编译时需要用到.

我都是默认安装, 几个系统环境变量如下

NDK_ROOT
C:\Users\Jac\AppData\Local\Android\Sdk\ndk-bundle\

ANDROID_SDK_ROOT
C:\Users\Jac\AppData\Local\Android\Sdk

ANT_ROOT
C:\r\apache-ant-1.9.7-bin\apache-ant-1.9.7\bin

今天打算修改一下hosts文件, 却发现文件不能修改. 上网查一下windows可否知道哪个进程锁定了文件? 貌似并没有方法. 需要借助其他软件.

  • 首先用下载 unlocker
    用unlocker看了一下,并没有什么锁定它.

  • 关掉所有的软件.只保留一个administrator权限的cmd窗口.

  • cmd下使用ren命令重命名hosts,发现可以, 然而很快就被某个进程创建一个新的hosts文件, 里面只有一句话:

    192.168.0.143 windows10.microdone.cn

这是什么鬼?
这首先说明了, 创建这个的不是windows的系统行为.因为微软就算升级了系统要锁定hosts也不可能指向一个莫名其妙的.cn地址.
那么问题来了, 到底是哪个进程创建了hosts?

解压缩打开procmon.exe后, 创建filter, 先通过下拉菜单选择event class is File System ,再选择 operation is CreateFile

确定后, 在输出的窗口搜索hosts, 发现一个可疑的对象UPService.exe

中毒了? 搜索发现这个对象是银联的软件... 我用银联吗? 不用, 删掉它!

然后发现hosts已经不会被自动创建了.

改好hosts, 用attrib +R hosts 先给加个只读属性, 以防哪个家伙修改. 当然这个级别的保护还是比较低的. 要升高保护, 可以再加上+S属性, 以及设定访问权限.

根据gamelook文章VR眼镜盒月出货超2000万,单台利润仅1毛,以及其他一些VR发展的历史事件, 猜测VR发展已过了The chasm裂口.

技术成熟度曲线和技术采纳周期

  • 2012年-2014年, Innovator阶段,如果这次VR技术的发展, 以2012年Oculus成立和众筹作为起点的话, 那么2014年7月, Oculus以20亿美元卖给Facebook, 同年谷歌发布VR盒子原型Cardboard, 暴风魔镜以及一批VR创业公司集中进入VR盒子开发领域, 意味着2014年到达VR发展的超高期望顶点(Peak Of Infacted Expectation)

  • 2014-2016年初, Early Adapters阶段, 同时也是裂口阶段The Chasm. 正如gamelook文章中所言: "2014年团队是淌着血过来的,每月尽亏80万", 而到了"去年(2015年)12月以后,销量开始往上蹭蹭地涨". 暴风的VR团队在今年也爆出大幅裁员的新闻.

  • 2016-今后3-5年, Early Majority阶段, 除了上述的VR盒子销量暴涨外, HTC Vive于2016年4月上市, 6月北美上市. HTC同时携steam带来超过100款游戏作品. HTC之后, Oculus有些乱了手脚, 先发后至, 发货之间到了5-8月之间. SONY PSVR以及适配PSVR的"PS4.5"版本PS4 Pro也同期发布, 同期上线30余款游戏. 由于VR设备昂贵, 深圳地区出现多家Vive体验中心, 多为初创公司创建.

参考文章:
* VR眼镜盒月出货超2000万,单台利润仅1毛
* Technology Adoption Cycles

快速迭代,快速试错似乎成为敏捷思想带给葫芦娃啊不互联网经济的灵丹妙药,经典图式常常拿一张蒙娜丽莎的画举例,你不应该做的是:画面分成五块,每一块填完色才画下一块;你应该先快速勾一个蒙娜丽莎的轮廓,哪怕很丑,但能立刻让别人知道你画的是什么,然后再修轮廓,描细线,画背景,最后上色。

敏捷不推荐的画法

敏捷推荐的画法

如果上面的图破了, 在bing.com搜索mona lisa agile

然而这不是万能的。这适用于做一些功能性应用,并且有一些创新的核心点需要快速早期验证的情况。但这不适合做艺术品,比如蒙娜丽莎。因为达芬奇不可能希望拿一个只描了轮廓丑不拉几的画作给世人看,更不可能问世人这么画对不对你喜不喜欢不喜欢我另画?你画这样我能喜欢吗?
对于另一些需要按时间依次浏览的艺术形式,如长篇小说,电视剧,和章节式游戏,有时可以先试试大家的兴趣。然而,发一个粗制滥造的框架或者只是讲述一下提纲,并不能说明你这是个好作品。而是应该一部分一部分的去向读者和观众呈现一个精雕细琢的作品,正如敏捷方法一开始所反对的那样。观众看完一部分,反馈的意见有用吗,或许有,但有时并不那么重要。极端情况,也许像中国网络小说最赚钱作者唐家三少所说,故事我一开始就想好了,读者的意见并不能改变我。