JAVA實現植物大戰殭屍連連看

說明:本篇博客主要講述練練看遊戲的設計與實現。前半部分爲分析與類和屬性的說明,後半部分爲程序的實現與程序代碼。第一次寫小遊戲,仍存在許多問題,也借鑑了CSDN前輩的代碼想法,如有不妥,還望多批評指正。

(一)需求分析

已經實現的部分:

1.遊戲開始界面
2.遊戲方塊消除功能
3.遊戲時間限制功能
4.方塊刷新重拍功能
5.在遊戲勝利失敗時提示並結束遊戲
6.炸彈功能
7.遊戲中鼠標移動和點擊的動態效果
8.遊戲分數記錄功能

未實現部分:

1.遊戲音效
2.遊戲分數排行榜記錄功能

(二)遊戲功能演示

遊戲開始界面
遊戲主界面

(三)遊戲總體設計和類圖

遊戲窗口總共分爲四類,第一個是遊戲初始窗口,提供了開始遊戲選項和更多選項,第二是遊戲主窗口,提供了遊玩遊戲的界面,第三類是結束窗口,在遊戲勝利或者失敗時彈出,第四個是更多信息窗口。這四類窗口都繼承了JFrame,其中其初始窗口和主窗口實現了MouseListener的接口,爲了對按鍵添加監聽。
玩家通過點擊開始遊戲打開一個遊戲主窗口,關閉當前初始窗口,或者點擊更多打開更多信息窗口。遊戲主窗口中通過對遊戲結束的判定打開結束窗口。
在這裏插入圖片描述

(四)項目代碼和註解

爲了方便學習,我幾乎對每一行關鍵代碼進行了註解,有些代碼,如刷新、炸彈功能代碼,可更改性比較大,而且不是特別完美,所有我沒有添加註解,關於最關鍵的方塊消除算法,下文會有詳細解答

遊戲初始窗口類代碼(MainWindow.java)

package myplantslink;

import java.awt.Cursor;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class MainWindow extends JFrame implements MouseListener {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private ImageIcon img,imgstart,imgstart2,imgmore,imgmore2;//背景圖片 開始圖片 更多圖片
	private JButton b1,b2;//開始按鈕  更多按鈕
	private int w1,w2,w3,h1,h2,h3;//背景 開始 更多 圖片的長寬
	private JLabel label;//用於裝載按鈕的控件
	MainWindow()
	{
		//圖片初始化
		img=new ImageIcon("pic//bg1.jpg");
		imgstart=new ImageIcon("pic//start.jpg");
		imgstart2=new ImageIcon("pic//start 2.jpg");
		imgmore=new ImageIcon("pic//more.jpg");
		imgmore2=new ImageIcon("pic//more2.jpg");
		//獲取長寬
		w1=img.getIconWidth();
		h1=img.getIconHeight();
		w2=imgstart.getIconWidth();
		h2=imgstart.getIconHeight();
		w3=imgmore.getIconWidth();
		h3=imgmore.getIconHeight();
		//開始 更多按鈕初始化
		b1=new JButton();
		b1.setBounds(183,270,w2,h2);
		b1.setIcon(imgstart);
		b1.setBorderPainted(false);
		b1.addMouseListener(this);
		b1.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
		b2=new JButton();
		b2.addMouseListener(this);
		b2.setIcon(imgmore);
		b2.setBounds(450,276,w3,h3);
		b2.setBorderPainted(false);
		b2.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
		//控件初始化
		label=new JLabel(img);
		label.add(b2);
		label.add(b1);
		label.setBounds(0,0,w1,h1);
		label.setLayout(null);
		//主窗口初始化
		this.add(label);
		this.setLayout(null);
		this.setBounds(300,160,w1+10,h1+30);
		this.setTitle("植物大戰殭屍");
		this.setVisible(true);
	}
	public void mouseClicked(MouseEvent e) {
		// TODO Auto-generated method stub
		if(e.getSource()==b1) //點擊開始  遊戲開始  此窗口消失
		{
			new GameWindow();
			this.dispose();
		}
		else if(e.getSource()==b2)//點擊更多 顯示更多信息窗口
		{
			new MoreWindow();
		}
	}

	public void mousePressed(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	//按鈕鼠標移入的動畫效果
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
		if(e.getSource()==b1) b1.setIcon(imgstart2);
		else if(e.getSource()==b2) b2.setIcon(imgmore2);
	}

	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub
		if(e.getSource()==b1) b1.setIcon(imgstart);
		else if(e.getSource()==b2) b2.setIcon(imgmore);
	}
}

