俄罗斯方块游戏 --- java
俄罗斯方块游戏
如有疑问请查看:http://zh.wikipedia.org/zh-tw/%E4%BF%84%E7%BD%97%E6%96%AF%E6%96%B9%E5%9D%97
更多疑问请参考:http://java.itcast.cn/news/b4c1f433/34fd/4a7b/96bf/f1ae5e00ce70.shtml
游戏的运行结果如下:



代码的整体目录结构如下:

游戏发生的场地是在面板(panel)上,是JFrame框架把面板圈了起来
图形具有自己本身的特征,比如说形状,颜色,会定时落下一个单位,以及被触发的变幻,左移,右移,下移,
障碍物是图形落下后到底边框或其它图形产生的障碍物由图形生成的,
控制器负责接受按键事件来控制面板上的图形的移动和产生
这里是程序的入口处:
package com.kodoyang.tetris.test;
import javax.swing.JFrame;
import com.kodoyang.tetris.control.Controller;
import com.kodoyang.tetris.pojo.Ground;
import com.kodoyang.tetris.pojo.ShapeFactory;
import com.kodoyang.tetris.view.Panel;
public class Game {
public static void main(String[] args) {
// TODO Auto-generated method stub
ShapeFactory shapeFactory = new ShapeFactory();
Ground ground = new Ground();
Panel panel = new Panel();
Controller controller = new Controller(shapeFactory, ground, panel);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(panel.getSize().width + 10, panel.getSize().height + 35);
frame.add(panel);
panel.addKeyListener(controller);
frame.addKeyListener(controller);
frame.setVisible(true);
controller.newGame();
}
}
先来看看图形类:
图形的body回填上制造啊它的工厂传给它的参数,
以及它的移动方式,坐标,颜色,画自己的方法,不断下落的线程
package com.kodoyang.tetris.pojo;
import java.awt.Color;
import java.awt.Graphics;
import com.kodoyang.tetris.listen.ShapeListener;
import com.kodoyang.tetris.util.Global;
public class Shape {
public static final int ROTATE = 0;
public static final int LEFT = 1;
public static final int RIGHT = 2;
public static final int DOWN = 3;
private int[][] body;
private int status;
private Color color;
private int left;
private int top;
public void setBody(int body[][]){
this.body = body;
}
public void setStatus(int status) {
this.status = status;
}
public int getTop(){
return top;
}
public int getLeft(){
return left;
}
private ShapeListener listener;
public void moveLeft() {
System.out.println("Shape's moveLeft");
--left;
}
public void moveRight() {
System.out.println("Shape's moveRight");
++left;
}
public void moveDown() {
System.out.println("Shape's moveDown");
++top;
}
public void rotate() {
System.out.println("Shape's rotate");
status = (status + 1) % body.length;
}
public void drawMe(Graphics g) {
System.out.println("Shape's drawMe");
g.setColor(color);
for(int x = 0; x < 4; ++x){
for(int y = 0; y < 4; ++y){
if(getFlagByPoint(x, y)){
g.fill3DRect(
(left + x) * Global.CELL_SIZE,
(top + y) * Global.CELL_SIZE,
Global.CELL_SIZE,
Global.CELL_SIZE,
true);
}
}
}
}
private boolean getFlagByPoint(int x, int y){
/*boolean res = false;
try {
// return body[status][x + y * 4] == 1;
res = body[status][x + y * 4] == 1;
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("(x, y) = (" + x + ", " + y + ")");
e.printStackTrace();
}
return res;*/
return body[status][x + y * 4] == 1;
}
public boolean isMember(int x, int y, boolean rotate){
int tempStatus = status;
if(rotate){
tempStatus = (status + 1) % body.length;
}
return body[tempStatus][x + y * 4] == 1;
}
private class ShapeDriver implements Runnable {
@Override
public void run() {
while(listener.isShapeMoveDownable(Shape.this)) {
moveDown();
listener.shapeMoveDown(Shape.this);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public Shape() {
new Thread(new ShapeDriver()).start();
}
public void addShapeListenner(ShapeListener l) {
if(l != null)
this.listener = l;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
}
产生图形的工厂类如下:
shapes中定义了一些预置的图形,colors中定义了一些图形可以使用的颜色
package com.kodoyang.tetris.pojo;
import java.awt.Color;
import java.util.Random;
import com.kodoyang.tetris.listen.ShapeListener;
public class ShapeFactory {
private int[][][] shapes = new int[][][]{
{
{
1, 0, 0, 0,
1, 1, 1, 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, 1, 1, 0,
0, 0, 1, 0,
0, 0, 0, 0,
0, 0, 0, 0
},
{
0, 1, 0, 0,
0, 1, 0, 0,
1, 1, 0, 0,
0, 0, 0, 0
}
},
{
{
1, 1, 1, 1,
0, 0, 0, 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
}
},
{
{
1, 1, 0, 0,
1, 1, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0
}
},
{
{
1, 1, 1, 0,
1, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0
},
{
1, 0, 0, 0,
1, 0, 0, 0,
1, 1, 0, 0,
0, 0, 0, 0
},
{
0, 0, 1, 0,
1, 1, 1, 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, 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
},
{
0, 1, 0, 0,
1, 1, 0, 0,
1, 0, 0, 0,
0, 0, 0, 0
},
{
1, 1, 0, 0,
0, 1, 1, 0,
0, 0, 0, 0,
0, 0, 0, 0
}
},
{
{
1, 0, 0, 0,
1, 1, 0, 0,
1, 0, 0, 0,
0, 0, 0, 0
},
{
0, 1, 0, 0,
1, 1, 1, 0,
0, 0, 0, 0,
0, 0, 0, 0
},
{
0, 1, 0, 0,
1, 1, 0, 0,
0, 1, 0, 0,
0, 0, 0, 0
},
{
1, 1, 1, 0,
0, 1, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0
}
},
{
{
0, 1, 1, 0,
1, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 0
},
{
1, 0, 0, 1,
0, 1, 1, 0,
0, 1, 1, 0,
1, 0, 0, 1
}
},
{
{
0, 1, 0, 0,
1, 1, 1, 1,
0, 1, 0, 0,
0, 1, 0, 1
},
{
1, 0, 1, 0,
0, 0, 1, 0,
1, 1, 1, 1,
0, 0, 1, 0
}
},
{
{
0, 1, 0, 0,
1, 1, 1, 1,
1, 0, 0, 1,
1, 0, 0, 1
},
{
0, 1, 1, 0,
1, 0, 1, 0,
0, 1, 0, 1,
0, 1, 1, 0
}
}
};
private Color[] colors = new Color[]{
Color.CYAN,
Color.BLACK,
Color.BLUE,
Color.GREEN,
Color.MAGENTA,
Color.ORANGE,
Color.PINK,
Color.RED,
Color.WHITE,
Color.YELLOW
};
public Shape getShape(ShapeListener listener) {
System.out.println("ShapeFactory's getShape");
Shape shape = new Shape();
shape.addShapeListenner(listener);
int type = new Random().nextInt(shapes.length);
shape.setBody(shapes[type]);
shape.setStatus(0);
shape.setColor(colors[new Random().nextInt(colors.length)]);
return shape;
}
}
图形监听器的接口类:
实现这个接口的类必须要实现两个方法,让图形下移,判断图形是否可以移动
package com.kodoyang.tetris.listen;
import com.kodoyang.tetris.pojo.Shape;
public interface ShapeListener {
void shapeMoveDown(Shape shape);
boolean isShapeMoveDownable(Shape shape);
}
接受图形的静寂大地类:
当图形不能移动时就变为寂静大地了,构成静寂大地的是一个个的障碍物,
它通过计算图形下一步的位置来得出图形能不能移动的信息
如果障碍物出现在面板的顶部,就表示已经满了,游戏结束
判断某一行满行就把满了的行消掉
package com.kodoyang.tetris.pojo;
import java.awt.Color;
import java.awt.Graphics;
import com.kodoyang.tetris.util.Global;
public class Ground {
private int[][] obstacles = new int[Global.WIDTH][Global.HEIGHT];
public void accept(Shape shape) {
System.out.println("Ground's accept");
for(int x = 0; x < 4; ++x){
for(int y = 0; y < 4; ++y){
if(shape.isMember(x, y, false)){
obstacles[shape.getLeft() + x][shape.getTop() + y]
= 1;
}
}
}
deleteFullLine();
}
private void deleteFullLine(){
for(int y = Global.HEIGHT - 1; y >= 0; --y){
boolean full = true;
for(int x = 0; x < Global.WIDTH; ++x){
if(obstacles[x][y] == 0)
full = false;
}
if(full){
deleteLine(y);
}
}
}
private void deleteLine(int lineNum) {
for(int y = lineNum; y > 0; --y){
for(int x = 0; x < Global.WIDTH; ++x){
obstacles[x][y] = obstacles[x][y - 1];
}
}
for(int x = 0; x < Global.WIDTH; ++x){
//obstacles[x][0] = 0;
}
}
public void drawMe(Graphics g) {
System.out.println("Ground's drawMe");
g.setColor(Color.DARK_GRAY);
for(int x = 0; x < Global.WIDTH; ++x){
for(int y = 0; y <Global.HEIGHT; ++y){
if(obstacles[x][y] == 1){
g.fill3DRect(
x * Global.CELL_SIZE,
y * Global.CELL_SIZE,
Global.CELL_SIZE,
Global.CELL_SIZE,
true);
}
}
}
}
public boolean isMoveable(Shape shape, int action){
int left = shape.getLeft();
int top = shape.getTop();
switch(action){
case Shape.LEFT:
--left;
break;
case Shape.RIGHT:
++left;
break;
case Shape.DOWN:
++top;
break;
}
for(int x = 0; x < 4; ++x){
for(int y = 0; y < 4; ++y){
if(shape.isMember(x, y, action == Shape.ROTATE)){
if(top + y >= Global.HEIGHT ||
left + x < 0 ||
left + x >= Global.WIDTH ||
obstacles[left + x][top + y] == 1)
return false;
}
}
}
return true;
}
public boolean isFull(){
for(int x = 0; x < Global.WIDTH; ++x){
if(obstacles[x][0] == 1)
return true;
}
return false;
}
}
用于显示的面板类:
它的画图方法就是在清空整个面板后,调用图形和静寂大地的画图方法
它的构造方法会决定游戏界面的大小
package com.kodoyang.tetris.view;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
import com.kodoyang.tetris.pojo.Ground;
import com.kodoyang.tetris.pojo.Shape;
import com.kodoyang.tetris.util.Global;
public class Panel extends JPanel {
private Ground ground;
private Shape shape;
public void display(Ground ground, Shape shape) {
System.out.println("TetrisPanel's display");
this.ground = ground;
this.shape = shape;
this.repaint();
}
@Override
protected void paintComponent(Graphics g) {
// 重新显示
g.setColor(Color.LIGHT_GRAY);
g.fillRect(0, 0, Global.WIDTH * Global.CELL_SIZE,
Global.HEIGHT * Global.CELL_SIZE);
if(shape != null && ground != null){
shape.drawMe(g);
ground.drawMe(g);
}
}
public Panel() {
this.setSize(
Global.WIDTH * Global.CELL_SIZE,
Global.HEIGHT * Global.CELL_SIZE);
}
}
常量定义在全局类中:
每一个正方形小块的大小,面板拥有多少个正方形的边长个单位
package com.kodoyang.tetris.util;
public class Global {
public static final int CELL_SIZE = 20;
public static final int WIDTH = 20;
public static final int HEIGHT = 25;
}
控制它们的中央控制器:
它继承自按键事件的监听并实现了图形监听的接口
它控制当前活动图形以及产生它的工厂,障碍物,面板
产生一个新游戏的方法,判断图形是否可以下落,更新面板上的图形和障碍物,
package com.kodoyang.tetris.control;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import com.kodoyang.tetris.listen.ShapeListener;
import com.kodoyang.tetris.pojo.Ground;
import com.kodoyang.tetris.pojo.Shape;
import com.kodoyang.tetris.pojo.ShapeFactory;
import com.kodoyang.tetris.view.Panel;
public class Controller extends KeyAdapter implements ShapeListener {
private Shape shape;
private ShapeFactory shapeFactory;
private Ground ground;
private Panel panel;
@Override
public synchronized boolean isShapeMoveDownable(Shape shape) {
// TODO Auto-generated method stub
if(this.shape != shape){
return false;
}
if( ground.isMoveable(shape, Shape.DOWN) )
return true;
ground.accept(this.shape);
if(!ground.isFull()){
this.shape = shapeFactory.getShape(this);
}
return false;
}
@Override
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()) {
case KeyEvent.VK_UP:
if(ground.isMoveable(shape, Shape.ROTATE))
shape.rotate();
break;
case KeyEvent.VK_DOWN:
// if(ground.isMoveable(shape, Shape.DOWN))
if(isShapeMoveDownable(shape))
shape.moveDown();
break;
case KeyEvent.VK_LEFT:
if(ground.isMoveable(shape, Shape.LEFT))
shape.moveLeft();
break;
case KeyEvent.VK_RIGHT:
if(ground.isMoveable(shape, Shape.RIGHT))
shape.moveRight();
break;
}
panel.display(ground, shape);
}
@Override
public void shapeMoveDown(Shape shape) {
panel.display(ground, shape);
}
public void newGame() {
shape = shapeFactory.getShape(this);
}
public Controller(ShapeFactory shapeFactory,
Ground ground, Panel panel) {
this.shapeFactory = shapeFactory;
this.ground = ground;
this.panel = panel;
}
}
跟多好文请查看:http://www.cnblogs.com/kodoyang/
俄罗斯方块游戏 --- java的更多相关文章
- java俄罗斯方块游戏代码
java俄罗斯方块游戏代码: package com; import java.awt.Color; import java.awt.Graphics; import java.awt.event.K ...
- 经典 HTML5 & Javascript 俄罗斯方块游戏
Blockrain.js 是一个使用 HTML5 & JavaScript 开发的经典俄罗斯方块游戏.只需要复制和粘贴一段代码就可以玩起来了.最重要的是,它是响应式的,无论你的显示屏多么宽都能 ...
- 从零开始---控制台用c写俄罗斯方块游戏(1)
从零开始---控制台用c写俄罗斯方块游戏(1) 很少写博文,一来自身知识有限,二来自己知道,已经有很多这样的博文了,三就是因为懒,文笔也一般,四来刚出来工作,时间也不多 之所以写这篇博文,是因为应群里 ...
- 用C写的俄罗斯方块游戏 By: hoodlum1980 编程论坛
/************************************ * Desc: 俄罗斯方块游戏 * By: hoodlum1980 * Email: jinfd@126.com * Dat ...
- 教你看懂网上流传的60行JavaScript代码俄罗斯方块游戏
早就听说网上有人仅仅用60行JavaScript代码写出了一个俄罗斯方块游戏,最近看了看,今天在这篇文章里面我把我做的分析整理一下(主要是以注释的形式). 我用C写一个功能基本齐全的俄罗斯方块的话,大 ...
- 俄罗斯方块游戏JavaScript代码
JavaScript代码俄罗斯方块游戏 早就听说网上有人仅仅用60行JavaScript代码写出了一个俄罗斯方块游戏,最近看了看,今天在这篇文章里面我把我做的分析整理一下(主要是以注释的形式). 我用 ...
- 使用JS实现俄罗斯方块游戏
简单的JS俄罗斯方块游戏源码 效果图: 代码如下,复制即可使用: <!DOCTYPE html> <html> <head> <meta charset=&q ...
- C++编写简单的俄罗斯方块游戏
代码地址如下:http://www.demodashi.com/demo/14593.html C++编写简单的俄罗斯方块游戏 使用C++编写一个简单的俄罗斯方块游戏. 1 环境要求 使用C++图形库 ...
- electron写俄罗斯方块游戏(Tetris)
背景 在折腾ES6,突然想起大学时用c语言写过俄罗斯方块,本项目中主要是利用ES6的Class特性进行面向对象编程.项目采用node.js v6.2.0 + electron v1.1.0 进行桌面开 ...
随机推荐
- iOS:核心动画之关键帧动画CAKeyframeAnimation
CAKeyframeAnimation——关键帧动画 关键帧动画,也是CAPropertyAnimation的子类,与CABasicAnimation的区别是: –CABasicAnimation只能 ...
- 整合Struts2+SiteMesh+Spring+MyFaces(JSF)+Freemarker的时候启动服务器报错ClassNotFoundException: org.apache.struts2.sitemesh.FreeMarkerPageFilter
我一琢磨,难道freemarker与struts2的整合也需要添加一个struts2-freemarker-plugin的jar包? 后来找了半天,确认不需要这个. 然后我就上网搜,这个FreeMar ...
- Initialization and Class loading - Java
可以说,类的代码在初次使用时才加载.这通常指加载发生于创建类的第一个对象之时,但当访问 static域或static方法时,也会发生加载(通过下面的这段代码验证). class LoadTest { ...
- Passing JavaScript Objects to Managed Code
Silverlight If the target managed property or input parameter is strongly typed (that is, not typed ...
- AE 将地图导出为图片的两种方法
在ArcGIS的开发中,我们经常需要将当前地图打印(或是转出)到图片文件中.将Map或Layout中的图象转出有两种方法,一种为通过IActiveView的OutPut函数,另外一种是通过IExpor ...
- struts配置。泪奔...
说多了都是泪啊,配置一个环境一天才搞定.不错the requested resource (/login) is not available in struts,就是找不到什么什么class.亦或th ...
- Python Mongo操作
# -*- coding: utf-8 -*- ''' Python Mongo操作Demo Done: ''' from pymongo import MongoClient conn = None ...
- Webservce、WCF、WebApi的区别
Web Service It is based on SOAP and return data in XML form. It support only HTTP protocol. It is no ...
- java中时间的获取(二)
java中时间的获取2 /** * 获取数据库操作记录时间 */ public static String getOpreateDbTime() { Calendar c = Calendar.get ...
- QQ邮箱附件发送
一.先造一个邮件发送的窗体 二.编辑邮件发送的代码(包括附件) ①附件添加对话框 string file; private void button6_Click(object sender, Even ...