0

I am working on creating a mini vector graphics ping pong table, as described in this previous post: Trying to use 3D vectors for a 2D ping pong game

Currently, the stage I am at, I am trying to make it so that when the ball exceeds the X bounds of the table, it will reflect backwards and at a new target: a random x,y,z position on the opponent's side of the table.

Trying to use this post as a starting point: How can I launch a GameObject at a target if I am given everything except for its launch angle? I have attempted to adapt some of that example code in my program, but I am not quite getting the desired results.

** updated code **

update: function(paceFactor) {
  this.ball.pos3D.x += this.ball.vel.x * paceFactor;
  this.ball.pos3D.y += this.ball.vel.y * paceFactor;
  this.ball.pos3D.z += this.ball.vel.z * paceFactor;
  this.ball.vel.y += this.gravity * paceFactor;

  if (!this.stop && Math.abs(this.ball.pos3D.x) > 15) {
    this.stop = true; // for testing to prevent velocity from getting changed due to bad values returned from velocityForNextTarget()
    var modifier = this.ball.pos3D.x < 0 ? 1 : -1;
    var velocity = this.velocityForNextTarget(modifier);
    this.ball.vel.x += velocity.x;
    this.ball.vel.y += velocity.y;
    this.ball.vel.z += velocity.z;
  }

  if (this.ball.pos3D.y >= 0) {
    this.ball.vel.y *= -1;
    this.ball.pos3D.y -= this.ball.pos3D.y;
  }

  this.convert3Dto2D();
},

velocityForNextTarget: function(modifier) {
  var targetX = 5 * modifier;
  var targetY = 0;
  var targetZ = 0;

  var deltaX = this.ball.pos3D.x - targetX;
  var deltaY = this.ball.pos3D.y - targetY;
  var deltaZ = this.ball.pos3D.z - targetZ;

  var sqrMagnitude = (deltaX * deltaX) + (deltaY * deltaY) + (deltaZ * deltaZ);
  var speed = Math.sqrt((this.ball.pos3D.x * this.ball.pos3D.x) + (this.ball.pos3D.y * this.ball.pos3D.y) + (this.ball.pos3D.z * this.ball.pos3D.z));

  var gSquared = this.gravity * this.gravity;
  var b = speed * speed + (deltaY * this.gravity);
  var discriminant = (b * b) - (gSquared * sqrMagnitude);

  var discRoot = Math.sqrt(discriminant);

  var t = Math.sqrt((b - discRoot) * 2 / gSquared);

  return {
    x: deltaX / t * t / 2,
    y: deltaY / t - this.gravity * t / 2,
    z: deltaZ / t * t / 2,
  };
},

So what I am trying to do is make it so that when the ball reaches the location of a player, it will target the center of the opponent's side of the table, and the ball will move there, and right now this code is making the ball rapidly jump off the screen as soon as it hits the x bounds, and I am not sure what I am doing wrong with the math in velocityForNextTarget()...

I should also mention that gravity is just a constant that I am only adding to my Y velocity so far. I am not sure if that's "right" ?

enter image description here

patrick
  • 209
  • 1
  • 9

1 Answers1

0

More errors following the updates:

  1. Your return velocity is not correctly calculated.

    In the source:

    velocity = delta / T - gravity * T/2.0

    Your code:

    return {
    x: deltaX / t * t / 2,
    y: deltaY / t - this.gravity * t / 2,
    z: deltaZ / t * t / 2,
    };

    Correct translation:
    (your gravity's x & z are zero, so those terms vanish: a - 0 * t / 2 = a not a * t / 2)

    return {
    x: deltaX / t,
    y: deltaY / t - this.gravity * t / 2,
    z: deltaZ / t,
    };
  2. You're adding the result velocity instead of setting it:

    var velocity = this.velocityForNextTarget(modifier);
    this.ball.vel.x += velocity.x;
    this.ball.vel.y += velocity.y;
    this.ball.vel.z += velocity.z;

    You want to use the new velocity as-is, not mix it with something else:

    var velocity = this.velocityForNextTarget(modifier);
    this.ball.vel.x = velocity.x;
    this.ball.vel.y = velocity.y;
    this.ball.vel.z = velocity.z;
  3. Your speed calculation is still not meaningful (it's the ball's distance from the origin, not its speed). Why not just pass the ball speed that you want as an input as it was in the source answer?

    velocityForNextTarget: function(modifier, speed) {

    Or treat it as a configuration parameter similar to your paceFactor

DMGregory
  • 134,153
  • 22
  • 242
  • 357
  • I hope I understood all your points correctly. I updated my code above to reflect the changes I made... 1) I added the paceFactor multiplication to "this.ball.vel.y += this.gravity * paceFactor;", 2) changed b to only use deltaY with gravity: "var b = speed * speed + (deltaY * this.gravity);" 3) tried using the speed of the actual current vector instead of the distance... Still something is not quite right though. The ball is going in the wrong direction (to the right and up, when I expect to the left and down). – patrick Mar 11 '18 at 08:13
  • And I tried experimenting with flipping the signs of x and y returned from the velocityForNextTarget() function, but that seemed wrong.. it seems like what I am doing for speed is still not quite right.. – patrick Mar 11 '18 at 08:15
  • Thank you again so much for your help and guidance! Re #3, I am confused by the concept of speed. I thought based off what I have read, for example: http://blog.wolfire.com/2009/07/linear-algebra-for-game-developers-part-2/ "We can think of V as a right triangle with sides 4 and 3, and use the Pythagorean theorem to find the hypotenuse: x2 + y2 = h2. That is, the length of a vector H with components (x,y) is sqrt(x2+y2). So, to calculate the speed of our ship, we just use: |V| = sqrt(42+32) = sqrt(25) = 5" From this, I thought my ball speed is defined by my ball's x/y/z velocity properties. – patrick Mar 11 '18 at 20:40
  • 1
    "I thought my ball speed is defined by my ball's x/y/z velocity properties." It is, but you're not using its vel properties, you're using its pos3D properties which represent position. I still would not recommend using the incoming velocity as your speed here though. This bounce represents a player hitting the ball with their paddle, right? So they're going to impart energy to it - this doesn't need to be an energy-preserving reflection. It's probably simpler to model it as a "player return speed" configuration parameter that represents how hard players hit the ball. – DMGregory Mar 11 '18 at 20:54
  • ohhhhhh... oops! I'm sorry-- I was totally not reading the fact that I was using pos3D instead of vel there! I understand now. So... using speed as an input parameter, I am finding that if I use anything less that 1, the ball just disappears? – patrick Mar 11 '18 at 21:23
  • 1
    Probably because you're not handling the case where discriminant is less than zero. You're probably taking the square root of a negative and getting NaNs in your math. These negative discriminants happen when the target is out of range for the given speed, so if you don't want to handle that case, keep your launch speed high enough that you can reach anywhere on the table. – DMGregory Mar 11 '18 at 21:26
  • Ok... I owe you at least a million thank you's for your patience and help! I really, really, really, really appreciate it. My LAST problem/question (I hope) is that, when serving, the ball needs to go from server side of table to opponent side of table. I thought I could just wait for the ball to reach the center of the table and then retarget the opponent's side of the table, but that looks so wrong and un-natural... It appears I need the trajectory function to be able to also accept where the 2nd bounce will be.. so that I can specify, target1 = x1,y1,z1 and target2 = x2,y2,z2-- ? – patrick Mar 11 '18 at 22:04
  • 1
    That's a whole new question worth asking separately. – DMGregory Mar 11 '18 at 22:05