【无标题】

贪吃蛇

一、创建新项目

创建一个新的项目,并命名。

创建一个名为images的文件夹用来存放游戏相关图片。

然后再在项目的src文件下创建一个com.xxx.view的包用来存放所有的图形界面类,

创建一个com.xxx.controller的包用来存放启动的入口类(控制类)

二、游戏界面 

 
package com.snake.view;


import java.awt.Color;

import java.awt.EventQueue;

import java.awt.Font;

import java.awt.Frame;

import java.awt.Graphics;

import java.awt.Image;

import java.util.ArrayList;

import java.util.List;

import java.util.Random;


import javax.swing.ImageIcon;

import javax.swing.JFrame;

import javax.swing.JOptionPane;

import javax.swing.JPanel;

import javax.swing.Timer;

import javax.swing.border.EmptyBorder;



import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.awt.event.KeyAdapter;

import java.awt.event.KeyEvent;


public class SnakeJPanel extends JPanel implements ActionListener{


private boolean start;//当前游戏状态


private int speed;//速度


private boolean exist;//当前是否存在食物


private int foodType;//食物种类


private int x;//豆子的横坐标

private int y;//豆子的纵坐标


private ArrayList<int[]> localList;//蛇



public String direction;//方向


private String direction2;//引导方向


public boolean flag;


Random rand = new Random();


private ImageIcon up;


private ImageIcon down;


private ImageIcon right;


private ImageIcon left;


private ImageIcon body;


private ImageIcon food;


private ImageIcon title;


Timer time;


private int score;//当前得分情况


private int num;//吃到的食物个数


// private Image offScreenImage; //图形缓存



//图片绘制

@Override

public void paint(Graphics g) {


direction = direction2;


g.setColor(Color.WHITE);

g.fillRect(0, 0, 900, 700);


//绘制游戏框

//标题框

// g.drawRect(25, 30, 800, 75);

title.paintIcon(this, g, 25, 10);


//内容框

g.setColor(Color.black);

g.fillRect(25, 75, 850, 600);


//绘制食物的坐标位置

if(!exist) {//如果当前不存在豆子,随机绘制一个豆子

if(num % 5 == 0) {

foodType = 1;

}else {

foodType = 0;

}

boolean isProduce = true;

while(isProduce) {

isProduce = false;

x = rand.nextInt(33) * 25 + 25;

y = rand.nextInt(23) * 25 + 75;

for (int[] arr:localList) {

if(x == arr[0] && y == arr[1]) {

isProduce = true;

break;

}

}


}

System.out.println(x + "---" + y);

}


if(eat()) {

exist = false;

}else {

exist = true;

}



if(foodType == 0) {

//绘制食物

g.setColor(Color.blue);

// g.fillRect(x, y, 25, 25);

g.drawImage(food.getImage(),x, y, 25, 25,null);

}else {

//绘制食物

g.setColor(Color.WHITE);

g.fillRect(x, y, 25, 25);

// g.drawImage(food.getImage(),x, y, 25, 25,null);

}



//绘制头

g.setColor(Color.red);

// g.fillRect(localList.get(0)[0], localList.get(0)[1], 25, 25);

ImageIcon head = null;

//判断当前方向

if(direction.equals("R")) {

head = right;

}else if(direction.equals("L")) {

head = left;

}else if(direction.equals("U")) {

head = up;

}else if(direction.equals("D")) {

head = down;

}

// g.drawImage(head.getImage(), localList.get(0)[0], localList.get(0)[1], 25, 25,null);

head.paintIcon(this, g,localList.get(0)[0], localList.get(0)[1]);


//绘制身体

g.setColor(Color.white);

for (int i = 1; i < localList.size(); i++) {

// g.fillRect(localList.get(i)[0], localList.get(i)[1], 25, 25);

// g.drawImage(body.getImage(), localList.get(i)[0], localList.get(i)[1], 25, 25,null);

body.paintIcon(this, g, localList.get(i)[0], localList.get(i)[1]);

}

// g.fillRect(localList.get(1)[0], localList.get(1)[1], 25, 25);

// g.fillRect(localList.get(2)[0], localList.get(2)[1], 25, 25);



//绘制分数和长度

//长度

g.setColor(Color.GREEN);

g.setFont(new Font("宋体", Font.BOLD, 18));

g.drawString("长度:" + (localList.size() - 1), 25, 30);


//分数

g.drawString("分数:" + score, 25, 48);


if(!start) {//如果游戏未启动,结束移动和重绘

g.setColor(Color.white);

g.setFont(new Font("宋体", Font.BOLD, 30));

g.drawString("暂停/开始(请按任意键开始,空格键暂停)", 150, 300);

time.stop();


}else {

time.start();

}


// speed();

//移动后进行下一次绘制

// move();//移动

// repaint();//重新绘制

}


// //解决闪烁问题

// //如果为JFrame 为重量级 程序不会调用update()方法

// //如果为Frame 为轻量级 重写update()方法 做双缓冲

// //如果为JPanel 不会闪烁

// @Override

// public void update(Graphics g)

// {

// System.out.println("update");

// if(offScreenImage == null)

// offScreenImage = this.createImage(900, 700); //新建一个图像缓存空间,这里图像大小为800*600

// Graphics gImage = offScreenImage.getGraphics(); //把它的画笔拿过来,给gImage保存着

// paint(gImage); //将要画的东西画到图像缓存空间去

// g.drawImage(offScreenImage, 0, 0, null); //然后一次性显示出来

// }



@Override

public void actionPerformed(ActionEvent e) {

//移动后进行下一次绘制

move();//移动

repaint();//重新绘制


}


/**

* 绘制速度

*/

// private void speed() {

// try {//按一定速度进行移动

// Thread.sleep(speed);//控制移动速度

// } catch (InterruptedException e) {

// // TODO 自动生成的 catch 块

// e.printStackTrace();

// }

// }


/**

* 初始化图片

*/

private void drawImage() {

up = new ImageIcon("images/up.png");

down = new ImageIcon("images/down.png");

right = new ImageIcon("images/right.png");

left = new ImageIcon("images/left.png");

body = new ImageIcon("images/body.png");

food = new ImageIcon("images/food.png");

title = new ImageIcon("images/title.jpg");

}


private boolean eat() {

if(localList.get(0)[0] == x && localList.get(0)[1] == y) {//如果当前蛇头吃到了豆子

System.out.println("eat");

num++;

if(foodType == 0) {

score += 10;

}else {

score += (rand.nextInt(5) * 10 + 10);

}

int last = localList.size() - 1;//蛇尾

//在蛇尾后面添加一节身体

localList.add(new int[] {localList.get(last)[0],localList.get(last)[1]});

return true;

}

return false;

}


//移动方法

public void move() {

//判断是否游戏结束

if(isbody()) {

System.out.println("game over");

start = false;//结束游戏移动

JOptionPane.showMessageDialog(null,"游戏已结束!");

time.stop();

init();

}


if(flag && localList != null) {//如果长度不为空且游戏未结束

int last = localList.size() - 1;//记录蛇尾


for (int i = last; i > 0; i--) {//从蛇尾开始,每节身体移动到前一节身体的位置上

localList.set(i,new int[] {localList.get(i - 1)[0],localList.get(i - 1)[1]});

}


//记录头位置

int[] local = localList.get(0);

//判断当前方向,并进行模拟移动,判断是否与边界重合

if(direction.equals("R")) {

if(local[0] >= 850) {

local[0] = 25;

}else {

local[0] += 25;

}


}else if(direction.equals("L")) {

if(local[0] <= 25) {

local[0] = 850;

}else {

local[0] -= 25;

}


}else if(direction.equals("U")) {


if(local[1] <= 75) {

local[1] = 650;

}else {

local[1] -= 25;

}


}else if(direction.equals("D")) {

if(local[1] >= 650) {

local[1] = 75;

}else {

local[1] += 25;

}


}


//更改头的位置

localList.set(0, local);

}

}


//判断下一步是否为蛇身

private boolean isbody() {

// TODO 自动生成的方法存根

//记录头位置

int x = localList.get(0)[0];

int y = localList.get(0)[1];


//判断当前方向,并进行模拟移动,判断是否与边界重合

if(direction.equals("R")) {

x += 25;

}else if(direction.equals("L")) {

x -= 25;

}else if(direction.equals("U")) {

y -= 25;

}else if(direction.equals("D")) {

y += 25;

}


for (int i = 1; i < localList.size(); i++) {

if(localList.get(i)[0] == x && localList.get(i)[1] == y) {

return true;

}

}

return false;


}


// //判断下一步是否为边界

// private boolean isborder() {

// // TODO 自动生成的方法存根

// //记录头位置

// // TODO 自动生成的方法存根

// //记录头位置

// int x = localList.get(0)[0];

// int y = localList.get(0)[1];

//

// //判断当前方向,并进行模拟移动,判断是否与边界重合

// if(direction.equals("R")) {

// x += 25;

// }else if(direction.equals("L")) {

// x -= 25;

// }else if(direction.equals("U")) {

// y -= 25;

// }else if(direction.equals("D")) {

// y += 25;

// }

//

// if(x < 25 || x > (33 * 25 + 25)) {

// return true;//当x坐标超出边界,则返回true

// }

// if(y < 105 || y > (23 * 25 + 105)) {

// return true;//当y坐标超出边界,则返回true

// }

// return false;//蛇头移动后未超出边界,返回false

//

// }


/**

* Create the frame.

*/

public SnakeJPanel(int speed) {


this.speed = speed; //初始化速度


//初始化游戏面板的基本信息

this.setSize(900, 700);

this.setLocation(0, 30);

this.setFocusable(true);


init();//初始化界面

drawImage();//绘制图片

moveByKey();//给界面添加一个键盘监听


}


/*

* 键盘监听

* 通过键盘输入上下左右来控制当前蛇头移动的方向

* 先判断当前蛇头方向,再来改变引导方向

* 当进行绘制时再修改蛇的方向

* 保证不会因为在短时间内快速变换方向导致蛇头逆向转向

*/

private void moveByKey() {

addKeyListener(new KeyAdapter() {

@Override

public void keyPressed(KeyEvent e) {

int key = e.getKeyCode();

//边界值判断

switch(key) {

case 65:

case 37:{//向左走

if(!direction.equals("R")) {

direction2 = "L";


}

break;

}

case 87:

case 38:{//向上走

if(!direction.equals("D")) {

direction2 = "U";

}

break;

}

case 68:

case 39:{//向右走

if(!direction.equals("L")) {

direction2 = "R";

}

break;

}

case 83:

case 40:{//向下走

if(!direction.equals("U")) {

direction2 = "D";

}

break;

}

case KeyEvent.VK_SPACE:{//如果当前键盘输入为空格

start = !start;//调整游戏状态

System.out.println("暂停/开始");

repaint();//重绘

}

}


//任意键开始

if(!start && key != KeyEvent.VK_SPACE) {//如果当前状态为暂停状态,且键盘输入不是空格

start = true;

repaint();//重绘


}

}

});

}


/**

* 初始化游戏基本信息

*/

private void init() {

start = false;


exist = true;


direction2 = "U";


flag = true;


localList = new ArrayList<int[]>();


localList.add(0,new int[] {75,125});//蛇头

localList.add(1,new int[] {75,150});//蛇身1

localList.add(2,new int[] {75,175});//蛇身2


//创建第一个食物的位置

//通过循环保证当前生成的食物不在身体所在的坐标上

boolean isProduce = true;

while(isProduce) {//循环生成食物坐标

isProduce = false;//结束本次循环

x = rand.nextInt(33) * 25 + 25;

y = rand.nextInt(23) * 25 + 75;

for (int[] arr:localList) {//循环遍历蛇头及蛇身的坐标

if(x == arr[0] && y == arr[1]) {//如果食物坐标和蛇的某一节坐标重合

isProduce = true;//跳转循环状态,继续下一次食物生成

break;

}

}

//蛇身遍历完成,没有重合坐标,结束食物坐标生成


}


time = new Timer(speed, this);

setLayout(null);


score = 0;


num = 0;


foodType = 0;


// repaint();


}



}

