1. 程式人生 > >Java寫俄羅斯方塊,瞭解一下

Java寫俄羅斯方塊,瞭解一下

Java俄羅斯方塊目錄:

簡要分析:

俄羅斯方塊的規則在這裡就不細說了,大家都知道,控制方塊的移動,到底即停,當方塊能填滿一行時,便消除那一行的方塊,並計分...

我們將用JPanel來完成整個遊戲的製作。

首先我們來看看遊戲執行時的圖片。

 

(遊戲圖片

上圖是遊戲製作過程中我截的一張圖片,從上圖中,我們可以把遊戲分為多個區域:

1)正在下落的四格方塊

2)下一個下落的四格方塊

3)遊戲有一個主場景區,即左邊的網格線區域

4)計分割槽,暫時還沒繪製

根據俄羅斯方塊的規則,我們知道,一個四格方塊,是可以左右和往下移動的,並且還能變換形狀。

然後我們在來看一張圖片:

 

(經典俄羅斯方塊的方塊形狀)

從上圖我們可以看出來,每個方塊都由四個小方格通過不同的排列組成,並且,我們可以把遊戲主場景區想象成用二維陣列來表示的區域,事實上,確實是用二維陣列來製作遊戲主區域。

在這裡,我們暫且把這個區域稱為------牆(Wall

把每個小方格稱為------單元格(Cell

每個不同的形狀其實就是4個單元格按不同順序組合而來,所以,我們可以用不同的座標來表示不同的形狀。

我們可以根據四格方塊的不同形狀,給他們一個名字:ITLJSZO

所以,在這裡我們用面向物件的思想,分別定義Cell類,和七個四格方塊類。

Cell()類:

    共同特徵:行號,列號,圖片

    共同行為:向左,向右,向下移動,提供JavaBean相關規範,JavaBean規範就是程式設計師在定義類時,預設遵守的一種規範如:

  1.     新增兩個構造器,無參,全參
  2. 屬性一般都是私有化(封裝)
  3. 提供公有(public)的get/set方法
  4. 重寫toString()方法,toString方法預設返回地址資訊,重寫後用來描述屬性的資訊
  5. 重寫equals方法和hashCode方法
import java.awt.image.BufferedImage;

/*
 * 俄羅斯方塊中的最小單位:方格(細胞)
 * 特徵(屬性):
 * 		row--行號
 * 		col--列號
 * 		image--對應的圖片
 *  行為(方法)
 *  	left()
 *  	right()
 *  	drop()
 */
public class Cell {
	private int row;
	private int col;
	private BufferedImage image;
	
	@Override
	public String toString() {
		return "(" + row + ", " + col + ")";
	}

	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;
	}

	public Cell() {}
	
	public Cell(int row, int col, BufferedImage image) {
		this.row = row;
		this.col = col;
		this.image = image;
	}
	
	/*向左移動*/
	public void left() {
		col--;
	}
	/*向右移動*/
	public void right() {
		col++;
	}
	/*向下移動*/
	public void drop() {
		row++;
	}
}

根據每個四格方塊的共性,即移動等。我們可以讓七個四格方塊繼承一個父類------Tetromino類,用於描述四格方塊的行為,左移,右移,下落,生成一個方塊。

Tetromino()類程式碼:

共同特徵:cells--四個小方塊(用陣列表示)--許可權修飾詞protected

共同行為:向左,向右,向下移動,提供JavaBean規範

新增randomOne()方法---用來隨機生成一個四格方塊

import java.util.Arrays;

/*
 * 四格方塊
 * 屬性:
 * 		--cells----四個方塊
 * 行為:
 * 		moveLeft()
 * 		moveRight()
 * 		softDrop()
 */
public class Tetromino {
	protected Cell[] cells=new Cell[4];
	/*四格方塊向左移動
	 * 實際上:就是每個方塊向左移動
	 */
	
	/*四格方塊向左移動*/
	public void moveLeft() {
		for(Cell c:cells)
			c.left();
	}
	/*四格方塊向右移動*/
	public void moveRight() {
		for(Cell c:cells)
			c.right();
	}
	/*四格方塊向下移動*/
	public void softDrop() {
		for(Cell c:cells)
			c.drop();
	}
	@Override
	public String toString() {
		return "[" + Arrays.toString(cells) + "]";
	}
	/*隨機生成一個四格方塊*/
	public static Tetromino randomOne() {
		Tetromino t = null;
		int num=(int)(Math.random()*7);//random的範圍是0.00-0.99(即包含0不包含1)
		switch (num) {
		case 0:t=new T();break;
		case 1:t=new O();break;
		case 2:t=new I();break;
		case 3:t=new J();break;
		case 4:t=new L();break;
		case 5:t=new S();break;
		case 6:t=new Z();break;
		}
		return t;
	}
}

然後在建立7個小方塊的類,來繼承Tetromino類,也就是把他們的共同點寫到一個父類中,子類在描述各自的特性。

根據父類Tetromino,定義出七種子類,給屬性賦具體元素。

L類程式碼:

public class L extends Tetromino{
	/*
	 * 提供構造器進行初始化
	 * L型的四格方塊的位置
	*/
	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);
	}
}

