KineticJS - 在接触/鼠标移动触发时交换形状位置

时间:2016-08-23 00:13:48

标签: javascript html5 canvas kineticjs

我正在使用KineticJS并尝试完成一些看似简单的事情:尝试使用当前被拖动的形状来改变位置。

这个想法是:
•您在画布上拾取形状。这会触发一个mousedown事件监听器,它会保存您拾取的形状的当前位置。
•在保持形状的同时,如果在另一个形状上触发mouseover,则会触发该形状的事件并根据当前形状的保存位置交换其位置。

以下是我试图让其工作的相关代码:

电路板设置: 只需设置电路板并在此处调用所需的功能即可。我还没有对舞台,gameBoard或ctx做任何事情(其中一部分是因为我试图让drawImage在多幅画布上工作,但现在已经放弃了)。

class BoardView {
  constructor(stage, gameBoard, ctx) {
    this.stage = stage;
    this.gameBoard = gameBoard;
    this.ctx = ctx;
    this.orbs = [[], [], [], [], []];
    this.setupBoard();
  }

电路板设置功能 这是我设置电路板并为每个Kinetic Circle提供在图层上渲染所需的属性的地方。也许我在这里遗漏了一些明显的东西?

  setupBoard () {
    for (let colIdx = 0; colIdx < 5; colIdx++) {
      this.addRow(colIdx);
    }

    this.renderBoard();
  }

  addRow (colIdx) {
    for (let rowIdx = 0; rowIdx < 6; rowIdx++) {
      let orbType = Math.round(Math.random() * 5);
      let orbColor;

      if (orbType === 0) {
          orbColor = "#990000";
        } else if (orbType === 1) {
          orbColor = "#112288";
        } else if (orbType === 2) {
          orbColor = "#005544";
        } else if (orbType === 3) {
          orbColor = "#776611";
        } else if (orbType === 4) {
          orbColor = "#772299";
        } else {
          orbColor = "#dd2277";
      }
      let orbject = new Kinetic.Circle({
        x: (rowIdx + 0.5) * 100, 
        y: (colIdx + 0.5) * 100,
        width: 100, 
        height: 100,
        fill: orbColor, 
        draggable: true
      });
      this.orbs[colIdx].push(orbject);
    }
  }

棋盘渲染功能 这是我将所有Kinetic Circle对象添加到新图层中的位置,并在调用事件处理程序时为这些图层提供所有自己的属性。在将图层添加到舞台后,我还在此处设置了事件处理程序。我是否可能通过添加太多图层来搞乱这一点?

  renderBoard () {

    for (let row = 0; row < this.orbs.length; row++) {
      for (let orb = 0; orb < this.orbs[row].length; orb++) {
        let layer = new Kinetic.Layer();

        layer.add(this.orbs[row][orb]);
        layer.moving = false;
        layer.orbId = `orb${row}${orb}`;
        layer.pos = [this.orbs[row][orb].attrs.x, this.orbs[row][orb].attrs.y];

        this.stage.add(layer);

        layer.on("mousedown", this.handleMouseDown);
        layer.on("mouseup", this.handleMouseUp);
        layer.on("mouseout", this.handleMouseOut);
        layer.on("mousemove", this.handleMouseMove);
      }
    }
  }

鼠标事件处理程序: 这是我认为我遇到主要问题的地方。我如何处理移动鼠标以改变球体的事件,也许我做了一些非常错误的事情?

  handleMouseDown (e) {
    window.currentOrb = this;
    console.log(window.currentOrb.orbId);

    this.moving = true;
  }

  //handleMouseUp (e) {
  //  window.currentOrb = undefined;
  //  this.moving = false;
  //}

  //handleMouseOut (e) {
  //}

  handleMouseMove (e) {
    if (window.currentOrb !== undefined && window.currentOrb.orbId != this.orbId) {
      this.children[0].attrs.x = window.currentOrb.pos[0];
      this.children[0].attrs.y = window.currentOrb.pos[1];
      this.children[0].draw();
    } else {
    }
  }
}


module.exports = BoardView;