三、构造启动类

 
package com.snake.controller;


import javax.swing.JFrame;

import javax.swing.JOptionPane;


import com.snake.view.SnakeJPanel;


public class SnakeStart {

public static void main(String[] args) {


int speed = 0;

String showInputDialog = null;//初始化时间

//得到速度

while(true) {

showInputDialog = JOptionPane.showInputDialog("蛇移动速度(1 - 5)","3");


if(showInputDialog == null) {

showInputDialog = "3";//默认速度

break;

}

if(showInputDialog.length() > 1) {

continue;

}

char[] a = showInputDialog.toCharArray();

if(a[0] >= '1' && a[0] <= '5') {

break;

}

}


speed = Integer.parseInt(showInputDialog) * 50;



SnakeJPanel snakeJPanel = new SnakeJPanel(speed);


//创建一个JFrame窗口,将游戏面板添加进行窗口中

JFrame jFrame = new JFrame();

//设置窗口的某些属性

jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

jFrame.setSize(920, 750);

jFrame.add(snakeJPanel);

jFrame.setLocationRelativeTo(null);

jFrame.setVisible(true);

}


}

四、游戏启动

设置游戏速度

游戏界面

 俄罗斯方块

游戏规则:

由小方块组成的不同形状的板块陆续从屏幕上方落下来,玩家通过调整板块的位置和方向,使它们在屏幕底部拼出完整的一条或几条。这些完整的横条会随即消失,给新落下来的板块腾出空间,与此同时,玩家得到分数奖励。没有被消除掉的方块不断堆积起来,一旦堆到屏幕顶端,玩家便告输,游戏结束。

