微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用 JS 画布创建轨道武器精灵会产生动画错误/故障

如何解决使用 JS 画布创建轨道武器精灵会产生动画错误/故障

我正在尝试制作一款玩家拥有可装备武器的游戏。截至目前,我已将此武器设置为弓的图像,并且我希望该武器在面对鼠标时可以在玩家周围移动。这类似于 buildroyale.io,玩家随着他的武器旋转以面对鼠标。

截至目前,在@Justin 的帮助下,我的弓在屏幕上旋转(有点)。它仅在按需要按下左键单击时显示,但不会按预期旋转。这是一个展示它如何移动的剪辑:clip

这是我使用的代码

    class EventHandler {

    equip_weapon() {

        if (holding) {

            player.weapon = player.bag.slot_1;

            canv.globalAlpha = 1;
            player.weapon.equip();
            player.weapon.update();
        
        }

    }

}

class Weapon {

    image_path;

    constructor(image_path) {

        this.x = player.x + 30;
        this.y = player.y + 30;
        this.width = 120;
        this.height = 120;
        this.angle = 0;
        this.distance = 50;
        this.image = image_path;

    }

    equip() {

        this.angle = Math.atan2(mouse.y - this.y,mouse.x - this.x)
        canv.save();
        canv.translate(this.x,this.y);
        canv.rotate(this.angle);
        canv.drawImage(this.image,this.distance,-this.height/2,this.width,this.height);
        canv.restore();  

    }

    update() {

        this.x = player.x + player.width / 2;
        this.y = player.y + player.height / 2;

    }

}

bow = new Weapon(bow_image);
player.bag.slot_1 = bow;

aim_bounds = document.documentElement.getBoundingClientRect();

类播放器{

constructor() {

    this.name = null;
    this.speed = 5;
    this.skin = player_sheet;
    this.can_move = true;
    this.is_moving = false;
    this.width = 68;
    this.height = 68;
    this.scale = 1;
    this.x = 566;
    this.y = 316;
    this.direction = facing.down;
    this.frame = 0;
    this.shadow_offset = 25;
    this.frame_rate = 10;
    this.health = 100;
    this.clip_amount = 10;
    this.weapon = null;

    // Player inventory
    this.bag = {

        slot_1 : null,slot_2 : null,slot_3 : null,slot_4 : null,slot_5 : null,offhand : null,armor : null

    }

    this.is_menu_open = false;

    console.log("Player constructed!");

}

update() {

    // Animation updates
    if (game.tick % this.frame_rate == 0 && this.is_moving && !this.is_menu_open) {

        this.frame += 68;

        if (this.frame >= 272) { this.frame = 0; }

    } else if (!this.is_moving) { this.frame = 0; }

    // Movement updates
    if (this.can_move) {

        if (controller.up) { this.direction = facing.up; this.y -= this.speed; this.is_moving = true; }

        else if (controller.down) { this.direction = facing.down; this.y += this.speed; this.is_moving = true; }

        else if (controller.left) { this.direction = facing.left; this.x -= this.speed; this.is_moving = true; }

        else if (controller.right) { this.direction = facing.right; this.x += this.speed; this.is_moving = true; }

        if (!controller.up && !controller.down && !controller.left && !controller.right) { this.is_moving = false; }
        
    }
    
    // Checks
    if (this.is_menu_open) { this.can_move = false; } else { this.can_move = true; }

    document.getElementById("health_bar").value = this.health;

    if (this.is_menu_open) { menu.style.display = "block"; } else { menu.style.display = "none"; }

}

animate() {

    //  Player shadow
    canv.drawImage(player_shadow,this.x,this.y + this.shadow_offset);

    // Player
    canv.globalAlpha = 1;
    canv.drawImage(player_sheet,(sprite.x + this.frame),(sprite.y * this.direction),sprite.width,sprite.height,this.y,this.height);

}
}

这里是我当前代码的下载,以防您需要更多调试:game.zip

解决方法

我处理这个问题的方法是确保我的图像首先正确定向。在我的情况下,我的弓形图像看起来像这样(忽略质量)。只要看到它朝右。

enter image description here

