天天看点

用JAVA写一个2048的小游戏。一、先看一下游戏运行什么样运行环境:二、代码部分详解:总结

文章目录

  • 一、先看一下游戏运行什么样
  • 运行环境:
  • 二、代码部分详解:
    • 1.项目结构及下载路径:
    • 2.所有代码部分
      • 1. Client.java:
      • 2.Constant.java
      • 3.Block.java
      • 4.BlockLoader.java
      • 5.Drawable.java
      • 6.Moveable.java
      • 7.MyFrame.java
  • 总结

一、先看一下游戏运行什么样

如图所示:

用JAVA写一个2048的小游戏。一、先看一下游戏运行什么样运行环境:二、代码部分详解:总结

运行环境:

使用软件:eclipse2021-12版

JDK版本:JDK15.0.1

二、代码部分详解:

1.项目结构及下载路径:

用JAVA写一个2048的小游戏。一、先看一下游戏运行什么样运行环境:二、代码部分详解:总结

链接:https://pan.baidu.com/s/1NVWaklg9K2wRmBOLew6iMQ

提取码:ts08

2.所有代码部分

1. Client.java:

package com.it.client;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.JOptionPane;

import com.it.constant.Constant;
import com.it.core.BlockLoader;
import com.it.core.MyFrame;


public class Client extends MyFrame{
	
	public BlockLoader loader = new BlockLoader();
	@Override
	public void loadFrame() {
		super.loadFrame();
		
		addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent e) {
				loader.keyPressed(e);
			}
		});
	}
	@Override
	public void paint(Graphics g) {
		drawBasic(g);
		drawScore(g);
		if(gameStart){
			try {
				loader.draw(g);
			} catch (CloneNotSupportedException e) {
				e.printStackTrace();
			}
		}else{
			if(!gameStart&flag)
				gameReset();
		}
	}
	public static boolean gameStart =true;
	public static boolean flag=true;
	public void gameReset(){
		flag=false;
		int m = JOptionPane.showOptionDialog(null, "对不起 , 游戏结束 ! 点击确定重新开始","游戏结束",JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE,null,new String[]{"确定","关闭游戏"},"确定");
		if(m==JOptionPane.YES_OPTION){
			gameStart=true;
			flag=true;
			loader=new BlockLoader();
		}else{
			System.exit(0);
		}
	}
	/**
	 * 画分数
	 */
	private void drawScore(Graphics g) {
		g.setColor(Color.RED);
		g.fillRoundRect(Constant.BACK_X, Constant.BACK_Y-100, 220, 80, 10, 10);
		g.setColor(Color.WHITE);
		g.setFont(new Font("幼圆", Font.BOLD, 30));
		g.drawString("分数:"+BlockLoader.score+"",Constant.BACK_X, Constant.BACK_Y-50);
		
		g.setColor(Color.GREEN);
		g.fillRoundRect(Constant.BACK_RIGHT_IN_X+Constant.BLOCK_SPACE-250, Constant.BACK_Y-100, 250, 80, 10, 10);
		g.setColor(Color.WHITE);
		g.setFont(new Font("幼圆", Font.BOLD, 30));
		g.drawString("最高分:"+BlockLoader.bestScore+"",Constant.BACK_RIGHT_IN_X+Constant.BLOCK_SPACE-250, Constant.BACK_Y-50);
		
	}
	/**
	 * 画背景
	 * @param g
	 */
	private void drawBasic(Graphics g) {
		g.setColor(Constant.COLOR_BACK);
		g.fillRoundRect(Constant.BACK_X, Constant.BACK_Y, Constant.BACK_WIDTH, Constant.BACK_HEIGHT, 20, 20);
		g.setColor(Constant.COLOR_BLOCK_BACK);
		for(int i=1;i<=4;i++){
			for(int j=1;j<=4;j++){
				int xStart =Constant.BACK_X+Constant.BLOCK_SPACE*j+Constant.BLOCK_WIDTH*(j-1);
				int yStart = Constant.BACK_Y+Constant.BLOCK_SPACE*i+Constant.BLOCK_WIDTH*(i-1);
				g.fillRoundRect(xStart, yStart, 
						Constant.BLOCK_WIDTH, Constant.BLOCK_WIDTH, 10, 10);
			}
		}
	}
	public static void main(String[] args) {
		new Client().loadFrame();
	}
}

           

2.Constant.java

package com.it.constant;

import java.awt.Color;

public class Constant {
	public static final int GAME_WIDTH = 900;
	public static final int GAME_HEIGHT = 850;

	public static final int BACK_X = 150;
	public static final int BACK_Y = 150;