整体代码分为三个模块:方格模块,七种图形模块,俄罗斯方块主模块。

小方块类:Cell

 
package com.zhao.demo.block;


import java.awt.image.BufferedImage;

import java.util.Objects;


/**

* @author xiaoZhao

* @date 2022/5/7

* @describe

* 小方块类

* 方法: 左移、右移、下落

*/

public class Cell {

// 行

private int row;

// 列

private int col;

private BufferedImage image;


public Cell() {

}


public Cell(int row, int col, BufferedImage image) {

this.row = row;

this.col = col;

this.image = image;

}


public int getRow() {

return row;

}


public void setRow(int row) {

this.row = row;

}


public int getCol() {

return col;

}


public void setCol(int col) {

this.col = col;

}


public BufferedImage getImage() {

return image;

}


public void setImage(BufferedImage image) {

this.image = image;

}


@Override

public String toString() {

return "Cell{" +

"row=" + row +

", col=" + col +

", image=" + image +

'}';

}


@Override

public boolean equals(Object o) {

if (this == o) {

return true;

}


if (!(o instanceof Cell)) {

return false;

}

Cell cell = (Cell) o;

return getRow() == cell.getRow() &&

getCol() == cell.getCol() &&

Objects.equals(getImage(), cell.getImage());

}


@Override

public int hashCode() {

return Objects.hash(getRow(), getCol(), getImage());

}


//左移动一格

public void left(){

col--;

}


//右移动一格

public void right(){

col++;

}


//下移动一格

public void down(){

row++;

}

}

 四方格图形的父类:Tetromino

 
