上一章讲的是马里奥速度改变的事件控制,本章改动较多,例如将马里奥位置改变拆分为一个一个的特征类,还有键盘事件监听,实现马里奥的跳跃功能,各位可以跟着原作者视频一起敲
本章的提交ID:e5caf33c8aecfe9655ccde05ad9700ae20f5ae31
github地址:ainuo5213的超级马里奥
目录说明:
1. traits/JumpTrait.js:马里奥的跳跃特征类,用于改变马里奥的纵向速度,实现跳跃
2. traits/Velocity.js:马里奥的速度特征类,将原有的马里奥位置改变,封装为特征类,实现马里奥位置改变
3. KeyBoardState.js:键盘事件监听类,针对空格键的监听键盘事件,用于调用马里奥的弹跳特征对象的update方法用,实现键盘的空格键的跳跃
入口文件中加入全局的键盘事件监听,用于空格键抬起和按下时,马里奥相应的取消跳跃和跳跃
马里奥抽象实体将入了抽象特征类Trait,并在马里奥抽象实体类Enityt中加入了addTrait、update方法,其中addTrait用于向实体添加特征,update用于将每个特征中的update方法执行一次,达到马里奥特征的改动,而这个update方法又被main中的时间函数不断的调用,所以只要特征类数据更新时,马里奥就会持续不断的调用update
马里奥对象里,将原本更新位置的方法拆分到了VelocityTrait特征类,加入了一个新的特征类JumpTrait,称为跳跃特征类。当空格键的抬起和按下动作,就会调用马里奥对象上跳跃特征类对应的jump方法和start方法,以此更新马里奥的特征数据,并渲染新的马里奥。
export const STATE_KEYDOWN = 1;
export const STATE_KEYUP = 0;
export const KEYCODE_SPACE = 32;
export class KeyboardState {
constructor() {
// 保存当前键盘状态
this.keyStates = new Map();
// 保存键盘事件对应的回调函数
this.keyMap = new Map();
}
addMapping = (keyCode, callback) => {
// 添加map映射
this.keyMap.set(keyCode, callback);
}
handleEvent = event => {
const { keyCode } = event;
if (!this.keyMap.has(keyCode)) {
return;
}
// 阻止键盘的默认行为,比如pageDown等
event.preventDefault();
const keyState = event.type === 'keydown' ? STATE_KEYDOWN : STATE_KEYUP;
// 如果当前键盘状态已经存在了,就不再添加新的相同的状态
if (this.keyStates.get(keyCode) === keyState) {
return;
}
this.keyStates.set(keyCode, keyState);
const callback = this.keyMap.get(keyCode);
callback(keyState);
}
listenTo = window => {
// 监听键盘按下和抬起的事件,并交由处理程序
['keydown', 'keyup'].forEach(r => {
window.addEventListener(r, event => {
event.preventDefault();
this.handleEvent(event);
});
})
}
}
监听键盘的空格按下和抬起动作需要提前设置映射规则,然后全局监听window,当空格的抬起和按下动作发生时,执行对应的回调函数,来达到马里奥的跳跃和取消跳跃
import { Trait } from '../Entity.js'
export class JumpTrait extends Trait {
constructor() {
super('jump');
// 时长
this.duration = 0.5;
// 下降速度
this.velocity = 200;
// 参与时间
this.engageTime = 0;
}
start = () => {
// 开始,设置参与时间为其时长
this.engageTime = this.duration;
}
cancel = () => {
// 结束,设置参与时间为0
this.engageTime = 0;
}
update = (entity, deltaTime) => {
// 更新方法,如果还剩余参与时间就还要更新,然后将参与时间减去已经过去的delta时间
if (this.engageTime > 0) {
entity.vel.y = -this.velocity;
this.engageTime -= deltaTime;
}
}
}
跳跃特征类继承自特征抽象类,并实现的update方法,新增了start和cancel,用于控制马里奥跳跃动作的开始和结束
import { Trait } from '../Entity.js'
export class VelocityTrait extends Trait {
constructor() {
super('velocity');
}
update = (entity, deltaTime) => {
// 改变马里奥的位置
entity.pos.x += entity.vel.x * deltaTime;
entity.pos.y += entity.vel.y * deltaTime;
}
}
马里奥位置改变的速度特征类也继承自特征抽象类,他的代码就是之前在马里奥实现类里面改变马里奥位置的代码。
至此整个跳跃过程更新完毕。
本章需要小伙伴们理解面向对象语言中的多态、封装和继承三大特征,实现类和基类调用方法时遵循的规则,本章不是很难,好好理解即可