JavaFX实战之游戏2048

该文章已生成可运行项目,

简介

源码下载

计算机是门实践性很强的学科,光看没用,一定要动手。比如你看了javaFX的教程,感觉啥都会了,然后一跑代码全是错,一做项目发现这个没学到,那个没人教。所以书和文档只是给你个方向指引,真正掌握一门技术,就是动手,干就完了。

2048是一个很简单的小游戏,整体上分成两部分,一部分是人机交互,另一部分是游戏逻辑控制。这两部分整合到一起就是个完整的游戏。人机交互部分就是画个图面(ui),接受用户输入,比如鼠标/键盘,用户输入后触发后台数据的变化,通过游戏逻辑返回相应的结果,再通过屏幕反馈给玩家。2048的游戏逻辑就是横纵方向的数字以2指数进行合并,这里边需要进行数字比较,相同的才能合并,不同的不能合并。

以下是2048的DEMO截图,这DEMO并不是完整的游戏。

前端实现

先是实现4*4的圆角矩形阵列,方框用Rectagle控件,数字用Label控件有数字显示,没数字不显示:

for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				double x = j * tile_width + (j + 1) * BLANK_COL_WIDTH;
				double y = i * tile_height + (i + 1) * BLANK_ROW_HEIGHT;

				double radius = (canvas_height > tile_width) ? (canvas_height / 20.0) : (tile_width / 20.0);

				Rectangle rect = new Rectangle(x, y, tile_width, tile_height);

				rect.setArcHeight(radius);
				rect.setArcWidth(radius);
				rect.setFill(Color.WHITE);
				backgroudPane.getChildren().add(rect);

				Label number = new Label();
				number.setFont(Font.font("Sans", FontWeight.BOLD, tile_height / 2));
				number.setAlignment(Pos.CENTER);
				number.setBackground(Background.EMPTY);
				number.setTextFill(Color.WHITE);
				number.setPrefWidth(tile_width);
				number.setPrefHeight(tile_height);
				number.setLayoutX(x);
				number.setLayoutY(y);
				backgroudPane.getChildren().add(number);

				tileHolder[i][j] = new TileView();
				tileHolder[i][j].number = number;
				tileHolder[i][j].backgroud = rect;
				tileHolder[i][j].val = 0;
			}
		}

用户响应

用户输入只有上下左右,这里用键盘的wasd四个键控制方向。

backgroudPane.getParent().setOnKeyPressed((event) -> {
			System.out.println(event.getCode());
			switch (event.getCode()) {
			case W:
			case UP:
				move(MoveRequest.UP);
				break;
			case A:
			case LEFT:
				move(MoveRequest.LEFT);
				break;
			case S:
			case DOWN:
				move(MoveRequest.DOWN);
				break;
			case D:
			case RIGHT:
				move(MoveRequest.RIGHT);
				break;
			default:
				break;
			}
			refresh();
		});

逻辑控制

比如向上移动,向上的纵向的变化,同列合并:

	private int move_down(int cols, int rows, int max_changed) {
		int m = 0;
		var grid = cellValues;
		for (short i = 0; i < cols; i++) {
			GridPosition free = new GridPosition();// { rows, i };
			free.row = rows;
			free.col = i;

			for (int j = 0; j < rows; j++) {
//从上往下
				int row = rows - j - 1;
				GridPosition cur = new GridPosition();// { row, i };
				cur.col = i;
				cur.row = row;

				int val = grid[cur.row][cur.col];
//0表示没有数字,跳过
				if (val == 0) {
					if (free.row == rows)
						free.row = row;
					continue;
				}

				// 查找前一个相同的数字
				GridPosition match = new GridPosition();// { 0, 0 };
				boolean has_match = false;
				for (int k = row - 1; k >= 0; k--) {
					int k_val = grid[k][cur.col];

					if (k_val != 0) {

						if (k_val == val) {
							has_match = true;
//                            match = { k, cur.col };
							match.row = k;
							match.col = cur.col;
						}
						break;
					}
				}
//找到后进行合并
				if (has_match) {
					if (free.row == rows)
						free.row = row; // temporarily
					m++;
					move_to_match(cur, free, match, val, max_changed);
					free.row--;
				} else if (free.row != rows) {
//没找到移到最上边。
					move_to_end(cur, free, val);
					m++;
					free.row--;
				}
			}
		}
		return m;
	}

界面刷新

后台数据变化要体验在前端界面上:

	private void refresh() {
		int rows = ROWS;
		int cols = COLS;
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				tileHolder[i][j].val = data.getValue(i, j);

				if (tileHolder[i][j].val == 0) {
					tileHolder[i][j].number.setText("");
				} else {
					tileHolder[i][j].number.setText("" + (int) Math.pow(2, tileHolder[i][j].val));
				}

				tileHolder[i][j].backgroud.setFill(colors.get(tileHolder[i][j].val));

			}
		}
	}

总结

此版本实现比较简单,玩家每次按一下键盘,然后就会得到一个结果,在合适的机会把数据刷出来,这里第次按键之后,进行一次刷新。因为游戏变化是跟按键一一对应的,所以这么实现没啥问题,只是效果差一点,如次想效果好一点,可以加上动画,让用户感受到方块的移动,在动画结束的时候再刷新界面,其结果是一样的,但有可能鼠标按太快没反应,因为动画还没结束。

本文章已经生成可运行项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值