package com.zhao.demo.block;


import com.zhao.demo.shape.*;


/**

* @author xiaoZhao

* @date 2022/5/11

* @describe 编写四方格父类

*/

public class Tetromino {


public Cell[] cells = new Cell[4];


//旋转的状态

protected State[] states;

//声明旋转次数

protected int count = 10000;



//左移方法

public void moveLeft() {

for (Cell cell : cells) {

cell.left();

}

}


//右移方法

public void moveRight() {

for (Cell cell : cells) {

cell.right();

}

}


//单元格下落

public void moveDrop() {

for (Cell cell : cells) {

cell.down();

}

}


//编写随机生成四方格

public static Tetromino randomOne() {

int num = (int) (Math.random() * 7);

Tetromino tetromino = null;

switch (num) {

case 0:

tetromino = new I();

break;

case 1:

tetromino = new J();

break;

case 2:

tetromino = new L();

break;

case 3:

tetromino = new O();

break;

case 4:

tetromino = new S();

break;

case 5:

tetromino = new T();

break;

case 6:

tetromino = new Z();

break;

}


return tetromino;

}


//顺时针旋转的方法

public void rotateRight() {

if (states.length == 0) {

return;

}


//旋转次数+1

count++;

State s = states[count % states.length];

Cell cell = cells[0];

int row = cell.getRow();

int col = cell.getCol();

cells[1].setRow(row + s.row1);

cells[1].setCol(col + s.col1);

cells[2].setRow(row + s.row2);

cells[2].setCol(col + s.col2);

cells[3].setRow(row + s.row3);

cells[3].setCol(col + s.col3);

}


//逆时针旋转的方法

public void rotateLeft() {

if (states.length == 0) {

return;

}


//旋转次数+1

count--;

State s = states[count % states.length];

Cell cell = cells[0];

int row = cell.getRow();

int col = cell.getCol();

cells[1].setRow(row + s.row1);

cells[1].setCol(col + s.col1);

cells[2].setRow(row + s.row2);

cells[2].setCol(col + s.col2);

cells[3].setRow(row + s.row3);

cells[3].setCol(col + s.col3);

}


//四方格旋转状态的内部类

protected class State {

//存储四方格各元素的位置

int row0, col0, row1, col1, row2, col2, row3, col3;


public State() {

}


public State(int row0, int col0, int row1, int col1, int row2, int col2, int row3, int col3) {

this.row0 = row0;

this.col0 = col0;

this.row1 = row1;

this.col1 = col1;

this.row2 = row2;

this.col2 = col2;

this.row3 = row3;

this.col3 = col3;

}


public int getRow0() {

return row0;

}


public void setRow0(int row0) {

this.row0 = row0;

}


public int getCol0() {

return col0;

}


public void setCol0(int col0) {

this.col0 = col0;

}


public int getRow1() {

return row1;

}


public void setRow1(int row1) {

this.row1 = row1;

}


public int getCol1() {

return col1;

}


public void setCol1(int col1) {

this.col1 = col1;

}


public int getRow2() {

return row2;

}


public void setRow2(int row2) {

this.row2 = row2;

}


public int getCol2() {

return col2;

}


public void setCol2(int col2) {

this.col2 = col2;

}


public int getRow3() {

return row3;

}


public void setRow3(int row3) {

this.row3 = row3;

}


public int getCol3() {

return col3;

}


public void setCol3(int col3) {

this.col3 = col3;

}


@Override

public String toString() {

return "State{" +

"row0=" + row0 +

", col0=" + col0 +

", row1=" + row1 +

", col1=" + col1 +

", row2=" + row2 +

", col2=" + col2 +

", row3=" + row3 +

", col3=" + col3 +

'}';

}

}

}