遊戲主界面類代碼(GameWindow.java)

package myplantslink;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Random;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.Timer;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/*練練看遊戲界面*/
public class GameWindow extends JFrame implements MouseListener{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private ImageIcon [] Pics=new ImageIcon [8]; //植物未被鼠標選中時顯示的圖片
	private ImageIcon [] PaintedPics=new ImageIcon[8]; //植物被鼠標選中後的圖片
	private ImageIcon Backgroundimg,Timeimg,Refreshimg,Bomimg,Scoreimg;//背景、時間圖標、刷新圖標、炸彈圖標、分數圖標
	private ImageIcon [] rn=new ImageIcon[4];//數字圖標0 1 2 3
	private int [] nums={10,10,10,8,8,8,8,8};//每種方塊的數量
	private int [] cnt=new int [9];//記錄每種方塊的數量  用於初始化  確保每種方塊不超過規定數量
	private int Cols=10,Rows=7;//行和列的長度
	/*地圖數組 用於後面的消除算法 長和寬要比實際方塊的要多2*/
	private boolean [][] Map=new boolean [Rows+2][Cols+2];
	private int w1,h1,wp,hp;//背景圖片長寬  植物圖片長寬
	private JLabel label;//背景圖片標籤  用於裝載背景圖
	private JButton [][]Blocks=new JButton [Rows+2][Cols+2];//植物方塊按鈕
	private int [][] type=new int [Rows+2][Cols+2];//記錄每個位置的植物類型
	private JPanel panel1,panel2;//裝載植物方塊的控件 用於裝載刷新按鈕 炸彈按鈕的控件
	private JButton TimeButton,RefreshButton,RefreshNumsButton,BomButton,BomNumsButton,ScoreButton,ScoreNumsButton;//時間 刷新 炸彈 分數 按鈕
	private final JProgressBar progressBar = new JProgressBar();//時間條
	private final int MIN_PROGRESS=0,MAX_PROGRESS=150;//最小時間值   最大時間值
	private static int currentProgress = 0,scores=0,currentblocks=70;//當前的時間值  分數  地圖上未消除的方塊數目
	private Point firstblock=new Point(-1,-1),secondblock=new Point(-1,-1);//同時選中的兩個植物  最多隻能有兩個
	private Check Judger=new Check();//判定消除類
	private static int refreshnums=3,bombnums=3,isend=0;//可用刷新次數  炸彈次數  是否結束標誌
	GameWindow()
	{
		//初始植物圖片數組  未選中
		for(int i=0;i<8;++i)
			Pics[i]=new ImageIcon("pic//植物"+(i+1)+".gif");
		//初始植物圖片數組  選中
		for(int i=0;i<8;++i)
			PaintedPics[i]=new ImageIcon("pic//植物"+(i+1)+"p.gif");
		//初始數字圖片數組
		for(int i=0;i<4;++i)
			rn[i]=new ImageIcon("pic//"+i+".png");
		//各個圖片初始化
		Backgroundimg=new ImageIcon("pic//背景2.png");
		Timeimg=new ImageIcon("pic//時間.png");
		Refreshimg=new ImageIcon("pic//刷新.png");
		Bomimg=new ImageIcon("pic//炸彈.png");
		Scoreimg=new ImageIcon("pic//分數.png");
		//獲取背景圖片 植物圖片  長寬
		w1=Backgroundimg.getIconWidth();
		h1=Backgroundimg.getIconHeight();
		wp=Pics[1].getIconWidth();
		hp=Pics[1].getIconHeight();
		//背景控件
		label=new JLabel();
		label.setBounds(0,0,w1,h1);
		label.setLayout(null);
		label.setIcon(Backgroundimg);
		//時間按鈕
		TimeButton=new JButton();
		TimeButton.setBounds(220,0,50,50);
		TimeButton.setIcon(Timeimg);
		TimeButton.setBorderPainted(false);
		//初始化刷新按鈕
		RefreshButton=new JButton();
		RefreshButton.setBounds(30,100,50,50);
		RefreshButton.setIcon(Refreshimg);
		RefreshButton.setBorderPainted(false);
		RefreshButton.addMouseListener(this);
		RefreshButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
		//刷新剩餘次數按鈕
		RefreshNumsButton=new JButton();
		RefreshNumsButton.setBounds(100,100,50,50);
		RefreshNumsButton.setIcon(rn[refreshnums]);
		RefreshNumsButton.setBorderPainted(false);
		//炸彈按鈕
		BomButton=new JButton();
		BomButton.setBounds(30,200,50,50);
		BomButton.setIcon(Bomimg);
		BomButton.setBorderPainted(false);
		BomButton.addMouseListener(this);
		BomButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
		//炸彈剩餘次數按鈕
		BomNumsButton=new JButton();
		BomNumsButton.setBounds(100,200,50,50);
		BomNumsButton.setIcon(rn[bombnums]);
		BomNumsButton.setBorderPainted(false);
		//分數按鈕
		ScoreButton=new JButton();
		ScoreButton.setBounds(30,300,102,39);
		ScoreButton.setIcon(Scoreimg);
		ScoreButton.setBorderPainted(false);
		//當前分數
		ScoreNumsButton=new JButton();
		ScoreNumsButton.setBounds(140,300,50,39);
		ScoreNumsButton.setText(scores+"");
		ScoreNumsButton.setContentAreaFilled(false);
		ScoreButton.setBorderPainted(false);
		//裝載所有植物方塊的控件
		panel1=new JPanel();
		panel1.setBounds(220,70,620,430);
		panel1.setLayout(null);
		panel1.setOpaque(false);
		//左側轉載  刷新  炸彈  分數的控件
		panel2=new JPanel();
		panel2.setBounds(0,0,200,480);
		panel2.setLayout(null);
		panel2.setOpaque(false);
		panel2.add(RefreshButton);
		panel2.add(RefreshNumsButton);
		panel2.add(BomButton);
		panel2.add(BomNumsButton);
		panel2.add(ScoreButton);
		panel2.add(ScoreNumsButton);
		this.add(panel1);
		this.add(panel2);
		//初始化植物方塊
		for(int i=1;i<=Rows;++i)
		{
			for(int j=1;j<=Cols;++j)
			{
				/*獲取0~7的隨機數   即獲取該位置植物的種類數   
				 * 同時保證該種類的植物數量不超過規定值  
				 * 如果超過  重新獲取  如果符合 則記錄爲位置植物的種類 該種類數量加1*/
				Random seed=new Random();
				int temp;
				do 
				{
					temp=seed.nextInt(8);
				}while(cnt[temp]>=nums[temp]);//獲取符合要求的植物種類
				cnt[temp]++; //該種類數量加1
				type[i][j]=temp;//記錄該位置植物種類
				Map[i][j]=true;//該位置存在植物
				Blocks[i][j]=new JButton();
				Blocks[i][j].setBounds((j-1)*wp,(i-1)*hp,wp,hp);//根據i j 設置植物方塊位置
				Blocks[i][j].setIcon(Pics[temp]);//根據種類設置圖片
				Blocks[i][j].setBorderPainted(false);
				Blocks[i][j].addMouseListener(this);
				Blocks[i][j].setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));//鼠標移到植物方塊上,改變鼠標形狀
				panel1.add(Blocks[i][j]);//將該植物方塊加入控件
			}
		}
		//時間進度條初始化
		progressBar.setMinimum(MIN_PROGRESS);
		progressBar.setMaximum(MAX_PROGRESS);
		progressBar.setBounds(300,10,500,20);
		progressBar.setValue(currentProgress);
		progressBar.setStringPainted(true);
		progressBar.setVisible(true);
		new Timer(500, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                currentProgress++;
                //如果超過最大規定時間  且遊戲未結束 結束遊戲  遊戲失敗
                if (currentProgress > MAX_PROGRESS&&isend==0) {
                    new EndWindow(0);//失敗窗口
                    isend=1;
                }
                //如果方塊全部被消除  且遊戲未結束 結束遊戲  遊戲勝利
                else if(currentblocks==0&&isend==0)
                {
                	new EndWindow(1);//勝利窗口
                	isend=1;
                }
                progressBar.setValue(currentProgress);
            }
        }).start();
		//遊戲窗口各屬性設置
		this.setBounds(300,160,w1+20,h1+40);
		this.setLayout(null);
		this.add(TimeButton);
		this.add(progressBar);
		this.add(label);
		this.setVisible(true);
		this.setTitle("植物大戰殭屍消消樂");
		
	}
	//刷新功能
	private void Refresh()
	{
		Point [] arr=new Point [71];
		int n=0;
		for(int i=1;i<=Rows;++i)
		{
			for(int j=1;j<=Cols;++j)
			{
				if(Map[i][j]==true)
				{
					arr[++n]=new Point(i,j);
				}
			}
		}
		int Left=1,Right=n;
		while(Left<Right)
		{
			int temp=type[arr[Left].x][arr[Left].y];
			type[arr[Left].x][arr[Left].y]=type[arr[Right].x][arr[Right].y];
			type[arr[Right].x][arr[Right].y]=temp;
			Blocks[arr[Left].x][arr[Left].y].setIcon(Pics[type[arr[Left].x][arr[Left].y]]);
			Blocks[arr[Right].x][arr[Right].y].setIcon(Pics[type[arr[Right].x][arr[Right].y]]);
			Left++;
			Right--;
		}
	}
	//炸彈功能
	public void Bom()
	{
		Point [] arr=new Point [71];
		int n=0;
		for(int i=1;i<=Rows;++i)
		{
			for(int j=1;j<=Cols;++j)
			{
				if(Map[i][j]==true)
				{
					arr[++n]=new Point(i,j);
				}
			}
		}
		for(int i=1;i<=n;++i)
		{
			for(int j=i+1;j<=n;++j)
			{
				if(type[arr[i].x][arr[i].y]==type[arr[j].x][arr[j].y])
				{
					Blocks[arr[i].x][arr[i].y].setVisible(false);
					Blocks[arr[j].x][arr[j].y].setVisible(false);
					Map[arr[i].x][arr[i].y]=false;
					Map[arr[j].x][arr[j].y]=false;
					currentblocks-=2;
					return;
				}
			}
		}
	}
	//鼠標監聽接口
	@Override
	public void mouseClicked(MouseEvent e) {
		// TODO Auto-generated method stub
		JButton temp=(JButton)e.getSource();
		Point now=temp.getLocation();
		int x=now.y/60+1,y=now.x/60+1;
		if(e.getSource()!=RefreshButton&&e.getSource()!=BomButton)//如果鼠標點擊的不是刷新 炸彈按鈕 即點擊的是植物按鈕
		{
			if(firstblock.equals(new Point(-1,-1)))//如果還未選中植物方塊 記錄第一個選中的
			{
				firstblock.x=x;
				firstblock.y=y;
				Blocks[x][y].setIcon(PaintedPics[type[x][y]]);
				Blocks[x][y].setBorderPainted(true);
			}
			else //即已選中一個  記錄選中的第二個 
			{
				secondblock.x=x;
				secondblock.y=y;
				if(type[firstblock.x][firstblock.y]==type[secondblock.x][secondblock.y]&&Judger.Judge(firstblock, secondblock)) //判斷選中的兩個是否能消除
				{
					//消除
					Map[firstblock.x][firstblock.y]=false;
					Map[secondblock.x][secondblock.y]=false;
					Blocks[firstblock.x][firstblock.y].setVisible(false);
					Blocks[secondblock.x][secondblock.y].setVisible(false);
					//分數增加  方塊數減少
					scores+=2;
					currentblocks-=2;
					//分數顯示
					ScoreNumsButton.setText(scores+"");
				}
				//如果不能消除   清空選中的信息
				Blocks[firstblock.x][firstblock.y].setIcon(Pics[type[firstblock.x][firstblock.y]]);	
				Blocks[firstblock.x][firstblock.y].setBorderPainted(false);
				firstblock.x=firstblock.y=secondblock.x=secondblock.y=-1;
			}
		}
		else if(e.getSource()==RefreshButton&&refreshnums!=0)//如果選中刷新按鈕 刷新次數減少 執行刷新操作
		{
			refreshnums--;
			RefreshNumsButton.setIcon(rn[refreshnums]);
			Refresh();
		}
		else if(e.getSource()==BomButton&&bombnums!=0)//炸彈
		{
			bombnums--;
			BomNumsButton.setIcon(rn[bombnums]);
			Bom();
		}
	}
	@Override
	public void mousePressed(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	//鼠標移入方塊時  方塊邊框顯示  動畫效果
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
		JButton temp=(JButton)e.getSource();
		Point now=temp.getLocation();
		int x=now.y/60+1,y=now.x/60+1;
		Blocks[x][y].setBorderPainted(true);
	}

	@Override
	//鼠標移出  效果消失
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub
		JButton temp=(JButton)e.getSource();
		Point now=temp.getLocation();
		int x=now.y/60+1,y=now.x/60+1;
		Blocks[x][y].setBorderPainted(false);
	}
	//類中類  消除算法
	class Check
	{
		private boolean Horizen(Point a,Point b)
		{
			if(a.x==b.x&&a.y==b.y) return false;
			if(a.x!=b.x) return false;
			int bg=Math.min(a.y,b.y),end=Math.max(a.y,b.y);
			for(int i=bg+1;i<end;++i)
				if(Map[a.x][i]==true) return false;
			return true;
		}
		private boolean Vertical(Point a,Point b)
		{
			if(a.x==b.x&&a.y==b.y) return false;
			if(a.y!=b.y) return false;
			int bg=Math.min(a.x, b.x),end=Math.max(a.x, b.x);
			for(int i=bg+1;i<end;++i)
				if(Map[i][a.y]==true) return false;
			return true;
		}
		private boolean TurnOnce(Point a,Point b)
		{
			if(a.x==b.x&&a.y==b.y) return false;
			Point temp1 = new Point(a.x,b.y),temp2 = new Point(b.x,a.y);
			if(Map[a.x][b.y]==false&&Horizen(a,temp1)==true&&Vertical(b,temp1)==true) return true;
			if(Map[b.x][a.y]==false&&Horizen(b,temp2)&&Vertical(a,temp2)) return true;
			return false;
		}
		private boolean TurnTwice(Point a,Point b)
		{
			if(a.x==b.x&&a.y==b.y) return false;
			for(int i=0;i<Rows+2;++i)
			{
				for(int j=0;j<Cols+2;++j)
				{
					if((i==a.x&&j==a.y)||(i==b.x&&i==b.y)) continue;
					if(Map[i][j]==true) continue;
					if(TurnOnce(a,new Point(i,j))&&(Horizen(b,new Point(i,j))||Vertical(b,new Point(i,j)))) return true;
					if(TurnOnce(b,new Point(i,j))&&(Horizen(a,new Point(i,j))||Vertical(a,new Point(i,j)))) return true;
				}
			}
			return false;
		}
		public boolean Judge(Point a,Point b)
		{
			if(Horizen(a,b)==true) return true;
			if(Vertical(a,b)==true) return true;
			if(TurnOnce(a,b)==true) return true;
			if(TurnTwice(a,b)==true) return true;
			return false;
		}
	}
}

