这是我参与更文挑战的第10天,活动详情查看: 更文挑战前端
项目源码node
偶然间我往webpack
标签中发了一篇文章,碰巧看到了然叔写的作了一晚上动画,让你们十分钟搞懂Webpack,我并不了解然叔,但我以为他极可能比我大,考虑到一位如此努力分享技术的大哥,为了奉献本身的光和热,作了一晚上,那属实让人有些心疼,故我想尽个人一点力,为大佬和你们们也发出个人一份热。react
首先领略了一下文章,并印证了“不用想确定比我参悟深,大佬就是大佬”这个”偏见“,但最直接吸引我并非webpack
😂,而是一束“光”,对就是大佬写了一晚上的动画,我感叹动画制做的如此之精巧,表达效果居然如此之显著,直接地,强烈地吸引了我。webpack
与其沉浸在喜好和膜拜的感受中,不如借着这份情感作点事。我心中审视了一下本身现有的能力,很快就得出了一个想法💡,我好像能整出来一个作出这种“光”的轮子,ok,说干就干。git
首先我不想作成静态资源那种的,好比视频,gif之类的,这种是没有“生命”的,只能称之为“物质”,我简单用“阴”代指,我所须要是基于物质所焕发同时也能够创造物质的的“生命,心灵”,我称他为阳。说ta是“活”的有点过,就是说能够交互,能够整合再利用,随时能够经过ta建立视频,gif之类的静态资源,岂不妙哉。github
首先做为一个前端,技术面要打开,就很容易接触到形形色色的技术,那么渲染引擎就是之一。首先出于个人需求,经过渲染引擎开发这会大大的提升开发的效率,其次也能够整合进我写的脚手架“Moderate”中,是一个优解。web
我总但愿用最简单的话语,描述一件事,我比较喜欢简单,那么咱们就用简单的方式把个人设计讲讲。markdown
视频能够快进,倒退,仅仅经过拨动进度条或者滑动屏幕便可,我喜欢这种交互,那就作成这样,舒服。app
我但愿设计出一系列独立个体,能够很好的串联起整个逻辑,它具有了基本的功能,同时又具有了扩展的能力,可互相联结,又彼此独立,目前有两个主要的个体,一个是单位个体entity
,另外一个是动做个体recation
ide
entity
大致应该具有如下行为:lenPercent
和startPercent
live
process
end
entityArr
entity
recationArr
recation
,recation
大致应该具有如下行为:start
和end
action()
那么个体设计好了,围绕个体所展开的逻辑,就瓜熟蒂落了。
代码以下:
export default cc.Class({
extends: cc.Component,
properties: {
lenPercent: cc.Float,
startPercent: cc.Float,
isAutoStart: cc.Boolean,
entityArr: {
default: [],
type: cc.Node
}
},
//externalDuration:外部时间(父节点传过来的时间),由父节点决定
//internalDuration:本身内部定的时间,有本身决定,
//为何要区分两个呢?因为外部应该只能肯定个人播放时间,不该该决定个人播放速率,然后者应该有个体自身决定,
//startTime和endTime:由父节点指定的开始和结束时间,(根据父节点的世界定的‘外部时间’!!!)
//timeLine-表示时间到哪了,(根据父节点的世界定的‘外部时间’!!!)
//totaTime-表示我在父节点应该播放的总时长,(根据父节点的世界定的‘外部时间’!!!)
//progressValue就是经过父节点传过来的timeLine,totaTime,timeLine得出我处于的播放进度百分比
//相应的往本身的子节点传的就得参照本身的
ctor() {
this.isLive = false;
this.startTime = undefined;
this.endTime = undefined;
this.internalDuration = 0;//个体内部的时长
this.externalDuration = 0;//个体相对父级的时长
this.progressValue = 0;
this.entryData = [];
this.recationArr = [];
this.startPosition = cc.v2();
this.entityArrEx = [];
},
// LIFE-CYCLE CALLBACKS:
start() {
this.startPosition = this.node.position;
},
onLoad() {
this.node.comName = this.__classname__;
this.internalDuration = this.node.getContentSize().height;
//防止设置的时间太长,强制设置为剩余的时长
if (this.lenPercent + this.startPercent > 1) {
this.lenPercent = 1 - this.startPercent;
}
if (this.isAutoStart) {
this.startPercent += Math.abs((this.node.position.y / this.node.parent.getContentSize().height));
}
},
onEnable() {
let self = this;
if (this.entityArr.length) {
this.entityArrEx = this.entityArr.map((item, index) => {
let entity = item.getComponent(item._name);
if (entity.isAutoStart) {
}
this.entryData.push(entity.initData({
startTime: this.getStarTime(entity.startPercent),
totaTime: self.internalDuration,
}));
return entity;
});
}
},
//业务接口
getStarTime(value) {
if (value <= 1) {
return value * this.internalDuration
} else {
return value
}
},
initData({ totaTime, startTime }) {
this.startTime = startTime;
this.externalDuration = this.lenPercent <= 1 ? totaTime * this.lenPercent : this.lenPercent;
//结束时间最大只能是父类节点结束时间
//由于父节点结束,子节点也必须结束
this.endTime = Math.min(totaTime, this.startTime + this.externalDuration);
return {
startTime: this.startTime,
internalDuration: this.internalDuration,
endTime: this.endTime
}
},
getCurrentTime(percent) {
return (
this.startTime + (percent <= 1 ? this.externalDuration * percent : percent)
);
},
live() {
this.isLive = true;
},
calcProgress() {
this.progressValue = (this.timeLine - this.startTime) / this.externalDuration;
},
calcReactionProgress({ start, end }) {
start = (start <= 1) ? this.internalDuration * start : start;
end = (end <= 1) ? this.internalDuration * end : end;
return Math.min((this.progressValue * this.internalDuration - start) / (end - start), 1);
},
process({ timeLine }) {
this.timeLine = timeLine;
this.calcProgress();
this.internalTimeLine = this.progressValue * this.internalDuration;
let actionArr = this.recationArr.filter((item) => {
if (item) {
let isOk = (timeLine > this.getCurrentTime(item.start) &&
timeLine <= this.getCurrentTime(item.end)) ||
(!item.start && !item.end)
if (isOk) {
item.isAction = true
} else {
if (item.isAction) {
item.action(this.calcActionData(item, true))
}
item.isAction = false
}
return isOk;
}
});
actionArr.forEach((item) => {
item.action(this.calcActionData(item));
});
},
update() {
let self = this;
this.actionEntityArr = this.entityArrEx.filter((entity) => {
if ((self.internalTimeLine) > entity.startTime && self.internalTimeLine <= entity.endTime) {
if (!entity.isLive) {
entity.live();
}
entity.process({
timeLine: self.progressValue * self.internalDuration,
});
return true;
} else {
if (entity.isLive) {
entity.end();
}
}
return false;
});
},
calcActionData(item, isEnd) {
let params = {};
let actionLen = (item.end - item.start) || 1;
let progress;
progress = Math.min((this.progressValue - item.start) / actionLen, 1);
if (isEnd) {
let isEndForce = window.GLOBAL.dir > 0;
let isEndForceStart = window.GLOBAL.dir < 0;
if (isEndForce) {
progress = 1
} else if (isEndForceStart) {
progress = 0
}
params = {
isEndForce: isEndForce,
isEndForceStart: isEndForceStart
}
}
params = {
actionLen,
progress,
...params,
...item
}
return params;
},
end() {
this.isLive = false;
//若是滑动很是快,而且是快进而非后退,那么就要直接强行设置反馈为结束
// if (window.GLOBAL.dir > 0) {
// }
this.recationArr.forEach(item => {
if (item.isAction) {
item.isAction = false
item.action(this.calcActionData(item, true))
}
});
},
});
复制代码
这是然哥的作的动画
个人版本(作的时候才发现这俩是一体的)
就在我开始着手作然叔第三个动画,摸索箭头如何实现的时候,机缘巧合地我有了另外一个新的灵感,我作出了这个。
“Moderate”新首页。
感谢然叔。
这是我为“Moderate”写专栏的第十篇了,颇有成就感,虽然不受欢迎,但整个过程我是快乐的。我碰见了好多好多热情的,才华的,可敬的coder和掘友,收获良多。最后由衷地感谢掘金营造的社区氛围,感叹相见恨晚,但一见如故,自强不息,将来可期。