Java不能做游戏?快来看看这个Java版超级玛丽吧。
一、游戲基本功能
1、能夠向左向右行走(鍵盤(pán)監(jiān)聽(tīng))
2、能夠跳躍
3、能夠發(fā)射×××
4、能夠檢測(cè)和障礙物之間的碰撞
5、背景圖片的移動(dòng)
二、游戲運(yùn)行界面
三、游戲大致實(shí)現(xiàn)思路:
1.窗體
2.自己角色的添加
3.背景圖片的添加
4.背景圖片的移動(dòng)
5.人物的移動(dòng)和跳躍
6.磚頭、水管等等障礙物的添加
7.任務(wù)和障礙物的碰撞
難點(diǎn)分析:
1.人物的多鍵控制
1)給人物設(shè)定方向boolean變量:向左、向右、向上、向下
2)通過(guò)鍵盤(pán)監(jiān)聽(tīng)來(lái)修改方向的變量值
按下某個(gè)鍵的時(shí)候,我們把相應(yīng)方向改為true,釋放的時(shí)候改false
2.地圖配置
自定義文件讀取方式實(shí)現(xiàn):文件流的使用和字符串String類的方法調(diào)用
3.碰撞檢測(cè)
封裝一個(gè)Rectangle類的對(duì)象
4.×××添加
1)先定義一個(gè)容器,這個(gè)用于封裝所有的×××對(duì)象
2)按下某個(gè)鍵的時(shí)候,創(chuàng)建一個(gè)×××對(duì)象(以角色的坐標(biāo)為基準(zhǔn)初始化)
3)把×××對(duì)象添加到容器當(dāng)中
4)在paint方法中,遍歷容器,取出×××對(duì)象并進(jìn)行繪制
5)檢測(cè)×××如果超出了窗體邊界,則需要把當(dāng)前×××從容器當(dāng)中移除掉
四、程序源代碼:
代碼結(jié)構(gòu)圖:分了三個(gè)包、敵人類包、游戲界面類包、游戲地圖配置包
com.huaxin.mario包:
package com.huaxin.mario;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import com.huaxin.enery.Enery;
import com.huaxin.enery.Pipe;
import Util.Map;
public class GameFrame extends JFrame{
public Mario mario;
public Enery pipe,cion,brick;
//背景圖片
public BackgroundImage bg ;
//容器裝敵人
public ArrayList<Enery> eneryList = new ArrayList<Enery>();
//×××容器
public ArrayList<Boom> boomList = new ArrayList<Boom>();
//×××的速度
public int bspeed=0;
//畫(huà)地圖,制定規(guī)則,是1畫(huà)磚頭,是2畫(huà)金幣,是3畫(huà)水管
public int [][] map =null;
//構(gòu)造函數(shù)里面初始化背景圖片和馬里奧對(duì)象
public GameFrame() throws Exception {
mario = new Mario(this);
mario.start();
Map mp= new Map();
bg = new BackgroundImage();
//窗體重繪線程
new Thread(){
public void run(){
while(true){
//重繪窗體
repaint();
//檢查×××是否出界
checkBoom();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
map=mp.readMap();
//讀取地圖,并配置地圖
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
//讀取到的是1,畫(huà)磚頭
if(map[i][j]==1){
brick = new Pipe(j*30,i*30,30,30,new ImageIcon("image/brick.png").getImage());
eneryList.add(brick);
}
//讀到2畫(huà)金幣
if(map[i][j]==2){
cion = new Pipe(j*30,i*30,30,30,new ImageIcon("image/coin_brick.png").getImage());
eneryList.add(cion);
}
//讀到3畫(huà)水管
if(map[i][j]==3){
pipe = new Pipe(j*30,i*30,60,120,new ImageIcon("image/pipe.png").getImage());
eneryList.add(pipe);
}
}
}
//設(shè)置背景音樂(lè)
com.huaxin.music.Util.startMusic("music/bg1.wav");
}
public void initFrame(){
//設(shè)置窗體相關(guān)屬性
this.setSize(800,450);
this.setTitle("山寨版超級(jí)瑪麗");
this.setResizable(false);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(3);
this.setVisible(true);
//該窗體添加鍵盤(pán)監(jiān)聽(tīng)
KeyListener kl = new KeyListener(this);
this.addKeyListener(kl);
}
public void paint(Graphics g) {
//利用雙緩沖畫(huà)背景圖片和馬里奧
BufferedImage bi =(BufferedImage)this.createImage(this.getSize().width,this.getSize().height);
Graphics big =bi.getGraphics();
big.drawImage(bg.img, bg.x, bg.y, null);
for (int i = 0; i <eneryList.size(); i++) {
Enery e =eneryList.get(i);
big.drawImage(e.img, e.x, e.y, e.width, e.height,null);
}
//畫(huà)×××
for (int i = 0; i < boomList.size(); i++) {
Boom b =boomList.get(i);
Color c =big.getColor();
big.setColor(Color.red);
big.fillOval(b.x+=b.speed, b.y, b.width, b.width);
big.setColor(c);
}
//畫(huà)人物
big.drawImage(mario.img, mario.x, mario.y, mario.width, mario.height,null);
g.drawImage(bi,0,0,null);
}
//檢查×××是否出界,出界則從容器中移除,不移除的話,內(nèi)存會(huì)泄漏
public void checkBoom(){
for (int i = 0; i < boomList.size(); i++) {
Boom b = boomList.get(i);
if(b.x<0 || b.x>800){
boomList.remove(i);
}
}
}
}
package com.huaxin.mario;
import java.awt.Image;
import java.awt.Rectangle;
import javax.swing.ImageIcon;
import com.huaxin.enery.Enery;
//自己的角色類
public class Mario extends Thread{
public GameFrame gf;
public boolean jumpFlag=true;
//馬里奧的坐標(biāo)
public int x=0,y=358;
//馬里奧的速度
public int xspeed=5,yspeed=1;
//馬里奧的寬高
public int width=30,height=32;
//馬里奧的圖片
public Image img = new ImageIcon("image/mari1.png").getImage();
public boolean left=false,right=false,down=false,up=false;
public String Dir_Up="Up",Dir_Left="Left",Dir_Right="Right",Dir_Down="Down";
public Mario (GameFrame gf) {
this.gf=gf;
this.Gravity();
}
public void run(){
while(true){
//向左走
if(left){
//碰撞到了
if(hit(Dir_Left)){
this.xspeed=0;
}
if(this.x>=0){
this.x-=this.xspeed;
this.img=new ImageIcon("image/mari_left.gif").getImage();
}
this.xspeed=5;
}
//向右走
if(right){
if(hit(Dir_Right)){
this.xspeed=0;
}
//任人物向右移動(dòng)
if(this.x<400){
this.x+=this.xspeed;
this.img=new ImageIcon("image/mari_right.gif").getImage();
}
if(this.x>=400){
//背景向左移動(dòng)
gf.bg.x-=this.xspeed;
//障礙物項(xiàng)左移動(dòng)
for (int i = 0; i <gf.eneryList.size(); i++) {
Enery enery = gf.eneryList.get(i);
enery.x-=this.xspeed;
}
this.img=new ImageIcon("image/mari_right.gif").getImage();
}
this.xspeed=5;
}
//向上跳
if(up){
if(jumpFlag && !isGravity){
jumpFlag=false;
new Thread(){
public void run(){
jump();
jumpFlag=true;
}
}.start();
}
}
try {
this.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//向上跳的函數(shù)
public void jump(){
int jumpHeigh=0;
for (int i = 0; i < 150; i++) {
gf.mario.y-=this.yspeed;
jumpHeigh++;
if(hit(Dir_Up)){
break;
}
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int i = 0; i <jumpHeigh; i++) {
gf.mario.y+=this.yspeed;
if(hit(Dir_Down)){
this.yspeed=0;
}
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.yspeed=1;//還原速度
}
//檢測(cè)碰撞
public boolean hit(String dir){
Rectangle myrect = new Rectangle(this.x,this.y,this.width,this.height);
Rectangle rect =null;
for (int i = 0; i < gf.eneryList.size(); i++) {
Enery enery = gf.eneryList.get(i);
if(dir.equals("Left")){
rect = new Rectangle(enery.x+2,enery.y,enery.width,enery.height);
}
else if(dir.equals("Right")){
rect = new Rectangle(enery.x-2,enery.y,enery.width,enery.height);
}
else if(dir.equals("Up")){
rect = new Rectangle(enery.x,enery.y+1,enery.width,enery.height);
}else if(dir.equals("Down")){
rect = new Rectangle(enery.x,enery.y-2,enery.width,enery.height);
}
//碰撞檢測(cè)
if(myrect.intersects(rect)){
return true;
}
}
return false;
}
//檢查是否貼地
public boolean isGravity=false;
public void Gravity(){
new Thread(){
public void run(){
while(true){
try {
sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(!jumpFlag){
}
while(true){
if(!jumpFlag){
break;
}
if(hit(Dir_Down)){
break;
}
if(y>=358){
isGravity=false;
}
else{
isGravity=true;
y+=yspeed;
}
try {
sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}.start();
}
}
package com.huaxin.mario;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
//鍵盤(pán)按下監(jiān)聽(tīng)類
public class KeyListener extends KeyAdapter{
public GameFrame gf;
public boolean jumpFlag=true;
public KeyListener(GameFrame gf) {
this.gf=gf;
}
//鍵盤(pán)監(jiān)聽(tīng)
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
switch(code){
//向右走
case 39:
gf.mario.right=true;
break;
//向左走
case 37:
gf.mario.left=true;
break;
case 66:
addBoom();
break;
//向上跳
case 74:
gf.mario.up=true;
break;
}
}
//添加×××
public void addBoom() {
Boom b = new Boom(gf.mario.x,gf.mario.y+5,10);
if(gf.mario.left) b.speed=-2;
if(gf.mario.right) b.speed=2;
gf.boomList.add(b);
}
//鍵盤(pán)釋放監(jiān)聽(tīng)
public void keyReleased(KeyEvent e) {
int code=e.getKeyCode();
if(code==39){
gf.mario.right=false;
gf.mario.img=new ImageIcon("image/mari1.png").getImage();
}
if(code==37){
gf.mario.left=false;
gf.mario.img=new ImageIcon("image/mari_left1.png").getImage();
}
if(code==74){
gf.mario.up=false;
}
}
}
package com.huaxin.mario;
import java.awt.Image;
import javax.swing.ImageIcon;
public class BackgroundImage {
public int x=0,y=0;
public int ox=0,oy=0;
public Image img=new ImageIcon("image/startBack.jpg").getImage();
}
package com.huaxin.mario;
//×××類
public class Boom {
//×××的坐標(biāo),大小,速度
int x,y;
int width;
int speed=1;
public Boom(int x, int y, int width) {
super();
this.x = x;
this.y = y;
this.width = width;
}
}
主函數(shù)類,作為整個(gè)程序的入口
package com.huaxin.mario;
public class Test {
//主函數(shù),程序入口
public static void main(String[] args) throws Exception {
GameFrame gf = new GameFrame();
gf.initFrame();
}
}
com.huaxin.enery包:
package com.huaxin.enery;
import java.awt.Image;
//障礙物的抽象父類
public abstract class Enery {
public int x,y;
public int width,height;
public Image img;
public Enery(int x, int y, int width, int height,Image img) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.img=img;
}
}
package com.huaxin.enery;
import java.awt.Image;
//金幣類
public class Coin extends Enery{
public Coin(int x, int y, int width, int height, Image img) {
super(x, y, width, height, img);
}
}
package com.huaxin.enery;
import java.awt.Image;
//磚頭類
public class Brick extends Enery {
public Brick(int x, int y, int width, int height, Image img) {
super(x, y, width, height, img);
}
}
package com.huaxin.enery;
import java.awt.Image;
//水管類
public class Pipe extends Enery {
public Pipe(int x, int y, int width, int height, Image img) {
super(x, y, width, height, img);
}
}
com.huaxin.util包:
package Util;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.util.ArrayList;
//地圖配置類
public class Map {
//數(shù)據(jù)容器
public ArrayList<String> list = new ArrayList<String>();
public int [][] map=null;
public int[][] readMap() throws Exception {
// 構(gòu)造文件輸入流
FileInputStream fis = new FileInputStream("map.txt");
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
//直接讀取一行數(shù)據(jù)
String value =br.readLine();
while(value!=null){
//將讀取到的一行數(shù)據(jù)加入到容器中
list.add(value);
value =br.readLine();
}
br.close();
//得到多少行多少列
int row=list.size();
int cloum=0;
for (int i = 0; i < 1; i++) {
String str=list.get(i);
String [] values=str.split(",");
cloum=values.length;
}
map = new int [row][cloum];
//將讀到的字符創(chuàng)轉(zhuǎn)換成整數(shù),并賦值給二位數(shù)組map
for (int i = 0; i < list.size(); i++) {
String str=list.get(i);
String [] values=str.split(",");
for (int j = 0; j < values.length; j++) {
map[i][j]=Integer.parseInt(values[j]);
}
}
return map;
}
}
五、項(xiàng)目總結(jié):
這個(gè)小項(xiàng)目看起來(lái)挺簡(jiǎn)單的,其實(shí)里面也有很多功能需要仔細(xì)去思考的,以前覺(jué)得游戲人物在窗體走的時(shí)候,覺(jué)得一直是人在走,其實(shí),人物走到中間或者走到某一位置的時(shí)候,人物已經(jīng)是在原地踏步了,取而代之的是背后那張長(zhǎng)度很長(zhǎng)的背景的圖片在移動(dòng),任務(wù)的左右移動(dòng)相對(duì)而言比較簡(jiǎn)答實(shí)現(xiàn),跳躍功能就不是那么簡(jiǎn)單了,需要永達(dá)線程,跟后面障礙物碰撞檢測(cè)又有關(guān)系,當(dāng)沒(méi)有碰到的時(shí)候,人物要往下掉,一不注意就會(huì)出現(xiàn)各種bug,比如,可以一直跳,在跳的同時(shí)還能再跳,還有就是下降可能不會(huì)落地面的同一高度,可能會(huì)高于地面的高度,可能會(huì)低于地面的高度;障礙物的添加,我們是通過(guò)配置地圖的方式,配置地圖有時(shí)通過(guò)讀入文件的操作,大致的原理是將后面的那張的背景圖片劃分成很多的小格子,將這些小格子用代碼轉(zhuǎn)換為二位數(shù)組,二維數(shù)組可以存入不同數(shù)字,代表不同的障礙物,通過(guò)操作文件就可以輕易配置地圖;首先通過(guò)文件輸入流將文件數(shù)據(jù)讀入,將字符轉(zhuǎn)換為數(shù)字,并存儲(chǔ)在二維數(shù)組中,后面,通過(guò)遍歷二維數(shù)組的不同位置的值,在相應(yīng)的格子填充相應(yīng)的障礙物;地圖就這樣配置好了;
覺(jué)得配地圖很炫酷,因?yàn)橐郧坝形粚W(xué)長(zhǎng)在演示的時(shí)候,覺(jué)得好難,現(xiàn)在自己掌握了覺(jué)得也不是很難了,當(dāng)然了,這里離不開(kāi)老師的指導(dǎo);碰撞檢測(cè)類似之前小球的碰撞檢測(cè),這里主要需要處理碰撞之后的一些邏輯,如何避免一直碰撞(人物貼著障礙物不能動(dòng))等;發(fā)射×××的話,也比較簡(jiǎn)單了,利用容器裝×××,不過(guò)需要注意的是要及時(shí)將容器中×××移除,不然內(nèi)存會(huì)很快被吃完的;
寫(xiě)程序,一定要按照思路一步一步來(lái),一點(diǎn)一點(diǎn)來(lái)實(shí)現(xiàn)!不要太過(guò)急于求成!
品略圖書(shū)館 http://www.pinlue.com/
轉(zhuǎn)載于:https://blog.51cto.com/14325182/2407278
總結(jié)
以上是生活随笔為你收集整理的Java不能做游戏?快来看看这个Java版超级玛丽吧。的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 邮箱服务器错误550,发送邮件常见的错误
- 下一篇: Java根据中国姓氏的拼音的首字母进行数