我已经尝试过查看KineticJS文档和许多StackOverflow答案,希望找到一个对我有用的解决方案,但到目前为止我还没有看过和尝试过(包括有关我写这个问题的时候出现了似乎是有帮助的,我知道我到目前为止的方式可能远远没有达到我想要的最佳方式,所以我&#39 ;我可以接受任何建议,指示,回答的问题,或任何可以指引我正确指向我所缺少的东西,以使其发挥作用。

如果这有用,这里还可以看到渲染电路板时的外观。

enter image description here

圈子都是动力圈(为了我想要的目的而选择的球体),然后点击并拖动一个到另一个圈子,那个没有被拖动但是悬停的圈子应移动到拖动圆圈的原始位置。

谢谢!

修改

从那时起,我对代码做了一些更改。首先,我改变了向舞台添加多个图层,只改为一个:

renderBoard () {
  let layer = new Kinetic.Layer();

  for (let row = 0; row < this.orbs.length; row++) {
    for (let orb = 0; orb < this.orbs[row].length; orb++) {

      layer.add(this.orbs[row][orb]);

      this.orbCanvases.push(orbCanvas.id);
    }
  }
  this.stage.add(layer);
} 

我改为将侦听器添加到orb对象中:

addRow (colIdx) {
  for (let rowIdx = 0; rowIdx < 6; rowIdx++) {

    //same code as before

    let orbject = new Kinetic.Circle({
      x: (rowIdx + 0.5) * 100, y: (colIdx + 0.5) * 100,
      width: 100, height: 100,
      fill: orbColor, draggable: true, pos: [rowIdx, colIdx]
    });
    orbject.on("mousedown", this.handleMouseDown);
    orbject.on("mouseup", this.handleMouseUp);
    orbject.on("mouseout", this.handleMouseOut);
    orbject.on("mousemove", this.handleMouseMove);

    this.orbs[colIdx].push(orbject);
  }
}

这样做的好处是可以在以前更快地进行拖放操作,速度非常慢,但我仍然无法让我的对象交换位置。

要明确,我的主要问题是知道我应该改变哪些x,y值。在handleMouseMove的那一刻,我一直试图改变:

e.target.attrs.x = newX;
e.target.attrs.y = newY;
// newX and newY can be any number

然而,无论我改变它,它都没有效果。因此,我可以帮助我知道我是否改变了错误的东西/地方,例如,我是否应该从我存储的阵列中更改Kinetic Circle?再次感谢。

编辑2:

我想我明白了!但是,我必须this.orbs并在window.orbs的窗口中设置它,并测试它我做了:

window.orbs[0][0].x(450);
window.orbs[0][0].draw();

这导致x位置发生变化。但把它放在一个窗口似乎不是一个好习惯吗?

编辑3:

我现在让球体连续交换,除非在mouseover继续射击时再次交换相同的球体。但是,在mouseup,它可以再次交换。我还必须再次设置多个图层以使mouseover事件在持有另一个orb时起作用,但性能似乎有所改善。

我将尝试弄清楚如何让它们能够在相同的鼠标保持下连续交换,但与此同时,这是我为实现这一目的而编写的代码:

addRow (colIdx) {
  for (let rowIdx = 0; rowIdx < 6; rowIdx++) {

    // same code as before, changed attr given to Kinetic.Circle

    let orbject = new Kinetic.Circle({
      x: (rowIdx + 0.5) * 100, y: (colIdx + 0.5) * 100,
      width: 100, height: 100,
      fill: orbColor, draggable: true, orbId: `orb${colIdx}${rowIdx}`
    });
  }
}

handleMouseDown (e) {
  window.currentOrb = window.orbs[e.target.attrs.orbId];
  window.newX = e.target.attrs.x;
  window.newY = e.target.attrs.y;
}

鼠标按下ID保存currentOrb及其X和Y

handleMouseUp (e) {
  window.currentOrb.x(window.newX);
  window.currentOrb.y(window.newY);
  window.currentOrb.parent.clear();
  window.currentOrb.parent.draw();
  window.currentOrb.draw();
  window.currentOrb = undefined;
  for (let i = 0; i < 5; i++) {
    for (let j = 0; j < 6; j++) {
      window.orbs[`orb${i}${j}`].draw();
    }
  }
}

当鼠标被释放时,目前所有的球体都被重新绘制,因此它们都可以被使用。我打算重构这个,所以只有这个变化的球体才会发生这种变化。

handleMouseMove (e) {

  if (window.currentOrb !== undefined && (window.currentOrb.attrs.orbId !== e.target.attrs.orbId)) {
    window.orbMove.pause();
    window.currentTime = 0;
    window.orbMove.play();
    let targOrbX = e.target.attrs.x;
    let targOrbY = e.target.attrs.y;
    // This is the target orb that's being changed's value
    // We're storing this in targOrb

    e.target.x(window.newX);
    e.target.y(window.newY);
    e.target.parent.clear();
    e.target.parent.draw();
    e.target.draw();

    // Here we have the previously set current orb's position becoming
    // the target orb's position

    window.newX = targOrbX;
    window.newY = targOrbY;

    // Now that the move is made, we can set the newX and Y to be the
    // target orb's position once mouseup
  }
}

Orb交换逻辑,用于传递一次orb,但不是如果它们在同一回合中再次传递。

1 个答案:

答案 0 :(得分:0)

什么时候&#34;悬停&#34;正式举行?

  • 当鼠标事件的位置进入第二个球体时?如果是,请点击测试鼠标与每个非拖动球:

    // pseudo-code -- make this test for every non-dragging orb
    var dx=orb[draggingIndex].x-orb[n].x;
    var dy=orb[draggingIndex].y-orb[n].y;
    var rSum=orb[draggingIndex].radius+orb[n].radius;
    if(dx*dx+dy*dy<=rSum*rSum){
        // change orb[n]'s x,y to the dragging orb's x,y (and optionally re-render)
    }
    
  • 当拖动球体与第二个球体相交时?如果是,则碰撞测试拖动球体与每个非拖动球体:

    In [3]: np.zeros([10, 10]) - 1
    Out[3]: 
    array([[-1., -1., -1., -1., -1., -1., -1., -1., -1., -1.],
       [-1., -1., -1., -1., -1., -1., -1., -1., -1., -1.],
       [-1., -1., -1., -1., -1., -1., -1., -1., -1., -1.],
       [-1., -1., -1., -1., -1., -1., -1., -1., -1., -1.],
       [-1., -1., -1., -1., -1., -1., -1., -1., -1., -1.],
       [-1., -1., -1., -1., -1., -1., -1., -1., -1., -1.],
       [-1., -1., -1., -1., -1., -1., -1., -1., -1., -1.],
       [-1., -1., -1., -1., -1., -1., -1., -1., -1., -1.],
       [-1., -1., -1., -1., -1., -1., -1., -1., -1., -1.],
       [-1., -1., -1., -1., -1., -1., -1., -1., -1., -1.]])
    
顺便说一句,如果你将一个球体拖到所有其他球体上,其他球体将全部叠加在拖动球体原始位置上 - 这就是你想要的吗?