更多信息窗口類代碼(MoreWindow.java)

package myplantslink;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class MoreWindow extends JFrame {

	private static final long serialVersionUID = 1L;
	private ImageIcon Farmerimg,Authorimg,Dancerimg;
	private JLabel Morelabel1,Morelabel2,Morelabel3;
	MoreWindow()
	{
		Farmerimg=new ImageIcon("pic//農夫.gif");
		Authorimg=new ImageIcon("pic//羊皮紙.png");
		Dancerimg=new ImageIcon("pic//跳舞殭屍.gif");
		Morelabel1=new JLabel();
		Morelabel1.setIcon(Farmerimg);
		Morelabel1.setBounds(0, 0, 300, 500);
		Morelabel2=new JLabel();
		Morelabel2.setBounds(270,50,300,270);
		Morelabel2.setIcon(Authorimg);
		Morelabel3=new JLabel();
		Morelabel3.setBounds(350,320,75,150);
		Morelabel3.setIcon(Dancerimg);
		this.setBounds(450,150,600,510);
		this.setLayout(null);
		this.add(Morelabel1);
		this.add(Morelabel2);
		this.add(Morelabel3);
		this.setTitle("更多信息");
		this.setVisible(true);
	}
}

結束窗口類代碼(EndWindow.java)

package myplantslink;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class EndWindow extends JFrame{

	
	private static final long serialVersionUID = 1L;
	private ImageIcon Victoryimg,Defeatimg;
	private JLabel Lastlabel;
	EndWindow(int n)
	{
		if(n==0)
		{
			Defeatimg=new ImageIcon("pic//失敗.png");
			Lastlabel=new JLabel();
			Lastlabel.setBounds(0,0,240,200);
			Lastlabel.setIcon(Defeatimg);
			this.setBounds(600,300,250,210);
			this.setLayout(null);
			this.add(Lastlabel);
			this.setTitle("遊戲失敗");
			this.setVisible(true);
		}
		else if(n==1)
		{
			Victoryimg=new ImageIcon("pic//勝利.png");
			Lastlabel=new JLabel();
			Lastlabel.setBounds(0,0,204,62);
			Lastlabel.setIcon(Victoryimg);
			this.setBounds(600,300,224,100);
			this.setLayout(null);
			this.add(Lastlabel);
			this.setTitle("遊戲勝利");
			this.setVisible(true);
		}
	}
}

