Rotate arc in pacman animation

Waka is the movement of the mouth/bite of pac man when its moving.

2 Likes

I made some work and progress…but i cant make the rotation…any help would be apreciated…
Pacman moves left, right, up and down…and makes the waka waka… but always pointing to the right… no matter the direction…
I dont know were the bug/error is… here is the code
Any ideas to improve the code are welcome…

const CLOCKWISE_ROTATION = 0;
const ANTICLOCKWISE_ROTATION = 1;

class PacMan {
  constructor(x, y) {
    this.speed = 10;
    this.stepFrame = 0.1;
    this.x = x;
    this.y = y;
    this.direction = 1; //ClockWise 1 Left, 2 up, 3 right, 4 down arbitrary numbers
    fill(255, 255, 0);
    this.biteSize = PI / 16;
    this.startAngle;
    this.endAngle;

  }
  stay() {
    this.startAngle = this.biteSize * sin(frameCount * this.stepFrame) + this.biteSize;
    this.endAngle = TWO_PI - this.startAngle;    
    arc(
      this.x,
      this.y,
      80,
      80,
      this.startAngle,
      this.endAngle,
      PIE
    );
  }
  moveRight() {
    switch (this.direction) {
      case 1:
        //Previous direction was 1 ( left) and new direction would be 3 (right). So i have to rotate from 0 to 180 degrees.
        this.rotatePacman(0, 180, CLOCKWISE_ROTATION);
        break;
      case 2:
        //Previous direction was 2 ( up) and new direction would be 3 (right). So i have to rotate from 90 to 180 degrees.
        this.rotatePacman(90, 180, CLOCKWISE_ROTATION);
        break;
      case 3:
        //Previous direction was 3 ( right) and new direction would be 3 (right). So no rotation needed.
        break;
      case 4:
        //Previous direction was 4 ( down) and new direction would be 3 (right). So i have to rotate from 270 to 180  degrees.
        this.rotatePacman(270, 180, ANTICLOCKWISE_ROTATION);
        break;
      default:
      //
    }
    //new direction ( moving right)
    this.direction = 3;
    this.x = this.x + this.speed;

    arc(this.x, this.y, 80, 80, this.startAngle, this.endAngle, PIE);
  }
  moveLeft() {
    switch (this.direction) {
      case 1:
        //Previous direction was 1 ( left) and new direction would be 1 (left). So no rotation needed.
        break;
      case 2:
        //Previous direction was 2 ( up) and new direction would be 1 (left). So i have to rotate from 90 to 0 degrees.
        this.rotatePacman(90, 0, ANTICLOCKWISE_ROTATION);
        break;
      case 3:
        //Previous direction was 3 ( right) and new direction would be 1 (left). So i have to rotate from 180 to 0 degrees.
        this.rotatePacman(180, 0, ANTICLOCKWISE_ROTATION);
        break;
      case 4:
        //Previous direction was 4 ( down) and new direction would be 1 (left). So i have to rotate from 270 to 0  degrees.
        //Better from -90 to 0. if possible
        this.rotatePacman(-90, 0, ANTICLOCKWISE_ROTATION);
        break;
      default:
      //
    }
    //new direction ( moving left)
    this.direction = 1;
    this.x = this.x - this.speed;

    arc(this.x, this.y, 80, 80, this.startAngle, this.endAngle, PIE);
  }

