【问题标题】:Phaser P2 Sprite Scale Change not working properly for all group childrenPhaser P2 Sprite Scale Scale更改不适用于所有组儿童
【发布时间】:2016-08-01 18:02:44
【问题描述】:

我希望这段代码能解释我想要做什么。我有一张台球桌,如果球离得足够近,我希望球能够加速进入球袋。在这一点上,我还没有检查距离,只是想弄清楚如何去做。

我相信有更好的方法!

  balls.forEachAlive(
    pockets.forEachAlive( moveBallTowardPocket, this), this);

更新:以下代码正在工作,除了一件事,前五个口袋上的球的比例发生变化。加速适用于所有球到所有口袋。比例变化仅适用于最后一个口袋,而不是前五个。

function update() {
  pockets.forEachAlive(function(pocket) {
    accelerateBallToPocket(flipper, pocket, 60);
    balls.forEachAlive(function(ball) {
      accelerateBallToPocket(ball, pocket, 60);
    });
  });
  //...
}

function accelerateBallToPocket(ball, pocket, speed) {
  if (typeof speed === 'undefined') {
    var speed = 120;
  }
  var pocket_body_x = pocket.body.x;
  var pocket_body_y = pocket.body.y;
  var ball_body_x   = ball.body.x;
  var ball_body_y   = ball.body.y;

  // move ball toward pocket if close enough
  var dx = ball_body_x - pocket_body_x;  //distance ship X to enemy X
  var dy = ball_body_y - pocket_body_y;  //distance ship Y to enemy Y
  var dist = Math.sqrt(dx*dx + dy*dy);   //pythagoras

  if (dist < pocket_radius * pocket_leniency_factor) {

    // accelerate ball to pocket on right angle
    var angle = Math.atan2(pocket.y - ball.y,
                             pocket.x - ball.x);
    ball.body.rotation = angle + game.math.degToRad(90);
    ball.body.force.x = Math.cos(angle) * speed;
    ball.body.force.y = Math.sin(angle) * speed;

    // change scale
    // FIXME only works on the last pocket lower right
    if (ball === flipper) {
      ball.scale.setTo(Math.tan(pocket.x - ball.x),
                         Math.tan(pocket.y - ball.y));
    } else {
      ball.scale.setTo(Math.sin(pocket.x - ball.x),
                         Math.cos(pocket.y - ball.y));
    }
  } else {
    // reset the scale when the ball is out of range of the pocket
    ball.scale.setTo(1.0, 1.0);
  }
}

第二次更新: 以下,基于解决方案,让我再次朝着正确的方向前进,我认为......

  for (var i = 0; i < pockets.children.length; i++) {
    accelerateBallToPocket(cue, pockets.children[i], 60);
    if (cue.pocketing) break;
  }

  for (var i = 0; i < balls.children.length; i++) {
    if (balls.children[i].pocketing) continue;
    for (var j = 0; j < pockets.children.length; j++) {
      accelerateBallToPocket(balls.children[i], pockets.children[j], 60);
      if (balls.children[i].pocketing) return;
    }
  }

【问题讨论】:

  • 秤应该做什么(我的意思是,用户应该看到什么)?
  • 当任何一个球(或脚蹼球)足够靠近口袋时,球的比例会使用三角函数发生变化,因此球会出现痉挛。它适用于一个口袋,但不适用于其他口袋。
  • @Tibe Lake 什么是脚蹼球?我第一次在泳池里听到这个词。也许你需要absXY 球和口袋之间的距离。
  • 我在做弹球游戏,结果变成了台球。我只是还没有重新命名它,但它与其他球的体型相同,但在不同的组中。请注意,该功能适用​​于除前五个口袋缩放之外的所有功能。所以距离度量是有效的。
  • 是的,但是当你改变比例时,你会使用这个距离:pocket.x - ball.x,它根据球和口袋之间的相对位置有不同的符号。我并不是说这是问题所在,但这肯定会使“痉挛”的行为根据口袋的哪个角落而有所不同。

标签: javascript game-physics phaser-framework


【解决方案1】:

好的,问题是如果球没有靠近口袋,您将比例设置为 1。而且,当您检查每个球与每个球袋时,总会有一个球袋(在循环中稍后检查),球也没有关闭,除了球袋列表中的最后一个球袋。因此,即使将球标尺设置为正确的值,在检查下一个pocket 时也会将其重置。

你可以做的是检查一个球是否靠近至少一个口袋,如果是,那么它不能靠近其他口袋,所以你不会再次检查其他口袋。

// Consider that every ball is not inside a pocket
balls.forEachAlive(function(ball) {
   ball.inPocket = false;
});
flipper.inPocket = false; // You should really add the flipper to the balls group to remove duplicate code

pockets.forEachAlive(function(pocket) {
    if(!flipper.inPocket) accelerateBallToPocket(flipper, pocket, 60);
    balls.forEachAlive(function(ball) {
      if(!ball.inPocket) accelerateBallToPocket(ball, pocket, 60);
    });
  });

然后,在你的移动函数中,如果球靠近口袋,你必须将 inPocket 成员设置为 true。

function accelerateBallToPocket(ball, pocket, speed) {

    ...

    if (ball === flipper) {
      ball.scale.setTo(Math.tan(pocket.x - ball.x),
                         Math.tan(pocket.y - ball.y));
      ball.inPocket = true;
    } else {
      ball.scale.setTo(Math.sin(pocket.x - ball.x),
                         Math.cos(pocket.y - ball.y));
      ball.inPocket = true;
    }
  } else {
    // reset the scale when the ball is out of range of the pocket
    ball.scale.setTo(1.0, 1.0);
  }
}

另一种方法是颠倒循环顺序,首先遍历所有球并为每个球检查每个口袋,一旦你发现它在口袋中,继续外循环(跳过检查其他口袋)。为此,您的accelerateBall 函数应返回truefalse,当球离口袋足够近时为true,否则为false

我会像这样重写你的迭代:

  for (var i = 0; i < pockets.children.length; i++) {
    accelerateBallToPocket(cue, pockets.children[i], 60);
    if (cue.pocketing) break;
  }

  // Stumped...
  for (var i = 0; i < balls.children.length; i++) {
    // No need for the check here, each ball should have pocketing=false, set at the top of the update loop
    // This means, that balls.children[i].pocketing will always be false here
    for (var j = 0; j < pockets.children.length; j++) {
      accelerateBallToPocket(balls.children[i], pockets.children[j], 60);
      if (balls.children[i].pocketing) break; // stop checking the rest of the pockets for this ball
    }
  }

【讨论】:

  • 这不太行,因为我要靠近口袋,所以如果我设置 inPocket = true,精灵就会停止更新。 “口袋”具有吸引力,但如果球靠近口袋,我还没有摆脱它们,只是让它们加速朝向它们并改变比例。
  • 我也不能在 forEachAlive 函数中使用 break 或 continue 。我得到“非法中断”并继续警告。
  • 我已经使用您描述的方法更新了我的问题。我已经完成了一半的工作,需要更多帮助。
  • 问题出在你的第二个 if (balls.children[i].pocketing) continue; 上。 Continue 只会跳过当前的迭代,不会停止循环。请改用break;。 (这是内循环中的那个):if (balls.children[i].pocketing) break;。另外,请参阅我的编辑。
猜你喜欢
  • 2017-08-20
  • 2015-09-20
  • 2014-10-27
  • 2015-02-10
  • 2013-02-12
  • 2023-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多