Java實(shí)現(xiàn)泡泡堂對戰(zhàn)版游戲的示例代碼
前言
《泡泡堂II》是一個基于java的自制游戲,使用了MVC模式,分離了模型、視圖和控制器,使得項目結(jié)構(gòu)清晰易于擴(kuò)展,使用配置文件來設(shè)置游戲基本配置,擴(kuò)展地圖人物道具等。同時,該程序編寫期間用了單例模式、工廠模式、模板模式等設(shè)計模式。為了游戲的可玩性,特意設(shè)計了平滑碰撞以及機(jī)器人。
主要設(shè)計
- 設(shè)計游戲界面,用swing實(shí)現(xiàn)
- 繪制游戲啟動界面、結(jié)束界面、地圖、主角、道具
- 實(shí)現(xiàn)泡泡爆炸
- 為了盡量復(fù)原泡泡堂游戲,初步實(shí)現(xiàn)了機(jī)器人功能。該機(jī)器人可以判斷障礙物釋放炸彈、規(guī)避炸彈、攻擊玩家。
- 實(shí)現(xiàn)道具掉落和相應(yīng)屬性加成
- 實(shí)現(xiàn)游戲音效和背景音樂
- 平滑碰撞:人物在拐角處移動的時候經(jīng)常不是剛好對齊的狀態(tài),程序會判定玩家碰撞了障礙物所以導(dǎo)致玩家無法拐彎。所以我們在處理這種情況的時候,會讓玩家進(jìn)行平滑的移動使得玩家看上去是滑進(jìn)去的,增強(qiáng)玩家游戲體驗
- 設(shè)計單/雙人模式
功能截圖
游戲啟動界面:

道具說明:

游戲開始:

釋放炸彈·:

炸彈爆炸效果:

