Triangular Pong for three players [game]

better implement this in our/my code above?

Absolutely, if it is correct.
I was thinking of timing the interval between the two consecutive key presses, but that can be done later (if it is useful).

@Chrisir

I am thinking about making it so the paddles do not meet or cross each other at the corners. I can think of a number of approaches, but I want to do something that is sympathetic with your excellent code. Is there an obvious way?

If not, I was thinking of three paddles that work exactly as they already do, but they are invisible. Then on top of the invisible paddles are visible paddles that are less wide. The visible paddles ‘inherit’ location, movement, etc. from the invisible paddles. Perhaps parent-child objects are not something that is done in Processing??

Do we make a subclass???

class Bat extends Paddle { 
  
    //add some visibility
    // change dimensions
 
} //subclass

Or even better (see code below). I think you (@Chrisir ) would use an array so perhaps you can tweak.```

// triangle data
PVector[] listCorners =  new PVector[3];
PVector middle01;
PVector middle10;
PVector middle12;
PVector middle21;
PVector middle20;
PVector middle02;

// Paddle data
Paddle[] listPaddles = new Paddle[3];

// we need this array to allow for multiple keys pressed at the same time
// cf. https://discourse.processing.org/t/keypressed-for-multiple-keys-pressed-at-the-same-time/18892
boolean[] moveKeys = new boolean[256];

// --------------------------------------------------------------------
// Core functions

void setup() {
  size( 800, 800);


  // make corners
  for (int i = 0; i < 3; i++) {
    float angle = i * (TWO_PI/3.0) + TWO_PI/20.0;
    float x1= width/2+cos(angle) * ((height / 2) -60);
    float y1= height /2+sin(angle) * ((height / 2) -60);
    listCorners [i] = new PVector( x1, y1) ;
  }

  // Make The paddles / players: the corners between the paddle moves and its 2 keys


  middle01 = PVector.lerp(listCorners [0], listCorners [1], 0.95);
  middle10 = PVector.lerp(listCorners [1], listCorners [0], 0.95);
  middle12 = PVector.lerp(listCorners [1], listCorners [2], 0.95);
  middle21 = PVector.lerp(listCorners [2], listCorners [1], 0.95);
  middle20 = PVector.lerp(listCorners [2], listCorners [0], 0.95);
  middle02 = PVector.lerp(listCorners [0], listCorners [2], 0.95);

  listPaddles[0] = new Paddle ( middle10, middle01, 'b', 'v', color(255, 255, 255)  );
  listPaddles[1] = new Paddle ( middle21, middle12, 'q', 'w', color(255, 255, 255)  );
  listPaddles[2] = new Paddle ( middle02, middle20, 'o', 'p', color(255, 255, 255)  );

} // setup

void draw() {
  background(0);

  // show game field
  showGameField();

  // manage paddles
  for (Paddle pd : listPaddles) {
    pd.checkKeys();
    pd.display();
  }//for
} // draw

// --------------------------------------------------------------------
// Input functions

void keyPressed() {
  if (key>32&&key<256)
    moveKeys[key] = true;
}//func

void keyReleased() {
  if (key>32&&key<256)
    moveKeys[key] = false;
}//func

// --------------------------------------------------------------------
// Other functions

void showGameField() {
  // show triangle

  stroke(0);
  noFill();
  triangle (listCorners[0].x, listCorners[0].y,
    listCorners[1].x, listCorners[1].y,
    listCorners[2].x, listCorners[2].y);

  fill(255, 2, 2);//red
  for (PVector pv : listCorners) {
    ellipse(pv.x, pv.y, 12, 12);
  }//for
}//func

// ====================================================================

class Paddle {

  final PVector from, to; // its 2 corner data
  final char leftC, rightC;

  float amt=1.5;
  final float speed1 = 0.01;
  final float amtHalfPaddleWidth  = 0.042;



  final color colorMy;

  int score=0;

  // -----------------

  //constr
  Paddle(PVector f_, PVector t_,
    char left_, char right_,
    color col_) {

    from =  f_;
    to   =  t_;

    leftC  = left_;
    rightC = right_;

    colorMy=col_;
  }//constr

  // -----------------

  void display() {
    // display Paddle

    //calc start and end of paddle line
    float x1=lerp(from.x, to.x, amt-amtHalfPaddleWidth);
    float y1=lerp(from.y, to.y, amt-amtHalfPaddleWidth);
    float x2=lerp(from.x, to.x, amt+amtHalfPaddleWidth);
    float y2=lerp(from.y, to.y, amt+amtHalfPaddleWidth);

    // draw paddle
    strokeWeight(12);
    strokeCap(PROJECT);
    stroke(colorMy);
    line (x1, y1,
      x2, y2 );
    //quad (x1, y1, x1+2, y1,
    //  x2, y2, x2+2, y2 );
    strokeWeight(1);
  }//func

  void checkKeys() {
    // check keys / move paddle

    if (moveKeys[leftC]) {
      amt-=speed1;
    } else if (moveKeys[rightC]) {
      amt+=speed1;
    }

    // check values
    if (amt-amtHalfPaddleWidth<0)
      amt=amtHalfPaddleWidth;
    if (amt+amtHalfPaddleWidth>1)
      amt=1-amtHalfPaddleWidth;
  }//func
  //
} //class
//
1 Like

I don’t have time at the moment…

:wink:

1 Like

Here we have a sketch that will detect if the ball is on a line. The line could be one of the three paddles or it could be any one of the sides of the triangle. With this ‘collision detection’, we should be able to connect the code for the moving and bouncing ball with the code for the moving paddles.

Press the ‘m’ key for a new random test.

//Check if Point C is on the line AB

float ax = 300; // left end of line
float ay = 400; // point A

// horizontal line
float bx = 500;  // right end of line
float by = 400;  // point B

int tilt = 0;

float cx = 400 + random(-150, 150); // point to be tested
float cy = 400 + random(-150, 150); // point C

float tolerance = 1;
float delta = 10;  // how close to line

void setup() {
  size( 800, 800);
}

void draw() {
  background(255);


  strokeWeight(1);
  fill(0);
  ellipse(cx, cy, 12, 12);

  if (tilt == 0) { // horizontal
    ax = 300;
    ay = 400;
    bx = 500;
    by = 400;
  } else if (tilt == 1) { // vertical
    ax = 400;
    ay = 300;
    bx = 400;
    by = 500;
  } else if (tilt == 2) {
    ax = 400 - 50;
    ay = 400 + (100 * sin(radians(60)));
    bx = 400 + 50;
    by = 400 - (100 * sin(radians(60)));
  } else if (tilt == 3) {
    ax = 400 - 50;
    ay = 400 - (100 * sin(radians(60)));
    bx = 400 + 50;
    by = 400 + (100 * sin(radians(60)));
  } else {
    println("whoops", tilt);
  }

  stroke(0);
  strokeCap(PROJECT);
  line (ax, ay, bx, by );

  // direct the flow to the relevant test

  if (ay == by) {  // line is horizontal
    testOne();
  } else if (ax == bx) {  // line is vertical
    testTwo();
  } else {
    testThree();
  }
}

void keyTyped() {
  if (key == 'm') {
    initTarget();
  }
}

void initTarget() {
  // set line randomly: vertical, horizontal, side of 60°, side of minus 60°
  // include vertical line for completeness
  tilt = int(random(4)); // horizontal, vertical, sixty, minus sixty

  //random location point C
  cx = 400 + random(-150, 150);
  cy = 400 + random(-150, 150);
}

void testOne() { //line is horizontal
  float hminx = min(ax, bx) - tolerance;
  float hmaxx = max(ax, bx) + tolerance;

  if ((cx <= hminx) || (cx >= hmaxx)) {
    text("FAIL", 400, 700);
  } else {

    if (abs(ay - cy) >= delta) {
      text("FAIL", 400, 700);
    } else {
      text("The ball is on the horizontal line", 200, 700);
    }
  }
}

void testTwo() { //line is vertical
  float vminy = min(ay, by) - tolerance;
  float vmaxy = max(ay, by) + tolerance;

  if ((cy <= vminy) || (cy >= vmaxy)) {
    text("FAIL", 400, 700);
  } else {

    if (abs(ax - cx) >= delta) {
      text("FAIL", 400, 700);
    } else {
      text("The ball is on the vertical line", 200, 700);
    }
  }
}


void testThree() { // bounding box
  float minx = min(ax, bx) - tolerance;
  float maxx = max(ax, bx) + tolerance;
  float miny = min(ay, by) - tolerance;
  float maxy = max(ay, by) + tolerance;

  // is C within the bounds of the line
  if ((cx >= maxx) || (cx <= minx) || (cy <= miny) || (cy >= maxy)) {
    text("FAIL", 400, 700);
  } else {

    testFour();
  }
}


void testFour() { // is close enough

  float topof = abs(((bx - ax)*(ay - cy))-((ax - cx)*(by - ay)));
  float botof =  sqrt((bx - ax) * (bx - ax) + (by - ay) * (by - ay));

  float dist = topof/botof;

  if (dist >= delta) {
    text("FAIL", 400, 700);
  } else {
    text("The ball is on the angled line", 200, 700);
  }
}
1 Like