	public static final int BACK_WIDTH = 600;
	public static final int BACK_HEIGHT = 600;
	
	public static final int BLOCK_SPACE = 20;
	public static final int BLOCK_WIDTH = (BACK_WIDTH - 5 * BLOCK_SPACE) / 4;
	public static final int BLOCK_HEIGHT = (BACK_HEIGHT - 5 * BLOCK_SPACE) / 4;
	
	public static final int BACK_UP_IN_Y = BACK_Y+BLOCK_SPACE;
	public static final int BACK_DOWN_IN_Y = BACK_Y + BACK_HEIGHT-BLOCK_SPACE;
	public static final int BACK_LEFT_IN_X = BACK_X +BLOCK_SPACE;
	public static final int BACK_RIGHT_IN_X = BACK_X + BACK_WIDTH-BLOCK_SPACE;

	

	public static final String IMG_PRE = "com/zzk/Game_2048/img/";

	public static final Color COLOR_BACK = new Color(187, 173, 160);
	public static final Color COLOR_BLOCK_BACK = new Color(205, 192, 180);

	public static final Color COLOR_BLOCKS_ACTIVE[] = new Color[] { 
					new Color(238, 228, 218), //2
					new Color(237, 224, 200),//4
					new Color(242, 177, 121), //8
					new Color(245, 149, 99), //16
					new Color(255, 204, 0),//32
					new Color(153, 255, 153) ,//64
					new Color(204, 204, 0),//128
					new Color(255, 204, 102),//256
					new Color(255, 80, 80),//512
					new Color(102, 102, 255),//1024
					new Color(204, 0, 102),//2048
					new Color(153, 102, 0),//4096
					new Color(153, 0, 153)//8192
	};

}

           

3.Block.java

package com.it.core;

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Label;
import java.awt.Rectangle;

import com.it.constant.Constant;


public class Block implements Drawable, Moveable {

	public static final int DIRECTION_NONE = 0;
	public static final int DIRECTION_UP = 1;
	public static final int DIRECTION_DOWN = -1;
	public static final int DIRECTION_LEFT = 2;
	public static final int DIRECTION_RIGHT = -2;
	
	public int direction = DIRECTION_NONE;// 默认静止
	private String value;
	public int xOrder;// 方块坐标(非像素坐标)
	public int yOrder;// 方块坐标
	public int x;// 像素坐标
	public int y;//
	public static final int SPEED = 5;
	int level;
	boolean live;
	public int directionX = 0;
	public int directionY = 0;
	public BlockLoader loader =null;
	public Block(int xOrder, int yOrder, int level,BlockLoader loader) {
		super();
		this.xOrder = xOrder;
		this.yOrder = yOrder;
		this.level = level;
		this.value = (int) Math.pow(2, level) + "";
		if (level == 0)
			this.live = false;
		else
			this.live = true;
		this.x = Constant.BACK_Y + Constant.BLOCK_SPACE * xOrder + Constant.BLOCK_WIDTH * (xOrder - 1);
		this.y = Constant.BACK_X + Constant.BLOCK_SPACE * yOrder + Constant.BLOCK_WIDTH * (yOrder - 1);
		this.loader=loader;
	}
	public void keyPressed(int newDirection) {
		this.direction = newDirection;
		switch (direction) {
		case DIRECTION_UP:
			directionX = 0;
			directionY = -1;
			break;
		case DIRECTION_DOWN:
			directionX = 0;
			directionY = 1;
			break;
		case DIRECTION_LEFT:
			directionX = -1;
			directionY = 0;
			break;
		case DIRECTION_RIGHT:
			directionX = 1;
			directionY = 0;
			break;
		}
		updateOrder();
	}
	
	@Override
	public void draw(Graphics g) throws CloneNotSupportedException {
		updateOrder();
		updateState();
		switch (state) {
		case STATE_UNKOWN:
		case STATE_MERGE:
			break;
		case STATE_MOVING:
		case STATE_FREE:
			move();// 移动
			break;
		}
		// 画内容
		drawContent(g);
	}