七种图形类:I、J、L、O、S、T、Z

 I

 
  1. package com.zhao.demo.shape;
    
    
    import com.zhao.demo.App.Tetris;
    
    import com.zhao.demo.block.Cell;
    
    import com.zhao.demo.block.Tetromino;
    
    
    /**
    
    * @author xiaoZhao
    
    * @date 2022/5/11
    
    * @describe
    
    */
    
    public class I extends Tetromino {
    
    
    public I() {
    
    cells[0] = new Cell(0,4, Tetris.I);
    
    cells[1] = new Cell(0,3, Tetris.I);
    
    cells[2] = new Cell(0,5, Tetris.I);
    
    cells[3] = new Cell(0,6, Tetris.I);
    
    
    //共有两种旋转状态
    
    states =new State[2];
    
    //初始化两种状态的相对坐标
    
    states[0]=new State(0,0,0,-1,0,1,0,2);
    
    states[1]=new State(0,0,-1,0,1,0,2,0);
    
    }
    
    
    }

J

 
package com.zhao.demo.shape;


import com.zhao.demo.App.Tetris;

import com.zhao.demo.block.Cell;

import com.zhao.demo.block.Tetromino;


/**

* @author xiaoZhao

* @date 2022/5/11

* @describe

*/

public class J extends Tetromino {

public J() {

cells[0] = new Cell(0,4, Tetris.J);

cells[1] = new Cell(0,3, Tetris.J);

cells[2] = new Cell(0,5, Tetris.J);

cells[3] = new Cell(1,5, Tetris.J);


states=new State[4];

states[0]=new State(0,0,0,-1,0,1,1,1);

states[1]=new State(0,0,-1,0,1,0,1,-1);

states[2]=new State(0,0,0,1,0,-1,-1,-1);

states[3]=new State(0,0,1,0,-1,0,-1,1);

}

}

 L

 
package com.zhao.demo.shape;


import com.zhao.demo.App.Tetris;

import com.zhao.demo.block.Cell;

import com.zhao.demo.block.Tetromino;


/**

* @author xiaoZhao

* @date 2022/5/11

* @describe

*/

public class L extends Tetromino {

public L() {

cells[0] = new Cell(0,4, Tetris.L);

cells[1] = new Cell(0,3, Tetris.L);

cells[2] = new Cell(0,5, Tetris.L);

cells[3] = new Cell(1,3, Tetris.L);


states=new State[4];

states[0]=new State(0,0,0,-1,0,1,1,-1);

states[1]=new State(0,0,-1,0,1,0,-1,-1);

states[2]=new State(0,0,0,1,0,-1,-1,1);

states[3]=new State(0,0,1,0,-1,0,1,1);

}

}

