Java简易俄罗斯方块
来源:互联网 发布:铁路造价软件下载 编辑:程序博客网 时间:2024/05/17 01:07
目前学到Swing第二章,这两天没有学新知识,写了个俄罗斯方块。
写之前想不好怎么实现,找来别人的程序看了一下,再加上自己的想法,做了下面这个半成品,接下来可以加上各种菜单、按钮贴图等美化,都是些锦上添花的动作,繁琐但不难。
我觉得写俄罗斯方块,难点在于如何将方块的形状(七种)、状态(四种翻转)、动作(左、右、下落)等提炼成数组。 这里采用四维数组来表示每一种方块:【种类】【翻转】【X坐标】【Y坐标】,每种方块都画在一个4*4的大方块中,把这个大方块作为一个整体进行移动。再写了一个方法遍历大方块,判断该方块的位置是否合法。
有了合适的模型,再把每个步骤转化成代码,就不难了。
import java.awt.Color;import java.awt.Dimension;import java.awt.Font;import java.awt.Graphics;import java.awt.Toolkit;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.KeyAdapter;import java.awt.event.KeyEvent;import java.awt.image.BufferedImage;import java.util.Arrays;import java.util.Random;import javax.swing.JFrame;import javax.swing.JPanel;import javax.swing.JCheckBox;import javax.swing.Timer;import javax.swing.JOptionPane;public class KingTetris{ // 20行,10列 private final int ROW = 20; private final int COL = 10; // 每个方块边长,单位为像素 private final int LEN = 35; // 游戏区域的左、上边距 private final int LEFT_MARGIN = LEN*2; private final int UP_MARGIN = LEN; // 面布大小,单位为像素 private final int AREA_WIDTH = LEN*22; private final int AREA_HEIGHT = LEN*22; // 是否需要网格 private boolean showGrid = true; // 是否彩色,将来可以作为贴图控制 private boolean isColor = true; // 得分 private int score = 0; // 画布 private MyCanvas drawArea = new MyCanvas(); // 窗口 private JFrame f = new JFrame("俄罗斯方块"); // 画图用的image private BufferedImage image = new BufferedImage(AREA_WIDTH, AREA_HEIGHT, BufferedImage.TYPE_INT_RGB); private Graphics g = image.createGraphics(); // 数组,用于保存背景 private int[][] map = new int[COL][ROW]; // 数组,用于保存颜色 private Color[] color = new Color[]{Color.green, Color.red, Color.orange, Color.blue, Color.cyan, Color.yellow, Color.magenta, Color.gray}; //默认灰色 private final int DEFAULT = 7; private Color[][] mapColor = new Color[COL][ROW]; //组件的横坐标 int wordX = LEN*14;// 组件的横坐标 int wordY = LEN*9; // 字的初始纵坐标 //shape的四个参数 private int type, state, x, y, nextType, nextState; //如果刚开始游戏,由于无nextType,先给type等随机一个,下为首次开始游戏的标志 private boolean newBegin = true; // 用数组来代表不同形状的下坠物,四维分别是类型Type、旋转状态State、横坐标X、纵坐标Y。画示意图即可得出坐标 // 方块共有7种,分别以S、Z、L、J、I、O、T这7个字母的形状来命名 private int[][][][] shape = new int[][][][]{ // S的四种翻转状态: { { {0,1,0,0}, {1,1,0,0}, {1,0,0,0}, {0,0,0,0} }, { {0,0,0,0}, {1,1,0,0}, {0,1,1,0}, {0,0,0,0} }, { {0,1,0,0}, {1,1,0,0}, {1,0,0,0}, {0,0,0,0} }, { {0,0,0,0}, {1,1,0,0}, {0,1,1,0}, {0,0,0,0} } }, // Z: { { {1,0,0,0}, {1,1,0,0}, {0,1,0,0}, {0,0,0,0} }, { {0,1,1,0}, {1,1,0,0}, {0,0,0,0}, {0,0,0,0} }, { {1,0,0,0}, {1,1,0,0}, {0,1,0,0}, {0,0,0,0} }, { {0,1,1,0}, {1,1,0,0}, {0,0,0,0}, {0,0,0,0} } }, // L: { { {0,0,0,0}, {1,1,1,0}, {0,0,1,0}, {0,0,0,0} }, { {0,0,0,0}, {0,1,1,0}, {0,1,0,0}, {0,1,0,0} }, { {0,0,0,0}, {0,1,0,0}, {0,1,1,1}, {0,0,0,0} }, { {0,0,1,0}, {0,0,1,0}, {0,1,1,0}, {0,0,0,0} } }, // J: { { {0,0,0,0}, {0,0,1,0}, {1,1,1,0}, {0,0,0,0} }, { {0,0,0,0}, {0,1,1,0}, {0,0,1,0}, {0,0,1,0} }, { {0,0,0,0}, {0,1,1,1}, {0,1,0,0}, {0,0,0,0} }, { {0,1,0,0}, {0,1,0,0}, {0,1,1,0}, {0,0,0,0} } }, // I: { { {0,1,0,0}, {0,1,0,0}, {0,1,0,0}, {0,1,0,0} }, { {0,0,0,0}, {1,1,1,1}, {0,0,0,0}, {0,0,0,0} }, { {0,1,0,0}, {0,1,0,0}, {0,1,0,0}, {0,1,0,0} }, { {0,0,0,0}, {1,1,1,1}, {0,0,0,0}, {0,0,0,0} } }, // O: { { {0,0,0,0}, {0,1,1,0}, {0,1,1,0}, {0,0,0,0} }, { {0,0,0,0}, {0,1,1,0}, {0,1,1,0}, {0,0,0,0} }, { {0,0,0,0}, {0,1,1,0}, {0,1,1,0}, {0,0,0,0} }, { {0,0,0,0}, {0,1,1,0}, {0,1,1,0}, {0,0,0,0} } }, // T: { { {0,1,0,0}, {1,1,0,0}, {0,1,0,0}, {0,0,0,0} }, { {0,0,0,0}, {1,1,1,0}, {0,1,0,0}, {0,0,0,0} }, { {0,1,0,0}, {0,1,1,0}, {0,1,0,0}, {0,0,0,0} }, { {0,1,0,0}, {1,1,1,0}, {0,0,0,0}, {0,0,0,0} } }, }; /** * 初始化界面 */ private void init(){ drawArea.setPreferredSize(new Dimension(AREA_WIDTH, AREA_HEIGHT)); f.add(drawArea); JCheckBox gridCB = new JCheckBox("显示网格",true); JCheckBox colorCB = new JCheckBox("彩色方块", false); gridCB.setBounds(wordX, wordY-LEN,LEN,LEN); colorCB.setBounds(wordX, wordY-2*LEN,LEN,LEN); // paintArea(); // 加键盘监听器 f.addKeyListener(new KeyAdapter(){ public void keyPressed(KeyEvent e){ switch (e.getKeyCode()) { case KeyEvent.VK_UP: turn(); break; case KeyEvent.VK_LEFT: left(); break; case KeyEvent.VK_RIGHT: right(); break; case KeyEvent.VK_DOWN: down(); break; } } }); Timer timer = new Timer(1000, new timerListener()); newShape(); timer.start(); // 窗口显示在屏幕正中 // Toolkit是抽象类,只能用getDefaultToolkit()方法来获取实例。 // getScreenSize()方法返回的是一个Dimension对象,还须用getWidth()获取宽度 f.pack(); int screenSizeX = (int)Toolkit.getDefaultToolkit().getScreenSize().getWidth(); int screenSizeY = (int)Toolkit.getDefaultToolkit().getScreenSize().getHeight(); int fSizeX = (int)f.getSize().getWidth(); int fSizeY = (int)f.getSize().getHeight(); f.setResizable(false);// 禁止改变Frame大小 f.setBounds((screenSizeX-fSizeX)/2, (screenSizeY-fSizeY)/2, fSizeX,fSizeY ); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setVisible(true); } /** * 绘图 */ private void paintArea(){ // 默认黑色,填充白色 g.setColor(Color.white); g.fillRect(0, 0, AREA_WIDTH, AREA_HEIGHT); // 方格线 // 先画最外围 g.setColor(Color.gray); for (int offset = 0; offset <= 2; offset++){ g.drawRect(LEFT_MARGIN-offset, UP_MARGIN-offset, COL*LEN+offset*2, ROW*LEN+offset*2); } // 如果showGrid为true则显示网格 if(showGrid){ g.setColor(Color.gray); // 9条竖线 for (int i = 1 ; i <= 9; i++){ g.drawLine(LEFT_MARGIN+LEN*i, UP_MARGIN, LEFT_MARGIN+LEN*i, UP_MARGIN+ROW*LEN); } // 19条横线 for(int i = 1; i <= 19; i++){ g.drawLine(LEFT_MARGIN, UP_MARGIN+LEN*i, LEFT_MARGIN+COL*LEN, UP_MARGIN+LEN*i); } } // 右上角显示下一个shape int offset2 = 3;// 边框粗细 int col = 4;// 右上角方框的列数 int row = 4;// 行数 g.setColor(Color.gray); g.setFont(new Font("Microsoft YaHei Mono", Font.BOLD, 20)); g.drawString("下一个:", wordX, LEN*2); int nextX = wordX; int nextY = LEN*2; //暂不画方框 // for (int offset = 0; offset <= 2; offset++){ // g.drawRect(nextX-offset+10, nextY+10-offset, col*LEN+offset*2, row*LEN+offset*2); // } //画下一次出现的下坠方块 g.setColor(isColor?color[nextType]:color[DEFAULT]); for(int i = 0; i < 4; i++){ for(int j = 0; j < 4; j++){ if (shape[nextType][nextState][i][j]==1) { g.fill3DRect(nextX+10+i*LEN, nextY+10+j*LEN, LEN, LEN,true); } } } g.setColor(Color.gray); g.setFont(new Font("Times", Font.BOLD, 15)); g.drawString("玩法:", wordX, wordY+LEN*2); g.drawString("上箭头:翻转", wordX, wordY+LEN*3); g.drawString("左箭头:左移", wordX, wordY+LEN*4); g.drawString("右箭头:右移", wordX, wordY+LEN*5); g.drawString("下箭头:下落", wordX, wordY+LEN*6); g.setFont(new Font("Times", Font.BOLD, 25)); g.drawString("得分:" + score, wordX, wordY+LEN*8); //画下坠物shape g.setColor(isColor?color[type]:color[DEFAULT]); for(int i = 0; i < 4; i++){ for(int j = 0; j < 4; j++){ if (shape[type][state][i][j]==1) { g.fill3DRect(LEFT_MARGIN+(x+i)*LEN, UP_MARGIN+(y+j)*LEN, LEN, LEN,true); } } } //画背景map for(int i = 0; i < COL; i++){ for(int j = 0; j < ROW; j++){ if (map[i][j] == 1) { g.setColor(mapColor[i][j]); g.fill3DRect(LEFT_MARGIN+i*LEN, UP_MARGIN+j*LEN, LEN, LEN,true); } } } drawArea.repaint(); } /** * 自定义画布,重写paint()方法 */ private class MyCanvas extends JPanel{ public void paint(Graphics g){ g.drawImage(image, 0, 0, null); } } /** * 判断位置是否合法 */ private boolean check(int type, int state, int x, int y){ for(int i = 0; i < 4; i++){ for(int j = 0; j < 4; j++){ if ( (shape[type][state][i][j] == 1) && ( (x+i>=COL) || (x+i<0 ) || (y+j>=ROW) || (map[x+i][y+j]==1) ) ) { return false; } } } return true; } /** * 判断游戏是否结束 */ private boolean isGameOver(int type, int state, int x, int y){ return !check(type, state, x, y); } /** * 新建方块 */ private void newShape(){ Random rand = new Random(); if(newBegin){ type = rand.nextInt(7); state = rand.nextInt(4); newBegin = false; } else{ type = nextType; state = nextState; } nextType = rand.nextInt(7); nextState = rand.nextInt(4); x = 3; y = 0; // 如果游戏已结束,则重新开始 if(isGameOver(type, state, x, y)){ JOptionPane.showMessageDialog(f, "GAME OVER!"); newGame(); } paintArea(); } /** * 新建游戏 */ private void newGame(){ newMap(); score = 0; newBegin = true; } /** * 清空背景图 */ private void newMap(){ for(int i = 0; i < COL; i++){ Arrays.fill(map[i],0); } } /** * 消行 */ private void delLine(){ boolean flag = true; int addScore = 0; for(int j = 0; j < ROW; j++){ flag = true; for( int i = 0; i < COL; i++){ if (map[i][j]==0){ flag = false; break; } } if(flag){ addScore += 10; for(int t = j; t > 0; t--){ for(int i = 0; i <COL; i++){ map[i][t] = map[i][t-1]; } } } } score += addScore*addScore/COL; } /** * 计时器所用的事件监听器 */ private class timerListener implements ActionListener{ public void actionPerformed(ActionEvent e){ if(check(type, state , x, y+1) ){ y = y +1; } else{ add(type, state, x, y); delLine(); newShape(); } paintArea(); } } /** * 把shape存到map的add方法 */ private void add(int type, int state, int x, int y){ for(int i = 0; i < 4; i++){ for(int j = 0; j < 4 ; j++){ if((y+j<ROW)&&(x+i<COL)&&(x+i>=0)&&(map[x+i][y+j]==0)){ map[x+i][y+j]=shape[type][state][i][j]; mapColor[x+i][y+j]=color[isColor?type:DEFAULT]; } } } } /** * 下面为四个方向键对应的方法 */ private void turn(){ int tmpState = state; state = (state + 1)%4; if (!check(type,state, x, y )) { state = tmpState; //不能转就什么都不做 } paintArea(); } private void left(){ if(check(type,state, x-1, y)){ --x; } paintArea(); } private void right(){ if (check(type,state, x+1, y)) { ++x; } paintArea(); } private void down(){ if (check(type,state, x, y+1)) { ++y; } //如果下不去则固定之 else{ add(type, state, x, y); delLine(); newShape(); } paintArea(); } /** * 主函数 */ public static void main(String[] args){ new KingTetris().init(); }}
0 0
- Java简易俄罗斯方块
- 简易俄罗斯方块
- 简易俄罗斯方块
- JAVA实战练习——俄罗斯方块(超简易版)
- QT/c++ 简易俄罗斯方块
- JAVA俄罗斯方块
- Java 俄罗斯方块
- java俄罗斯方块
- java 俄罗斯方块
- Java 俄罗斯方块
- java俄罗斯方块
- Java俄罗斯方块
- C语言俄罗斯方块(简易版)
- Qt学习之路_13(简易俄罗斯方块)
- Qt学习之路 简易俄罗斯方块
- Qt学习之路_13(简易俄罗斯方块)
- [JAVA] 俄罗斯方块游戏
- [JAVA] 俄罗斯方块游戏
- CocoaPods详解之----使用篇
- 在C语言怎样对数据和操作的封装
- 解决 SDK Manger update 速度慢
- 创建程序输出字符的unicode码
- 用strtoken函数识别以“\0”分割的字符串
- Java简易俄罗斯方块
- 有一段文本,将文本中的所有单词,存放到一个字符串数组中。(要求占用内存最少)
- back to top 功能实现
- CocoaPods详解之----制作篇
- unity之数组
- Android 4.0的图形硬件加速及绘制技巧
- Oracle-SQL_TRACE使用
- 消息栏的应用
- 读背包九讲之二——完全背包