有人可以修復它的腳本以使其正常作業嗎?
我的期望:
- 運行腳本
- 單擊畫布以設定目標(圓圈)
- 物件(三角形)開始旋轉并向目標(圓形)移動
- 隨時改變目標
這個怎么運作:
- 有時物件正確旋轉,有時不正確
- 看起來一個半球效果很好,另一個則不行
謝謝!
// prepare 2d context
const c = window.document.body.appendChild(window.document.createElement('canvas'))
.getContext('2d');
c.canvas.addEventListener('click', e => tgt = { x: e.offsetX, y: e.offsetY });
rate = 75 // updates delay
w = c.canvas.width;
h = c.canvas.height;
pi2 = Math.PI * 2;
// object that moves towards the target
obj = {
x: 20,
y: 20,
a: 0, // angle
};
// target
tgt = undefined;
// main loop
setInterval(() => {
c.fillStyle = 'black';
c.fillRect(0, 0, w, h);
// update object state
if (tgt) {
// draw target
c.beginPath();
c.arc(tgt.x, tgt.y, 2, 0, pi2);
c.closePath();
c.strokeStyle = 'red';
c.stroke();
// update object position
// vector from obj to tgt
dx = tgt.x - obj.x;
dy = tgt.y - obj.y;
// normalize
l = Math.sqrt(dx*dx dy*dy);
dnx = (dx / l);// * 0.2;
dny = (dy / l);// * 0.2;
// update object position
obj.x = dnx;
obj.y = dny;
// angle between x and tgt
a = Math.atan2(0 * dx - 1 * dy, 1 * dx 0 * dy);
// update object angle
obj.a = -a * 0.04;
}
// draw object
c.translate(obj.x, obj.y);
c.rotate(obj.a);
c.beginPath();
c.moveTo(5, 0);
c.lineTo(-5, 4);
c.lineTo(-5, -4);
//c.lineTo(3, 0);
c.closePath();
c.strokeStyle = 'red';
c.stroke();
c.rotate(-obj.a);
c.translate(-obj.x, -obj.y);
}, rate);
uj5u.com熱心網友回復:
結果證明這比我最初想象的更具挑戰性,我最終只是重新撰寫了代碼。
挑戰:
- 確保船只只旋轉到目標的確切點。這需要我比較從船舶當前位置到我們希望它去的地方的兩個角度。
- 確保目標沒有旋轉越過目標并且船舶沒有平移越過目標。這需要每個緩沖區空間,因為當物件移動時具有 this.x === this.x 的影片是非常罕見的,所以我們需要一些空間讓邏輯作業。
- 確保船以最短的方向轉向目標。
我在代碼中添加了注釋以更好地解釋。希望您可以將其實作到您的或按原樣使用。哦,您可以根據需要更改移動速度和旋轉速度。
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
canvas.width = 400;
canvas.height = 400;
let mouse = { x: 20, y: 20 };
let canvasBounds = canvas.getBoundingClientRect();
let target;
canvas.addEventListener("mousedown", (e) => {
mouse.x = e.x - canvasBounds.x;
mouse.y = e.y - canvasBounds.y;
target = new Target();
});
class Ship {
constructor() {
this.x = 20;
this.y = 20;
this.ptA = { x: 15, y: 0 };
this.ptB = { x: -15, y: 10 };
this.ptC = { x: -15, y: -10 };
this.color = "red";
this.angle1 = 0;
this.angle2 = 0;
this.dir = 1;
}
draw() {
ctx.save();
//use translate to move the ship
ctx.translate(this.x, this.y);
//angle1 is the angle from the ship to the target point
//angle2 is the ships current rotation angle. Once they equal each other then the rotation stops. When you click somewhere else they are no longer equal and the ship will rotate again.
if (!this.direction(this.angle1, this.angle2)) {
//see direction() method for more info on this
if (this.dir == 1) {
this.angle2 = 0.05; //change rotation speed here
} else if (this.dir == 0) {
this.angle2 -= 0.05; //change rotation speed here
}
} else {
this.angle2 = this.angle1;
}
ctx.rotate(this.angle2);
ctx.beginPath();
ctx.strokeStyle = this.color;
ctx.moveTo(this.ptA.x, this.ptA.y);
ctx.lineTo(this.ptB.x, this.ptB.y);
ctx.lineTo(this.ptC.x, this.ptC.y);
ctx.closePath();
ctx.stroke();
ctx.restore();
}
driveToTarget() {
//get angle to mouse click
this.angle1 = Math.atan2(mouse.y - this.y, mouse.x - this.x);
//normalize vector
let vecX = mouse.x - this.x;
let vecY = mouse.y - this.y;
let dist = Math.hypot(vecX, vecY);
vecX /= dist;
vecY /= dist;
//Prevent continuous x and y increment by checking if either vec == 0
if (vecX != 0 || vecY != 0) {
//then also give the ship a little buffer incase it passes the given point it doesn't turn back around. This allows time for it to stop if you increase the speed.
if (
this.x >= mouse.x 3 ||
this.x <= mouse.x - 3 ||
this.y >= mouse.y 3 ||
this.y <= mouse.y - 3
) {
this.x = vecX; //multiple VecX by n to increase speed (vecX*2)
this.y = vecY; //multiple VecY by n to increase speed (vecY*2)
}
}
}
direction(ang1, ang2) {
//converts rads to degrees and ensures we get numbers from 0-359
let a1 = ang1 * (180 / Math.PI);
if (a1 < 0) {
a1 = 360;
}
let a2 = ang2 * (180 / Math.PI);
if (a2 < 0) {
a2 = 360;
}
//checks whether the target is on the right or left side of the ship.
//We use then to ensure it turns in the shortest direction
if ((360 a1 - a2) % 360 > 180) {
this.dir = 0;
} else {
this.dir = 1;
}
//Because of animation timeframes there is a chance the ship could turn past the target if rotating too fast. This gives the ship a 1 degree buffer to either side of the target to determine if it is pointed in the right direction.
//We then correct it to the exact degrees in the draw() method above once the if statment defaults to 'else'
if (
Math.trunc(a2) <= Math.trunc(a1) 1 &&
Math.trunc(a2) >= Math.trunc(a1) - 1
) {
return true;
}
return false;
}
}
let ship = new Ship();
class Target {
constructor() {
this.x = mouse.x;
this.y = mouse.y;
this.r = 3;
this.color = "red";
}
draw() {
ctx.strokeStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, false);
ctx.stroke();
}
}
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillRect(0, 0, canvas.width, canvas.height);
ship.draw();
ship.driveToTarget();
if (target) {
target.draw();
}
requestAnimationFrame(animate);
}
animate();
<canvas id="canvas"></canvas>
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/374639.html
標籤:javascript 数学 帆布 2d
上一篇:如何找到顫振變數之間最近的數字?
下一篇:計算其十進制版本的值