O

 
package com.zhao.demo.shape;


import com.zhao.demo.App.Tetris;

import com.zhao.demo.block.Cell;

import com.zhao.demo.block.Tetromino;


/**

* @author xiaoZhao

* @date 2022/5/11

* @describe

*/

public class O extends Tetromino {

public O() {

cells[0] = new Cell(0, 4, Tetris.O);

cells[1] = new Cell(0, 5, Tetris.O);

cells[2] = new Cell(1, 4, Tetris.O);

cells[3] = new Cell(1, 5, Tetris.O);


//无旋转状态

states = new State[0];

}

}

 
package com.zhao.demo.shape;


import com.zhao.demo.App.Tetris;

import com.zhao.demo.block.Cell;

import com.zhao.demo.block.Tetromino;


/**

* @author xiaoZhao

* @date 2022/5/11

* @describe

*/

public class S extends Tetromino {

public S() {

cells[0] = new Cell(0,4, Tetris.S);

cells[1] = new Cell(0,5, Tetris.S);

cells[2] = new Cell(1,3, Tetris.S);

cells[3] = new Cell(1,4, Tetris.S);


//共有两种旋转状态

states =new State[2];

//初始化两种状态的相对坐标

states[0]=new State(0,0,0,1,1,-1,1,0);

states[1]=new State(0,0,1,0,-1,-1,0,-1);

}

}

 
package com.zhao.demo.shape;


import com.zhao.demo.App.Tetris;

import com.zhao.demo.block.Cell;

import com.zhao.demo.block.Tetromino;


/**

* @author xiaoZhao

* @date 2022/5/11

* @describe

*/

public class T extends Tetromino {

public T() {

cells[0] = new Cell(0,4, Tetris.T);

cells[1] = new Cell(0,3, Tetris.T);

cells[2] = new Cell(0,5, Tetris.T);

cells[3] = new Cell(1,4, Tetris.T);


states=new State[4];

states[0]=new State(0,0,0,-1,0,1,1,0);

states[1]=new State(0,0,-1,0,1,0,0,-1);

states[2]=new State(0,0,0,1,0,-1,-1,0);

states[3]=new State(0,0,1,0,-1,0,0,1);

}

}

 
package com.zhao.demo.shape;


import com.zhao.demo.App.Tetris;

import com.zhao.demo.block.Cell;

import com.zhao.demo.block.Tetromino;


/**

* @author xiaoZhao

* @date 2022/5/11

* @describe

*/

public class Z extends Tetromino {

public Z() {

cells[0] = new Cell(1,4, Tetris.Z);

cells[1] = new Cell(0,3, Tetris.Z);

cells[2] = new Cell(0,4, Tetris.Z);

cells[3] = new Cell(1,5, Tetris.Z);


//共有两种旋转状态

states =new State[2];

//初始化两种状态的相对坐标

states[0]=new State(0,0,-1,-1,-1,0,0,1);

states[1]=new State(0,0,-1,1,0,1,1,0);

}

}

俄罗斯方块游戏主类:Tetris

 
package com.zhao.demo.App;


import com.zhao.demo.block.Cell;

import com.zhao.demo.block.Tetromino;


import javax.imageio.ImageIO;

import javax.swing.*;

import java.awt.*;

import java.awt.event.KeyAdapter;

import java.awt.event.KeyEvent;

import java.awt.event.KeyListener;

import java.awt.image.BufferedImage;

import java.io.File;

import java.io.IOException;

import java.security.cert.Certificate;


/**

* @author xiaoZhao

* @date 2022/5/11

* @describe 俄罗斯方块游戏主类

*/

