我正在参加掘金社区游戏创意投稿大赛团队赛,详情请看:游戏创意投稿大赛
我也是个临时抱佛脚的,对 vue 和 ts 都不熟,借此机会也算学习一把,做个益智拼图小游戏。团队是 大帅 带队,永恒君 主架构,我做的部分倒不多,所以本篇主要用于记录开发过程中遇到的技术点。
ts Partial<T>
先上一道 ts 方面的前菜:
interface GameConfig {
fps: number;
canvasWidth: number;
canvasHeight: number;
initialized: boolean;
pause: boolean;
}
class Config implements GameConfig {
fps: number = 60;
canvasWidth: number = 0;
canvasHeight: number = 0;
initialized: boolean = false;
pause: boolean = false;
constructor(config = {}) {
Object.keys(config).forEach(key => {
this[key] = config[key];
});
}
}
代码如上,由于 GameConfig 作为接口肯定不能把字段改为 ?:,但传入的 config 显然是需要约束和提示的。直接约定 config: GameConfig 肯定不行,不然每个属性都得必传了。再写一堆带 ?: 的约定也不现实。
后来找到 config: Partial<GameConfig> 这样的处理,这个 Partial<T> 就很巧妙,给这个对象自动加上了 ?:,相信它在实战中会很有用。
class Config implements GameConfig {
constructor(config: Partial<GameConfig> = {}) {}
}
new Config(); // 不报错
new Config({}); // 不报错
new Config({ f }); // 有提示 fps?
new Config({ xx: 1 }); // 报错 not exist in type
ts 范式
在写容器 Stage 类时,永恒君说由于项目简单要偷个懒,所以直接把子组件写了出来而没有进一步抽象,但 addElementByKey 这里的类型约定就让我头大起来了。
interface StageConfig = {
background: StageBackground;
container: PuzzleContainer;
idle: IdleContainer;
items: PuzzleItem[];
}
class Stage implements StageConfig {
addElementByKey(key, element) {}
}
显然 key 与 element 的类型是要对应的才行,不然就无法避免错误了。假设 key: keyof StageConfig,那 element 理应是 StageConfig[key] 相对应的,好像也只能用范式来解决它了。
不得不说,范式还是理解起来挺有难度的,试了挺多才得到下面的结果。
type setByKey<T> = <K extends keyof T>(key: K, value: T[K]) => void;
另外函数约定使用起来也容易和箭头函数混淆,让我一度怀疑是不是我理解错误。
class Stage implements StageConfig {
addElementByKey: setByKey<StageConfig> = (key, element) => {}
}
动画 easing
以前写动画都是 (v2 - v1) * progress + v1 这样的写法,这次想试试加上动画 easing 的逻辑,主要借鉴 jquery.easing 的思路。
传入四个值,已运行时间 t,起始量 b,需变动总量 c,需变动总时长 d,然后就可以套用一些函数了。
type EasingType = (t: number, b: number, c: number, d: number) => number;
const easeLinear: EasingType = (t, b, c, d) => {
return c * t / d + b;
}
const easeInQuad : EasingType = (t, b, c, d) => {
return c * (t /= d) * t + b;
}
动画类也很好写,只是此处的 start 为 number 类型,后续可进行抽象为接口,重写 start 和 update 即可实现比如颜色、数组等其他类型的动画效果。
type MoreOption = {
easing?: string,
onProgress?: (result: any, progress: number) => void,
onFinish?: () => void,
};
class Animation {
start: number = 0;
end: number = 0;
duration: number = 1000;
easing?: string = 'easeLinear';
_time: number = 0; // 本类创建时的时间
done: boolean = false;
constructor(start: number, end: number, duration = 1000, options?: MoreOption | VoidFunction) {}
update(now: number) {
const t = now - this._time;
const b = this.start;
const c = this.end - this.start;
const d = this.duration;
}
}
代码不复杂,但还是感谢这次实战中的学习,以及大佬们的指教。
Github: github.com/forever-z-1…