其他6個按照方塊所在的座標編寫,點選檢視座標,這樣一來,便寫好了最基本的類。

然後在建立一個主類,這個類就是遊戲的入口,也是遊戲的所有邏輯所在。

Tetris類程式碼:

提供靜態屬性,載入靜態資源,遊戲圖片,場景等--靜態程式碼塊

  1. 面板會自動呼叫繪製方法paint(Graphics g)
  2. 重寫paint方法,繪製圖片背景,繪製網格和嵌入牆中的方塊。
  3. 繪製網格和嵌入牆中的方塊。paintWall(Graphics g)
        提供屬性wall---是一個Cell型別的二維陣列,20行,10列
        屬性CELL_SIZE---一個方塊的寬度
  4. 提供屬性
        currentOne---正在下落的四格方塊
        nextOne---下一個將要下落的四格方塊
  5. 提供繪製正在下落的方塊的方法
        paintCurrentOne(Graphics g)
        在重寫的paint方法中取呼叫
  6. 編寫start()方法,用於封裝遊戲主要邏輯
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

/*
 * 俄羅斯方塊的主類:
 * 前提:必須是一塊麵板Jpanel,可以嵌入視窗
 * 面板上自帶一個畫筆,有一個功能:自動繪製
 * 其實是呼叫了JPanel裡的paint()方法
 * 
 * 
 * (1)載入靜態資源
 */
public class Tetris extends JPanel{
	
	/*屬性:正在下落的四格方塊*/
	private Tetromino currentOne = Tetromino.randomOne();
	/*屬性:將要下落的四格方塊*/
	private Tetromino nextOne = Tetromino.randomOne();
	/*屬性:牆,20行 10列的 表格  寬度為26*/
	private Cell[][] wall=new Cell[20][10];
	private static final int CELL_SIZE=26;
	