代碼實(shí)現(xiàn)
游戲啟動類
public class GameStart {
private static GameFrame gameFrame;
//游戲啟動入口
public static void main(String[] args) {
// 資源加載
try {
ElementLoader.getElementLoader().readGamePro();
ElementLoader.getElementLoader().readImagePro();
ElementLoader.getElementLoader().readCharactorsPro();
ElementLoader.getElementLoader().readBubblePro();
ElementLoader.getElementLoader().readSquarePro();
} catch (IOException e) {
System.out.println("資源加載失敗");
e.printStackTrace();
}
//初始化
gameFrame = new GameFrame();
//界面顯示
gameFrame.setVisible(true);
//音樂播放
GameMusicPlayer musicPlayer = new GameMusicPlayer();
musicPlayer.start();
}
/**
* 界面切換
* @param panelName 界面名稱
*/
public static void changeJPanel(String panelName){
if(panelName == "game") {
GameController.setGameRunning(true);
gameFrame.addListener();
} else {
GameController.setGameRunning(false);
gameFrame.removeListener();
}
gameFrame.changePanel(panelName);
//強(qiáng)制刷新,否則監(jiān)聽無效
gameFrame.setVisible(false);
gameFrame.setVisible(true);
}
public static void startNewGame() {
GameController.setGameRunning(true);
gameFrame.startGame();
changeJPanel("game");
}
}核心監(jiān)聽類
public class GameThread extends Thread{
private boolean running; //表示當(dāng)前關(guān)卡是否在進(jìn)行
private boolean over = false; //表示游戲是否結(jié)束,結(jié)束返回開始菜單
private static int sleepTime = 20; //runGame刷新時間
//倒計時變量
private static int allTime = 600*1000; //10分鐘
@Override
public void run() {
while(!over) {
running = true;//當(dāng)前關(guān)卡正在進(jìn)行
//加載元素
loadElement();
//顯示人物,流程,自動化
runGame();
//結(jié)束當(dāng)前關(guān)
overGame(over);
}
GameStart.changeJPanel("over");
}
//加載元素
private void loadElement() {
ElementManager.getManager().loadMap();//加載地圖及其元素
}
/**
* 關(guān)卡結(jié)束
* 如果over為真則游戲失敗返回界面,否則進(jìn)入下一關(guān)
* @param over
*/
private void overGame(Boolean over) {
ElementManager.getManager().overGame(over);
}
//顯示人物,游戲流程,自動化
private void runGame() {
allTime = 600*1000;
while(running) {
Map<String, List<SuperElement>> map = ElementManager.getManager().getMap();
Set<String> set = map.keySet();
for(String key:set) {
List<SuperElement> list = map.get(key);
for(int i=list.size()-1; i>=0; i--) {
list.get(i).update();
if(!list.get(i).isAlive())
list.remove(i);
}
}
//添加游戲的流程控制linkGame()?
//玩家與炸彈碰撞死亡
playerBoom();
//可破壞物與炸彈碰撞
fragilityBoom();
//電腦與炸彈碰撞死亡
npcBoom();
//電腦與道具碰撞效果,暫時不開啟
//npcMagicBox();
//玩家與道具碰撞效果
playerMagicBox();
//檢測是否玩家全部死亡
defeat();
//控制runGame進(jìn)程
allTime = allTime - sleepTime;
try {
sleep(20);
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
private void defeat() {
boolean allDead = true;
int surviveP = 0;
int winner = 2;//0為玩家1,1為玩家2,2為電腦獲勝
List<SuperElement> playerList = ElementManager.getManager().getElementList("player");
List<SuperElement> npcList = ElementManager.getManager().getElementList("npc");
for(SuperElement se:playerList) {
if(!((Player)se).isDead()) {
surviveP++;
}
}
for(SuperElement npc:npcList) {
if(!((Npc)npc).isDead()) {
allDead = false;
}
}
//玩家失敗
if(surviveP==0||(allTime<=0 && !allDead)) {
running = false;
over = true;
OverJPanel.getResult().setText("defeated");
}
//玩家勝利
if(allDead&&surviveP==1) {
running = false;
over = true;
for(SuperElement se:playerList) {
if(!((Player)se).isDead()) {
surviveP++;
winner = ((Player)se).getPlayerNum();
}
}
OverJPanel.getResult().setText("player "+(winner+1)+" win");
}
//時間到,兩個玩家都活著
if(allTime<=0&&surviveP==2&&allDead) {
running = false;
over = true;
int score1 = ((Player)playerList.get(0)).score;
int score2 = ((Player)playerList.get(0)).score;
if(score1==score2) {
OverJPanel.getResult().setText("defeated");
}
else if(score1>score2)
{
OverJPanel.getResult().setText("player 1 win");
}
else {
OverJPanel.getResult().setText("player 2 win");
}
}
}
//玩家與炸彈碰撞判斷
private void playerBoom() {
List<SuperElement> playerList = ElementManager.getManager().getElementList("player");
List<SuperElement> explodeList = ElementManager.getManager().getElementList("explode");
for(int i=0; i<playerList.size(); i++) {
for(int j=0; j<explodeList.size(); j++) {
if(explodeList.get(j).crash(playerList.get(i))){
Player player = (Player) playerList.get(i);
player.setHealthPoint(-1);//生命值-1
}
}
}
}
//npc與炸彈碰撞判斷
private void npcBoom() {
List<SuperElement> playerList = ElementManager.getManager().getElementList("player");
List<SuperElement> npcList = ElementManager.getManager().getElementList("npc");
List<SuperElement> explodeList = ElementManager.getManager().getElementList("explode");
for(int i=0; i<npcList.size(); i++) {
for(int j=0; j<explodeList.size(); j++) {
if(explodeList.get(j).crash(npcList.get(i))){
Npc npc = (Npc) npcList.get(i);
npc.setDead(true);
npc.setX(-100);
npc.setY(-100);
BubbleExplode e = (BubbleExplode)explodeList.get(j);
if(e.getPlayerNum()<2)//目前只有玩家計分
((Player)playerList.get(e.getPlayerNum())).setScore(((Player)playerList.get(e.getPlayerNum())).getScore()+50);
}
}
}
}
//障礙物與炸彈碰撞判斷
private void fragilityBoom() {
List<SuperElement> playerList = ElementManager.getManager().getElementList("player");
List<SuperElement> explodes = ElementManager.getManager().getElementList("explode");
List<SuperElement> fragility = ElementManager.getManager().getElementList("fragility");
for(int i=0; i<fragility.size(); i++) {
for(int j=0; j<explodes.size(); j++) {
if(explodes.get(j).crash(fragility.get(i))) {
MapFragility mapFragility = (MapFragility)fragility.get(i);
mapFragility.setDestoried(true);
BubbleExplode e = (BubbleExplode)explodes.get(j);
if(e.getPlayerNum()<2)//目前只有玩家計分
((Player)playerList.get(e.getPlayerNum())).setScore(((Player)playerList.get(e.getPlayerNum())).getScore()+10);
}
}
}
}
//玩家與道具碰撞判斷
private void playerMagicBox() {
List<SuperElement> playerList = ElementManager.getManager().getElementList("player");
List<SuperElement> magicBoxList = ElementManager.getManager().getElementList("magicBox");
for(int i=0; i<playerList.size(); i++) {
for(int j=magicBoxList.size()-1; j>=0; j--) {
if(magicBoxList.get(j).crash(playerList.get(i))){
MagicBox magicBox = (MagicBox) magicBoxList.get(j);
magicBox.setCharacterIndex(i);//誰吃方塊
magicBox.setEaten(true);//方塊被吃
((Player)playerList.get(i)).setScore(((Player)playerList.get(i)).getScore()+30);
}
}
}
}
//玩家與道具碰撞判斷
private void npcMagicBox() {
List<SuperElement> npcList = ElementManager.getManager().getElementList("npc");
List<SuperElement> magicBoxList = ElementManager.getManager().getElementList("magicBox");
for(int i=0; i<npcList.size(); i++) {
for(int j=magicBoxList.size()-1; j>=0; j--) {
if(magicBoxList.get(j).crash(npcList.get(i))){
MagicBox magicBox = (MagicBox) magicBoxList.get(j);
magicBox.setCharacterIndex(i+2);//誰吃方塊
magicBox.setEaten(true);//方塊被吃
}
}
}
}
//runGame調(diào)用,加入拓展
public void linkGame() {}
public static int getAllTime() {
return allTime;
}
}核心線程類
public class GameKeyListener implements KeyListener{
/**
* 用棧來解決按鍵沖突
* 每個棧用來存放不同用戶的按鍵,通過判斷按鍵的code來設(shè)置移動方向或者攻擊
*
*/
private List<?> list;
private Stack<Integer> p1PressStack = new Stack<>();
private Stack<Integer> p2PressStack = new Stack<>();
@Override
public void keyPressed(KeyEvent e) {
list = ElementManager.getManager().getElementList("player");
Player player1 = (Player) list.get(0);
int code = e.getKeyCode();
switch (code) {
case 10://炸彈鍵
if(player1.isKeepAttack())//不允許一直按著炸彈鍵,每次只能放一個炸彈
player1.setAttack(false);
else {
player1.setKeepAttack(true);
player1.setAttack(true);
}
break;
case 37://左右上下
case 38:
case 39:
case 40:
if(!p1PressStack.contains(code)) {
p1PressStack.push(code);
}
player1.setMoveType(MoveTypeEnum.codeToMoveType(code));
break;
default://其它按鍵無視
break;
}
if(GameController.isTwoPlayer()) {
Player player2 = (Player) list.get(1);
switch (code) {
case 32:
if(player2.isKeepAttack())
player2.setAttack(false);
else {
player2.setKeepAttack(true);
player2.setAttack(true);
}
break;
case 65:
case 87:
case 68:
case 83:
if(!p2PressStack.contains(code)) {
p2PressStack.push(code);
}
player2.setMoveType(MoveTypeEnum.codeToMoveType(code));
break;
default:
break;
}
}
}
@Override
public void keyReleased(KeyEvent e) {
List<?> list = ElementManager.getManager().getElementList("player");
int code = e.getKeyCode();
Player player1 = (Player) list.get(0);
if(!player1.isDead()) {
switch (code) {
case 10:
player1.setAttack(false);
player1.setKeepAttack(false);
break;
case 37:
case 38:
case 39:
case 40:
if(p1PressStack.peek()!=code) {
p1PressStack.remove(new Integer(code));
} else {
p1PressStack.pop();
if(p1PressStack.size()==0) {
player1.setMoveType(MoveTypeEnum.STOP);
} else {
player1.setMoveType(MoveTypeEnum.codeToMoveType(p1PressStack.peek()));
}
}
break;
default:
break;
}
}
if(GameController.isTwoPlayer()) {
Player player2 = (Player) list.get(1);
if(!player2.isDead()) {
switch (code) {
case 32:
player2.setAttack(false);
player2.setKeepAttack(false);
break;
case 65:
case 87:
case 68:
case 83:
if(p2PressStack.peek()!=code) {
p2PressStack.remove(new Integer(code));
} else {
p2PressStack.pop();
if(p2PressStack.size()==0) {
player2.setMoveType(MoveTypeEnum.STOP);
} else {
player2.setMoveType(MoveTypeEnum.codeToMoveType(p2PressStack.peek()));
}
}
break;
default:
break;
}
}
}
}
@Override
public void keyTyped(KeyEvent arg0) {
// TODO 自動生成的方法存根
}
public void clearKeyStatcks() {
p1PressStack.clear();
p2PressStack.clear();
}
}總結(jié)
通過此次的《泡泡堂對戰(zhàn)版》實(shí)現(xiàn),讓我對JAVA的相關(guān)知識有了進(jìn)一步的了解,對java這門語言也有了比以前更深刻的認(rèn)識。
java的一些基本語法,比如數(shù)據(jù)類型、運(yùn)算符、程序流程控制和數(shù)組等,理解更加透徹。java最核心的核心就是面向?qū)ο笏枷?,對于這一個概念,終于悟到了一些。
以上就是Java實(shí)現(xiàn)泡泡堂對戰(zhàn)版游戲的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于Java泡泡堂的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
解決Springboot配置excludePathPatterns不生效的問題
這篇文章主要介紹了解決Springboot配置excludePathPatterns不生效的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10
java實(shí)現(xiàn)隨機(jī)森林RandomForest的示例代碼
本篇文章主要介紹了java實(shí)現(xiàn)隨機(jī)森林RandomForest的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-08-08
Spring實(shí)戰(zhàn)之使用@Resource配置依賴操作示例
這篇文章主要介紹了Spring實(shí)戰(zhàn)之使用@Resource配置依賴操作,結(jié)合實(shí)例形式分析了Spring使用@Resource配置依賴具體步驟、實(shí)現(xiàn)及測試案例,需要的朋友可以參考下2019-12-12
Java中動態(tài)地改變數(shù)組長度及數(shù)組轉(zhuǎn)Map的代碼實(shí)例分享
這篇文章主要介紹了Java中動態(tài)地改變數(shù)組長度及數(shù)組轉(zhuǎn)map的代碼分享,其中轉(zhuǎn)Map利用到了java.util.Map接口,需要的朋友可以參考下2016-03-03
Java實(shí)現(xiàn)實(shí)時監(jiān)控目錄下文件變化的方法
今天小編就為大家分享一篇關(guān)于Java實(shí)現(xiàn)實(shí)時監(jiān)控目錄下文件變化的方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-03-03