  moveDown() {
    switch (this.direction) {
      case 1:
        //Previous direction was 1 ( left) and new direction would be 4 (down).So i have to rotate from 0 to 270 o from 0 to -90
        //this.rotatePacman(0, 270, CLOCKWISE_ROTATION);
        this.rotatePacman(0, -90, ANTICLOCKWISE_ROTATION);
        break;
      case 2:
        //Previous direction was 2 ( up) and new direction would be 4 (down). So i have to rotate from 90 to 270 degrees.
        this.rotatePacman(90, 270, CLOCKWISE_ROTATION);
        break;
      case 3:
        //Previous direction was 3 ( right) and new direction would be 4 (down). So i have to rotate from 180 to 270 degrees.
        this.rotatePacman(180, 270, CLOCKWISE_ROTATION);
        break;
      case 4:
        //Previous direction was 4 ( down) and new direction would be 4 (down). So no rotation needed.
        break;
      default:
      //
    }
    //new direction ( moving down)
    this.direction = 4;
    this.y = this.y + this.speed;

    arc(this.x, this.y, 80, 80, this.startAngle, this.endAngle, PIE);
  }
  moveUp() {
    switch (this.direction) {
      case 1:
        //Previous direction was 1 ( left) and new direction would be 2 (up).So i have to rotate from 0 to 90
        //this.rotatePacman(0, 270, CLOCKWISE_ROTATION);
        this.rotatePacman(0, 90, CLOCKWISE_ROTATION);
        break;
      case 2:
        //Previous direction was 2 ( up) and new direction would be 2 (up). So no rotation needed.
        break;
      case 3:
        //Previous direction was 3 ( right) and new direction would be 2 (UP). So i have to rotate from 180 to 90 degrees.
        this.rotatePacman(180, 90, ANTICLOCKWISE_ROTATION);
        break;
      case 4:
        //Previous direction was 4 ( down) and new direction would be 2 (up). So rotation needed from 270 to 90 or -90 to 90.
        this.rotatePacman(270, 90, ANTICLOCKWISE_ROTATION);
        //this.rotatePacman(90, -90, ANTICLOCKWISE_ROTATION);
        break;
      default:
      //
    }
    //new direction ( moving up)
    this.direction = 2;
    this.y = this.y - this.speed;

    arc(this.x, this.y, 80, 80, this.startAngle, this.endAngle, PIE);
  }

  /**
   * Rotate pacman from one start angle to a end angle, rotation direction could be clockwise or anticlockwise.
   * @constructor
   * @param {int} startAngle - start angle of the rotation.
   * @param {int} endAngle - the end angle of the rotation.
   * @param {int} direction - CLOCKWISE_ROTATION or ANTICLOCK_ROTATION
   */
  rotatePacman(startAngle, endAngle, direction) {
    
    const STEP_ANGLE = 0.5;
    fill(255, 255, 0);
    noStroke();

    // Update start and stop angles
    this.biteSize = PI / 16; // smaller the denominator, bigger the bite
    startAngle = this.biteSize * sin(frameCount * 0.1) + this.biteSize;
    endAngle = TWO_PI - startAngle;
    let pacAngle = startAngle
    // this is the only Pacman that you are drawing
    while ( pacAngle < endAngle) 
    {
      push();
      translate(this.x, this.y);
      /*if( direction == CLOCKWISE_ROTATION){
        pacAngle= pacAngle + 0.5;
       }
      else if ( direction == ANTICLOCKWISE_ROTATION) {
        pacAngle = pacAngle + 0.5;
      }
      else {
        console.log("Aqui pasa algo raro")
      }*/
       pacAngle = pacAngle + STEP_ANGLE;
       if( direction == CLOCKWISE_ROTATION){
        rotate(radians(pacAngle)); // this angle changes
       }
      else if ( direction == ANTICLOCKWISE_ROTATION) {
       rotate(radians(-pacAngle)); // this angle changes
      }
      else {
        console.log("Aqui pasa algo raro")
      }
//rotate(radians(pacAngle)); // this angle changes
      arc(this.x, this.y, 80, 80, startAngle, startAngle + pacAngle, PIE);
      pop();
    }
    //pacAngle = pacAngle + 0.5; // grow angle, makes Pacman turn
  } //Close method rotatePacman
} // Close Paman class

function setup() {
  createCanvas(1200, 800);
  pacMan = new PacMan(50, 50);
  pacMan.direction = 3;
}

function draw() {
  background(0);
  pacMan.stay();
}

