Qyouu
您需要相对于 ITS 位置渲染汽车。此外,您可以在其 RENDER 中进行旋转。下面的更改将处理汽车的旋转,但您有更大的问题。我会花时间投资学习向量的工作原理。位置、速度和加速度都应该是提供向量数学的二维向量,例如加法和乘法。此外,为您的汽车提供一个初始角度,以便它最初以正确的方式呈现。您的加速和减速似乎也混淆了。function Car(map, x, y) { this.map = map; this.x = x; this.y = y; this.angle = 0; // IMPORTANT this.width = map.tsize; this.height = map.tsize; this.image = Loader.getImage('car');}Car.speed = 0;Car.acceleration = 0;Car.friction = 5;Car.moveAngle = 0;Car.maxSpeed = 500;Car.forward = 'FORWARD';Car.backward = 'BACKWARD';Car.left = 'LEFT';Car.right = 'RIGHT';// Render relative to car...Car.prototype.render = function(ctx) { ctx.save(); ctx.translate(this.x, this.y); ctx.rotate(this.angle); ctx.drawImage(this.image, -this.width / 2, -this.height / 2); ctx.restore();};Game.update = function (delta) { var dirx = 0; var diry = 0; if (Keyboard.isDown(Keyboard.LEFT)) { this._rotate(dirx, Car.left) } else if (Keyboard.isDown(Keyboard.RIGHT)) { this._rotate(dirx, Car.right) } else if (Keyboard.isDown(Keyboard.UP)) { this._rotate(dirx, Car.up) diry = accelerate(diry, Car.forward); } else if (Keyboard.isDown(Keyboard.DOWN)) { this._rotate(dirx, Car.down) diry = accelerate(diry, Car.backward); } else { decelerate(); } this.car.move(delta, dirx, diry); this.camera.update();};Game._rotate = function(dirx, direction) { let angleInDegrees = 0; switch (direction) { case 'UP': angleInDegrees = 0; break; case 'RIGHT': angleInDegrees = 90; break; case 'DOWN': angleInDegrees = 180; break; case 'LEFT': angleInDegrees = 270; break; } this.car.angle = angleInDegrees * (Math.PI / 180);}Game.render = function () { // draw map background layer this._drawLayer(0); this.car.render(this.ctx); // draw map top layer this._drawLayer(1);};矢量图这是一个使用向量的例子。loadImage('https://i.stack.imgur.com/JY7ai.png') .then(function(img) { main(img); })function main(img) { let game = new Game({ canvas: document.querySelector('#viewport') }); let car = new Car({ img: img, imgRadiansOffset : -Math.PI / 2, position: new Victor(game.canvas.width, game.canvas.height).divide(new Victor(2, 2)), velocity: new Victor(0, -1), showBorder: true }); game.addLayer(car); game.start();}class Game { constructor(options) { Object.assign(this, Game.defaultOptions, options); if (this.canvas != null) { Object.assign(this, { width: this.canvas.width, height: this.canvas.height }); this.addListeners(); } } addLayer(layer) { this.layers.push(layer); layer.parent = this; } start() { this.id = setInterval(() => { this.render(); }, 1000 / this.rate); // frames per second } render() { let ctx = this.canvas.getContext('2d'); ctx.clearRect(0, 0, this.width, this.height); this.layers.forEach(layer => layer.render(ctx)); } addListeners() { if (this.canvas != null) { window.addEventListener('keydown', (e) => { this.handleKeyDown(e.keyCode); }); window.addEventListener('keyup', (e) => { this.handleKeyUp(e.keyCode); }); } } handleKeyDown(keyCode) { this.layers.forEach(layer => { layer.update(keyCode !== this.lastKeyCode ? keyCode : null); }); this.lastKeyCode = keyCode; } handleKeyUp(keyCode) { this.layers.forEach(layer => { layer.update(this.lastKeyCode); // calls reset... }); }}Game.defaultOptions = { id: null, rate: 30, layers: [], canvas: null, width: 0, height: 0};class Car { constructor(options) { Object.assign(this, Car.defaultOptions, options); if (this.img != null) { Object.assign(this, { width: this.img.width, height: this.img.height }); } } render(ctx) { ctx.save(); ctx.translate(this.position.x, this.position.y); ctx.rotate(this.velocity.angle() - this.imgRadiansOffset); ctx.drawImage(this.img, -this.width / 2, -this.height / 2, this.width, this.height); if (this.showBorder) { ctx.strokeStyle = '#C00'; ctx.setLineDash([4, 8]); ctx.lineWidth = 1; ctx.beginPath(); ctx.rect(-this.width / 2, -this.height / 2, this.width, this.height); ctx.stroke(); } ctx.restore(); } update(keyCode) { if (keyCode != null) this.changeDirection(keyCode); this.position.add(this.velocity.add(this.acceleration)); this.detectCollision(); } detectCollision() { let xMin = this.width / 2, xMax = this.parent.width - xMin; let yMin = this.height / 2, yMax = this.parent.height - yMin; if (this.position.x < xMin) this.position.x = xMin; if (this.position.x > xMax) this.position.x = xMax; if (this.position.y < yMin) this.position.y = yMin; if (this.position.y > yMax) this.position.y = yMax; } changeDirection(keyCode) { switch (keyCode) { case 37: this.reset(new Victor(-1, 0)); // LEFT break; case 38: this.reset(new Victor(0, -1)); // UP break; case 39: this.reset(new Victor(1, 0)); // RIGHT break; case 40: this.reset(new Victor(0, 1)); // DOWN break; } } reset(dirVect) { this.velocity = new Victor(this.speedFactor, this.speedFactor).multiply(dirVect); this.acceleration = new Victor(this.accelFactor, this.accelFactor).multiply(dirVect); }}Car.defaultOptions = { position: new Victor(0, 0), width: 0, height: 0, img: null, imgRadiansOffset: 0, velocity: new Victor(0, 0), acceleration: new Victor(0, 0), showBorder: false, speedFactor: 3, // Velocity scalar accelFactor: 1 // Acceleration scalar};function loadImage(url) { return new Promise(function(resolve, reject) { var img = new Image; img.onload = function() { resolve(this) }; img.onerror = img.onabort = function() { reject("Error loading image") }; img.src = url; })}#viewport { border: thin solid grey;}<script src="https://cdnjs.cloudflare.com/ajax/libs/victor/1.1.0/victor.min.js"></script><canvas id="viewport" width="400" height="160"></canvas>