主函數代碼

package myplantslink;

public class Main {
	public static void main(String [] argv)
	{
		new MainWindow();
	}
}

(五)核心算法——方塊消除

以下的示例代碼中:

Map[x][y]//表示位置x y處是否有方塊

1.水平方向檢測
水平檢測用來判斷兩個點的縱座標是否相等,同時判斷兩點間有沒有障礙物。

在這裏插入圖片描述
因此直接檢測兩點間是否有障礙物就可以了,代碼如下:

        boolean Horizen(Point a,Point b)
		{
			if(a.x==b.x&&a.y==b.y) return false;
			if(a.x!=b.x) return false;
			int bg=Math.min(a.y,b.y),end=Math.max(a.y,b.y);
			for(int i=bg+1;i<end;++i)
				if(Map[a.x][i]==true) return false;
			return true;
		}

2.垂直方向檢測
垂直檢測用來判斷兩個點的橫座標是否相等,同時判斷兩點間有沒有障礙物。

2.png

同樣地,直接檢測兩點間是否有障礙物,代碼如下:

        boolean Vertical(Point a,Point b)
		{
			if(a.x==b.x&&a.y==b.y) return false;
			if(a.y!=b.y) return false;
			int bg=Math.min(a.x, b.x),end=Math.max(a.x, b.x);
			for(int i=bg+1;i<end;++i)
				if(Map[i][a.y]==true) return false;
			return true;
		}

