From Nand to Tetris week 9
这次回顾第九章的内容,这一章介绍了Jack编程语言。
课程官网:
视频地址:
https://www.coursera.org/learn/build-a-computer
Part 1:课程回顾
背景介绍
这章介绍了Jack语言,项目为利用Jack语言写一个app,背景介绍部分从略。
Part 2:项目
这部分编写了Breakout游戏,截图如下:
该程序的构成如下:
Ball
/** BALL */
class Ball{
// screen location of the ball's center
field int x, y;
// radius of the ball
field int r;
// x direction of the ball, 0 means right, 1 means left
field int directionx;
// y direction of the ball, 0 means down, 1 means up
field int directiony;
/** Constructs a new ball. */
constructor Ball new(int Ax, int Ay, int Ar) {
let directionx = 0;
let directiony = 0;
let x = Ax;
let y = Ay;
let r = Ar;
do draw();
return this;
}
/** Draw thet ball */
method void draw() {
do Screen.setColor(true);
do Screen.drawCircle(x, y, r);
return;
}
/** Moves the ball left and up by 1 pixels. */
method void moveUpLeft(){
if (((x - r) > 1) & ((y - r) > 1)) {
do Screen.setColor(false);
do Screen.drawCircle(x, y, r);
let x = x - 1;
let y = y - 1;
do Screen.setColor(true);
do Screen.drawCircle(x, y, r);
}
return;
}
/** Moves the ball left and down by 1 pixels. */
method void moveDownLeft(){
if (((x - r) > 1) & ((y + r) < 255)) {
do Screen.setColor(false);
do Screen.drawCircle(x, y, r);
let x = x - 1;
let y = y + 1;
do Screen.setColor(true);
do Screen.drawCircle(x, y, r);
}
return;
}
/** Moves the ball right and up by 1 pixels. */
method void moveUpRight() {
if (((x + r) < 511) & ((y - r) > 1)) {
do Screen.setColor(false);
do Screen.drawCircle(x, y, r);
let x = x + 1;
let y = y - 1;
do Screen.setColor(true);
do Screen.drawCircle(x, y, r);
}
return;
}
/** Moves the ball right and down by 1 pixels. */
method void moveDownRight() {
if (((x + r) < 511) & ((y + r) < 255)) {
do Screen.setColor(false);
do Screen.drawCircle(x, y, r);
let x = x + 1;
let y = y + 1;
do Screen.setColor(true);
do Screen.drawCircle(x, y, r);
}
return;
}
/** Erase the ball. */
method void erase() {
do Screen.setColor(false);
do Screen.drawCircle(x, y, r);
return;
}
/** Return radius. */
method int r() {
return r;
}
/** Return x. */
method int x() {
return x;
}
/** Return y. */
method int y() {
return y;
}
/** Return directionx. */
method int directionx() {
return directionx;
}
/** Return directiony. */
method int directiony() {
return directiony;
}
/** Set directionx. */
method void set_directionx(int x){
let directionx = x;
return;
}
/** Set directiony. */
method void set_directiony(int y){
let directiony = y;
return;
}
}
Brick
/** Brick. */
class Brick {
// screen location of the square's top-left corner
field int x, y;
// width of the brick
field int width;
// height of the brick
field int height;
// judge whether to show the brick
field int state;
/** Constructs a new Bricks with a given location and size. */
constructor Brick new(int Ax, int Ay, int w, int h) {
let x = Ax;
let y = Ay;
let width = w;
let height = h;
let state = 1;
do draw();
return this;
}
/** Draws the brick on the screen. */
method void draw() {
do Screen.setColor(true);
do Screen.drawRectangle(x, y, x + width, y + height);
return;
}
/** Erases the brick from the screen. */
method void erase() {
do Screen.setColor(false);
do Screen.drawRectangle(x, y, x + width, y + height);
return;
}
/** Return state. */
method int state() {
return state;
}
/** Set state. */
method void set_state(int s) {
let state = s;
return;
}
/** Return x. */
method int x() {
return x;
}
/** Return y. */
method int y() {
return y;
}
/** Return width. */
method int width() {
return width;
}
/** Return height. */
method int height() {
return height;
}
}
Paddle
/** PADDLE */
class Paddle{
// screen location of the square's top-left corner
field int x, y;
// width of the paddle
field int width;
// height of the paddle
field int height;
/** Constructs a new paddle. */
constructor Paddle new(int Ax, int Ay, int w, int h) {
let x = Ax;
let y = Ay;
let width = w;
let height = h;
do draw();
return this;
}
/** Draws the paddle on the screen. */
method void draw() {
do Screen.setColor(true);
do Screen.drawRectangle(x, y, x + width, y + height);
return;
}
/** Moves the paddle left by 2 pixels. */
method void moveLeft() {
if (x > 1) {
do Screen.setColor(false);
do Screen.drawRectangle((x + width) - 1, y, x + width, y + height);
let x = x - 2;
do Screen.setColor(true);
do Screen.drawRectangle(x, y, x + 1, y + height);
}
return;
}
/** Moves the paddle right by 2 pixels. */
method void moveRight() {
if ((x + width) < 510) {
do Screen.setColor(false);
do Screen.drawRectangle(x, y, x + 1, y + height);
let x = x + 2;
do Screen.setColor(true);
do Screen.drawRectangle((x + width) - 1, y, x + width, y + height);
}
return;
}
/** Erases the paddle from the screen. */
method void erase() {
do Screen.setColor(false);
do Screen.drawRectangle(x, y, x + width, y + height);
return;
}
/** Return x. */
method int x() {
return x;
}
/** Return y. */
method int y() {
return y;
}
/** Return width. */
method int width() {
return width;
}
/** Return height. */
method int height() {
return height;
}
}
Breakout game
/** Breakout game */
class Breakoutgame{
// brick
field Brick brick;
// width of the brick
field int width;
// height of the brick
field int height;
// number of bricks in each row
field int row;
// number of rows of bricks
field int col;
// brick's start location of x
field int x;
// brick's start location of y
field int y;
// separation between neighboring bricks, in pixels
field int sep;
// array to store bricks
field Array Bricks;
// Counter
field int i, j;
// paddle
field Paddle paddle;
// width of the paddle
field int paddle_width;
// height of the paddle
field int paddle_height;
// x location of paddle
field int paddle_x;
// y location of paddle
field int paddle_y;
// paddle's direction
field int direction;
// ball
field Ball ball;
// x location of ball
field int ball_x;
// y location of ball
field int ball_y;
// r of ball
field int ball_r;
// whether fail
field int flag;
// judge whether hit the brick in a double loop
field int judge;
// judge whether hit the brick in a loop
field int p;
// count the number of finished bricks
field int cnt;
/** Constructs a new Breakout Game. */
constructor Breakoutgame new() {
// brick
let row = 5;
let col = 8;
let width = 60;
let height = 12;
let x = 0;
let y = 30;
let sep = 4;
let Bricks = Array.new(row * col);
// paddle
let paddle_height = 10;
let paddle_width = 80;
let paddle_x = 216;
let paddle_y = 240;
let direction = 0;
// ball
let ball_x = 256;
let ball_y = 200;
let ball_r = 2;
// counter
let i = 0;
let j = 0;
let cnt = 0;
// initialization
let flag = 0;
let judge = 0;
let p = 0;
// Set up bricks
while (i < col){
let j = 0;
while (j < row){
let brick = Brick.new(x + (i * (width + sep)), y + (j * (height + sep)),
width, height);
let Bricks[i * row + j] = brick;
let j = j + 1;
}
let i = i + 1;
}
// Set up ball
let ball = Ball.new(ball_x, ball_y, ball_r);
// Set up paddle
let paddle = Paddle.new(paddle_x, paddle_y, paddle_width, paddle_height);
// Run the game
do run();
return this;
}
/** Moves the paddle in the current direction. */
method void movePaddle() {
//do Output.printInt(1);
if (direction = 1) { do paddle.moveLeft(); }
if (direction = 2) { do paddle.moveRight(); }
do Sys.wait(3); // delays the next movement
return;
}
/** Run the game */
method void run() {
var char key; // the key currently pressed by the user
var boolean exit;
let exit = false;
while (~exit) {
// waits for a key to be pressed
while (key = 0) {
let key = Keyboard.keyPressed();
do movePaddle();
// if fail, restart
if (flag = 1) {
do paddle.erase();
do ball.erase();
let paddle = Paddle.new(paddle_x, paddle_y, paddle_width, paddle_height);
let ball = Ball.new(ball_x, ball_y, ball_r);
let flag = 0;
}
// refresh the state
do Ball_state();
// move the ball
do Ball_run();
// if finish, break the game
if (cnt = (row * col)) {
let exit = true;
}
}
if (key = 81) { let exit = true; } // q key
if (key = 130) { let direction = 1; } // left arrow
if (key = 132) { let direction = 2; } // right arrow
// waits for the key to be released
while (~(key = 0)) {
let key = Keyboard.keyPressed();
do movePaddle();
// if fail, restart
if (flag = 1) {
do Output.printInt(1);
do paddle.erase();
do ball.erase();
let paddle = Paddle.new(paddle_x, paddle_y, paddle_width, paddle_height);
let ball = Ball.new(ball_x, ball_y, ball_r);
let flag = 0;
}
// refresh the state
do Ball_state();
// move the ball
do Ball_run();
// if finish, break the game
if (cnt = (row * col)) {
let exit = true;
}
}
} // while
return;
}
/** Change the state of the ball */
method void Ball_state() {
// change the state when hit the wall
if (((ball.x() + ball.r()) = 511)) {
do ball.set_directionx(1);
}
if (((ball.x() - ball.r()) = 1)) {
do ball.set_directionx(0);
}
if (((ball.y() + ball.r()) = 255)) {
do ball.set_directiony(1);
}
if (((ball.y() - ball.r()) = 1)) {
do ball.set_directiony(0);
}
// change the state when hit the paddle
if (((ball.y() + ball.r()) = (paddle.y() - 1)) & (ball.x() > paddle.x())
& (ball.x() < (paddle.x() + paddle_width))) {
do ball.set_directiony(1);
}
// judge whether fail
if (((ball.y() + ball.r()) > (paddle.y() - 1)) |
(((ball.y() + ball.r()) = paddle.y()) & (ball.x() < paddle.x())) |
(((ball.y() + ball.r()) = paddle.y()) & (ball.x() > (paddle.x() + paddle_width)))) {
let flag = 1;
return;
}
// change the state when hit the brick
// Counter
let i = 0;
let j = 0;
let p = 0;
while ((i < col) & (p = 0)){
let j = 0;
while ((j < row) & (p = 0)){
let brick = Bricks[i * row + j];
let judge = 0;
if (brick.state() = 1) {
if (((ball.x() + ball.r()) = brick.x()) &
(ball.y() > (brick.y() - ball_r)) &
(ball.y() < (brick.y() + brick.height() + ball_r)) &
(judge = 0)) {
do ball.set_directionx(1);
do brick.set_state(0);
do brick.erase();
let judge = 1;
let p = 1;
let Bricks[i * row + j] = brick;
let cnt = cnt + 1;
}
if (((ball.x() - ball.r()) = (brick.x() + brick.width())) &
(ball.y() > (brick.y() - ball_r)) &
(ball.y() < (brick.y() + brick.height() + ball_r)) &
(judge = 0)) {
do ball.set_directionx(0);
do brick.set_state(0);
do brick.erase();
let judge = 1;
let p = 1;
let Bricks[i * row + j] = brick;
let cnt = cnt + 1;
}
if (((ball.y() + ball.r()) = brick.y()) &
(ball.x() > (brick.x() - ball_r)) &
(ball.x() < (brick.x() + brick.width() + ball_r)) &
(judge = 0)){
do ball.set_directiony(1);
do brick.set_state(0);
do brick.erase();
let judge = 1;
let p = 1;
let Bricks[i * row + j] = brick;
let cnt = cnt + 1;
}
if (((ball.y() - ball.r()) = (brick.y() + brick.height())) &
(ball.x() > (brick.x() - ball_r)) &
(ball.x() < (brick.x() + brick.width() + ball_r)) &
(judge = 0)) {
do ball.set_directiony(0);
do brick.set_state(0);
do brick.erase();
let judge = 1;
let p = 1;
let Bricks[i * row + j] = brick;
let cnt = cnt + 1;
}
}
let j = j + 1;
}
let i = i + 1;
}
return;
}
/** ball_run */
method void Ball_run() {
if ((ball.directionx() = 0) & (ball.directiony() = 0)){
do ball.moveDownRight();
//do Sys.wait(1);
}
if ((ball.directionx() = 0) & (ball.directiony() = 1)){
do ball.moveUpRight();
//do Sys.wait(1);
}
if ((ball.directionx() = 1) & (ball.directiony() = 0)){
do ball.moveDownLeft();
//do Sys.wait(1);
}
if ((ball.directionx() = 1) & (ball.directiony() = 1)){
do ball.moveUpLeft();
//do Sys.wait(1);
}
return;
}
}
Main
/** Initializes a new Breakout game and starts running it. */
class Main {
function void main() {
var BreakoutGame game;
let game = Breakoutgame.new();
return;
}
}
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Doraemonzzz!
评论
ValineLivere