	/**
	 * 画内容
	 * 
	 * @param g
	 */
	public void drawContent(Graphics g) {
		this.value = (int) Math.pow(2, level) + "";
		g.setColor(Constant.COLOR_BLOCKS_ACTIVE[level - 1]);
		Font f = new Font("微软雅黑", Font.BOLD, 60 - 5 * value.length());
		g.setFont(f);
		FontMetrics fm = new Label().getFontMetrics(f);
		int xValueStart = x + (Constant.BLOCK_WIDTH - fm.stringWidth(value)) / 2;
		int yValueStart = y+Constant.BLOCK_HEIGHT- (Constant.BLOCK_HEIGHT - fm.getHeight()) / 2-fm.getDescent();

		// 画背景
		g.fillRoundRect(x, y, Constant.BLOCK_WIDTH, Constant.BLOCK_WIDTH, 10, 10);
		g.setColor(Color.BLACK);
		// 画数字
		g.drawString(value, xValueStart, yValueStart);

//		 //测试记录
//		 f = new Font("微软雅黑", Font.BOLD, 20);
//		 g.setFont(f);
//		 String s = "(" + x + "," + y + ")" + moveCount;
//		 g.drawString(s, x, y + 20);
	}

	/**
	 * 移动
	 */
	int moveCount = 0;
	// 移动次数最大值
	public static final int MOVE_COUNT_MAX = (Constant.BLOCK_WIDTH + Constant.BLOCK_SPACE) / SPEED;

	/**
	 * 移动
	 */
	@Override
	public void move() {
		// 0到MOVE_COUNT_MAX
		switch (direction) {
		case DIRECTION_UP:
			y -= SPEED;
			break;
		case DIRECTION_DOWN:
			y += SPEED;
			break;
		case DIRECTION_LEFT:
			x -= SPEED;
			break;
		case DIRECTION_RIGHT:
			x += SPEED;
			break;
		}
		moveCount++;
		if (moveCount >= MOVE_COUNT_MAX) {
			moveCount = 0;
		}
		// 1到MOVE_COUNT_MAX
	}
	public int state=STATE_UNKOWN;
	public static final int STATE_UNKOWN = 0;// 未知态(判断态)
	public static final int STATE_MOVING = 1;// 移动态
	public static final int STATE_FREE = 2;// 自由态
	public static final int STATE_MERGE = 3;// 合并态

	/**
	 * 获得状态
	 * @return
	 */
	public int updateState() {
		if (moveCount != 0) {
			state = STATE_MOVING;
		} else if (moveCount == 0) {
			state = STATE_UNKOWN;
		}
		if (direction != DIRECTION_NONE && getNextBlock() == null) {
			state = STATE_FREE;
		}
		Block b = (Block) getNextBlock();
		//合并态判断
		if (direction != DIRECTION_NONE && b != null && b.level == level && (b.state != STATE_FREE)) {
			this.live = false;
			b.level++;
			b.state=STATE_MERGE;
			setThisBlock(null);
			BlockLoader.score += b.level * 10;
			if(BlockLoader.score>=BlockLoader.bestScore){
				BlockLoader.bestScore=BlockLoader.score;
			}
			if(b.getNextBlock()!=null&&b.getNextBlock().live&&b.getNextBlock().state==STATE_FREE){
			}else{
				b.direction=DIRECTION_NONE;
				b.directionX=0;
				b.directionY=0;
			}
			
		}
		return state;
	}
	/**
	 * 更新order
	 * 
	 * @throws CloneNotSupportedException
	 */
	public void updateOrder() {
		if (moveCount == 0) {// 判断态
			xOrder = (x - Constant.BACK_LEFT_IN_X) / (Constant.BLOCK_WIDTH + Constant.BLOCK_SPACE) + 1;
			yOrder = (y - Constant.BACK_UP_IN_Y) / (Constant.BLOCK_HEIGHT + Constant.BLOCK_SPACE) + 1;
			loader.blocks[xOrder][yOrder] = this;
			if (direction != 0 && getLastBlock() != null && getLastBlock().live && (getLastBlock() == this))
				setLastBlock(null);// 设置历史轨迹为空
		}
	}

	public void setLastBlock(Block block) {
		loader.blocks[xOrder - directionX][yOrder - directionY] = block;
	}

	public Block getLastBlock() {
		return loader.blocks[xOrder - directionX][yOrder - directionY];
	}

	public Block getNextBlock() {
		return loader.blocks[xOrder + directionX][yOrder + directionY];
	}
	public void setThisBlock(Block block){
		loader.blocks[xOrder][yOrder]=block;
	}
	/**
	 * 返回block对应的矩形
	 * 
	 * @return
	 */
	public Rectangle getRectangle() {
		return new Rectangle(x, y, Constant.BLOCK_WIDTH, Constant.BLOCK_HEIGHT);
	}

	/**
	 * 判断是否在边界
	 * 
	 * @return
	 */
	boolean xIsBounds = (x == (Constant.BACK_RIGHT_IN_X - Constant.BLOCK_WIDTH)) || (x == Constant.BACK_LEFT_IN_X);
	boolean yIsBounds = (y == (Constant.BACK_DOWN_IN_Y - Constant.BLOCK_HEIGHT)) || (y == Constant.BACK_UP_IN_Y);

