最近在學習Java,看了First learning Java,以及Java從入門到精通,大致對於Java的語法規則有個大致的瞭解,可是對於寫程序,還是far far from,怎麼辦了,上網看看別人的代碼唄,於是就找了一個喫豆豆的程序,很是不錯,註釋多,而且代碼寫的也不是很晦澀,於是就有種衝動學習的衝動。
大部分的代碼還是他的,只是我改了其中的一些東西而已,還有,我的程序需要後期做的還有很多,
我打算下一步做的就是,當大魚碰到魚池邊緣的時候減分,或者讓小魚也可以進行移動,大家可以看看我的代碼的運行結果,不怎樣,但是可以跑
界面做的有點挫,我也懶得再調了,等着下一步一起來改動吧
下面看看我的代碼
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.Random;
import javax.swing.*;
import javax.swing.border.LineBorder;
import javax.swing.border.MatteBorder;
import javax.swing.border.TitledBorder;
/*
* 這個程序修改自網上的喫豆豆的程序,很多都是借鑑這個程序
* 思想就是隨機生成一個小豆豆的原點,以及一條小魚,移動小魚可以將豆喫掉,隨之
* 邊上會顯示你的成績以及喫豆的個數,在程序中用小魚所包含的值來顯示這個數量
* 每吃了N個豆的時候,會提高小魚的移動速度
* 可以判斷小魚是否是移動到邊界了
* 這裏面有個難點就睡如何判定小魚可以或者不可以喫到小豆
* 這個是通過數學中的Math.pow函數來實現的
*/
public class BigMouseFish extends JFrame
{
/**
* 遊戲的主界面已經搭建出來了
*/
private static final long serialVersionUID = 1L;//Java的序列化機制是通過在運行時判斷類的serialVersionUID來驗證版本一致性的。
/**
* @param args
* 首先來構建遊戲中的主界面,所有的組件都是搭建在JPanel上面,顯示的組件
* 基本上是用的都是Jlabel這個控件
*/
private FishPool pool = null;
//主窗口的大小
public static int width = 800;
public static int height = 600;
private JLabel label_infor = new JLabel("歡迎來到我的世界!");
private JLabel label_size = new JLabel("\t大 小 :");
private JLabel label_score = new JLabel("\t得 分 :");
private JLabel label_speed = new JLabel("\t速 度 :");
//默認設置,魚的大小速度和得分
public static JLabel size = new JLabel("50");
public static JLabel score = new JLabel("0");
public static JLabel speed = new JLabel("5");
//可以多行文字顯示框
private JTextArea textinfo = new JTextArea();
//構造函數
public BigMouseFish()
{
pool = new FishPool();
/*
* 使得主界面顯示出陽浮雕的效果
*/
//pool.setBorder(new EtchedBorder(EtchedBorder.RAISED));
/*
* 使得主界面顯示出陰浮雕的效果
*/
//pool.setBorder(new EtchedBorder(EtchedBorder.LOWERED));
/*
* 使得主界面顯示出綠色邊框的特點
*/
pool.setBorder(new MatteBorder(5,5,30,30,Color.GREEN));
setTitle("bedlamite的第一個大魚喫小魚的遊戲!!");
setSize(width+180,height+50);
/*
* 這個函數可以實現遊戲框架的大小的變化,直接進行鼠標邊緣拖動就可以
*/
setResizable(true);
/*
* 此類是所有 Abstract Window Toolkit 實際實現的抽象超類。Toolkit 的子類被用於將各種組件綁定到特定本機工具包實現。
*/
Toolkit tk = Toolkit.getDefaultToolkit();//拿到默認工具包
setLocation((tk.getScreenSize().width-getSize().width)/2,tk.getScreenSize().height-getSize().height/2);
/*
* 遊戲的標題位置和大小
*/
label_infor.setSize(150,20);
label_infor.setLocation(width+25,240);
/*
* 遊戲的開發者說明和使用說明書
*/
String info_devp = "大魚喫小魚的遊戲,就是使用方向鍵上下左右來控制小魚移動的方向" +
"每喫小魚一條,得分加10,每喫十條小魚,大魚將打怪升級,大小加1,速度將加5.\n\n" +
"開發者:bedlamite\n" +
"時間:2014年7月\n" +
"地點:徐州\n";
textinfo.append(info_devp);
textinfo.setBackground(getBackground());
textinfo.setEditable(false);//文本框不可編輯
textinfo.setLineWrap(true);//文本顯示可以自動適應文本框的大小
textinfo.setSize(150,240);
textinfo.setLocation(width+15,370);
textinfo.setBorder(new TitledBorder(new LineBorder(Color.BLUE),"遊戲介紹!!"));
JPanel pan = new JPanel();
pan.setSize(150,100);
pan.setLocation(width+15,265);
pan.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
pan.setBorder(new TitledBorder(new LineBorder(Color.BLUE),"遊戲積分!!"));
pan.add(label_size);
pan.add(size);
pan.add(label_speed);
pan.add(speed);
pan.add(label_score);
pan.add(score);
setLayout(null);
add(pool);
this.add(label_infor);
this.add(pan);
this.add(textinfo);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new BigMouseFish();
}
}
/*
* 遊戲的主界面已經出來了,剩下的就是把大魚和小魚的類寫出來了
* 下面這個類就是搭建大魚的框架
*/
class BigFish implements ActionListener
{
/*
* 很多同學和我一樣不知道ActionListener有啥用,其實我現在也不知道
* 百度了一下,oh,yeah,依然不知道
* ActionListener用於接收操作事件的偵聽器接口。
* 對處理操作事件感興趣的類可以實現此接口,
* 而使用該類創建的對象可使用組件的
* addActionListener 方法向該組件註冊。
* 在發生操作事件時,調用該對象的 actionPerformed 方法。
*/
/*
* 大魚的移動的方向,通過上下左右來移動
*/
public static int up = 0;
public static int right = 1;
public static int down = 2;
public static int left = 3;
/*
* 大魚的大小,通過圓來繪製,半徑爲size
*/
public int size = 50;
//大魚現在的方向,默認爲朝向左
public int direction = left;
//大魚的顏色,默認是黑色
private Color color = Color.BLACK;
//大魚現在的位置,在X軸的座標
public int posx = 80;
//大魚現在的位置,在Y軸的座標
public int posy = 80;
//大魚現在的速度
public int speed = 5;
//大魚眼睛的大小
private int eyesize = size/7;
//大魚眼睛的位置,在X軸的座標
private int eyesposx = posx + size/2;
//大魚眼睛的位置,在Y軸的座標
private int eyesposy = posy + size/4;
//大魚眼睛的顏色,默認是紅色
private Color eyecolor = Color.RED;
//大魚的嘴可以最大張開的角度(正向)
private int maxmouse = 30;
//大魚現在嘴的角度
private int mousesize = 30;
//大魚現在的嘴是否張開
private boolean isopen = true;
/*
* 在應用開發中,經常需要一些週期性的操作,比如每5分鐘執行某一操作等。
* 對於這樣的操作最方便、高效的實現方式就是使用java.util.Timer工具類。
*/
private Timer time = null;
/*
* 大魚的默認構造函數
*/
public BigFish()
{
this(80,80,50,left,Color.BLACK,5);
}
public BigFish(int posx, int posy, int size, int direction, Color color, int speed)
{
// TODO Auto-generated constructor stub
this.posx = posx;
this.posy = posy;
this.size = size;
//方向只有四個
if(direction == 0||direction == 1||direction == 2||direction == 3)
this.direction = direction;
this.color = color;
this.speed = speed;
eyesize = size/7;
initeye();
time = new Timer(FishPool.retime,this);
time.start();
}
/*
* 大魚的移動
*/
public void move()
{
switch (direction) {
case 0:
posy--;
break;
case 1:
posx++;
break;
case 2:
posy++;
break;
case 3:
posx--;
break;
default:
break;
}
}
public void change_direction(int direction)
{
this.direction = direction;
}
/*
* 開始繪製大魚的身體
*/
public void paint_bigfish(Graphics g)
{
//Graphics這個是抽象類,它的對象是用來傳給paint()方法作爲畫筆的
//畫筆的顏色
Color c = g.getColor();
/*
* 繪製大魚的輪廓
* 從默認的大魚位置開始繪製大魚
*/
g.fillArc(posx, posy, size, size, (direction%2==0?(direction+1):(direction-1))*90+mousesize, 360-2*mousesize);//沒整明白
//繪製大魚的眼睛
initeye();
g.setColor(eyecolor);
g.fillOval(eyesposx, eyesposy, eyesize, eyesize);
//恢復畫筆的顏色
g.setColor(c);
}
/*
* (non-Javadoc)
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
* 用於接收操作事件的偵聽器接口。對處理操作事件感興趣的類可以實現此接口,
* 而使用該類創建的對象可使用組件的 addActionListener
* 方法向該組件註冊。在發生操作事件時,調用該對象的 actionPerformed 方法。
* 這個ActionListener接口中只有一個方法
* 雖然這個方法貌似看起來在整個工程中沒有被調用,可是在ActionListener這個接口中有,
* 必須被實現,實現了
*/
public void actionPerformed(ActionEvent e)
{
if(isopen)
{
mousesize -= 2;
if(mousesize<=0)
{
isopen = false;
}
}
else
{
mousesize += 2;
if(mousesize>=maxmouse)
{
isopen = true;
}
}
}
/*初始化魚眼睛,當方向變化了,魚的眼睛必然會變化
* 這個座標軸爲什麼會這個樣子變化大家自己拿筆慢慢的研究吧
*/
private void initeye()
{
switch (direction) {
case 0:
eyesposx = posx + size/7;
eyesposy = posy +size/2 - eyesize;
break;
case 1:
eyesposx = posx + size/2;
eyesposy = posy +size/7;
break;
case 2:
eyesposx = posx + size*5/7;
eyesposy = posy +size/2;
break;
case 3:
eyesposx = posx + size/2 - eyesize;
eyesposy = posy +size/7;
break;
default:
break;
}
}
/*
* 大魚的類已經寫完了,很顯然下一步需要寫小魚的類,也就是豆豆的類
*/
}
class LittlerFish implements ActionListener
{
//小魚的位置(X座標)
public int posx = 200;
//小魚的位置(Y座標)
public int posy = 200;
//小魚的大小
public int size = 20;
//小魚的顏色
public Color color = Color.BLUE;
/*
* 如果超過一段時間大魚還沒有把小魚喫掉的話,那麼小魚就會自動閃爍
* 固定時間然後消失,之後重新再新的位置上出現小魚
*/
public static int flicktime = 300;
/*
* 小魚每次閃爍的次數,默認是10次
*/
public static int flicknum = 10;
private int hasfilcknum = 0;
/*
* 小魚的的閃爍定時器
*/
private Timer timer = null;
/*
* 小魚的構造函數
*/
public LittlerFish()
{
this(200,200,20,Color.BLUE);
}
public LittlerFish(int posx, int posy, int size, Color color)
{
// TODO Auto-generated constructor stub
this.posx = posx;
this.posy = posy;
this.size = size;
this.color = color;
timer = new Timer(flicktime,this);
}
/*
* 小魚的新位置
*/
public void newPos(int posx,int posy)
{
this.posx = posx;
this.posy = posy;
}
/*
*繪製小魚的函數
*/
public void paint(Graphics g)
{
Color c = g.getColor();
g.setColor(color);
g.fillOval(posx, posy, size, size);
g.setColor(c);
}
/*
* 計時器停止函數
*/
public void stopTimer()
{
timer.stop();//計時器停止
hasfilcknum = 0;//計數器重置
}
/*
* 重新繪製小魚之後,開始重啓計時器
*/
public void runTimer()
{
timer.start();
}
/*
* (non-Javadoc)
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
hasfilcknum++;
if(hasfilcknum == flicknum && timer.isRunning())
{
stopTimer();
}
}
/*
* 判定定時器是否運行
*/
public boolean timerIsRunning()
{
return timer.isRunning();
}
}
/*
* 這個類需要做的就是判斷大魚到底抓到小魚沒有
* 通過判定這兩個圓之間的距離來判定兩個小魚有沒有相交或者相切
* 只要滿足其中任何一個條件的話,就判定小魚被大魚喫掉
*/
class collision_detect
{
/*
* 小魚是否被大魚喫掉的判定條件是:
* 2個圓心之間的距離小於兩個圓的半徑和就可以
* 它的判定方法比較詭異,我捉摸了比較長的時間,數學功底有點噁心
* @param bigfish
* @param littlefish
* @return 小魚是否被大魚喫掉
*/
public static boolean isCollision(BigFish bigfish,LittlerFish littlerfish)
{
/*
* 下面註釋的語句是看打印輸出的,也就是判定碰撞時候的座標值
System.out.println("the bean.posx is: "+bean.posx);
System.out.println("the bean.posy is: "+bean.posy);
System.out.println("the bean.size is: "+bean.size);
System.out.println("the fish.posx is: "+fish.posx);
System.out.println("the fish.posy is: "+fish.posy);
System.out.println("the fish.size is: "+fish.size);
System.out.println("the fish.size/2 is: "+fish.size/2);
System.out.println("fish.posx+fish.size/2-bean.posx-bean.size/2,2||"+Math.pow(fish.posx+fish.size/2-bean.posx-bean.size/2,2));
System.out.println("fish.posy+fish.size/2-bean.posy-bean.size/2,2||"+Math.pow(fish.posy+fish.size/2-bean.posy-bean.size/2,2));
System.out.println("fish.size/2,2||"+Math.pow(fish.size/2,2));
System.out.println("the result of judgment is: "+(Math.pow(fish.posx+fish.size/2-bean.posx-bean.size/2,2)
*/
return Math.pow(bigfish.posx+bigfish.size/2-littlerfish.posx-littlerfish.size/2, 2)
+Math.pow(bigfish.posy+bigfish.size/2-littlerfish.posy-littlerfish.size/2, 2)
<=Math.pow(bigfish.size/2, 2);
}
}
/*
* 大魚和小魚的繪製程序都寫完了
* 兩個魚的碰撞程序也寫完了
* 下面需要考慮的是,每次小魚出現的位置
* 因爲小魚是隨機出現的,所以需要寫一個小魚出現的隨機函數類
*/
class random_occu
{
/*
* 這個我自己嘗試了很多次隨機函數,無論怎樣,都會出現死角的情況
* 死角的情況就是小魚出現在魚池的邊角上,大魚的和它永遠都沒有交點
* 這樣永遠都不能被喫掉
*/
public static int random_number(int a,int b)
{
//這個函數我完全沒搞明白爲什麼這麼寫
int t,n = 0;
if(a>b)
{
t = a;
a = b;
b = t;
}
t = (int)(Math.ceil(Math.log10(b)));
while(true)
{
n = (int)(Math.random()*Math.pow(10,t));
if(n>=a&&n<=b)
break;
}
return n;
}
public static int random_number(int a)
{
return new Random().nextInt();
}
}
/*
*
* 所有的零部件都已經寫完了
* 剩下的就是把這個函數組件放到魚池中
* 下面就是構造魚池
*/
class FishPool extends JLabel
{
/**
*
*/
private static final long serialVersionUID = 1L;
private BigFish bigfish = null;
private LittlerFish littlerfish = null;
/*
* 控制messagebox中的輸出的內容格式,文字的大小和字體
*/
Font font;
//小魚存在的時間
private int timelength = 20*1000;
static int retime = 100;
//魚池重回定時器
private Timer timer = null;
//小魚生成的定時器
private Timer time = null;
private int sizeAdd = 5;
private int speedAdd = 2;
private int scoreAdd = 1;
//大魚現在的分數、速度、喫魚的數量
private int score = 0;
private int upgradeNumber = 10;
private int eatnumber = 0;
//大魚規定的邊界
private int max_x = 0;
private int max_y = 0;
private int min_x = 0;
private int min_y = 0;
public FishPool()
{
setSize(BigMouseFish.width,BigMouseFish.height);
setLocation(10,10);
bigfish = new BigFish();
initLittlerfish();
min_x = 3;
max_x = BigMouseFish.width-bigfish.size-3;
min_y = 3;
max_y = BigMouseFish.height-bigfish.size-3;
//註冊一下控制鍵,也就是鍵盤上的上下左右鍵
//向上鍵
getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP,0),"Up");
getActionMap().put("Up", new UplistenerImpl());
//向右鍵
getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,0),"Right");
getActionMap().put("Right",new RightlistenerImpl());
//向下鍵
getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN,0), "Down");
getActionMap().put("Down", new DownlistenerImpl());
//向左鍵
getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT,0), "Left");
getActionMap().put("Left", new LeftlistenerImpl());
timer = new Timer(retime, new TimerListennerImpl());
timer.start();
time = new Timer(timelength-littlerfish.flicktime*littlerfish.flicknum, new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
// TODO Auto-generated method stub
time.stop();
littlerfish.runTimer();
new Thread()
{
public void run()
{
while(true)
{
if(!littlerfish.timerIsRunning())
{
littlerfishNewPos();
timer.restart();
break;
}
}
}
}.start();
}
});
time.start();
}
//初始化小魚
private void initLittlerfish()
{
int size = 20;
int posx = 0;
int posy = 0;
do{
posx = random_occu.random_number(BigMouseFish.width-size);
posy = random_occu.random_number(BigMouseFish.height-size);
}while(posx>=bigfish.posx && posx<=bigfish.posx+bigfish.size && posy>=bigfish.posy && posy<=bigfish.posy+bigfish.size &&
posx+size>=bigfish.posx && posx+size<=bigfish.posx+bigfish.size && posy+size>=bigfish.posy && posy+size<=bigfish.posy+bigfish.size);
littlerfish = new LittlerFish( posx, posy, size,Color.YELLOW);
}
/**
* 小魚重新生成新位置。
* 保證小魚生成的位置與大嘴魚的位置不重疊。
*/
public int size = 15;
public int litterfish_posx = 0;
public int littlerfish_posy = 0;
private void littlerfishNewPos(){
do{
litterfish_posx = random_occu.random_number(2*size, BigMouseFish.width-2*size);
littlerfish_posy = random_occu.random_number(2*size,BigMouseFish.height-2*size);
}while (litterfish_posx>=bigfish.posx && litterfish_posx<=bigfish.posx+bigfish.size && littlerfish_posy>=bigfish.posy && littlerfish_posy<=bigfish.posy+bigfish.size &&
litterfish_posx+size>=bigfish.posx && litterfish_posx+size<=bigfish.posx+bigfish.size && littlerfish_posy+size>=bigfish.posy && littlerfish_posy+size<=bigfish.posy+bigfish.size);
littlerfish.newPos(litterfish_posx, littlerfish_posy);
/*System.out.println("the bean.posx is: "+bean_posx);
System.out.println("the bean.posx is: "+posy);*/
}
public void paint(Graphics g)
{
super.paint(g);
bigfish.paint_bigfish(g);
littlerfish.paint(g);
}
private void bigfishMove(int direction){
int i;
while(true)
{
for(i=0;i<bigfish.speed;i++){
bigfish.change_direction(direction);
//大嘴魚到池邊,不可在移動
switch(direction){
case 0:
if(bigfish.posy>=min_y+1)
if(istouched()) break;
break;
case 1:
if(bigfish.posx<=max_x-1)
if(istouched()) break;
break;
case 2:
if(bigfish.posy<=max_y-1)
if(istouched()) break;
break;
case 3:
if(bigfish.posx>=min_x+1)
if(istouched()) break;
break;
}
}
if(i==bigfish.speed)
break;
}
}
private boolean istouched()
{
font = new Font("宋體",0,22);
bigfish.move();
boolean b = collision_detect.isCollision(bigfish, littlerfish);
if(b)
{
//碰撞了,大魚就需要升級
eatnumber++;
score += scoreAdd;
BigMouseFish.score.setText(score+"");
if(eatnumber==upgradeNumber)
{
eatnumber = 0;
bigfish.size += sizeAdd;
bigfish.speed += speedAdd;
BigMouseFish.size.setText(bigfish.size+"");
BigMouseFish.speed.setText(bigfish.speed+"");
//下面的這段代碼是發現遊戲bug後增加的代碼
//bug:如果大嘴魚在魚池邊界處恰好升級,將使魚出界。
if(bigfish.posx==max_x || bigfish.posy==max_y){
bigfish.posx -= sizeAdd;
bigfish.posy -= sizeAdd;
}
}
//下面的這段代碼是發現遊戲bug後增加的代碼。
//bug:如果大嘴魚在小魚閃爍時喫到小魚。小魚將觸發新位置,而又將使小魚繼續閃爍。
//停止小魚閃爍的定時器,更改顏色爲原來的顏色。已經閃爍次數爲0。
if(littlerfish.timerIsRunning()){
littlerfish.stopTimer();
}
littlerfishNewPos();
time.restart();
//////////////////////////////////////////////////////////////加上的爲了使得顯示更加明顯,無任何意義
font = new Font("宋體",0,42);
UIManager.put("Button.font",font);
UIManager.put("Label.font",font);
ImageIcon img = new ImageIcon("D:\\2.jpg");
JOptionPane.showMessageDialog( null , "Big Dark " ,"國棟-王" , JOptionPane.INFORMATION_MESSAGE,img) ;
//JOptionPane.showMessageDialog( null , "Big Dark " ,"國棟-王" , JOptionPane.INFORMATION_MESSAGE) ;
//JOptionPane.s
///////////////////////////////////////////////////////////////
}
return b;
}
///////////////////////////////////////////////////////////////////////////////////////////
//向上的按鈕事件
private class UplistenerImpl extends AbstractAction
{
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
bigfishMove(0);
}
}
//向右按鈕事件
private class RightlistenerImpl extends AbstractAction
{
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
bigfishMove(1);
}
}
//向下的按鈕事件
private class DownlistenerImpl extends AbstractAction
{
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
bigfishMove(2);
}
}
//向左的按鈕事件
private class LeftlistenerImpl extends AbstractAction
{
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
bigfishMove(3);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
private class TimerListennerImpl implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
repaint();
}
}
}
自認爲代碼的註釋已經相當的詳細了,但是中間有兩個代碼段沒有看懂,沒法跟大家分享我的註釋了,如果有大神的話,可以幫我補充一下