public class Tetris extends JPanel {


//正在下落的方块

private Tetromino currentOne = Tetromino.randomOne();

//将要下落的方块

private Tetromino nextOne = Tetromino.randomOne();

//游戏主区域

private Cell[][] wall = new Cell[18][9];

//声明单元格的值

private static final int CELL_SIZE = 48;


//游戏分数池

int[] scores_pool = {0, 1, 2, 5, 10};

//当前游戏的分数

private int totalScore = 0;

//当前消除的行数

private int totalLine = 0;


//游戏三种状态 游戏中、暂停、结束

public static final int PLING = 0;

public static final int STOP = 1;

public static final int OVER = 2;

//当前游戏状态值

private int game_state;

//显示游戏状态

String[] show_state = {"P[pause]", "C[continue]", "S[replay]"};



//载入方块图片

public static BufferedImage I;

public static BufferedImage J;

public static BufferedImage L;

public static BufferedImage O;

public static BufferedImage S;

public static BufferedImage T;

public static BufferedImage Z;

public static BufferedImage background;


static {

try {

I = ImageIO.read(new File("images/I.png"));

J = ImageIO.read(new File("images/J.png"));

L = ImageIO.read(new File("images/L.png"));

O = ImageIO.read(new File("images/O.png"));

S = ImageIO.read(new File("images/S.png"));

T = ImageIO.read(new File("images/T.png"));

Z = ImageIO.read(new File("images/Z.png"));

background = ImageIO.read(new File("images/background.png"));

} catch (IOException e) {

e.printStackTrace();

}

}


@Override

public void paint(Graphics g) {

g.drawImage(background, 0, 0, null);

//平移坐标轴

g.translate(22, 15);

//绘制游戏主区域

paintWall(g);

//绘制正在下落的四方格

paintCurrentOne(g);

//绘制下一个将要下落的四方格

paintNextOne(g);

//绘制游戏得分

paintSource(g);

//绘制当前游戏状态

paintState(g);

}


public void start() {

game_state = PLING;

KeyListener l = new KeyAdapter() {

@Override

public void keyPressed(KeyEvent e) {

int code = e.getKeyCode();

switch (code) {

case KeyEvent.VK_DOWN:

sortDropActive();

break;

case KeyEvent.VK_LEFT:

moveleftActive();

break;

case KeyEvent.VK_RIGHT:

moveRightActive();

break;

case KeyEvent.VK_UP:

rotateRightActive();

break;

case KeyEvent.VK_SPACE:

hadnDropActive();

break;

case KeyEvent.VK_P:

//判断当前游戏状态

if (game_state == PLING) {

game_state = STOP;

}

break;

case KeyEvent.VK_C:

if (game_state == STOP) {

game_state = PLING;

}

break;

case KeyEvent.VK_S:

//重新开始

game_state = PLING;

wall = new Cell[18][9];

currentOne = Tetromino.randomOne();

nextOne = Tetromino.randomOne();

totalScore = 0;

totalLine = 0;

break;

}

}

};

//将窗口设置为焦点

this.addKeyListener(l);

this.requestFocus();


while (true) {

if (game_state == PLING) {

try {

Thread.sleep(500);

} catch (InterruptedException e) {

e.printStackTrace();

}

if (camDrop()) {

currentOne.moveDrop();

} else {

landToWall();

destroyLine();

if (isGameOver()) {

game_state = OVER;

} else {

//游戏没有结束

currentOne = nextOne;

nextOne = Tetromino.randomOne();

}

}

}

repaint();

}

}


//创建顺时针旋转

public void rotateRightActive() {

currentOne.rotateRight();

if (outOFBounds() || coincide()) {

currentOne.rotateLeft();

}

}


//瞬间下落

public void hadnDropActive() {

while (true) {

//判断能否下落

if (camDrop()) {

currentOne.moveDrop();

} else {

break;

}

}

//嵌入到墙中

landToWall();

destroyLine();

if (isGameOver()) {

game_state = OVER;

} else {

//游戏没有结束

currentOne = nextOne;

nextOne = Tetromino.randomOne();

}

}


//按键一次,下落一格

public void sortDropActive() {

if (camDrop()) {

//当前四方格下落一格

currentOne.moveDrop();

} else {

landToWall();

destroyLine();

if (isGameOver()) {

game_state = OVER;

} else {

//游戏没有结束

currentOne = nextOne;

nextOne = Tetromino.randomOne();

}

}

}


//单元格嵌入墙中

private void landToWall() {

Cell[] cells = currentOne.cells;

for (Cell cell : cells) {

int row = cell.getRow();

int col = cell.getCol();

wall[row][col] = cell;

}

}


//判断四方格能否下落

public boolean camDrop() {

Cell[] cells = currentOne.cells;

for (Cell cell : cells) {

int row = cell.getRow();

int col = cell.getCol();

//判断是否到达底部

if (row == wall.length - 1) {

return false;

} else if (wall[row + 1][col] != null) {

return false;

}

}

return true;

}


//消除行

public void destroyLine() {

int line = 0;

Cell[] cells = currentOne.cells;

for (Cell cell : cells) {

int row = cell.getRow();

if (isFullLine(row)) {

line++;

for (int i = row; i > 0; i--) {

System.arraycopy(wall[i - 1], 0, wall[i], 0, wall[0].length);

}

wall[0] = new Cell[9];

}

}

//分数池获取分数,累加到总分

totalScore += scores_pool[line];

//总行数

totalLine += line;

}


//判断当前行是否已经满了

public boolean isFullLine(int row) {

Cell[] cells = wall[row];

for (Cell cell : cells) {

if (cell == null) {

return false;

}

}

return true;

}


//判断游戏是否结束

public boolean isGameOver() {

Cell[] cells = nextOne.cells;

for (Cell cell : cells) {

int row = cell.getRow();

int col = cell.getCol();

if (wall[row][col] != null) {

return true;

}

}

return false;

}


private void paintState(Graphics g) {

if (game_state == PLING) {

g.drawString(show_state[PLING], 500, 660);

} else if (game_state == STOP) {

g.drawString(show_state[STOP], 500, 660);

} else {

g.drawString(show_state[OVER], 500, 660);

g.setColor(Color.RED);

g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 60));

g.drawString("GAME OVER!", 30, 400);

}

}