	public boolean isAtBounds() {
		if ((xIsBounds || yIsBounds)) {
			return true;
		}
		return false;
	}

	/**
	 * 判断是否在角落
	 * 
	 * @return
	 */
	public boolean isAtCorner() {
		if ((xIsBounds && yIsBounds)) {
			return true;
		}
		return false;
	}

	/**
	 * 处理出界问题
	 */
	public void outOfBounds() {
		if (x > (Constant.BACK_RIGHT_IN_X - Constant.BLOCK_WIDTH)) {
			x = Constant.BACK_RIGHT_IN_X - Constant.BLOCK_WIDTH;
		}
		if (x < Constant.BACK_LEFT_IN_X) {
			x = Constant.BACK_LEFT_IN_X;
		}
		if (y == (Constant.BACK_DOWN_IN_Y - Constant.BLOCK_HEIGHT)) {
			y = Constant.BACK_DOWN_IN_Y - Constant.BLOCK_HEIGHT;
		}
		if (y == Constant.BACK_UP_IN_Y) {
			y = Constant.BACK_UP_IN_Y;
		}
	}

	@Override
	public String toString() {
		String s = "value=" + value + " (" + xOrder + "," + yOrder + "),Direction=";
		switch (direction) {
		case DIRECTION_UP:
			s += "↑";
			break;
		case DIRECTION_DOWN:
			s += "↓";
			break;
		case DIRECTION_LEFT:
			s += "←";
			break;
		case DIRECTION_RIGHT:
			s += "→";
			break;
		case DIRECTION_NONE:
			s += "0";
			break;
		default:
			s += "方向异常";
			break;
		}
		if (getNextBlock() == null)
			s += ",block=null(" + (xOrder + directionX) + "," + (yOrder + directionY) + ")";
		else
			s += ",block=(" + getNextBlock().xOrder + "," + getNextBlock().yOrder + ")";
		return s + "(state=" + state + ")";
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + direction;
		result = prime * result + directionX;
		result = prime * result + directionY;
		result = prime * result + level;
		result = prime * result + (live ? 1231 : 1237);
		result = prime * result + moveCount;
		result = prime * result + ((value == null) ? 0 : value.hashCode());
		result = prime * result + x;
		result = prime * result + xOrder;
		result = prime * result + y;
		result = prime * result + yOrder;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Block other = (Block) obj;
		if (direction != other.direction)
			return false;
		if (directionX != other.directionX)
			return false;
		if (directionY != other.directionY)
			return false;
		if (level != other.level)
			return false;
		if (live != other.live)
			return false;
		if (moveCount != other.moveCount)
			return false;
		if (value == null) {
			if (other.value != null)
				return false;
		} else if (!value.equals(other.value))
			return false;
		if (x != other.x)
			return false;
		if (xOrder != other.xOrder)
			return false;
		if (y != other.y)
			return false;
		if (yOrder != other.yOrder)
			return false;
		return true;
	}

}

           

4.BlockLoader.java

package com.it.core;

import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;

import com.it.client.Client;
import com.it.constant.Constant;

public class BlockLoader implements Drawable {

	public static Random random = new Random();
	public Block[][] blocks = new Block[6][6];
	public List<Block> blockList = new CopyOnWriteArrayList<Block>();

	public BlockLoader() {
		super();
		init();
	}

	public void init() {
		for (int i = 0; i < 6; i++) {
			for (int j = 0; j < 6; j++) {
				if (i == 5 || j == 5 || i == 0 || j == 0) {
					blocks[i][j] = new Block(i, j, 0, this);
				}
			}
		}
		 int x1 = randomBlockPoint().x;// 1-4
		 int y1 = randomBlockPoint().y;
		 blocks[x1][y1] = new Block(x1, y1, 1,this);
		 blockList.add(blocks[x1][y1]);
		 int x2 = randomBlockPoint().x;
		 int y2 = randomBlockPoint().y;
		 while (x1 == x2 && y1 == y2) {
		 x2 = randomBlockPoint().x;
		 y2 = randomBlockPoint().y;
		 }
		 blocks[x2][y2] = new Block(x2, y2, 1,this);
		 blockList.add(blocks[x2][y2]);
		 score=0;
	}

	public static Point randomBlockPoint() {
		return new Point(random.nextInt(4) + 1, random.nextInt(4) + 1);
	}