// **** Click on canvas to start **** //
function keyPressed(event) {
  if (keyCode === LEFT_ARROW) {
    pacMan.moveLeft();
  } else if (keyCode === RIGHT_ARROW) {
    pacMan.moveRight();
  } else if (keyCode === UP_ARROW) {
    pacMan.moveUp();
  } else if (keyCode === DOWN_ARROW) {
    pacMan.moveDown();
  }
}

Hello @edufissure,

This topic inspired this:
Pac-Man Waka Waka Arcs

I wrote from scratch… there may be elements in there that may help.

:)

Made some progress…i do the waka waka animation and pacman can move in the four directions…the only thing im missing and i really need help it to rotate from looking left to looking up, for example in some kind of nice transition, lets say degree by degree

The code:


/*frameCount

A Number variable that tracks the number of frames drawn since the sketch started.

frameCount's value is 0 inside setup(). It increments by 1 each time the code in draw() finishes executing.
*/
const CLOCKWISE_ROTATION = 0;
const ANTICLOCKWISE_ROTATION = 1;

class PacMan {
  constructor(x, y) {
    this.speed = 10;
    this.stepFrame = 0.1;
    this.x = x;
    this.y = y;
    this.direction = 1; //ClockWise 1 Left, 2 up, 3 right, 4 down arbitrary numbers
    fill(255, 255, 0);
    this.biteSize = PI / 16;
    this.startBiteAngle;
    this.endBiteAngle;
  }
  stay() {
    //angleMode(DEGREES);

    switch (this.direction) {
      case 1:
        this.startBiteAngle = radians(-168.75) + this.biteSize * sin(frameCount * this.stepFrame);
        this.endBiteAngle = radians(168.75) - this.biteSize * sin(frameCount * this.stepFrame);
        break;
      case 2:
        this.startBiteAngle = radians(-78.75) + this.biteSize * sin(frameCount * this.stepFrame);
        this.endBiteAngle = radians(258.75) - this.biteSize * sin(frameCount * this.stepFrame);
        break;
      case 3:
        this.startBiteAngle = this.biteSize * sin(frameCount * this.stepFrame) + this.biteSize;
        this.endBiteAngle = TWO_PI - this.startBiteAngle;
        break;
      case 4:
        this.startBiteAngle = radians(-258.75) + this.biteSize * sin(frameCount * this.stepFrame);
        this.endBiteAngle = radians(78.75) - this.biteSize * sin(frameCount * this.stepFrame);
        break;
      default:
      //
    }

    arc(this.x, this.y, 80, 80, this.startBiteAngle, this.endBiteAngle, PIE);
  }
  moveRight() {
    switch (this.direction) {
      case 1:
        //Previous direction was 1 ( left) and new direction would be 3 (right). So i have to rotate from 0 to 180 degrees.
        this.rotatePacman(0, 180, CLOCKWISE_ROTATION);
        break;
      case 2:
        //Previous direction was 2 ( up) and new direction would be 3 (right). So i have to rotate from 90 to 180 degrees.
        this.rotatePacman(90, 180, CLOCKWISE_ROTATION);
        break;
      case 3:
        //Previous direction was 3 ( right) and new direction would be 3 (right). So no rotation needed.
        break;
      case 4:
        //Previous direction was 4 ( down) and new direction would be 3 (right). So i have to rotate from 270 to 180  degrees.
        this.rotatePacman(270, 180, ANTICLOCKWISE_ROTATION);
        break;
      default:
      //
    }
    //new direction ( moving right)
    this.direction = 3;
    this.x = this.x + this.speed;
    
    this.startBiteAngle = this.biteSize * sin(frameCount * this.stepFrame) + this.biteSize;
    this.endBiteAngle = TWO_PI - this.startBiteAngle;
    arc(this.x, this.y, 80, 80, this.startBiteAngle, this.endBiteAngle, PIE);
  }
  moveLeft() {
    switch (this.direction) {
      case 1:
        //Previous direction was 1 ( left) and new direction would be 1 (left). So no rotation needed.
        break;
      case 2:
        //Previous direction was 2 ( up) and new direction would be 1 (left). So i have to rotate from 90 to 0 degrees.
        this.rotatePacman(90, 0, ANTICLOCKWISE_ROTATION);
        break;
      case 3:
        //Previous direction was 3 ( right) and new direction would be 1 (left). So i have to rotate from 180 to 0 degrees.
        this.rotatePacman(180, 0, ANTICLOCKWISE_ROTATION);
        break;
      case 4:
        //Previous direction was 4 ( down) and new direction would be 1 (left). So i have to rotate from 270 to 0  degrees.
        //Better from -90 to 0. if possible
        this.rotatePacman(-90, 0, ANTICLOCKWISE_ROTATION);
        break;
      default:
      //
    }
    //new direction ( moving left)
    this.direction = 1;
    this.x = this.x - this.speed;
    this.stay();
    /*
    this.startBiteAngle = radians(-168.75) + this.biteSize * sin(frameCount * this.stepFrame);
    this.endBiteAngle = radians(168.75) - this.biteSize * sin(frameCount * this.stepFrame);

    arc(this.x, this.y, 80, 80, this.startBiteAngle, this.endBiteAngle, PIE);*/
  }

