?? mypanel.java
字號:
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 long serialVersionUID = 1L;
//窗體的寬與高
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兩個軸組成的,X與Y的交織點,即為
//一條數據。
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,估x與y的極限數值也皆為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;
}
}
}
}
public void keyPressed(KeyEvent e) {
//獲得按鍵編號
int keyCode = e.getKeyCode();
//通過轉換器匹配事件
switch (keyCode) {
//當觸發Left時
case KeyEvent.VK_LEFT :
//進行left操作,僅符合move()中[規范]時執行,以下相同
move(LEFT);
break;
//當觸發Right時
case KeyEvent.VK_RIGHT :
move(RIGHT);
break;
//當觸發Up時
case KeyEvent.VK_UP :
move(UP);
break;
//當觸發Down時
case KeyEvent.VK_DOWN :
move(DOWN);
break;
}
// 重新繪制窗體圖像
// PS:在此例程中,僅進行了角色的簡單移動處理
// ,關于避免閃爍及限制活動區域問題,請見后續
// 案例。
repaint();
}
/**
* 用于判定是否允許移動的發生,被move()函數調用
* @param x
* @param y
* @return
*/
private boolean isAllow(int x, int y) {
// 以(x,y)交點進行數據判定,我們都知道,
// 在本例中我僅以0作為地板的參數,1作為
// 墻的參數,由于我們的主角是[人類],而
// 不是[幽靈],所以當他要[撞墻]時,我們
// 當然不會允許,至少,是我講到劇情的觸發
// 以前……
if (map[y][x] == 1) {
// 不允許移動時,返回[假]
return false;
}
// 允許移動時時,返回[真]
return true;
}
/**
* 判斷移動事件,關聯isAllow()函數
* @param event
*/
private void move(int event) {
//以轉換器判斷相關事件,僅執行符合[規范]的操作。
switch (event) {
case LEFT:
//依次判定事件
if (isAllow(x-1, y)) x--;
break;
case RIGHT:
if (isAllow(x+1, y)) x++;
break;
case UP:
if (isAllow(x, y-1)) y--;
break;
case DOWN:
if (isAllow(x, y+1)) y++;
break;
default:
break;
}
}
/**
* 暫無釋放鍵盤事件
*/
public void keyReleased(KeyEvent e) {
}
/**
* 暫無字符輸入事件
*/
public void keyTyped(KeyEvent e) {
}
//內部類,用于處理計步動作。
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();
}
}
}
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -