技术标签: cocos-creator CocosCreator javascript
作用:设置一个定时器,在指定时间(毫秒)后触发,调用传入的回调函数。
参数类型:(function/code, delayTime, args…)
function: 回调函数
code: 字符串形式的代码,会使用eval()执行,因此不推荐使用
delayTime: (可选) 延迟的时间(毫秒),默认0,尽快执行。
args: (可选) 不定长参数列表,会传递给回调函数
作用:设置一个定时器,每隔一段时间触发一次,调用传入的回调函数。
参数类型:(function/code, delayTime, args…)
和sertTimeout一致,区别是setInterval会一直执行回调函数,但setTimeout**仅执行一次。**delayTime就是每次间隔的时间。
// UserInfoView.js
cc.Class({
extends: cc.Component,
ctor () {
// 定义测试变量
this.testInfo = 222;
},
start () {
// 1. 箭头函数
setTimeout(() => {
// do something
}, 10000);
// 2. bind方式
setTimeout(function() {
// do something
cc.log(this); // 指向当前组件 UserInfoView{xxxxx}
cc.log(this.testInfo); // 222
}.bind(this), 1000);
// 3. 直接传递
setTimeout(function() {
// do something
cc.log(this); // 指向Window对象
cc.log(this.testInfo); // undefined
}, 1000);
}
作用:结合了setTimeout和setInterval,如官方文档所说,提供了更大的灵活性,可以设置执行次数、第一次的延迟以及触发间隔时间。注:该方法定义于cc.Component,故只能在继承cc.Component的对象上调用(从编辑器创建的js类会默认继承cc.Component)。
参数列表:(callback, interval, repeat, delay)
callback: 回调函数
interval: 触发间隔(秒)
repeat: 重复次数,可设置cc.macro.REPEAT_FOREVER让它一直重复。注:实际执行次数是重复次数+1
delay: 延迟时间(秒)
// CCComponent.js cocos2d\core\components\CCComponent.js
schedule (callback, interval, repeat, delay) {
// 1619: callback function must be non-null 回调函数不能为空
cc.assertID(callback, 1619);
// 默认触发间隔为0
interval = interval || 0;
// 1620:interval must be positive 间隔必须是有效的(>=0)
cc.assertID(interval >= 0, 1620);
// repeat不是数字时, 默认为无限重复
repeat = isNaN(repeat) ? cc.macro.REPEAT_FOREVER : repeat;
// 默认延迟时间为0
delay = delay || 0;
// 获得获取系统定时器(是唯一的,cc.director是单例的,在init方法中创建了一个Scheduler定时器)
// scheduler: cc.Scheduler类型 定义于engine/cocos2d/core/CCScheduler.js
var scheduler = cc.director.getScheduler();
// scheduler内部维护了一个叫_hashForTimers的键值对,通过传入的this可以获得一个HashTimerEntry对象(定义于CCScheduler)
// HashTimerEntry中保存了paused属性(boolean),当组件_onDisabled/_onEnabled时,paused会被设置为true/false
// 也有可能是_hashForUpdates。_hashForTimers保存的是自定义定时器的信息,_hashForUpdates保存的是update定时器的信息
var paused = scheduler.isTargetPaused(this);
// 调用CCScheduler中的方法,这里传递的target为this,所以回调函数不需要bind/使用箭头函数
scheduler.schedule(callback, this, interval, repeat, delay, paused);
}
// CCScheduler.js cocos2d\core\CCScheduler.js
schedule: function (callback, target, interval, repeat, delay, paused) {
'use strict';
if (typeof callback !== 'function') {
// 交换callback和target的值
var tmp = callback;
callback = target;
target = tmp;
}
// 适配不同参数长度
//selector, target, interval, repeat, delay, paused
//selector, target, interval, paused
if (arguments.length === 4 || arguments.length === 5) {
paused = !!repeat;
repeat = cc.macro.REPEAT_FOREVER;
delay = 0;
}
// 1502:cc.scheduler.scheduleCallbackForTarget(): target should be non-null. target不能为空
cc.assertID(target, 1502);
// 获得组件的id
var targetId = target._id;
if (!targetId) {
if (target.__instanceId) {
// 1513:cc.Scheduler: scheduler stopped using `__instanceId` as id since v2.0, you should do scheduler.enableForTarget(target) before all scheduler API usage on target
// 提示2.0版本后不再使用__instanceId属性 这里应该是为了保持兼容
cc.warnID(1513);
targetId = target._id = target.__instanceId;
}
else {
// 1510:cc.Scheduler: Illegal target which doesn't have uuid or instanceId.
// target非法,没有uuid和instanceId
cc.errorID(1510);
}
}
// 通过targetId获得对应的定时器实例(HashTimerEntry),有点拗口的感觉,里面保存了timers target paused等属性
var element = this._hashForTimers[targetId];
if (!element) {
// 没有取到实例 使用get方法从对象池(_hashTimerEntries)中获得一个实例
// Is this the 1st element ? Then set the pause level to all the callback_fns of this target
element = HashTimerEntry.get(null, target, 0, null, null, paused);
this._arrayForTimers.push(element);
this._hashForTimers[targetId] = element;
} else if (element.paused !== paused) {
// 1511:cc.Scheduler: pause state of the scheduled task doesn't match the element pause state in Scheduler, the given paused state will be ignored.
// 定时器实例中的paused属性和传入的paused不匹配,传入的值会被忽略(可能在创建的过程中,组件disable/enable状态改变了)
cc.warnID(1511);
}
var timer, i;
// 定时器列表(timers)为空 初始化为空数组
if (element.timers == null) {
element.timers = [];
}
else {
// 遍历列表 判断是否有相同的回调函数
for (i = 0; i < element.timers.length; ++i) {
timer = element.timers[i];
if (timer && callback === timer._callback) {
// 1507:CCScheduler#scheduleSelector. Selector already scheduled. Updating interval from: %s to %s"
// 回调已存在,将更新interval属性
cc.logID(1507, timer.getInterval(), interval);
timer._interval = interval;
return;
}
}
}
// 获得一个定时器实例(CallbackTimer),这里也有一个对象池(_timers)
timer = CallbackTimer.get();
// 初始化 里面的代码基本类似 _callback = callback 这样的赋值
timer.initWithCallback(this, callback, target, interval, repeat, delay);
// 加到定时器列表中
element.timers.push(timer);
// 修改_currentTargetSalvaged防止当前的HashTimerEntry被删除 这个在update函数中会有相关解释
if (this._currentTarget === element && this._currentTargetSalvaged) {
this._currentTargetSalvaged = false;
}
}
以上就是创建计时器的代码,感觉许多代码量都在做一些验证、兼容之类的操作,最后创建计时器相关对象储存起来,而触发回调的代码则是在update函数中
// scheduler的update函数在cc.director.mainLoop()中触发
// CCDirector.js cocos2d\core\CCDirector.js
this._scheduler.update(this._deltaTime);
// 而director的mainLoop函数在cc.game._runMainLoop()中触发
// CCGame.js cocos2d\core\CCGame.js
_runMainLoop: function () {
// 省略部分代码
callback = function (now) {
if (!self._paused) {
self._intervalId = window.requestAnimFrame(callback);
if (!CC_JSB && !CC_RUNTIME && frameRate === 30) {
if (skip = !skip) {
return;
}
}
// 在这~
director.mainLoop(now);
}
};
// 使用requestAnimFrame设置一个每帧触发的回调,会在下一次的重绘之前被调用,一般来说60次/秒。
// 详情可参考MDN文档https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestAnimationFrame
self._intervalId = window.requestAnimFrame(callback);
self._paused = false;
}
// CCScheduler.js cocos2d\core\CCScheduler.js
/**
* !#en 'update' the scheduler. (You should NEVER call this method, unless you know what you are doing.)
* !#zh update 调度函数。(不应该直接调用这个方法,除非完全了解这么做的结果)
* @method update
* @param {Number} dt delta time
*/
update: function (dt) {
// boolean属性 加锁 避免执行update定时器过程中出现删除操作
this._updateHashLocked = true;
// 时间缩放 可以实现慢/快动作
if(this._timeScale !== 1)
dt *= this._timeScale;
var i, list, len, entry;
// 此处省略触发update定时器的代码
// Iterate over all the custom selectors
// 遍历自定义定时器
var elt, arr = this._arrayForTimers;
for(i=0; i<arr.length; i++){
elt = arr[i];
this._currentTarget = elt;
this._currentTargetSalvaged = false;
// 目标没有被停止则执行
if (!elt.paused){
// The 'timers' array may change while inside this loop
// 遍历定时器列表。列表有可能在循环过程中被改变(repeat次数执行完了)
for (elt.timerIndex = 0; elt.timerIndex < elt.timers.length; ++(elt.timerIndex)){
elt.currentTimer = elt.timers[elt.timerIndex];
elt.currentTimerSalvaged = false;
// 调用定时器的update函数
elt.currentTimer.update(dt);
elt.currentTimer = null;
}
}
// only delete currentTarget if no actions were scheduled during the cycle (issue #481)
// _currentTargetSalvaged在上面被设为false,但仍有可能在update函数执行后被改变(repeat次数执行完了)
// 但是不会直接回收,而是通过设置_currentTargetSalvaged,在这里统一回收。(避免了重复回收?)
if (this._currentTargetSalvaged && this._currentTarget.timers.length === 0) {
this._removeHashElement(this._currentTarget);
--i;
}
}
// 此处省略清理update定时器的代码
// 解除锁
this._updateHashLocked = false;
this._currentTarget = null;
}
// CallbackTimer 定义于cocos2d\core\CCScheduler.js
/**
* triggers the timer
* @param {Number} dt delta time
*/
proto.update = function (dt) {
// _elapsed: boolean 离上一次触发的事件 调用CallbackTimer.initWithCallback()的时候会被设为-1
if (this._elapsed === -1) {
// 第一次触发的时候 重置_elapsed和_timesExecuted,(所以定时器是在下一帧开始才正式生效的?)
this._elapsed = 0;
this._timesExecuted = 0;
} else {
// 累加_elapsed 实现delay和interval的效果
this._elapsed += dt;
// 当前计时器是一直循环的且不需要延迟
if (this._runForever && !this._useDelay) {
//standard timer usage
// 标准触发流程
// _elapsed达到interval间隔时间,触发事件,重置_elapsed
if (this._elapsed >= this._interval) {
this.trigger();
this._elapsed = 0;
}
} else {
//advanced usage
// 高级用法(?)
if (this._useDelay) {
// 需要延迟 达到延迟时间的时候触发
if (this._elapsed >= this._delay) {
this.trigger();
// 扣除延迟的时间、已执行次数+1、重置延迟状态为false
this._elapsed -= this._delay;
this._timesExecuted += 1;
this._useDelay = false;
}
} else {
// 不需要延迟(或延迟已经触发过了) 达到间隔时间触发
if (this._elapsed >= this._interval) {
this.trigger();
// 重置_elapsed、已执行次数+1
this._elapsed = 0;
this._timesExecuted += 1;
}
}
// 设置了repeat次数的定时器,执行次数大于_repeat次数的时候 取消这个定时器
// 这就是上面的update中提到的定时器列表有可能被改变
if (this._callback && !this._runForever && this._timesExecuted > this._repeat)
this.cancel();
}
}
};
// 触发回调
proto.trigger = function () {
if (this._target && this._callback) {
// 加锁 放回对象池中的时候会判断_lock是否为true
this._lock = true;
// 调用回调函数
this._callback.call(this._target, this._elapsed);
this._lock = false;
}
};
start () {
this.testInfo = 222;
this.schedule((dt)=>{
// 每0.1s执行一次
cc.log("回调1", dt);
}, 0.1);
this.schedule((dt)=>{
// 每0.1s执行一次,重复一次(总共执行两次)
cc.log("回调2", dt);
}, 0.1, 1);
this.schedule((dt)=>{
// 每0.1s执行一次,不重复,延迟0.2秒后触发
cc.log("回调3", dt);
cc.log("测试this", this.testInfo);
}, 0.1, 0, 0.2);
this.schedule((dt)=>{
// 0.5s后触发,测试active对计时器的影响
cc.log("回调4", dt);
this.node.active = false;
}, 0.5);
}
// 输出1
// 回调1 0.10002300000000003
// 回调2 0.10002300000000003
// 回调1 0.10004099999999994
// 回调2 0.10004099999999994
// 回调3 0.200064
// 测试this 222
// 回调1 0.11671000000000005
// 回调1 0.10003199999999993
// 回调4 0.5000120000000001
// 输出2
// 回调1 0.10002899999999999
// 回调2 0.10002899999999999
// 回调3 0.20002500000000004
// 测试this 222
// 回调1 0.11670800000000003
// 回调2 0.11670800000000003
// 回调1 0.116745
// 回调1 0.11657899999999996
// 回调4 0.5001940000000001
秋招挺凄惨的,想去的都挂了。主要原因还是自己以前对基础知识不够重视,这个结局算是还债吧。
因为一些原因,开始复习的也比较晚。复(yu)习的时候就想顺便写点东西记录一下。
文章是真的难写啊淦(x 很怕写错。
应该是第一次相对深入的读cocos creator的源码,还挺有意思的。但是毕竟还是小菜鸡,有纰漏还望大家多多包涵2333。
文章浏览阅读1.1k次。<el-input size="small" @keyup.enter.native="handleInputConfirm"></el-input>_el-input上使用键盘事件.native被废弃了
文章浏览阅读94次。Structured Query Language:结构化查询语言数据库的注释:单行注释:-- 注释内容 #注释内容(mysql特有)多行注释:/* 注释内容 */1、DDL(Data Definition Language)数据定义语言数据库,表,列等。关键字:create, drop,alter 等create database-- 查询所有数据库show database;-- 查询某个数据库的创建语句show create database databa_"7.sql 语句\"show database like “%name’\",能显示出 数据库。"
文章浏览阅读166次。参考博客1参考博客21、Integer和int的区别Integer是int的包装类,int是八大基本数据类型之一Integer是类,默认值为null,int默认值为0Integer 表示的是对象,用一个引用指向这个对象,而int是基本数据类型,直接存储数值2 、Integer的自动拆箱和装箱自动拆箱和装箱是jdk1.5之后的功能装箱就是由基本数据类型封装成类的过程,拆箱反之。装箱:正常创建类的对象是new一个出来,但是Integer类可以直接Integer a=11;通过反编_integer -1
文章浏览阅读6.4k次,点赞5次,收藏20次。文章目录前言一、确定思路二、书写代码1.HTML部分2.CSS部分3.JS部分(重点)3.1.点击选择图片按钮,调用input文件框事件的的代码3.2.转换格式3.3.发送图片给后端前言在网站中,上传图片这个功能,这个还是挺常见的。比如说:在填写信息中,上传头像中。提示:以下是本篇文章正文内容,下面案例可供参考一、确定思路整个功能,大致可以分为三个步骤。点击选择图片的按钮,从本地选择一张图片。(选图片)选择好之后,会进行预览。就好比自己微信要换头像,选择好之后,都会有预览的步骤。(预_input上传图片并预览
文章浏览阅读530次。网络空间安全学院2020年硕士研究生招生复试调剂公告一、学院简况网络空间安全学院前身为2004年成立的网络工程系,2008年更名为网络工程学院,2013年更名为信息安全工程学院,2017年改为现名。学院建有新一代密码技术与系统安全四川省重点实验室(筹)、网络空间安全四川省高校重点实验室、成都市信息安全保密重点实验室和成都商用密码技术研究院;设有信息安全、信息对抗技术、网络工程、物联网工程四个本科专..._成都有计算机专业调剂的研究生
文章浏览阅读470次。1、建议先更新列表sudo apt-get update2、安装MySQL-Workbenchsudo apt-get install mysql-workbench中间提示“您希望继续执行吗”,输入y,按回车继续3、安装成功,输入以下代码查看,可以看到已安装的相关服务及版本。dpkg -l|grep mysql-workbench5、在搜索栏找到已安装的mysql-wor..._ubantu mysql 可视化
文章浏览阅读375次。本题目要求计算下列分段函数f(x)的值:输入格式:输入在一行中给出实数x。输出格式:在一行中按“f(x) = result”的格式输出,其中x与result都保留一位小数。输入样例1:10输出样例1:f(10.0) = 0.1输入样例2:0输出样例2:f(0.0) = 0.0代码:import java.util.Scanner;public class Main { public static void main(S._7-3 计算分段函数[1]
文章浏览阅读928次,点赞3次,收藏7次。为了更好的学习scrapy库,我决定先其前驱内容lxml库此次我们爬取豆瓣电影Top250代码如下:import requests from lxml import etreeimport timeimport csvheaders={ 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/53..._importrequestsfromlxmlimportetree headers={"user-agent":"mozilla/5.0 (wi
文章浏览阅读1.6k次。1.为什么要使用promise/*需求:异步的按顺序去读取1.txt、2.txt、3.txt文件的内容假设 1.txt内容为111 、2.txt内容为222、3.txt内容为333*/var fs = require('fs');、 fs.readFile('./files/1.txt','utf8',function(err,data){ if(err){ ..._nodejs new promise
文章浏览阅读740次。开发工具(eclipse/idea/vscode等):数据库(sqlite/mysql/sqlserver等):功能模块(请用文字描述,至少200字):_基于ssm框架的妙橙水果屋的设计与实现
文章浏览阅读1.5k次,点赞2次,收藏2次。boost::function的用法本片文章主要介绍boost::function的用法。 boost::function 就是一个函数的包装器(function wrapper),用来定义函数对象。1. 介绍 Boost.Function 库包含了一个类族的函数对象的包装。它的概念很像广义上的回调函数。其有着和函数指针相同的特性但是又包含了一个调用的接口。一个_boost::function0 function1
文章浏览阅读7k次。K8S:使用Filebeat收集K8S内Pod应用日志一、环境描述没有K8S集群时应用日志通过filebeat–>redis–>logstash–>es–>kibana进行收集展示,上K8S集群后也需要考虑收集日志的问题,此处仅考虑 pod 中java应用生产的 info 和error文本日志。Kubernetes集群中的日志收集解决方案我们采用sidecar方案,将filebeat与应用部署到同一个pod,将应用日志挂载到主机目录,filebeat将日志挂载到其容器内。_filebeat收集pod日志