  moveDown() {
    switch (this.direction) {
      case 1:
        //Previous direction was 1 ( left) and new direction would be 4 (down).So i have to rotate from 0 to 270 o from 0 to -90
        //this.rotatePacman(0, 270, CLOCKWISE_ROTATION);
        this.rotatePacman(0, -90, ANTICLOCKWISE_ROTATION);
        break;
      case 2:
        //Previous direction was 2 ( up) and new direction would be 4 (down). So i have to rotate from 90 to 270 degrees.
        this.rotatePacman(90, 270, CLOCKWISE_ROTATION);
        break;
      case 3:
        //Previous direction was 3 ( right) and new direction would be 4 (down). So i have to rotate from 180 to 270 degrees.
        this.rotatePacman(180, 270, CLOCKWISE_ROTATION);
        break;
      case 4:
        //Previous direction was 4 ( down) and new direction would be 4 (down). So no rotation needed.
        break;
      default:
      //
    }
    //new direction ( moving down)
    this.direction = 4;
    this.y = this.y + this.speed;
    this.stay();
    /*
    this.startBiteAngle = radians(-258.75) + this.biteSize * sin(frameCount * this.stepFrame);
    this.endBiteAngle = radians(78.75) - this.biteSize * sin(frameCount * this.stepFrame);

    arc(this.x, this.y, 80, 80, this.startBiteAngle, this.endBiteAngle, PIE);*/
  }
  moveUp() {
    switch (this.direction) {
      case 1:
        //Previous direction was 1 ( left) and new direction would be 2 (up).So i have to rotate from 0 to 90
        //this.rotatePacman(0, 270, CLOCKWISE_ROTATION);
        this.rotatePacman(0, 90, CLOCKWISE_ROTATION);
        break;
      case 2:
        //Previous direction was 2 ( up) and new direction would be 2 (up). So no rotation needed.
        break;
      case 3:
        //Previous direction was 3 ( right) and new direction would be 2 (UP). So i have to rotate from 180 to 90 degrees.
        this.rotatePacman(180, 90, ANTICLOCKWISE_ROTATION);
        break;
      case 4:
        //Previous direction was 4 ( down) and new direction would be 2 (up). So rotation needed from 270 to 90 or -90 to 90.
        this.rotatePacman(270, 90, ANTICLOCKWISE_ROTATION);
        //this.rotatePacman(90, -90, ANTICLOCKWISE_ROTATION);
        break;
      default:
      //
    }
    //new direction ( moving up)
    this.direction = 2;
    this.y = this.y - this.speed;
    this.stay();
    /*
  this.startBiteAngle = radians(-78.75) + this.biteSize * sin(frameCount * this.stepFrame);
   this.endBiteAngle = radians(258.75) - this.biteSize * sin(frameCount * this.stepFrame);
    arc(this.x, this.y, 80, 80, this.startBiteAngle, this.endBiteAngle, PIE);*/
  }

