summaryrefslogtreecommitdiff
path: root/projects/11/Pong/Ball.jack
diff options
context:
space:
mode:
Diffstat (limited to 'projects/11/Pong/Ball.jack')
-rw-r--r--projects/11/Pong/Ball.jack203
1 files changed, 203 insertions, 0 deletions
diff --git a/projects/11/Pong/Ball.jack b/projects/11/Pong/Ball.jack
new file mode 100644
index 0000000..02e47f9
--- /dev/null
+++ b/projects/11/Pong/Ball.jack
@@ -0,0 +1,203 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/11/Pong/Ball.jack
+
+/**
+ * A graphical ball. Characterized by a screen location and distance of
+ * last destination. Has methods for drawing, erasing and moving on the screen.
+ * The ball is displayed as a filled, 6-by-6 pixles rectangle.
+ */
+class Ball {
+
+ field int x, y; // the ball's screen location (in pixels)
+ field int lengthx, lengthy; // distance of last destination (in pixels)
+
+ field int d, straightD, diagonalD; // used for straight line movement computation
+ field boolean invert, positivex, positivey; // (same)
+
+ field int leftWall, rightWall, topWall, bottomWall; // wall locations
+
+ field int wall; // last wall that the ball was bounced off of
+
+ /** Constructs a new ball with the given initial location and wall locations. */
+ constructor Ball new(int Ax, int Ay,
+ int AleftWall, int ArightWall, int AtopWall, int AbottomWall) {
+ let x = Ax;
+ let y = Ay;
+ let leftWall = AleftWall;
+ let rightWall = ArightWall - 6; // -6 for ball size
+ let topWall = AtopWall;
+ let bottomWall = AbottomWall - 6; // -6 for ball size
+ let wall = 0;
+ do show();
+ return this;
+ }
+
+ /** Deallocates the Ball's memory. */
+ method void dispose() {
+ do Memory.deAlloc(this);
+ return;
+ }
+
+ /** Shows the ball. */
+ method void show() {
+ do Screen.setColor(true);
+ do draw();
+ return;
+ }
+
+ /** Hides the ball. */
+ method void hide() {
+ do Screen.setColor(false);
+ do draw();
+ return;
+ }
+
+ /** Draws the ball. */
+ method void draw() {
+ do Screen.drawRectangle(x, y, x + 5, y + 5);
+ return;
+ }
+
+ /** Returns the ball's left edge. */
+ method int getLeft() {
+ return x;
+ }
+
+ /** Returns the ball's right edge. */
+ method int getRight() {
+ return x + 5;
+ }
+
+ /** Computes and sets the ball's destination. */
+ method void setDestination(int destx, int desty) {
+ var int dx, dy, temp;
+ let lengthx = destx - x;
+ let lengthy = desty - y;
+ let dx = Math.abs(lengthx);
+ let dy = Math.abs(lengthy);
+ let invert = (dx < dy);
+
+ if (invert) {
+ let temp = dx; // swap dx, dy
+ let dx = dy;
+ let dy = temp;
+ let positivex = (y < desty);
+ let positivey = (x < destx);
+ }
+ else {
+ let positivex = (x < destx);
+ let positivey = (y < desty);
+ }
+
+ let d = (2 * dy) - dx;
+ let straightD = 2 * dy;
+ let diagonalD = 2 * (dy - dx);
+
+ return;
+ }
+
+ /**
+ * Moves the ball one unit towards its destination.
+ * If the ball has reached a wall, returns 0.
+ * Else, returns a value according to the wall:
+ * 1 (left wall), 2 (right wall), 3 (top wall), 4 (bottom wall).
+ */
+ method int move() {
+
+ do hide();
+
+ if (d < 0) { let d = d + straightD; }
+ else {
+ let d = d + diagonalD;
+
+ if (positivey) {
+ if (invert) { let x = x + 4; }
+ else { let y = y + 4; }
+ }
+ else {
+ if (invert) { let x = x - 4; }
+ else { let y = y - 4; }
+ }
+ }
+
+ if (positivex) {
+ if (invert) { let y = y + 4; }
+ else { let x = x + 4; }
+ }
+ else {
+ if (invert) { let y = y - 4; }
+ else { let x = x - 4; }
+ }
+
+ if (~(x > leftWall)) {
+ let wall = 1;
+ let x = leftWall;
+ }
+ if (~(x < rightWall)) {
+ let wall = 2;
+ let x = rightWall;
+ }
+ if (~(y > topWall)) {
+ let wall = 3;
+ let y = topWall;
+ }
+ if (~(y < bottomWall)) {
+ let wall = 4;
+ let y = bottomWall;
+ }
+
+ do show();
+
+ return wall;
+ }
+
+ /**
+ * Bounces off the current wall: sets the new destination
+ * of the ball according to the ball's angle and the given
+ * bouncing direction (-1/0/1=left/center/right or up/center/down).
+ */
+ method void bounce(int bouncingDirection) {
+ var int newx, newy, divLengthx, divLengthy, factor;
+
+ // dividing by 10 first since results are too big
+ let divLengthx = lengthx / 10;
+ let divLengthy = lengthy / 10;
+ if (bouncingDirection = 0) { let factor = 10; }
+ else {
+ if (((~(lengthx < 0)) & (bouncingDirection = 1)) | ((lengthx < 0) & (bouncingDirection = (-1)))) {
+ let factor = 20; // bounce direction is in ball direction
+ }
+ else { let factor = 5; } // bounce direction is against ball direction
+ }
+
+ if (wall = 1) {
+ let newx = 506;
+ let newy = (divLengthy * (-50)) / divLengthx;
+ let newy = y + (newy * factor);
+ }
+ else {
+ if (wall = 2) {
+ let newx = 0;
+ let newy = (divLengthy * 50) / divLengthx;
+ let newy = y + (newy * factor);
+ }
+ else {
+ if (wall = 3) {
+ let newy = 250;
+ let newx = (divLengthx * (-25)) / divLengthy;
+ let newx = x + (newx * factor);
+ }
+ else { // assumes wall = 4
+ let newy = 0;
+ let newx = (divLengthx * 25) / divLengthy;
+ let newx = x + (newx * factor);
+ }
+ }
+ }
+
+ do setDestination(newx, newy);
+ return;
+ }
+}