如何重新启动循环 requestAnimationFrame
how to restart a loop requestAnimationFrame
我想做一个游戏,我想用window.requestAnimationFrame()让角色移动,一开始看起来移动是对的。
但是有问题,当我重新触发 move()
触发pause()
后,移动会越来越快,我有代码吹,move()
、pause()
和initListener()
是关于移动的函数
type state = "init" | "mount" | "moving" | "pause" | "end";
interface position {
left: number;
top: number;
}
interface elProps {
id: string;
text: string;
avatar: string;
}
export default class Bullet {
public el: HTMLElement;
public targetEl: HTMLElement;
public unit: string = "px";
private id:string;
private state: state;
private position: position;
private animationId: number | undefined;
constructor(props: elProps) {
if (!props) return;
this.el = document.createElement("div");
this.initEl(props);
}
initEl(props: elProps) {
const defaultStyle = {};
this.el.style["height"] = "40px";
this.el.style["background"] = "lightblue";
this.el.style["display"] = "inline-flex";
this.el.style["position"] = "absolute";
//
const { text, avatar, id } = props;
this.el.setAttribute("id", id);
this.id = id
const textEl = document.createElement("div");
textEl.innerText = text;
const avatarEl = document.createElement("img");
avatarEl.setAttribute("src", avatar);
//
this.el.appendChild(avatarEl);
this.el.appendChild(textEl);
//
this.state = "init";
}
mount(targetEl: HTMLElement, position: position, unit: string) {
//
this.position = position;
this.unit = unit;
this.targetEl = targetEl;
this.el.style["left"] = this.position.left + this.unit;
//
targetEl.appendChild(this.el);
//
this.state = "mount";
const domEl = document.querySelector(`#${SPECIAL_ID}`);
if (!domEl) {
throw new Error("mount bullet error");
}
this.el = domEl as HTMLElement;
}
move(duration: number) {
this.state = "moving";
this.initListener();
const animation = () => {
if (this.state !== "moving") return;
this.position.left -= 1.2;
this.el.style["left"] = this.position.left + this.unit;
this.animationId = requestAnimationFrame(animation);
};
animation();
}
pause() {
if(this.animationId){
cancelAnimationFrame(this.animationId)
this.animationId = undefined
}
}
initListener() {
this.el.addEventListener("mouseenter", () => {
this.state = "pause";
this.pause()
});
this.el.addEventListener("mouseover", () => {
this.state = "pause";
this.pause()
});
this.el.addEventListener("mouseout", () => {
this.state = "moving";
this.move()
});
}
}
我猜是因为当我重新触发move()
时,javascript堆栈中还有一些requestAnimationFrame()
运行?
我该如何解决这个问题?
您应该在暂停时取消注册您的事件侦听器 - 或者在 move()
函数之外注册它们(例如在 mount()
中)
我想做一个游戏,我想用window.requestAnimationFrame()让角色移动,一开始看起来移动是对的。
但是有问题,当我重新触发 move()
触发pause()
后,移动会越来越快,我有代码吹,move()
、pause()
和initListener()
是关于移动的函数
type state = "init" | "mount" | "moving" | "pause" | "end";
interface position {
left: number;
top: number;
}
interface elProps {
id: string;
text: string;
avatar: string;
}
export default class Bullet {
public el: HTMLElement;
public targetEl: HTMLElement;
public unit: string = "px";
private id:string;
private state: state;
private position: position;
private animationId: number | undefined;
constructor(props: elProps) {
if (!props) return;
this.el = document.createElement("div");
this.initEl(props);
}
initEl(props: elProps) {
const defaultStyle = {};
this.el.style["height"] = "40px";
this.el.style["background"] = "lightblue";
this.el.style["display"] = "inline-flex";
this.el.style["position"] = "absolute";
//
const { text, avatar, id } = props;
this.el.setAttribute("id", id);
this.id = id
const textEl = document.createElement("div");
textEl.innerText = text;
const avatarEl = document.createElement("img");
avatarEl.setAttribute("src", avatar);
//
this.el.appendChild(avatarEl);
this.el.appendChild(textEl);
//
this.state = "init";
}
mount(targetEl: HTMLElement, position: position, unit: string) {
//
this.position = position;
this.unit = unit;
this.targetEl = targetEl;
this.el.style["left"] = this.position.left + this.unit;
//
targetEl.appendChild(this.el);
//
this.state = "mount";
const domEl = document.querySelector(`#${SPECIAL_ID}`);
if (!domEl) {
throw new Error("mount bullet error");
}
this.el = domEl as HTMLElement;
}
move(duration: number) {
this.state = "moving";
this.initListener();
const animation = () => {
if (this.state !== "moving") return;
this.position.left -= 1.2;
this.el.style["left"] = this.position.left + this.unit;
this.animationId = requestAnimationFrame(animation);
};
animation();
}
pause() {
if(this.animationId){
cancelAnimationFrame(this.animationId)
this.animationId = undefined
}
}
initListener() {
this.el.addEventListener("mouseenter", () => {
this.state = "pause";
this.pause()
});
this.el.addEventListener("mouseover", () => {
this.state = "pause";
this.pause()
});
this.el.addEventListener("mouseout", () => {
this.state = "moving";
this.move()
});
}
}
我猜是因为当我重新触发move()
时,javascript堆栈中还有一些requestAnimationFrame()
运行?
我该如何解决这个问题?
您应该在暂停时取消注册您的事件侦听器 - 或者在 move()
函数之外注册它们(例如在 mount()
中)