千里冰封
          JAVA 濃香四溢
          posts - 151,comments - 2801,trackbacks - 0

          3.      游戲的開發(fā)與編碼

          在我們開發(fā)這個(gè)游戲之前,我們先講一個(gè)這個(gè)游戲的實(shí)現(xiàn)所采用的方法,那就是經(jīng)典的MVC模式,因?yàn)樵陂_發(fā)游戲的時(shí)候,結(jié)構(gòu)很重要,必須要理清楚每一塊負(fù)責(zé)什么,每一個(gè)類負(fù)責(zé)什么,而MVC模式正好就是解決這種問題的很好的方案,我們可以把游戲的運(yùn)行流程交由一個(gè)類去統(tǒng)一調(diào)度,游戲的呈現(xiàn)也就是繪圖用專門一個(gè)類去負(fù)責(zé),而繪圖所需的數(shù)據(jù)可以從一個(gè)模型類里面去取,控制的類負(fù)責(zé)更改模型里面的數(shù)據(jù)并調(diào)用視圖類去更新當(dāng)前的視頻,這樣整個(gè)游戲的流程就很清晰明了。所以我們?cè)O(shè)計(jì)了如下幾個(gè)類,它們之間互相交互,形成整個(gè)游戲的框架。

          1,ClientControl

                 顧名思義,這個(gè)類就是我們的控制端類,它負(fù)現(xiàn)整個(gè)游戲的流程控制以及事件處理。它在MVC里面的角色是C。

          2,ClientModel

                 它就是我們程序運(yùn)行的時(shí)候,放數(shù)據(jù)的地方,它存放的數(shù)據(jù)并不是一般的數(shù)據(jù),而是需要雙方一起交互的數(shù)據(jù),它只是做為一個(gè)橋梁,連接控制端和視圖端的紐帶。它是MVC的角色里面是M.

          3,ClientView

                 它是我們今天需要重點(diǎn)講解的地方,它是我們MVC里面的視圖的實(shí)現(xiàn),它負(fù)責(zé)呈現(xiàn)整個(gè)游戲的界面,并且它也受控制端ClientControl的支配,由ClientControl請(qǐng)求它重繪。它重繪的時(shí)候,一些數(shù)據(jù)將從ClientModel里面去取。

                 那么我們重點(diǎn)來看一看ClientView的代碼:

          /*
           * ClientView.java
           *
           * Created on 2007年10月2日, 下午2:00
           * 此類專門負(fù)責(zé)視圖的實(shí)現(xiàn),此類中須定義從模型中
           * 取出數(shù)據(jù)并重繪的方法
           * To change this template, choose Tools | Template Manager
           * and open the template in the editor.
           
          */

          package com.hadeslee.apple.client;

          import com.hadeslee.apple.common.Bet;
          import java.awt.Color;
          import java.awt.Cursor;
          import java.awt.Font;
          import java.awt.FontMetrics;
          import java.awt.Graphics;
          import java.awt.Graphics2D;
          import java.awt.Image;
          import java.awt.MediaTracker;
          import java.awt.Point;
          import java.awt.RenderingHints;
          import java.awt.Toolkit;
          import java.util.logging.Level;
          import java.util.logging.Logger;
          import javax.swing.*;
          import java.util.Vector;

          /**
           *
           * 
          @author lbf
           
          */
          public class ClientView extends JPanel {

              
          private ClientModel cm; //模型類的一個(gè)對(duì)象
              private volatile boolean isStar;
              
          private Image starA; //表示當(dāng)前星星的圖片
              private Image[] star; //星星的數(shù)組
              private int x1;
              
          private int y1; //星星的座標(biāo)
              private Image bg2; //表示底襯的那層
              private Image ratio; //賠率底襯的那層
              private int x;
              
          private int length; //表示跑馬燈的位置

              
          /** Creates a new instance of ClientView */
              
          public ClientView(ClientModel cm) {
                  
          this.cm = cm;
                  initOther();
                  x 
          = 646;
                  
          new RunStar().start();
                  
          new Draw().start();
              }

              
          //初始化視圖類的一些參數(shù)
              private void initOther() {
                  
          try {
                      star 
          = new Image[3];
                      MediaTracker mt 
          = new MediaTracker(this);
                      
          for (int i = 0; i < 3; i++) {
                          star[i] 
          = Toolkit.getDefaultToolkit().createImage(this.getClass().getResource("pic/game/star/" + (i + 1+ ".png"));
                          mt.addImage(star[i], i);
                      }
                      bg2 
          = Toolkit.getDefaultToolkit().createImage(this.getClass().getResource("pic/game/bg2.png"));
                      ratio 
          = Toolkit.getDefaultToolkit().createImage(this.getClass().getResource("pic/game/ratio.png"));
                      mt.addImage(bg2, 
          4);
                      mt.addImage(ratio, 
          5);
                      
                      mt.waitForAll();

                      starA 
          = star[0];
                      
          //把默認(rèn)的鼠標(biāo)改成我們自定義的鼠標(biāo)形式,以配合主題
                      Image icon = Toolkit.getDefaultToolkit().createImage(this.getClass().getResource("pic/login/icon.png"));
                      Cursor cu 
          = Toolkit.getDefaultToolkit().createCustomCursor(icon, new Point(00), "my");
                      
          this.setCursor(cu);
                  } 
          catch (InterruptedException ex) {
                      Logger.getLogger(ClientView.
          class.getName()).log(Level.SEVERE, null, ex);
                  }
              }
              
          //覆蓋的方法
              protected void paintComponent(Graphics g) {
                  
          //先調(diào)用父類的方法,清除以前畫的內(nèi)容
                  super.paintComponent(g);
                  
          //然后設(shè)置一些提示,比如屏幕抗鋸齒,以及文字抗鋸齒
                  Graphics2D gd = (Graphics2D) g;
                  gd.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                  gd.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
                  
          //畫背景
                  g.drawImage(cm.getBg(), 00this);
                  g.drawImage(bg2, 
          00this); //再畫第二個(gè)背景
                  
          //畫賠率的閃動(dòng)
                  if (cm.isRunning()) {
                      drawRatio(g);
                  }
                  
          //再畫桌面
                  drawTable(g);
                  
          //如果現(xiàn)在正在跑,那么就調(diào)用跑的那個(gè)方法
                  if (cm.isRunning()) {
                      drawRunning(g);
                  }
                  
          //如果現(xiàn)在正在賭剪刀石頭布,那么就調(diào)用比倍的方法
                  if (cm.isBetting()) {
                      drawBetting(g);
                  }
                  
          //畫出永遠(yuǎn)存在的星星
                  if (isStar) {
                      g.drawImage(starA, x1, y1, 
          this);
                  }
                  
          //畫出跑馬燈,提示文字
                  drawTip(g);
              }

              
          private void drawTip(Graphics g) {
                  g.setFont(
          new Font("宋體", Font.PLAIN, 22));
                  g.setColor(Color.RED);
                  g.drawString(cm.getInfo().getTip(), x, 
          25);
                  FontMetrics fm 
          = g.getFontMetrics();
                  length 
          = (int) fm.getStringBounds(cm.getInfo().getTip(),g).getWidth();
              }

              
          //畫出賠率
              private void drawRatio(Graphics g) {
                  RatioA ra 
          = cm.getRa();
                  RatioB rb 
          = cm.getRb();
                  
          if (ra != null) {
                      g.drawImage(ratio, ra.x, ra.y, 
          this);
                  }
                  
          if (rb != null) {
                      g.drawImage(ratio, rb.x, rb.y, 
          this);
                  }
              }

              
          //畫出正在跑的方法
              private void drawRunning(Graphics g) {
                  Vector
          <PP> ps = cm.getP();
                  
          for (PP p : ps) {
                      g.drawImage(p.current, p.x, p.y, 
          this);
                  }
              }

              
          //畫出跑完的方法
              private void drawRunOver(Graphics g) {
                  Vector
          <PP> ps = cm.getP();
                  
          for (PP p : ps) {
                      g.drawImage(p.current, p.x, p.y, 
          this);
                  }
              }

              
          //畫出正在比倍的方法
              private void drawBetting(Graphics g) {
                  g.drawImage(cm.getPKBG(), 
          17239this);
                  g.drawImage(cm.getPkA(), 
          267245this);
                  g.drawImage(cm.getPkB(), 
          386247this);
              }

              
          //畫桌面以及桌面上的一些信息
              private void drawTable(Graphics g) {
                  g.drawImage(cm.getTable(), 
          00this);
                  drawMoney(g);
                  drawBet(g);
              }

              
          //畫下注的那九格下注數(shù)字
              private void drawBet(Graphics g) {
                  Bet b 
          = cm.getBet();
                  drawNumber(
          805701219, b.getBet(1), g, b.getWin(1));
                  drawNumber(
          1835701219, b.getBet(2), g, b.getWin(2));
                  drawNumber(
          2525701219, b.getBet(3), g, b.getWin(3));
                  drawNumber(
          3185701219, b.getBet(4), g, b.getWin(4));
                  drawNumber(
          4245701219, b.getBet(5), g, b.getWin(5));
                  drawNumber(
          5275701219, b.getBet(6), g, b.getWin(6));
                  drawNumber(
          5975701219, b.getBet(7), g, b.getWin(7));
                  drawNumber(
          6645701219, b.getBet(8), g, b.getWin(8));
                  drawNumber(
          7675701219, b.getBet(9), g, b.getWin(9));
              }

              
          //畫有余額,贏的錢,用戶ID,大小彩金等的方法
              private void drawMoney(Graphics g) {
                  
          //畫余額和贏的錢
                  int allMoney = cm.getAllMoney();
                  
          int winMoney = cm.getWinMoney();
                  
          if (allMoney < 10000) {
                      drawNumber(
          762882438, allMoney, g);
                  } 
          else {
                      drawNumber(
          762941828, allMoney, g);
                  }
                  
          if (winMoney < 10000) {
                      drawNumber(
          129862438, winMoney, g);
                  } 
          else {
                      drawNumber(
          129901828, winMoney, g);
                  }
                  drawNumber(
          7402081219, cm.getId(), g); //畫ID號(hào)
                  
          //畫大彩金和小彩金
                  int smallBonus = cm.getInfo().getSmallBonus();
                  
          int bigBonus = cm.getInfo().getBigBonus();
                  
          if (smallBonus < 10000) {
                      drawNumber(
          7603902438, smallBonus, g);
                  } 
          else {
                      drawNumber(
          7603961828, smallBonus, g);
                  }
                  
          if (bigBonus < 10000) {
                      drawNumber(
          1283902438, bigBonus, g);
                  } 
          else {
                      drawNumber(
          1283961828, bigBonus, g);
                  }
              }

              
          //定義兩個(gè)重載的方法,分別針對(duì)于圖放大的圖片和一般大小的圖片
              private void drawNumber(int startX, int startY, int num, Graphics g, boolean isWin) {
                  drawNumber(startX, startY, 
          2438, num, g, isWin);
              }

              
          private void drawNumber(int startX, int startY, int width, int height, int num, Graphics g) {
                  drawNumber(startX, startY, width, height, num, g, 
          false);
              }

              
          private void drawNumber(int startX, int startY, int width, int height, int num, Graphics g, boolean isWin) {
                  String ns 
          = Integer.toString(num);
                  
          int i = 0;
                  
          for (int start = ns.length() - 1; start >= 0; start--) {
                      i
          ++;
                      
          char c = ns.charAt(start);
                      
          int index = c - 48;
                      
          if (isWin) {
                          g.drawImage(cm.getWinNumber(index), startX 
          - (i * width), startY, width, height, this);
                      } 
          else {
                          g.drawImage(cm.getNumber(index), startX 
          - (i * width), startY, width, height, this);
                      }
                  }
              }

          //此類專門用于后臺(tái)調(diào)用重繪線程
              private class Draw extends Thread {

                  
          public void run() {
                      
          while (true) {
                          
          try {
                              x 
          -= 5;
                              
          if (x + length < 0) {
                                  x 
          = 800;
                              }
                              Thread.sleep(
          200);
                              repaint(x,
          0,length+20,30);
                          } 
          catch (Exception exe) {
                              exe.printStackTrace();
                          }
                      }
                  }
              }

          //此類專門用于跑星星的閃動(dòng)
              private class RunStar extends Thread {

                  
          private int total;

                  
          public RunStar() {
                      isStar 
          = true;
                      x1 
          = 339;
                      y1 
          = 106;
                  }

                  
          public void run() {
                      
          int index = 0;
                      
          while (true) {
                          
          try {
                              Thread.sleep(
          100);
                              
          if (index < star.length - 1) {
                                  starA 
          = star[++index];
                              } 
          else {
                                  starA 
          = star[0];
                                  index 
          = 0;
                                  total
          ++;
                              }
                              
          if (total > 1) {
                                  isStar 
          = false;
                                  repaint();
                                  total 
          = 0;
                                  x1 
          = (int) (Math.random()*100-50+ 339;
                                  y1 
          = (int) (Math.random()*100-50+ 106;
                                  
          int sleep = (int) (Math.random()*3000+ 1000;
                                  Thread.sleep(sleep);
                                  isStar 
          = true;
                              }
          else{
                                  repaint(x1,y1,
          150,150);
                              }
                          } 
          catch (Exception exe) {
                              exe.printStackTrace();
                          }
                      }
                  }
              }
          }

          代碼其實(shí)不長,二百多行而已,我們先來看看如下幾個(gè)代碼片段:

          Toolkit.getDefaultToolkit().createImage(this.getClass().getResource("pic/game/bg2.png"));

          這句話有兩個(gè)需要我們注意的地方:

          一是我們?nèi)绾伟褕D片導(dǎo)入程序當(dāng)中,二是我們?nèi)绻褕D片打包進(jìn)JAR包,然后如何得到它們的URL。

          我們先講第一個(gè),如何把圖片導(dǎo)入程序中,在這里我們用的是Toolkit的方法createImage,它確實(shí)是一個(gè)很實(shí)用的方法,它是一個(gè)重載的方法,可以傳入很多種參數(shù),除了可以傳入U(xiǎn)RL之處,還可以有如下的重載方法:

          Image

          createImage(byte[] imagedata)
                    
          創(chuàng)建一幅圖像,該圖像對(duì)存儲(chǔ)在指定字節(jié)數(shù)組中的圖像進(jìn)行解碼。

          abstract  Image

          createImage(byte[] imagedata, int imageoffset, int imagelength)
                    
          創(chuàng)建一幅圖像,該圖像對(duì)存儲(chǔ)在指定字節(jié)數(shù)組中指定偏移量和長度處的圖像進(jìn)行解碼。

          abstract  Image

          createImage(ImageProducer producer)
                    
          使用指定的圖像生成器創(chuàng)建一幅圖像。

          abstract  Image

          createImage(String filename)
                    
          返回從指定文件獲取像素?cái)?shù)據(jù)的圖像。

          abstract  Image

          createImage(URL url)
                    
          返回一幅圖像,該圖像從指定 URL 獲取像素?cái)?shù)據(jù)。

           

          有一點(diǎn)需要注意的是,它的createImage是一個(gè)異步的方法,也就是說我們調(diào)用了這個(gè)方法以后,程序會(huì)立即返回,并不會(huì)等到圖片完全加載進(jìn)內(nèi)存之后才返回,所以當(dāng)我們用這種方法加載比較大的圖片的時(shí)候,如果圖片又沒有完全進(jìn)入內(nèi)存,而我們卻去draw它,這個(gè)時(shí)候就會(huì)出現(xiàn)撕裂的情況,大大影響了我們程序的性能以及可玩性,那怎么辦呢?

          辦法有兩種,一種是像我們?cè)诔绦蚶飳?shí)現(xiàn)的一樣,用一個(gè)媒體跟蹤器來跟蹤我們要加載的圖片,然后調(diào)用一個(gè)同步方法等待它們?nèi)考虞d進(jìn)入內(nèi)存之后才繼續(xù)往下運(yùn)行,這樣就可以保存在初始化以后,所需要用到的圖片確實(shí)都全部加載進(jìn)內(nèi)存了,這樣畫的時(shí)候,才能保證效果。如下所示:

           

          MediaTracker mt = new MediaTracker(this);

          mt.addImage(star[i], i);

          ...
          mt.waitForAll();

           

          我們生成一個(gè)媒體跟蹤器,然后把我們需要跟蹤的圖片放到里面去,然后等待所有的圖片加載,mt.waitForAll()方法是會(huì)拋出一個(gè)InterruptedException的方法。我們需要捕獲處理它。

              另外一種辦法就是利用javax.imageio.ImageIO的方法,它的read方法可以同步的把圖片完全讀入內(nèi)存,某些情況下這是更方便的方法,因?yàn)槭褂盟馊チ思用襟w跟蹤器的代碼。javax.imageio.ImageIO的read方法也有很多重載的版本,它的方法如下:

          static BufferedImage

          read(File input)
                    
          返回一個(gè) BufferedImage,作為使用 ImageReader(它是從當(dāng)前已注冊(cè) ImageReader 中自動(dòng)選擇的)解碼所提供 File 的結(jié)果。

          static BufferedImage

          read(ImageInputStream stream)
                    
          返回一個(gè) BufferedImage,作為使用 ImageReader(它是從當(dāng)前已注冊(cè) ImageReader 中自動(dòng)選擇的)解碼所提供 ImageInputStream 的結(jié)果。

          static BufferedImage

          read(InputStream input)
                    
          返回一個(gè) BufferedImage,作為使用 ImageReader(它是從當(dāng)前已注冊(cè) ImageReader 中自動(dòng)選擇的)解碼所提供 InputStream 的結(jié)果。

          static BufferedImage

          read(URL input)
                    
          返回一個(gè) BufferedImage,作為使用 ImageReader(它是從當(dāng)前已注冊(cè) ImageReader 中自動(dòng)選擇的)解碼所提供 URL 的結(jié)果。

          所以我們用read方法的話,會(huì)顯得更加方一些,但是為什么我們?cè)诔绦虍?dāng)中不使用它,而使用再加繁瑣的Toolkit加上MediaTracker的方法呢?因?yàn)镮mageIO讀入內(nèi)存的圖片在呈現(xiàn)的過程中會(huì)有如下缺點(diǎn):

          1,當(dāng)加載的圖片是動(dòng)態(tài)的gif圖片的時(shí)候,圖片在呈現(xiàn)的時(shí)候,將沒有動(dòng)畫效果,它只會(huì)讀取第一幀。

          2,當(dāng)加載的圖片是半透明的時(shí)候,圖片在呈現(xiàn)的時(shí)候,會(huì)比用Toolkit加載進(jìn)來的圖片更耗CPU。

          所以我們選擇了用Toolkit而不是ImageIO,當(dāng)我們沒有用到以上兩種情況的圖片的時(shí)候,是完全可以用ImageIO來加載圖片的。

              圖片導(dǎo)入程序中的問題解決了,我們現(xiàn)在來看一看如何把圖片打包進(jìn)JAR包,然后又如何在程序運(yùn)行的時(shí)候把JAR包里面的資源提取出來。在這里我們用的是一個(gè)很有用的方法getResource(),它是定義在Class類里面的,當(dāng)我們把我們的的圖片提取出來的時(shí)候,可以用相對(duì)路徑也可以用絕對(duì)路來來提取,當(dāng)我們用相對(duì)路徑的時(shí)候,路徑就是相對(duì)于當(dāng)前的class文件所在目錄的路徑,如果是用絕對(duì)路徑的時(shí)候,路徑就是從JAR內(nèi)部的根目錄開始算的。把圖片等一些資源打入JAR包有很多好處,一是可以實(shí)現(xiàn)資源的初步隱藏,二是可以利用JAR的特性對(duì)文件進(jìn)行一些壓縮,因?yàn)镴AR包就是一個(gè)壓縮包,只不過后綴名改了而已。

              下面我們?cè)賮砜匆幌聀aintComponent方法,它是一個(gè)重寫的方法,它重寫了父類JPanel里面的paintComponent方法,一般來說,當(dāng)我們要繪制一些內(nèi)容的時(shí)候,都是采用重寫此方法的辦法,在以前AWT的編程中,對(duì)重量型組件進(jìn)行重寫,一般重寫的是paint方法,所以在用輕量級(jí)組件的時(shí)候,這一點(diǎn)要注意,最好不要再重寫paint方法了,而是改為重寫paintComponent。在它里面我們看到如下三句:

           

          Graphics2D gd = (Graphics2D) g;

                  gd.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

                  gd.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

           

          它的意思就是設(shè)置圖形上下文在繪制的時(shí)候,要注意哪些方面,我們可以利用這個(gè)方法給圖形上下文一些提示。在本文里面我們提示了兩點(diǎn),一點(diǎn)是圖片抗鋸齒打開,二是文本抗據(jù)齒我們也打開,除了這兩個(gè)之外還要很多提示我們可以設(shè)置的,在興趣的朋友可以查看java.awt.RenderingHints這個(gè)類。利用這個(gè)特性,我們可以使我們呈現(xiàn)的界面更加完美,不過完美是需要代價(jià)的,呈現(xiàn)的越清晰越完美就越需要更多的CPU的運(yùn)算,所以當(dāng)電腦的性能不太好的時(shí)候,我們可以把這兩個(gè)提示去掉,讓JVM自行把握繪制的質(zhì)量。

              還有一點(diǎn)我們要注意的地方,那就是我們調(diào)用repaint的地方。在我們需要重繪的時(shí)候,我們可以調(diào)用repaint方法,它會(huì)發(fā)送一個(gè)重繪的請(qǐng)求,那個(gè)會(huì)把這個(gè)請(qǐng)求放到重繪線程里面去,在我們調(diào)用repaint的時(shí)候,有很重要的一點(diǎn)就是盡量不要去調(diào)用repaint的默認(rèn)方法,而要調(diào)用repaint(int x,int y,int width,int height)方法,因?yàn)樗粫?huì)請(qǐng)求重繪某一個(gè)區(qū)域,而repaint()則會(huì)重繪整個(gè)區(qū)域,所以為了性能著想,最好不要重繪整個(gè)區(qū)域,當(dāng)你開發(fā)了有關(guān)JAVA2D的程序后,你會(huì)發(fā)現(xiàn),程序的大部份CPU都耗在重繪上面,所以優(yōu)化重繪區(qū)域?qū)τ趦?yōu)化整個(gè)程序的性能是很有效果的。





          盡管千里冰封
          依然擁有晴空

          你我共同品味JAVA的濃香.
          posted on 2007-11-10 08:57 千里冰封 閱讀(2020) 評(píng)論(5)  編輯  收藏 所屬分類: JAVASE

          FeedBack:
          # re: JAVA實(shí)現(xiàn)游戲編程(3)
          2007-11-10 10:17 | cping1982
          加油……努力……  回復(fù)  更多評(píng)論
            
          # re: JAVA實(shí)現(xiàn)游戲編程(3)
          2007-11-10 10:19 | cping1982
          有時(shí)間的話可以去http://blog.csdn.net/cping1982上看看我寫的一些java圖形操作實(shí)例,多少會(huì)有點(diǎn)參考價(jià)值的……  回復(fù)  更多評(píng)論
            
          # re: JAVA實(shí)現(xiàn)游戲編程(3)
          2007-11-10 11:07 | 千里冰封
          謝謝,看了你的博客,收獲良多  回復(fù)  更多評(píng)論
            
          # re: JAVA實(shí)現(xiàn)游戲編程(3)
          2007-11-10 15:11 | ci
          不錯(cuò)  回復(fù)  更多評(píng)論
            
          # re: JAVA實(shí)現(xiàn)游戲編程(3)
          2007-12-18 19:07 | xu
          不錯(cuò)。。。不錯(cuò)。。。
          受益良多

          我一直搞不明白的就是把圖片打包進(jìn)jar包以后,再如何讀取它,現(xiàn)在終于明白了,

          我還有一個(gè)問題就是如果把一個(gè)文件打包進(jìn)jar包以后,如何獲得它的File對(duì)象呢?  回復(fù)  更多評(píng)論
            
          主站蜘蛛池模板: 雷波县| 武夷山市| 云霄县| 峡江县| 长岭县| 怀来县| 乌鲁木齐县| 霍林郭勒市| 宁武县| 遂溪县| 五常市| 聂拉木县| 财经| 天长市| 霍邱县| 齐齐哈尔市| 深泽县| 忻州市| 千阳县| 石城县| 垣曲县| 古浪县| 蓬莱市| 故城县| 云南省| 绥滨县| 宜宾市| 将乐县| 尼勒克县| 筠连县| 邳州市| 安陆市| 长子县| 天全县| 抚宁县| 铁岭县| 信阳市| 千阳县| 加查县| 白朗县| 田林县|