生效场景
1.我们在做网游的时候经常会有这样子的一个场景。玩家点击“领取金币”按钮。此时,需要同后端进行数据上的交互。等待后端给你答复之后。才会弹出“”恭喜你领取了100金币“之类的对话框。同时,领取按钮会自动消失。不会让玩家再次领取。
2.要实现这个功能,我们当然要确保玩家在第一次点击领取金币按钮到服务器返回数据的这个时间段内。不要重复点击这个“领取金币”的按钮。大部分的做法是在全场景上挂一个转圈。转圈存在的时候,吞噬掉所有的触摸。
3.但是我接触过的很多游戏,比如说《皇室战争》却不是这样子的,我开宝箱的时候,网络经常卡主,但是我还可以玩命的点击这个打开宝箱。只不过后边的这些个点击,按钮有缩放的反馈,但是却不真正的发送网络请求。
4.笔者最近观摩了TS语法内的注解。想到了使用注解来拦截函数并且实现上述功能的目的。特此记录分享给大家。
简单的例子
- 假设我们场景有一个按钮,点击可以获取金币。但是要等待服务器返回。我们可以这样子写
//领取按钮绑定了这个 onButtonClick方法
public onButtonClick() {
console.log('我要去获取金币了');
setTimeout(() => {
//模拟网络请求回来需要五秒中
this.onCoinResp();
}, 5000);
}
//网络请求回来后获得金币
public onCoinResp() {
console.log('恭喜你获得了100金币');
}
2.现在我们希望在第一次点击按钮并且发出网络请求之后立刻锁住 onButtonClick这个函数,必须等到onCoinResp被触发后,onButtonClick才会被解锁。为此,我们需要写一些注解(对于注解不了解的可以去查阅一下TS的文档)。注解的核心代码 FunLockUtils.ts如下。
interface PropertyDescriptor {
configurable?: boolean;
enumerable?: boolean;
value?: any;
writable?: boolean;
get?(): any;
set?(v: any): void;
}
interface FunItem {
target: any,
fun: any
};
let funList: Array<FunItem> = [];
export function lockable() {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
let oldValue = descriptor.value;
descriptor.value = function (...args: any) {
for (let item of funList) {
if (item.target == this && item.fun == descriptor.value) {
log(propertyKey + '已经被锁定了,无法执行');
return;
}
}
oldValue.call(this, ...args);
}
}
}
export function lockFunction(target: any, fun: any): boolean {
for (let item of funList) {
if (item.target == target && item.fun == fun) {
return false;
}
}
funList.push({ target: target, fun: fun });
return true;
}
export function unlockFunction(target: any, fun: any): boolean {
for (let i = 0; i < funList.length; i++) {
let item = funList[i];
if (item.target == target && item.fun == fun) {
funList.splice(i, 1);
return true;
}
}
return true;
}
3.接着改造我们的刚才写上函数
//这里为onButtonClick 加上lockable注解,表示这个函数是可以被锁上的
@lockable()
public onButtonClick() {
console.log('我要去获取金币了');
//在发送网络请求后立刻锁上onButtonClick这个函数
lockFunction(this, this.onButtonClick);
setTimeout(() => {
//模拟网络请求回来的样子
this.onCoinResp();
}, 5000);
}
onCoinResp() {
console.log('恭喜你获得了100金币');
//这网络协议返回后才会解锁onButtonClick这个函数
unlockFunction(this, this.onButtonClick);
}
4.接着运行我们的项目,并且狂点击“获取金币”这个按钮。可以看到控制台的输出如下

5.至此,大功告成。