分类 未分类 下的文章
如果是真的,国内原创音乐令人惊讶
试听win10上的网易云音乐的轻音乐, 发现即便是自动推荐的, 也有很多蛮好听的曲子. 去看了一下作曲者, 竟然很多是国内的原创音乐人. 比如这个: 饭碗的彼岸, 就有好几首好听的曲子《小河》《小樱》。
感觉真是高手在民间啊。
java的交互式命令环境(REPL)
java8及其以前是不支持交互式命令环境REPL的.
Java9 将引入一个JShell来支持. 但目前Java9还没有推出, 怎么办呢? 有一个github的项目, 支持java的REPL
使用前, 需要安装JDK(不是JRE), 以及gradle. 下面是命令行中的安装方法
git clone https://github.com/albertlatacz/java-repl.git
cd java-repl
gradle shadowJar
cd build/libs
java -jar javarepl-dev.jar
需要注意的是,gradle这一步需要执行数分钟, 我的电脑上是8分多钟.
java运行这一步, 需要是类似于jdk1.8.0_111/bin/java这样的目录
cocos creator 音频部分控制
由于当前cocos creator音频部分的文档还没有, 这儿简单介绍一下音频部分.
- 普通的音频的组件是cc.AudioSource, 可以附加在一个node节点上, 同时只能播放一个音频, 添加组件后, 需要将音频拖放到Clip一栏里面(属性为audio-clip).
组件可以进行的操作包括播放/暂停/停止/继续
audioSource.play()
audioSource.pause()
audioSource.stop()
audioSource.resume()
可以获取播放进度和总长度
audioSource.getCurrentTime() //单位为秒的浮点数
audioSource.getDuration() //同样是单位为秒的浮点数
从属性浏览器中可以发现还有如下属性:
clip
volume
mute
loop
playOnLoad
preload
- 使用音频引擎
引擎是一个cc下的对象cc.audioEngine来操作的.
引擎并不需要去操作一个node对象, 而是直接操作一个资源管理器里面的源文件.所以在定义cc.Class的时候与audioSource不同. 以url的方式定义, 音乐文件(很可能)需要放在resources目录中.
// 在操作audioSource的AudioSourceControl.js文件中, 定义属性为cc.AudioSource类型. 然后, 从资源管理器中拖动一个音乐文件到audiosource节点的clip上. 再从层级管理器中拖动audiosource节点到另一个节点的AudioSourceControl.js属性的audioSource上
cc.Class({
properties: {
audioSource: {
type: cc.AudioSource,
default: null
},
// 省略其他代码
})
// 在操作audioEngine的AudioEngineControl.js文件中, 定义**url**为cc.AudioClip类型. 然后, 从资源管理器中拖动一个音乐文件到使用此AudioEngineControl.js的节点的audio属性上.
// 从示例代码中来看, 这个文件是放在resources目录中的,也就是说, 需要动态加载的.
cc.Class({
properties: {
audio: {
url: cc.AudioClip,
default: null
},
// 省略其他代码
})
使用引擎播放, 每次会产生一个audio id, 记住这个id, 用来在后面对该播放中的音乐进行操作.
// 播放,暂停,继续, 停止
var id = cc.audioEngine.play(this.audio, false, 1); //参数分别为filepath, loop, volume. filepath示例为res/raw-assets/resources/audio/music_logo.mp3, 如果是拖进来的就不用管这个了.
cc.audioEngine.pause(id)
cc.audioEngine.resume(id)
cc.audioEngine.stop(id)
对所有的播放中音乐统一操作:
cc.audioEngine.stopAll();
cc.audioEngine.pauseAll();
cc.audioEngine.resumeAll();
获取各种状态
cc.audioEngine.getCurrentTime(id) // 秒数, 有对应set方法
cc.audioEngine.getDuration(id) // 秒数
cc.audioEngine.getStatus(id) // 返回值-1: 停止状态, 1: 播放状态, 2: 暂停状态.
cc.audioEngine.getVolume(id) // 有对应set方法
- 下面放出cocos creator的示例代码, 先是AudioSourceControl
cc.Class({
extends: cc.Component,
properties: {
audioSource: {
type: cc.AudioSource,
default: null
},
label: {
type: cc.Label,
default: null
}
},
// use this for initialization
onLoad: function () {
// cc.audioEngine.setMaxWebAudioSize(1024*10);
},
update: function () {
if (!this.label) {
return;
}
var audio = this.audioSource;
this.label.string = audio.getCurrentTime().toFixed(1) + ' s / ' + audio.getDuration().toFixed(1) + ' s';
},
play: function () {
this.audioSource.play();
},
pause: function () {
this.audioSource.pause();
},
stop: function () {
this.audioSource.stop();
},
resume: function () {
this.audioSource.resume();
}
});
- 再是audioEngineControl
cc.Class({
extends: cc.Component,
properties: {
audio: {
url: cc.AudioClip,
default: null
},
label: {
type: cc.Label,
default: null
}
},
onLoad: function () {
this.maxNum = cc.audioEngine.getMaxAudioInstance();
this.audioPool = [];
// check deprecated
['playMusic', 'playEffect'].forEach(function (name) {
if (!cc.audioEngine[name]) {
cc.warn('.' + name + ' is not found!');
}
});
},
update: function () {
if (!this.label) return;
for (var i=0; i<this.audioPool.length; i++) {
var id = this.audioPool[i];
var state = cc.audioEngine.getState(id);
if (state < 0) {
this.audioPool.splice(i, 1);
i--;
}
}
this.label.string = 'Instance: ' + this.audioPool.length + ' / ' + this.maxNum;
},
play: function () {
if (!this.audio) return;
var id = cc.audioEngine.play(this.audio, false, 1);
this.audioPool.push(id);
},
stopAll: function () {
if (!this.audio) return;
cc.audioEngine.stopAll();
},
pauseAll: function () {
if (!this.audio) return;
cc.audioEngine.pauseAll();
},
resumeAll: function () {
if (!this.audio) return;
cc.audioEngine.resumeAll();
},
});
微软拥抱开源?!
微软目前的开源项目:
- 代码编辑器Visual Studio Code, 基于github的开源项目electron
- Edge浏览器的JS引擎Chakra, 甚至被允许用于node.js, 以替换V8.
- ANGLE, OpenGL ES到DirectX的翻译器
- HoloJS, 微软增强现实眼镜Hololens的开发库
- WinJS, 是的, 你可以用WinJS+HTML+JavaScript开发win10的UWP软件, 哦, 不过这和electron有什么区别?
关于this和箭头函数
箭头函数里使用的this不是它自己的this, 是上层环境的this. 默认情况下, 是window.
cocos creator学习浅谈
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下的制作方法查看这儿
动画 动画目前就我所知, 有三种形式:
- 通过creator编辑的动画, 以.anim结尾, 实际上也是json文件. 这个应该和项目是紧密耦合的, 因为在文件里面规定了frame帧引用的资源是uuid形式的, 而uuid是在项目中生成的.
- spine骨骼动画 是使用spine软件制作的骨骼动画, 收费才能使用, 恩, 因此我也不知道这个文件是什么样子的.
- DragonBones骨骼动画 是使用DragonBones软件制作的骨骼动画, 常被称为龙骨动画, 免费开源, 但似乎以前cocos不支持, 现在貌似也支持的吧太好, 我下载了一个动画加入, 发现骨头缺了一块...不厚道地揣测, 也许是因为龙骨软件的开发商是Egret, 也就是另一个游戏引擎白鹭的开发方, 白鹭引擎貌似现在发展的也不错, 在知乎上还能看到两个引擎的拥护者对喷, 是由于这种竞争关系导致的支持不好吗? 龙骨动画包括三个文件, xxx_ske.json, xxx_tex.json, _tex.png. 在creator中, 将xxx_ske.json拖进层级管理器, 再把_tex.png拖到Dragon Atlas Asset中即可.
- 音乐等其他文件, 目前暂未涉及.
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发射的事件, 通过冒泡的方式逐层被上级节点接收到.
sublime3中运行JavaScript
这儿介绍使用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"
}
再试试!
如何让vim不生成备份文件
以下在windows系统中测试过.
默认vim编辑完一个文件后, 要生成一个以~为结尾的备份文件.
不需要该文件, 则需要在用户的根目录如/user/name/下设置 _vimrc 文件.
加入
set nobackup
也可以指定一个其备份的地方:
set backupdir=D:/Program/ Files/Vim /tmp
safari怎么进入类似chrome的模拟手机显示模式?
Safari需要先打开开发菜单,然后在开发菜单里面选择"Responsive Design Mode".
letter-spacing文字不居中的问题的解决方式
有时,为了设计美观的关系, 需要字体留一定空隙, 使用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">呐喊Pro</div>
</div>
显示效果如下:
然而, 却会发现, 下面的文字和上面的没有letter-spacing的文字对不齐.
用鼠标选择下面的文字, 你会发现letter-spacing的45px空间是加在每一个字符后面的, 这样字符都会靠左一点点.
怎么解决呢? 有的网友建议在前面加空格, 当然是转义的空格了:
代码改为:
<div style="text-align: center;">
<div style="font-size: 88px;color: #f7517f;">loading</div>
<div style="font-size: 28px;letter-spacing:45px;color:#806d92"> 呐喊Pro</div>
</div>
显示效果如下:
然而加上空格你又会发现,由于空格还是占用了空间, 整体字符又会靠右一点点...
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">呐喊Pro</div>
</div>
显示效果如下:
除了text-indent方案以外,应该还可以使用padding-left. 不过, 能在text的css属性内解决的, 就不要放到box的属性去解决, 所以text-indent的方式要更优雅一些吧
在nginx中限速以测试网络不好的时候的网页表现
打开"nginx根目录/conf/nginx.conf"配置文件修改如下:
http{
……
limit_zone one $binary_remote_addr 10m;
……
server {
location / {
……
limit_conn one 2;
limit_rate 40k;
}
}
}
JS类,对象,function...
正常情况下的一个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.
如何将HTML转为图片下载?
可能会有这么几个方案:
如何获取dom元素的实际宽高?
获取dom元素的实际宽高,而不是style里面设置的宽高, 使用offsetWidth/offsetHeight.例如:
<div id="element">test</div>
<script>
console.log(element.offsetWidth, element.offsetHeight)
</script>