1. 程式人生 > >人生如夢遊戲間,RPG遊戲開源開發講座 JAVA篇 3 ——邯鄲學步

人生如夢遊戲間,RPG遊戲開源開發講座 JAVA篇 3 ——邯鄲學步

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

書接前文,事表上回。話說上回書提到“畫面閃爍問題和角色動作的變更”是目前我們所面臨的兩大難點之一,本次,將就解決畫面閃爍的前提條件——角色動作變更,也即“動畫”進行較為深入的分析。

大家都很清楚的知道,所謂的動畫,並不是一個“會動的畫”,而是一組“連續變動的畫”,就好比Flash

製作時的需要憑藉“楨”調節畫面運動,在Java遊戲開發中一樣要通過類似的方式來控制畫面。

要實現這點,首先我們需要一組連續的影象。

如下圖:

 

日常生活中,我們很少會不知道自己應該邁左腳還是邁右腳,但對計算機而言,這是我們必須明確提示給他的條件。所以,我們還需要一個變數充當“計步器”,以明確下步狀態。

  private int count;

    而要想實現動畫,最重要的一點,就是畫面的連續,即多步操作的處理,為此我們使用到了Java中的Thread,也即執行緒。

 

 private Thread threadAnime;

 

 Java中,目前不支援如C#式的函式直接被執行緒呼叫方式。Java要實現執行緒,必需要通過繼承Thread類或實現Runnable介面。

 

  我們以Thread類的繼承為例:

 

   //內部類,用於處理計步動作。

    private class AnimationThread extends Thread {

       

public void run() {

            while (true) {

                // count計步

                if (count == 0) {

                    count = 1;

                } else if (count == 1) {

                    count = 0;

                }

                // 重繪畫面。

                repaint();

               

                // 300毫秒改變一次動作。

                try {

                    Thread.sleep(300);

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

            }

        }

    }

 

所謂的繼承,也可以簡單的理解為COPY下所繼承類的全部方法,而這裡我們重寫了run()方法,沒有改變其他。也就是說,我們將以自己的方式執行AnimationThread這個類。

   另外,在處理drawRole方法時,我們將其內部變更如下:

        //count作為影象的偏移數值

  g.drawImage(roleImage, x*CS, y*CS, x*CS+CS, y*CS+CS,

                count*CS, 0, CS+count*CS, CS, this);

 

  推導公式如下圖:

       

 

  最後,我們在MyPanel構建之初即啟動執行緒,令執行緒的相關操作活性化。

 

   //例項化內部執行緒AnimationThread

        threadAnime = new Thread(new AnimationThread());

        //啟動執行緒

        threadAnime.start();

 

MyPanel程式碼如下:

 

package org.loon.chair.example3;

 

import java.awt.Dimension;

import java.awt.Graphics;

import java.awt.Image;

import java.awt.event.KeyEvent;

import java.awt.event.KeyListener;

 

import javax.swing.ImageIcon;

import javax.swing.JPanel;

 

/**

 * Example3中自定義面板,用於描繪底層地圖。

 *

 * @author chenpeng

 *

 * Loon Framework in Game

 *

 * PS:請注意,此處與前例不同,新增鍵盤事件監聽

 */

public class MyPanel extends JPanel implements  KeyListener {

 

    //窗體的寬與高

    private static final int WIDTH = 480;

    private static final int HEIGHT = 480;

 

    //設定背景方格預設行數

    private static final int ROW = 15;

    //設定背景方格預設列數

    private static final int COL = 15;

   

    //單個影象大小,我預設採用32x32圖形,可根據需要調整比例。

    //當時,始終應和窗體大小比例協調;比如32x32的圖片,如何

    //一行設定15個,那麼就是480,也就是本例子預設的窗體大小,

    //當然,我們也可以根據ROW*CS,COl*CS在初始化時自動調整

    //窗體大小,以後的例子中會用到類似情況。總之一句話,程式設計

    //[為目的而存在的],所有的方法,大家都可任意嘗試和使用。

    private static final int CS = 32;

 

    //設定地圖,通常在rpg型別遊戲開發中,以[二維陣列]物件為

    //基礎進行地圖處理,用以描繪出X座標和Y座標。實際上,即令

    //再華麗的RPG類遊戲,都是從這些簡單的X,Y座標開始的。

    //PS:所謂[陣列],大家可以簡單的理解為即資料的集合,一維陣列

    //僅包含X軸,而二維是由X,Y兩個軸組成的,XY的交織點,即為

    //一條資料。

    private int[][] map = {

        {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},

        {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},

        {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},

        {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},

        {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},

        {1,0,0,0,0,1,1,1,1,1,0,0,0,0,1},

        {1,0,0,0,0,1,0,0,0,1,0,0,0,0,1},

        {1,0,0,0,0,1,0,0,0,1,0,0,0,0,1},

        {1,0,0,0,0,1,0,0,0,1,0,0,0,0,1},

        {1,0,0,0,0,1,1,0,1,1,0,0,0,0,1},

        {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},

        {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},

        {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},

        {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},

        {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}};

 

    //設定顯示影象物件

    private Image floorImage;

    private Image wallImage;

    //角色

    private Image roleImage;

 

    //角色座標

    private int x, y;

    

    //增加計步器

    private int count;

 

    //此處我們新增一組常數,用以區別左右上下按鍵的觸發,

    //之所以採用數字進行區別,原因大家都很清楚^^,數字

    //運算效率高嘛~

    private static final int LEFT = 0;

    private static final int RIGHT = 1;

    private static final int UP = 2;

    private static final int DOWN = 3;

    private Thread threadAnime;

    public MyPanel() {

        //設定初始構造時面板大小

        setPreferredSize(new Dimension(WIDTH, HEIGHT));

 

        //於初始化時載入圖形

        loadImage();

       

        //初始化角色所在位置,由於本例行列皆為15,估xy的極限數值也皆為15

        //即由15x15的方格影象,組成了角色的可見活動區域。

        x = 8;

        y = 8;

 

        //在面板構建時賦予計步器初值

        count = 0;

       

        //設定焦點在本窗體並付與監聽物件

        setFocusable(true);

        addKeyListener(this);

       

        //例項化內部執行緒AnimationThread

        threadAnime = new Thread(new AnimationThread());

        //啟動執行緒

        threadAnime.start();

    }

 

    //描繪窗體,此處在預設JPanel基礎上構建底層地圖.

    public void paintComponent(Graphics g) {

        super.paintComponent(g);

 

        //畫出地圖

        drawMap(g);

       

        //畫出人物

        drawRole(g);

    }

 

    /**

     * 載入影象

     *

     */

    private void loadImage() {

        //獲得當前類對應的相對位置image資料夾下的地板影象

       

        ImageIcon icon = new ImageIcon(getClass().getResource("image/floor.gif"));

        //將地板影象例項付與floorImage

        floorImage = icon.getImage();

        //獲得當前類對應的相對位置image資料夾下的牆體影象

        icon = new ImageIcon(getClass().getResource("image/wall.gif"));

        //將牆體影象例項付與wallImage

        wallImage = icon.getImage();

       

        icon = new ImageIcon(getClass().getResource("image/hero.gif"));

        roleImage = icon.getImage();

    }

   

   

    /**

     * 繪製角色

     */

    private void drawRole(Graphics g) {

        //count作為影象的偏移數值

        g.drawImage(roleImage, x*CS, y*CS, x*CS+CS, y*CS+CS,

                count*CS, 0, CS+count*CS, CS, this);

    }

   

    private void drawMap(Graphics g) {

        //Java或任何遊戲開發中,演算法都是最重要的一步,本例盡使用

        //簡單的雙層for迴圈進行地圖描繪,

        for (int x = 0; x < ROW; x++) {

            for (int j = 0; j < COL; j++) {

               

                // switch作為java中的轉換器,用於執行和()中數值相等

                // case操作。請注意,在case操作中如果不以break退出

                // 執行;switch函式將持續運算到最後一個case為止。

                switch (map[x][j]) {

                   

                    case 0 : //map的標記為0時畫出地板

                        //在指定位置[描繪]出我們所載入的圖形,以下同

                        g.drawImage(floorImage, j * CS, x * CS, this);

                        break;

              

                    case 1 : //map的標記為1時畫出城牆

                        g.drawImage(wallImage, j * CS, x * CS, this);

                        break;

                     //我們可以依次類推出無數的背景組合,如定義椅子為2、寶座為3

                     //很容易即可勾勒出一張背景地圖。  

              

                    default: //當所有case值皆不匹配時,將執行此操作。

                        break;

                }

  

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述