3.一個拐角檢測
一個拐角檢測可分解爲水平檢測和垂直檢測,當兩個同時滿足時,便兩點可通過一個拐角相連。即:

一個拐角檢測 = 水平檢測 && 垂直檢測

3.png

A 點至 B 點能否連接可轉化爲滿足任意一點:

A 點至 C 點的垂直檢測,以及 C 點至 B 點的水平檢測;
A 點至 D 點的水平檢測,以及 D 點至 B 點的垂直檢測。
代碼如下:

        boolean TurnOnce(Point a,Point b)
		{
			if(a.x==b.x&&a.y==b.y) return false;
			Point temp1 = new Point(a.x,b.y),temp2 = new Point(b.x,a.y);
			if(Map[a.x][b.y]==false&&Horizen(a,temp1)==true&&Vertical(b,temp1)==true) return true;
			if(Map[b.x][a.y]==false&&Horizen(b,temp2)&&Vertical(a,temp2)) return true;
			return false;
		}

4.兩個掛角檢測

兩個拐角檢測可分解爲一個拐角檢測和水平檢測或垂直檢測。即:

兩個拐角檢測 = 一個拐角檢測 && (水平檢測 || 垂直檢測)

4.png

如圖,水平、垂直分別穿過 A B 共有四條直線,掃描直線上所有不包含 A B 的點,看是否存在一點 C ,滿足以下任意一項:

A 點至 C 點通過水平或垂直檢測,C 點至 B 點可通過一個拐角連接。(圖中用 C 表示)
A 點至 C 點可通過一個拐角連接,C 點至 B 點通過水平或垂直連接。(圖中用 C 下劃線表示)
代碼如下:

        boolean TurnTwice(Point a,Point b)
		{
			if(a.x==b.x&&a.y==b.y) return false;
			for(int i=0;i<Rows+2;++i)
			{
				for(int j=0;j<Cols+2;++j)
				{
					if((i==a.x&&j==a.y)||(i==b.x&&i==b.y)) continue;
					if(Map[i][j]==true) continue;
					if(TurnOnce(a,new Point(i,j))&&(Horizen(b,new Point(i,j))||Vertical(b,new Point(i,j)))) return true;
					if(TurnOnce(b,new Point(i,j))&&(Horizen(a,new Point(i,j))||Vertical(a,new Point(i,j)))) return true;
				}
			}
			return false;
		}

5.最終的檢驗算法

        boolean Judge(Point a,Point b)
		{
			if(Horizen(a,b)==true) return true;
			if(Vertical(a,b)==true) return true;
			if(TurnOnce(a,b)==true) return true;
			if(TurnTwice(a,b)==true) return true;
			return false;
		}

筆者不才,由於製作時間比較短,而且沒有其他同伴的測試,代碼中可能會有BUG,代碼僅供參考!!

## 如果你覺得此篇文章對您有幫助,麻煩您點個贊嘿嘿,如果你有更多的問題,可以聯繫我,我很樂意一起解決。

源代碼及其圖片鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章