在绘制函数中,我使用 translate() 来定位图像,并使用 x 内的 ydrawImage(img,x,y,w,h) 来绘制沿顶部边缘居中的图像画布。 x(在本例中设置为 50)位置本质上是图像旋转的半径,而 y 只是为了使我的弓箭在画布的 y 轴上居中。

使用 Math.atan2() 我可以旋转图像

this.angle = Math.atan2(mouse.y - this.y,mouse.x - this.x)

在这个片段中,我有两行被注释掉了。如果您取消注释它们,您将更好地了解正在发生的事情。

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
canvas.width = 600;
canvas.height = 600;

let mouse = {x: 10,y: 10}
let canvasBounds = canvas.getBoundingClientRect();

canvas.addEventListener('mousemove',e => {
  mouse.x = e.x - canvasBounds.x
  mouse.y = e.y - canvasBounds.y
})

let bow = new Image();
bow.src = "https://lh3.googleusercontent.com/g5Sr3HmGZgWx07sRQMvgvtxZ-ErhWNT0_asFdhLIlw-EQMTuUq3BV3YY8d5rrIrZBiJ-Uo2l836Qlmr8dmaCi-dcCCqN6veS6xnE8jSrmdtRtZKnmF5FQ5aTxuVBgB28n6ICoxSlpA=w2400";

class Weapon {
  constructor() {
    this.x = 200;
    this.y = 200;
    this.w = 60;
    this.h = 60;
    this.angle = 0
  }
  draw() {
    this.angle = Math.atan2(mouse.y - this.y,mouse.x - this.x)
    ctx.save();
    ctx.translate(this.x,this.y);
    ctx.rotate(this.angle);
    //ctx.fillStyle = 'lightgrey';
    //ctx.fillRect(0,canvas.width,canvas.height);
    ctx.drawImage(bow,50,-this.h/2,this.w,this.h)
    ctx.restore();  
  }
}

let bowArrow = new Weapon();

function animate() {
  ctx.clearRect(0,canvas.height);
  bowArrow.draw();
  requestAnimationFrame(animate)
}
animate();
<canvas id="canvas"></canvas>

更新:

以下是我在您的文件中更改的内容,并且在我这边效果很好。

engine.controller.js 更改 mousemove 并添加监听器以调整大小。我也很确定有一种方法可以摆脱 getMouse 函数,因为下面的侦听器会为您获取鼠标坐标。

canvas.addEventListener("mousemove",function (event) {
  mouse_position = event
  mouse.x = event.x - canvas_bounds.x;
  mouse.y = event.y - canvas_bounds.y;
})

window.addEventListener('resize',() => {
  canvas_bounds = canvas.getBoundingClientRect();
})

engine.eventhandler.js

class Weapon {

    image_path;

    constructor(image_path) {

        this.x = player.x + player.width/2;
        this.y = player.y + player.height/2;
        this.w = 60;
        this.h = 60;
        this.angle = 0;
        this.image = image_path;

    }

    equip() {
        this.x = player.x + player.width/2;
        this.y = player.y + player.height/2;
        this.angle = Math.atan2(mouse.y - this.y,mouse.x - this.x)
        canv.save();
        canv.translate(this.x,this.y);
        canv.rotate(this.angle);
        canv.drawImage(this.image,this.h);
        canv.restore();  

    }

}

engine.main.js

function setup() {

    game = new Game;
    player = new Player;
    controller = new Controller;
    event_handler = new EventHandler;
    canvas.width = 1200;
    canvas.height = 700;
    canvas_bounds = canvas.getBoundingClientRect();
    
    //  REMOVE LATER
    bow = new Weapon(bow_image);
    player.bag.slot_1 = bow;

    document.getElementById("bag").style.display = "block";

}

engine.setup.js

// Weapon stuff
var weapon_equiped = false;
var canvas = document.getElementById("canvas");
let mouse = {

    x : 10,y : 10

}
let canvas_bound;
var mouse_position,holding;
var rect,mouse_x,mouse_y;

...and
//you have a space between canvas. height in both fillRect
canv.fillRect(0,canvas. height);

我想这就是我改变的全部。很确定您可以使用 mouse_x 或 mouse.x,但您的代码中可能不需要这两者。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。