private void paintSource(Graphics g) {

g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 30));

g.drawString("分数: " + totalScore, 500, 250);

g.drawString("行数: " + totalLine, 500, 430);

}


private void paintNextOne(Graphics g) {

Cell[] cells = nextOne.cells;

for (Cell cell : cells) {

int x = cell.getCol() * CELL_SIZE + 370;

int y = cell.getRow() * CELL_SIZE + 25;

g.drawImage(cell.getImage(), x, y, null);

}

}


private void paintCurrentOne(Graphics g) {

Cell[] cells = currentOne.cells;

for (Cell cell : cells) {

int x = cell.getCol() * CELL_SIZE;

int y = cell.getRow() * CELL_SIZE;

g.drawImage(cell.getImage(), x, y, null);

}

}


private void paintWall(Graphics g) {

for (int i = 0; i < wall.length; i++) {

for (int j = 0; j < wall[i].length; j++) {

int x = j * CELL_SIZE;

int y = i * CELL_SIZE;

Cell cell = wall[i][j];

//判断是否有小方块

if (cell == null) {

g.drawRect(x, y, CELL_SIZE, CELL_SIZE);

} else {

g.drawImage(cell.getImage(), x, y, null);

}

}

}

}


//判断是否出界

public boolean outOFBounds() {

Cell[] cells = currentOne.cells;

for (Cell cell : cells) {

int col = cell.getCol();

int row = cell.getRow();

if (row < 0 || row > wall.length - 1 || col < 0 || col > wall[0].length-1) {

return true;

}

}

return false;

}


//按键一次,左移一次

public void moveleftActive() {

currentOne.moveLeft();

//判断是否越界或重合

if (outOFBounds() || coincide()) {

currentOne.moveRight();

}

}


//按键一次,右移一次

public void moveRightActive() {

currentOne.moveRight();

//判断是否越界或重合

if (outOFBounds() || coincide()) {

currentOne.moveLeft();

}

}


//判断是否重合

public boolean coincide() {

Cell[] cells = currentOne.cells;

for (Cell cell : cells) {

int row = cell.getRow();

int col = cell.getCol();

if (wall[row][col] != null) {

return true;

}

}

return false;

}


public static void main(String[] args) {

JFrame jFrame = new JFrame("俄罗斯方块");

//创建游戏界面

Tetris panel = new Tetris();

jFrame.add(panel);

//设置可见

jFrame.setVisible(true);

//设置窗口大小

jFrame.setSize(810, 940);

//设置剧中

jFrame.setLocationRelativeTo(null);

//设置窗口关闭时停止

jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


//游戏主要开始逻辑

panel.start();

}

}

三、效果展示

游戏开始,方快下落,右边区域展示即将下落的方块图、分数、消除的行数以及游戏切换的状态。

按下空格键,方块瞬间下落, 按下P键游戏暂停,消除一行分数为1(此处由分数池进行控制)

  按下C键游戏继续。

方块占满,游戏结束,此时可以按下S键重新开始游戏。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值