  /**
   * Rotate pacman from one start angle to a end angle, rotation direction could be clockwise or anticlockwise.
   * @constructor
   * @param {int} startBiteAngle - start angle of the rotation.
   * @param {int} endBiteAngle - the end angle of the rotation.
   * @param {int} direction - CLOCKWISE_ROTATION or ANTICLOCK_ROTATION
   */
  rotatePacman(startAngle, endAngle, direction) {
    noLoop();
    const STEP_ANGLE = 0.5;
    fill(255, 255, 0);
    noStroke();

    
    let pacAngle = startAngle;
    // this is the only Pacman that you are drawing
    while (pacAngle < endAngle) {
      push();
      translate(this.x, this.y);
      pacAngle = pacAngle + STEP_ANGLE;
      if (direction == CLOCKWISE_ROTATION) {
        rotate(radians(pacAngle)); // this angle changes
      } else if (direction == ANTICLOCKWISE_ROTATION) {
        rotate(radians(-pacAngle)); // this angle changes
      } else {
        console.log("Aqui pasa algo raro");
      }
      console.log("Estoy en "+ pacAngle + " y quiero llegar a endAngle" + endAngle);
    //  rotate(radians(pacAngle)); // this angle changes
      //arc( this.x, this.y, 80,  80, startBiteAngle, startBiteAngle + pacAngle, PIE);
      pop();
    }
    loop();
    //pacAngle = pacAngle + 0.5; // grow angle, makes Pacman turn
  } //Close method rotatePacman
} // Close Paman class

function setup() {
  createCanvas(700, 700);
  pacMan = new PacMan(50, 50);
  pacMan.direction = 1;
}

function draw() {
  background(0);
  pacMan.stay();
}

// **** Click on canvas to start **** //
function keyPressed(event) {
  if (keyCode === LEFT_ARROW) {
    pacMan.moveLeft();
  } else if (keyCode === RIGHT_ARROW) {
    pacMan.moveRight();
  } else if (keyCode === UP_ARROW) {
    pacMan.moveUp();
  } else if (keyCode === DOWN_ARROW) {
    pacMan.moveDown();
  }
}

Also any help imporving the code would be apreciated, i think it can be easier to paint the arc (pacman) with start and end bite angle…But i havent found a better or more easy solution.

Thanks
pd: think if you wanna help that my students would be happy :slight_smile:

@GoToLoop can you adapt or give some hints this code: Reddit - Dive into anything

To my code, if you test my code it gives some weird behaviour when pressing more than one key at once ( left, right, up, down arrow). I think the code is right but if you press simultaneally or almost same time lets say right and left, then the result movement is weird…some kind of give some priority or waiting some time miliseconds to avoid this… i saw that in you code the movement is clean and smooth…

Thanks

Another rotation example (rotate PacMan by hitting spaceBar):

float rotDegStart = 12; // start facing right
float rotDegEnd = 348;
float biteSize;

void setup() {
  size(400, 200);
  surface.setTitle("PacMan Rotate");
  fill(255, 255, 0);
  biteSize = PI/16; //smaller denominator => bigger bite
}

void draw() {
  background(0);
  arc(width/2, height/2, 80, 80, radians(rotDegStart)-biteSize*sin(frameCount*0.1), radians(rotDegEnd)+biteSize*sin(frameCount*0.1), PIE);
}

void keyPressed() {
  // spaceBar = 32
  if (keyCode == 32) {
    rotDegStart += 2;
    rotDegEnd += 2;
  }
}

There’s also a p5.js version of it:
https://www.Reddit.com/r/processing/comments/bshqa8/how_would_i_make_a_keypressed_function_support/eoolcrm/
Maybe it’s easier to understand the code.