I’m tring to make a game and i want to use window.requestAnimationFrame() to make roles move, the movement seems to be right at first.
but there is problem that when i re-trigger move()
immediately after triggering pause()
, the movement will be faster and faster, i have code blow, move()
、pause()
and initListener()
are functions about movement
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() }); } }
I guess it’s because when i re-trigger move()
, there are still some requestAnimationFrame()
running in javascript stack?
how can I fix this?
Advertisement
Answer
You should either unregister your event listeners when doing a pause – or register them outside of the move()
function (e.g. in mount()
)