【发布时间】:2021-12-02 09:48:52
【问题描述】:
我正在创造在画布上飞行的蜜蜂,我给它随机到达的目的地,一旦它到达它就会产生新的目的地,所以它会继续徘徊。现在我正在尝试这样做,如果我的鼠标足够近,它将开始跟随我的鼠标而不是目标点。一切都会好起来的,我想我知道该怎么做,但问题是我的听众在使用 react 时会触发两次,而仅在 Js 中触发一次。编辑:看起来一切都在重复,只是在不清除画布的情况下尝试绘制,我得到了两只蜜蜂两个目的地。
应用程序
import Canvas from "./canvas/Canvas";
import "./App.css";
import { useRef, useEffect, useState } from "react";
function App() {
const appRef = useRef();
const [loaded, setLoaded] = useState(false);
useEffect(() => {
if (appRef) {
setLoaded(true);
}
return () => setLoaded(false);
}, []);
return (
<div className="App" ref={appRef}>
{loaded ? (
<Canvas
width={appRef.current.clientWidth}
height={appRef.current.clientHeight}
/>
) : (
<></>
)}
</div>
);
}
export default App;
画布
import Bee from "./bee";
import { useState, useCallback, useEffect } from "react";
import "./canvas.css";
const Canvas = ({ width, height }) => {
const [canvas, setCanvas] = useState();
const [context, setContext] = useState();
const canvasCallback = useCallback((node) => {
if (node) {
setCanvas(node);
}
}, []);
useEffect(() => {
if (canvas) {
setContext(canvas.getContext("2d"));
canvas.width = width;
canvas.height = height;
}
}, [canvas]);
if (context) {
// Game loop
// let fps = 60;
// let now;
// let then = Date.now();
// let delta;
const bee = new Bee(context, canvas.width, canvas.height, canvas);
const gameLoop = () => {
// let interval = 1000 / fps;
window.requestAnimationFrame(gameLoop);
// now = Date.now();
// delta = now - then;
// if (delta > interval) {
// then = now - (delta % interval);
bee.move();
// }
};
window.requestAnimationFrame(gameLoop);
//Game loop end
}
return <canvas id="canvas" ref={canvasCallback} />;
};
export default Canvas;
蜜蜂
import beeImg from "./bee.png";
import beeLeftImg from "./bee-left.png";
function Bee(ctx, width, height, parent) {
this.currentPos = { x: width / 5, y: height / 3 };
this.beeWidth = 32;
this.beeHeight = 32;
this.velocity = { x: 0.1, y: 0 };
this.acc = { x: 0, y: 0 };
this.direction = { x: Math.random() * width, y: Math.random() * height };
this.mouse = { x: 0, y: 0 };
this.mouseInside = false;
let loadedR = false;
let loadedL = false;
let img = new Image();
img.src = beeImg;
img.onload = () => {
loadedR = true;
};
let imgLeft = new Image();
imgLeft.src = beeLeftImg;
imgLeft.onload = () => {
loadedL = true;
};
this.createBee = (x, y) => {
if (this.velocity.x >= 0 && loadedR) {
ctx.clearRect(0, 0, width, height, this.bee);
ctx.drawImage(img, x, y, this.beeHeight, this.beeHeight);
}
if (this.velocity.x < 0 && loadedL) {
ctx.clearRect(0, 0, width, height, this.bee);
ctx.drawImage(imgLeft, x, y, this.beeHeight, this.beeHeight);
}
};
window.addEventListener("mousemove", (e) => {
this.mouse = { x: e.clientX, y: e.clientY };
});
parent.addEventListener("mouseenter", (e) => {
console.log(e, "enter");
e.stopPropagation()
});
parent.addEventListener("mouseleave", (e) => {
console.log(e, "left");
e.stopPropagation()
});
let goTo = (x, y) => {
let v = {
x: this.currentPos.x - x,
y: this.currentPos.y - y,
};
let mag = Math.sqrt(Math.pow(v.x, 2) + Math.pow(v.y, 2));
let normalize = { x: v.x / mag, y: v.y / mag };
this.acc.x -= normalize.x;
this.acc.y -= normalize.y;
this.velocity.x += this.acc.x / 50;
this.velocity.y += this.acc.y / 50;
this.currentPos.x += this.velocity.x;
this.currentPos.y += this.velocity.y;
this.acc.x = 0;
this.acc.y = 0;
if (this.currentPos.x >= width - this.beeWidth) {
this.currentPos.x = width - this.beeWidth;
this.velocity.x = 0;
}
if (this.currentPos.x <= 0) {
this.currentPos.x = 0;
this.velocity.x = 0;
}
if (this.currentPos.y >= height - this.beeHeight) {
this.currentPos.y = height - this.beeHeight;
this.velocity.y = 0;
}
if (this.currentPos.y <= 0) {
this.currentPos.y = 0;
this.velocity.y = 0;
}
this.createBee(this.currentPos.x, this.currentPos.y);
ctx.beginPath();
ctx.arc(this.direction.x, this.direction.y, 10, 0, 2 * Math.PI);
ctx.stroke();
};
this.move = () => {
let mouseV = {
x: this.currentPos.x - this.mouse.x,
y: this.currentPos.y - this.mouse.y,
};
let mouseMag = Math.sqrt(Math.pow(mouseV.x, 2) + Math.pow(mouseV.y, 2));
if (mouseMag < 200) {
goTo(this.mouse.x, this.mouse.y);
} else {
let dirV = {
x: this.currentPos.x - this.direction.x,
y: this.currentPos.y - this.direction.y,
};
let dirMag = Math.sqrt(Math.pow(dirV.x, 2) + Math.pow(dirV.y, 2));
if (dirMag <= 100) {
this.direction = {
x: Math.random() * width,
y: Math.random() * height,
};
}
goTo(this.direction.x, this.direction.y);
}
};
}
export default Bee;
这是在 javascript 单个文件中,如果有人想测试它,只需添加一些您选择的 image.src
if (canvas.getContext) {
const ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
function Bee(ctx, width, height) {
this.currentPos = { x: width / 5, y: height / 3 };
this.beeWidth = 32;
this.beeHeight = 32;
this.velocity = { x: 0.1, y: 0 };
this.acc = { x: 0, y: 0 };
this.direction = { x: width / 2, y: height / 2 };
this.mouse = { x: 0, y: 0 };
this.createBee = (x, y) => {
// ctx.clearRect(0, 0, width, height, this.bee);
// ctx.beginPath();
// ctx.arc(x, y, 10, 0, 2 * Math.PI);
// ctx.stroke();
const img = new Image();
img.src = "./bee.png";
const imgLeft = new Image();
imgLeft.src = "./bee-left.png";
if (this.velocity.x >= 0) {
img.onload = () => {
ctx.clearRect(0, 0, width, height, this.bee);
ctx.drawImage(img, x, y, this.beeHeight, this.beeHeight);
};
}
if (this.velocity.x < 0) {
imgLeft.onload = () => {
ctx.clearRect(0, 0, width, height, this.bee);
ctx.drawImage(imgLeft, x, y, this.beeHeight, this.beeHeight);
};
}
};
window.addEventListener("mousemove", (e) => {
this.mouse = { x: e.clientX, y: e.clientY };
});
canvas.addEventListener("mouseenter", (e) => {
console.log(e, "enter");
// e.stopPropagation()
});
canvas.addEventListener("mouseleave", (e) => {
console.log(e, "left");
// e.stopPropagation()
});
let goTo = (x, y) => {
let v = {
x: this.currentPos.x - x,
y: this.currentPos.y - y,
};
let mag = Math.sqrt(Math.pow(v.x, 2) + Math.pow(v.y, 2));
let normalize = { x: v.x / mag, y: v.y / mag };
this.acc.x -= normalize.x;
this.acc.y -= normalize.y;
this.velocity.x += this.acc.x / 50;
this.velocity.y += this.acc.y / 50;
this.currentPos.x += this.velocity.x;
this.currentPos.y += this.velocity.y;
this.acc.x = 0;
this.acc.y = 0;
if (this.currentPos.x >= width - this.beeWidth) {
this.currentPos.x = width - this.beeWidth;
this.velocity.x = 0;
}
if (this.currentPos.x <= 0) {
this.currentPos.x = 0;
this.velocity.x = 0;
}
if (this.currentPos.y >= height - this.beeHeight) {
this.currentPos.y = height - this.beeHeight;
this.velocity.y = 0;
}
if (this.currentPos.y <= 0) {
this.currentPos.y = 0;
this.velocity.y = 0;
}
this.createBee(this.currentPos.x, this.currentPos.y);
ctx.beginPath();
ctx.arc(this.direction.x, this.direction.y, 10, 0, 2 * Math.PI);
ctx.stroke();
};
this.move = () => {
let mouseV = {
x: this.currentPos.x - this.mouse.x,
y: this.currentPos.y - this.mouse.y,
};
let mouseMag = Math.sqrt(Math.pow(mouseV.x, 2) + Math.pow(mouseV.y, 2));
if (mouseMag < 200) {
goTo(this.mouse.x, this.mouse.y);
} else {
let dirV = {
x: this.currentPos.x - this.direction.x,
y: this.currentPos.y - this.direction.y,
};
let dirMag = Math.sqrt(Math.pow(dirV.x, 2) + Math.pow(dirV.y, 2));
if (dirMag <= 100) {
this.direction = {
x: Math.random() * width,
y: Math.random() * height,
};
}
goTo(this.direction.x, this.direction.y);
}
};
}
const bee = new Bee(ctx, 700, 700);
// Game loop
let fps = 60;
let now;
let then = Date.now();
let delta;
const gameLoop = () => {
let interval = 1000 / fps;
window.requestAnimationFrame(gameLoop);
now = Date.now();
delta = now - then;
if (delta > interval) {
then = now - (delta % interval);
bee.move();
}
};
window.requestAnimationFrame(gameLoop);
//Game loop end
}
【问题讨论】:
-
我不知道它是否应该这样,但是当我在 App.js 中使用 console.log(Canvas) 时,它的 console.logs 也是两倍。
标签: javascript reactjs canvas