	//載入方塊圖片
	public static  BufferedImage T;
	public static  BufferedImage I;
	public static  BufferedImage O;
	public static  BufferedImage J;
	public static  BufferedImage L;
	public static  BufferedImage S;
	public static  BufferedImage Z;
	public static  BufferedImage background;
	public static  BufferedImage gameover;
	static {
		try {
			/*
			 * getResource(String url)
			 * url:載入圖片的路徑
			 * 相對位置是同包下
			 */
			T = ImageIO.read(Tetris.class.getResource("T.png"));
			I = ImageIO.read(Tetris.class.getResource("I.png"));
			O = ImageIO.read(Tetris.class.getResource("O.png"));
			J = ImageIO.read(Tetris.class.getResource("J.png"));
			L = ImageIO.read(Tetris.class.getResource("L.png"));
			S = ImageIO.read(Tetris.class.getResource("S.png"));
			Z = ImageIO.read(Tetris.class.getResource("Z.png"));
			background = ImageIO.read(Tetris.class.getResource("tetris.png"));
			gameover = ImageIO.read(Tetris.class.getResource("game-over.png"));
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/*
	 * 重寫JPanel類中的paint(Graphics g)方法
	 * 
	 */
	public void paint(Graphics g) {
		//繪製背景
		/*
		 * g:畫筆
		 * g.drawImage(image,x,y,null)
		 * image:繪製的圖片
		 * x:開始繪製的橫座標
		 * y:開始繪製的縱座標
		 */
		g.drawImage(background, 0,0, null);
		//平移座標軸
		g.translate(15, 15);
		//繪製牆
		paintWall(g);
		//繪製正在下落的四格方塊
		paintCurrentOne(g);
		//繪製下一個將要下落的四格方塊
		paintNextOne(g);
	}
	/*
	 * 繪製下一個將要下落的四格方塊
	 * 繪製到面板的右上角的相應區域
	 * @param g
	 */
	public void paintNextOne(Graphics g) {
		//獲取nextOne物件的四個元素
		Cell[] cells = nextOne.cells;
		for(Cell c:cells) {
			//獲取每一個元素的行號和列號
			int row = c.getRow();
			int col = c.getCol();
			//橫座標
			int x = col*CELL_SIZE+260;
			//縱座標
			int y = row*CELL_SIZE+26;
			g.drawImage(c.getImage(),x,y,null);
		}
	}
	
	/*繪製正在下落的四格方塊
	 * 取出陣列的元素
	 * 繪製元素的圖片
	 * 橫座標x
	 * 縱座標y 
	 */
	public void paintCurrentOne(Graphics g){
		Cell[] cells = currentOne.cells;
		for(Cell c:cells)
		{
			int x = c.getCol()*CELL_SIZE;
			int y = c.getRow()*CELL_SIZE;
			g.drawImage(c.getImage(),x,y,null);
		}
	}
	public void paintWall(Graphics a) {
		//外層迴圈控制行數
		for(int i=0;i<20;i++)
		{
			//內層迴圈控制列數
			for(int j=0;j<10;j++)
			{
				int x = j*CELL_SIZE;
				int y = i*CELL_SIZE;			
				Cell cell=wall[i][j];
				if(cell==null)
				{
					a.drawRect(x, y, CELL_SIZE, CELL_SIZE);
				}
				else
				{
					a.drawImage(cell.getImage(),x,y,null);
				}
			}
		}
	}
	
	/*
	 * 封裝了遊戲的主要邏輯
	 */
	public void start() {
		//開啟鍵盤監聽事件
		
		KeyListener l = new KeyAdapter() {
			/*
			 * KeyPressed()
			 * 是鍵盤按鈕 按下去所呼叫的方法
			 */
			@Override
			public void keyPressed(KeyEvent e) {
				// 獲取一下鍵子的代號
				int code = e.getKeyCode();
				switch (code) {
				case KeyEvent.VK_DOWN:
					softDropAction();
					break;
				case KeyEvent.VK_LEFT:
					moveLeftAction();
					break;
				case KeyEvent.VK_RIGHT:
					moveRightAction();
					break;
				case KeyEvent.VK_UP:
				
					break;
				default:
					break;
				}
				//按一次重新繪製一次
				repaint();
			}
			

			
		};
		//面板新增監聽事件物件
		this.addKeyListener(l);
		//面板物件設定成焦點
		this.requestFocus();
		
		while(true) {
			/*
			 * 當程式執行到此,會進入睡眠狀態,
			 * 睡眠時間為300毫秒,單位為毫秒
			 * 300毫秒後,會自動執行後續程式碼
			 */
			try {
				Thread.sleep(300);
			} catch (InterruptedException e) {
				// 抓取打斷異常
				e.printStackTrace();
			}

			if(canDrop()) {
				currentOne.softDrop();
			}
			else {
				landToWall();
				//將下一個下落的四格方塊賦值給正在下落的變數
				currentOne = nextOne;
				nextOne = Tetromino.randomOne();
			}
			/*
			 * 下落之後,要重新進行繪製,才會看到下落後的位置
			 * repaint方法,也是JPanel類中提供的
			 * 此方法中呼叫了paint方法
			 */
			repaint();
			elimination();
		}
	}
	
	
	/*
	 * 使用Right鍵控制四格方塊右移
	 */
	public void moveRightAction() {
		currentOne.moveRight();
		if(outOfBounds()||coincide())
			currentOne.moveLeft();
	}

	/*
	 * 使用Left鍵控制四格方塊左移
	 */
	public void moveLeftAction() {
		currentOne.moveLeft();
		if(outOfBounds()||coincide()) {
			currentOne.moveRight();
		}
	}
	private boolean coincide() {
		Cell[] cells = currentOne.cells;
		for(Cell c:cells) {
			int row = c.getRow();
			int col = c.getCol();
			if(wall[row][col]!=null)
				return true;
		}
		return false;
	}
	public boolean outOfBounds() {
		Cell[] cells = currentOne.cells;
		for(Cell c:cells) {
			int col = c.getCol();
			if(col<0||col>9)
				return true;
		}
		return false;
	}
	
	/*
	 * 使用Down鍵控制四格方塊的下落
	 */
	public void softDropAction() {
		if(canDrop()) {
			currentOne.softDrop();
		}
		else {
			landToWall();
			currentOne = nextOne;
			nextOne = Tetromino.randomOne();
		}
	}
	public boolean canDrop() {
		Cell[] cells = currentOne.cells;
		/* 
		 * 
		 */
		for(Cell c:cells) {
			/* 獲取每個元素的行號,列號
			 * 判斷:
			 * 只要有一個元素的下一行上有方塊
			 * 或者只要有一個元素到達最後一行
			 * 就不能再下落了
			 */
			int row = c.getRow();
			int col = c.getCol();
			if (row==19) {//判斷是否到達底部
				return false;
			}
			else if(wall[row+1][col]!=null) {//判斷下方是否有方塊
				return false;
			}
			
		}
		return true;
	}
	/*
	 * 當不能再下落時,需要將四格方塊嵌入到牆中
	 * 也就是儲存到二維陣列中相應的位置上
	 */
	public void landToWall() {
		Cell[] cells = currentOne.cells;
		for(Cell c:cells) {
			//獲取最終的行號和列號
			int row = c.getRow();
			int col = c.getCol();
			wall[row][col] = c;
		}
	}
	/*啟動遊戲的入口  遊戲開始*/
	public static void main(String[] args) {
		//1:建立一個視窗物件
		JFrame frame=new JFrame("玩玩俄羅斯方塊");
		
		//建立遊戲介面,即畫板(面板)
		Tetris panel = new Tetris();
		//將面板嵌入視窗
		frame.add(panel);
		
		//2:設定為可見
		frame.setVisible(true);
		//3:設定視窗的尺寸
		frame.setSize(535, 595);
		//4:設定視窗居中
		frame.setLocationRelativeTo(null);
		//5:設定視窗關閉,即程式中止
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				
		//遊戲的主要邏輯封裝在start方法中
		panel.start();
	}
}
未完待續。。。

相關推薦

Java俄羅斯方塊瞭解一下

Java俄羅斯方塊目錄:簡要分析:俄羅斯方塊的規則在這裡就不細說了,大家都知道,控制方塊的移動,到底即停,當方塊能填滿一行時,便消除那一行的方塊,並計分...我們將用JPanel來完成整個遊戲的製作。首先我們來看看遊戲執行時的圖片。 (遊戲圖片 )上圖是遊戲製作過程中我截的一

Java俄羅斯方塊

假期閒著無事,就用一週多的時間看了百度java吧的一位大神(alwing)釋出的視訊,學著用java寫了一個俄羅斯方塊,在此就以釋出原始碼以及必要講解的形式來感謝他的幫助。當然我這裡也是做了一些改動,做出來的程式介面以及功能沒有和他的完全一樣。 整個程式執行起

推薦幾款目前比較優秀star較高的JAVA開源商城瞭解一下

在知乎上面看到的,都是碼雲上面的開源商城,覺得不錯,收藏一波。1. 專案名稱:分散式B2C商城 xbin-store專案介紹:模仿國內知名B2C網站,實現的一個分散式B2C商城 使用Spring Boot 自動配置 Dubbox / MVC / MyBatis / Druid

自己了3天的俄羅斯方塊純原創!

#include <stdio.h> #include <time.h> #include <conio.h> int f,g,h,i,j,k,l,m,n,o=3,p,q=0,(*x)[3], a[20][10]={0},map[

記錄一下第一次用java那麼長60行略長的程式碼想了好久才懂怎麼用

class Point { public int x; //定義三點座標 public int y; public int z; //編寫構造器 public Po

Excel資料錄入技巧瞭解一下

1.資料有效性 快速錄入多個不同條件,用下拉列表來完成是比較快的~ 步驟:選中目標區域—資料—資料驗證—序列—來源—輸入目標條件(來源中隔開文字的逗號是英文逗號) 2.提取年齡 在一大波出生年月中,想要提取年齡的話,一個個弄是不現實的,用公式最快~ 公式應用:=DATEDIF(B2,TO

爬蟲敏感圖片的識別與過濾瞭解一下

需求 我們需要識別出敏感作者的avatar頭像,把”皮卡丘“換成”優雅的python“。 敏感圖片樣本屬性: 爬蟲獲取的圖片屬性: 替換成: 原理 檢查兩個圖片的相似度,一個簡單而快速的演算法:感知雜湊演算法(Perceptual Hash),通過某種提取

史上最短小精悍的JavaScript編寫的俄羅斯方塊僅僅60行程式碼

我要分享 經常會看見某些所謂的大牛,老是拿工作年限做實力的標籤,要他拿出硬本事有人還真不如一個入行兩年的前端工作者,一個經驗用很多年真的有用嗎?希望那些所謂的大牛能反省下。也希望能警醒到各位學程式設計的小夥伴。 今天給大家秀的肌肉就是70行程式碼搞定俄羅斯方塊,效果圖如下:

c++俄羅斯方塊小遊戲

第二篇部落格 把我之前用c++寫的一個俄羅斯方塊也傳上來算了,這個程式是我學完c++後寫的,雖然有點長,看起來比較嚇人,但是程式碼絕對是你能夠找到的理解起來最簡單的俄羅斯方塊的程式碼,對於一些基礎不好的同學還是非常友好的。(歡迎批評指正) #include<iostream>

MindManager 2019新版上市 瞭解一下

 所有的等待都是值得的!MindManager在蓄力一年後,給各位思維導圖愛好者帶來了全新的MindManager 2019 for Windows。全新的版本包含英語、德語、法語、俄語、中文、日語,新增的優先檢視,時間表檢視,業務戰略工具包等為使用者帶來了全新的操作體驗。在使用MindManage

中國版的 Fama-French 三因子模型瞭解一下

作者:石川,量信投資創始合夥人,清華大學學士、碩士,麻省理工學院博士;精通各種概率模型和統計方法,擅長不確定性隨機系統的建模及優化。(已獲授權轉載) 摘要:Liu et al. (2018) 通過剔除市值最小的 30% 的股票降低了殼價值汙染,在 Fama-French 三因子的基礎上提出了適合

不用L約束又不會梯度消失的GAN瞭解一下

先擺結論: 1. 論文提供了一種分析和構造概率散度的直接思路,從而簡化了構建新 GAN 框架的過程; 2. 推匯出了一個稱為 GAN-QP 的 GAN 框架,這個 GAN 不需要像 WGAN 那樣的 L 約束,又不會有 SGAN 的梯度消失問題,實驗表明它至少有不遜色於、甚至優於 WGAN 的表現。

“鍵”和”正規化”瞭解一下~

超鍵: 能確定一條資訊的屬性或屬性集合 候選鍵: 最小超鍵,能確定一條資訊的最小屬性集合(可能有幾組,也可能只一組) 主鍵: 從候選鍵中任意定義其中的一組屬性集合,即為主鍵 外來鍵: 兩個關係中,一個關係的主鍵即為另一關係的外來鍵,||該外來鍵需在此關係中做普通屬性||

機器學習瞭解一下

1. 為什麼要學? 老師上課時候就說過:傳統演算法解決確定性問題,而機器學習解決非確定性問題。 好吧,確實激起了我的興趣,所以系統學習一下吧。 文章圖片來源於 GitHub,網速不佳的朋友請點我看原文。 順便軟廣一下個人技術小站:godbmw.com。歡迎常來♪(^∇^*) 2. 機器學習演算法 機器學習

iOS Push詳述瞭解一下

歡迎大家前往騰訊雲+社群,獲取更多騰訊海量技術實踐乾貨哦~ 作者:陳裕發, 騰訊系統測試工程師 商業轉載請聯絡騰訊WeTest獲得授權,非商業轉載請註明出處。 WeTest 導讀 本文主要對iOS Push的線上push、本地push及離線(遠端)push進行梳理,介紹了相關邏輯,測試時要注意的要點以及

express中介軟體瞭解一下

本篇文章從express原始碼上來理解中介軟體,同時可以對express有更深層的理解 前言 中介軟體函式可以執行哪些任務? 執行任何程式碼。 對請求和響應物件進行更改。 結束請求/響應迴圈。 呼叫堆疊中的下一個中介軟體函式。 我們從一個app.use開始,逐

[原始碼和文件分享]基於Java俄羅斯方塊遊戲

一 需求分析 掌握基本的圖形程式設計方法 掌握Java事件處理程式編寫方法 掌握編寫基於TCP或UDP協議的網路通訊程式 掌握Java的流、檔案、多執行緒等程式設計技術 二 程式設計 2.1 類之間關係 關係圖如下所示: 2.2

Bash這個Shell瞭解一下概念

BoumeAgain Shell(bash),是一個Bourne Shell的增強版本,基準於GNU架構下發展出來。 GNU是一個自由的作業系統,其內容軟體完全以GPL方式釋出。這個作業系統是GNU計劃的主要目標,名稱來自GNU’s Not Unix!的遞迴縮

史上最強資源網站瞭解一下

2018/4/23推薦列表虫部落快搜美劇線上看線上格式工廠論文導航PPT模板搜圖1.虫部落快搜連結http://search.chongbuluo.com/簡介這個網站真的無所不能,大家看圖片就知道了,你想查的所有的東西基本上都能在這上面找到,查字型,查文獻,查ACG資源,電子書資源,GitHub程式,論文資

async/await瞭解一下

  一開始寫文章的時候太晚了,程式碼有一處複製錯誤,已改正,謝謝博友提醒,保證以後不會再犯。   上一篇部落格我們在現實使用和麵試角度講解了Promise(原文可參考《面向面試題和實際使用談promise》),但是Promise 的方式雖然解決了 callback hell,但是這種方式充滿了 Promise