	public void newBlock() {
		int x = randomBlockPoint().x;// 1-4
		int y = randomBlockPoint().y;
		int i = 0;
		while (blocks[x][y] != null && i < 100) {
			x = randomBlockPoint().x;
			y = randomBlockPoint().y;
			i++;
		}
		if (blocks[x][y] == null) {
			newBlock = blocks[x][y] = new Block(x, y, 1, this);
			blockList.add(newBlock);
			System.out.println("newBlock:" + newBlock);
		} else {
			Client.gameStart = false;// 游戏结束
		}
	}

	public static boolean isPressed = false;
	public static Block newBlock = null;

	public void keyPressed(KeyEvent e) {
		if (!isPressed) {
			int direction = e.getKeyCode();
			switch (direction) {
			case KeyEvent.VK_UP:
			case KeyEvent.VK_W:
				direction = Block.DIRECTION_UP;
				isPressed = true;
				break;
			case KeyEvent.VK_DOWN:
			case KeyEvent.VK_S:
				direction = Block.DIRECTION_DOWN;
				isPressed = true;
				break;
			case KeyEvent.VK_LEFT:
			case KeyEvent.VK_A:
				direction = Block.DIRECTION_LEFT;
				isPressed = true;
				break;
			case KeyEvent.VK_RIGHT:
			case KeyEvent.VK_D:
				direction = Block.DIRECTION_RIGHT;
				isPressed = true;
				break;
			default:
				direction = -1;
				break;
			}
			if (isPressed) {
				for (Block block : blockList) {
					block.keyPressed(direction);
				}
			}
		}
		// newBlock();
	}

	public static int score = 0;
	public static int bestScore = 0;
	@Override
	public void draw(Graphics g) throws CloneNotSupportedException {
		boolean newFlag = true;
		for (Block block : blockList) {
			if (block.live) {
				block.draw(g);
				g.setFont(new Font("微软夜黑", Font.BOLD, 20));
				if (block.state != Block.STATE_UNKOWN) {
					newFlag = false;
				}
			} else {
				blockList.remove(block);
			}
		}
		if (newFlag && isPressed) {
			newBlock();
			isPressed = false;
		}
//		 drawTestInfo(g);//测试信息
	}

	public void drawTestInfo(Graphics g) {
		// 测试
		for (int i = 0; i < 6; i++) {
			for (int j = 0; j < 6; j++) {
				int x = Constant.BACK_Y + Constant.BLOCK_SPACE * i + Constant.BLOCK_WIDTH * (i - 1);
				int y = Constant.BACK_X + Constant.BLOCK_SPACE * j + Constant.BLOCK_WIDTH * (j - 1);
				if (blocks[i][j] == null) {
					g.drawString("null", x, y);
				} else {
					g.drawString("(" + x + "," + y + ")" + blocks[i][j].state, x, y);
				}
			}
		}
	}
}

           

5.Drawable.java

package com.it.core;

import java.awt.Graphics;

public interface Drawable {
	void draw(Graphics g) throws CloneNotSupportedException;
}
           

6.Moveable.java

package com.it.core;

public interface Moveable {
	void move();
}

           

7.MyFrame.java

package com.it.core;

import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import com.it.constant.Constant;

public class MyFrame extends Frame{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * 加载窗体
	 */
	public void loadFrame(){
		this.setTitle("2048");
		this.setSize(Constant.GAME_WIDTH, Constant.GAME_HEIGHT);
		this.setBackground(Color.WHITE);
		this.setLocationRelativeTo(null);//居中
		
		this.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		
		this.setVisible(true);
		
		new MyThread().start();
	}
	/**
	 * 防止图片闪烁
	 * 
	 * @param g
	 */
	Image backImg = null;

	@Override
	public void update(Graphics g) {
		if (backImg == null) {
			backImg = createImage(Constant.GAME_WIDTH, Constant.GAME_HEIGHT);
		}
		Graphics backg = backImg.getGraphics();
		Color c = backg.getColor();
		backg.setColor(Color.WHITE);
		backg.fillRect(0, 0, Constant.GAME_WIDTH, Constant.GAME_HEIGHT);
		backg.setColor(c);
		paint(backg);		
		g.drawImage(backImg, 0, 0, null);
	}
	/**
	 * 这种 创建一个重新画的线程内部类
	 * 
	 * @param args
	 */
	class MyThread extends Thread{
		@Override
		public void run() {
			while(true){
				repaint();
				try {
					sleep(5);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

           

总结

提示:代码写的有些臃肿,其中也有一些BUG,理解源码以后可以修正。

链接:https://pan.baidu.com/s/1NVWaklg9K2wRmBOLew6iMQ

提取码:ts08

上一篇: UE4 随记1
下一篇: PEP