整体思想:主界面、主角鱼、被吃的鱼、气泡、声音
程序主要有7个类组成:DrawStart、Fish、EatenFish、AirBubble、Music、GetImage、MyMouseListener
DrawStart:
主界面:简单界面,用swing实现,只需要游戏图片和切换图片;内含主方法,启动游戏;创建几乎全部的属性,最重要的是创建一
个内部类线程来实现被吃的鱼
气泡的产生
在这里介绍一种获得项目图片资源的两种方法:一:得到窗体的工具包 Toolkit tool = Toolkit.getDefaultToolkit();(包 java.awt.Toolkit;)
获取图 Image image = tool.getImage(DrawStart.class.getResource("图片路径"));(包 java.awt.Image;)
二:直接获取 Image image = new ImageIcon("图片路径").getImage();
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
public class DrawStart extends JFrame{
int Gametype = 0;
public Toolkit tool = Toolkit.getDefaultToolkit();//得到窗体的工具包
Image logo = tool.getImage(DrawStart.class.getResource("logo.png"));//窗体标志
//创建缓冲图片
Image bg_img = null;
//创建线程类对象
MyThread thread = new MyThread();
//创建一个集合存放多个气泡
ArrayList<AirBubble> air_list = new ArrayList<AirBubble>();
//创建鱼类对象
private Fish fish = new Fish(this);
//创建一个集合存放多个被吃的鱼
ArrayList<EatenFish> eatenfish_list = new ArrayList<EatenFish>();
//创建背景类对象
GetImage startBg = new GetImage(this);
//创建一个音乐对象
Music music = new Music();
//显示游戏界面
public void showFrame(){
this.setTitle("大鱼吃小鱼");
this.setSize(850,710);
this.setResizable(false);
setIconImage(logo);//窗体上的标志
//设置窗体可见
this.setVisible(true);
//添加鼠标监听
MyMouseListener mouse_listener = new MyMouseListener();
this.addMouseListener(mouse_listener);
this.addMouseMotionListener(mouse_listener);
//添加键盘监听
addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent key) {
if (key.getKeyCode() == 10 && Gametype == 0) {
Gametype = 1;
music.playBgMusic();
repaint();
}
}
});
this.setDefaultCloseOperation(EXIT_ON_CLOSE);//关闭窗体
thread.start();
}
public void createFish(){
//Fish fish = new Fish(370,300);
Fish fish = new Fish(this);
}
//创建随机数对象
Random r = new Random();
//创建被吃的鱼
public void createEatenfish() {
if (r.nextInt(2) == 0) {
EatenFish cr_eatenfish = new EatenFish(this, -50, r.nextInt(705),r.nextInt(2));
eatenfish_list.add(cr_eatenfish);
}
if (r.nextInt(2) == 1) {
EatenFish cr_eatenfish = new EatenFish(this, getWidth() + 110, r.nextInt(705),r.nextInt(2));
eatenfish_list.add(cr_eatenfish);
}
}
//创建气泡
public void createAirBubble() {
music.playBubblesMusic();
AirBubble ab_air = new AirBubble(this, r.nextInt(getWidth() - 40), 705);
air_list.add(ab_air);
}
//重写paint方法
public void paint(Graphics p) {
//判断游戏是否是开始的
if (Gametype == 0) {
startBg.startBackground(p);
}
//判断游戏是否是在加载中
if (Gametype == 1) {
startBg.loadBackground(p);
for (int i = 0; i < eatenfish_list.size(); i++) {
EatenFish eatenfish = eatenfish_list.get(i);
// 画被吃的鱼
eatenfish.drawEatenfish(p);
}
for (int i = 0; i < air_list.size(); i++) {
AirBubble Dr_qipao = air_list.get(i);
//画气泡
Dr_qipao.drawAirBubble(p);
}
fish.drawFish(p);//画主角
}
}
// 创建定时器
int time = 0;
int eaten = 0;
// 内部类,不停的重绘窗体图像
private class MyThread extends Thread {
public void run() {
Fish.list.add( 1);
Fish.list.add( 2);
while (true) {
try {
Thread.sleep(50);
time++;
eaten++;
createFish();
if (Gametype == 1 && time % 25 == 0) {
createAirBubble();
time = 0;
}
if (Gametype == 1 && eaten % 10 == 0) {
createEatenfish();
eaten = 0;
}
//重绘
repaint();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args){
DrawStart ds = new DrawStart();
ds.showFrame();
}
}
AirBubble:得到气泡的图片并实现随机在界面底层生成,并创建数组来实现它的产生和消失,通过线程控制
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
public class AirBubble {
//得到窗体的工具包
Toolkit tool = Toolkit.getDefaultToolkit();
Image air = tool.getImage( AirBubble.class.getResource("qipao.png"));// 气泡图片
Image air_1 = tool.getImage( AirBubble.class.getResource("qipao.png"));//气泡图片
//设置气泡的初始坐标
int air_x = 0;
int air_y = 705;
DrawStart StartBg = null;
//通过构造方法传递窗体对象和气泡的初始位置
public AirBubble(DrawStart StartBg,int air_x,int air_y){
this.StartBg = StartBg;
this.air_x = air_x;
this.air_y = air_y;
}
//画气泡
public void drawAirBubble(Graphics g){
g.drawImage(air, air_x, air_y, StartBg);
moveBackGround();
}
//气泡的移动
public void moveBackGround(){
air_y -=5;
if(air_y <=0){
StartBg.air_list.remove(this);
air_y = 705;
}
}
}
EatenFish:得到被吃的鱼的图片,并实现随机产生和随机游动的方法,也有队列存起来,再被吃掉时可用remove方法删除,通过线
程实现(主要是随机数的运用)
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.util.Random;
public class EatenFish {
//得到窗体的工具包
public Toolkit tool = Toolkit.getDefaultToolkit();
//得到被吃的小鱼的图片
Random r = new Random();
//获取向左图片
Image smallFish_1 = tool.getImage(DrawStart.class.getResource("eatenfish_right/"+r.nextInt(3)+".gif"));
//Image bigFish_1 = tool.getImage(DrawStart.class.getResource("eatenfish_right/"+2+".gif"));
//向右游动的初始坐标
Image smallFish_2 = tool.getImage(DrawStart.class.getResource("eatenfish_left/"+r.nextInt(3)+".gif"));
//Image bigFish_2 = tool.getImage(DrawStart.class.getResource("eatenfish_right/"+2+".gif"));
//向右游动的初始坐标
int eaten_x = 0;
int eaten_y = 0;
//存储判断传过来的数 0表示向右游 反之向左
int m = 0;
DrawStart StartBg =null;
//通过构造方法传递窗体类和被吃鱼的初始坐标
public EatenFish(DrawStart StartBg,int eaten_x,int eaten_y,int m){
this.StartBg = StartBg;
if(this.m == m ){
this.eaten_x = eaten_x;
}else{
//向左游的初始坐标
this.eaten_x = 1000;
}
this.eaten_y = eaten_y;
}
public EatenFish(DrawStart StartBg){
this.StartBg = StartBg;
}
//定义定时器
int time = 0;
//定义存储随机数变量,如果随机数等于0画向右的鱼 等于1画向左的鱼
int oo = 0;
//画被吃的鱼
public void drawEatenfish(Graphics g){
if(time%(StartBg.getWidth()+100)==0){
oo = r.nextInt(5);
}
if(oo==0){
g.drawImage(smallFish_1, eaten_x, eaten_y,70,60, StartBg);
fishmove_right();
}
if(oo==1){
g.drawImage(smallFish_2, eaten_x, eaten_y, 70,60,StartBg);
fishmove_left();
}
if(oo==2){
g.drawImage(smallFish_1, eaten_x, eaten_y,70,60, StartBg);
fishmove_lu();
}
if(oo==3){
g.drawImage(smallFish_2, eaten_x, eaten_y, 70,60,StartBg);
fishmove_ru();
}
time++;
}
//画被吃的鱼的游动 右边
public void fishmove_right(){
eaten_x +=3;
if(eaten_x >= StartBg.getWidth()){
StartBg.eatenfish_list.remove(this);
eaten_x = 0;
}
}
//画被吃的鱼的游动 左边
public void fishmove_left(){
eaten_x -=3;
if(eaten_x <= -50){
StartBg.eatenfish_list.remove(this);
eaten_x = 1000;
}
}
//画左斜线
public void fishmove_lu(){
eaten_x +=2;
eaten_y +=2;
if(eaten_x >1000&&eaten_y>750){
StartBg.eatenfish_list.remove(this);
eaten_x = 0;
eaten_y = 1000;
}
}
//画右斜线
public void fishmove_ru(){
eaten_x -=2;
eaten_y +=2;
if(eaten_x <= -50&&eaten_y>1000){
StartBg.eatenfish_list.remove(this);
eaten_x = 1000;
eaten_y = 0;
}
}
//返回被吃鱼的矩形区域
public Rectangle getRectangle(){
return new Rectangle(eaten_x, eaten_y, 60,50);
}
}
Fish: 得到主角鱼的图片,并判断鱼游动的方向,能实现变大,能实现吃掉小鱼,玩家用鼠标控制的鱼
主角鱼和被吃的鱼都会返回一个和自身位置差不多大小的矩形,只要判断矩形相交就可以“吃鱼”!
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.util.ArrayList;
import java.util.List;
public class Fish {
int count = 0;//统计吃鱼的个数
static List<Integer> list = new ArrayList<Integer>() ;
Rectangle rect ;
//得到窗体的工具包
Toolkit tool = Toolkit.getDefaultToolkit();
//得到主角图片
Image fish_right = tool.getImage(Fish.class.getResource("right.png"));
Image fish_left = tool.getImage(Fish.class.getResource("left.png"));
private DrawStart StartBg = null ;
public Fish(DrawStart StartBg){
this.StartBg=StartBg;
}
static int eat_x = 400;
static int eat_y = 350;
//创建被吃鱼类对象
EatenFish eatenfish = new EatenFish(StartBg);
//画主角鱼
public void drawFish(Graphics g) {
if(count<25){
if(list.get(list.size()-2)<list.get(list.size()-1)){
g.drawImage(fish_right,eat_x-40,eat_y-35,80,70,StartBg);
}else{
g.drawImage(fish_left,eat_x-40,eat_y-35,80,70,StartBg);
}
}else{
if(list.get(list.size()-2)<list.get(list.size()-1)){
g.drawImage(fish_right,eat_x-55,eat_y-48,110,96,StartBg);
}else{
g.drawImage(fish_left,eat_x-55,eat_y-48,110,96,StartBg);
}
}
if(list.size()>4){
list.remove(0);
list.remove(1);
}
eatenFish_bye();
}
//返回主角鱼的矩形区域
public Rectangle getRectangle(){
if(count<25){
rect = new Rectangle(eat_x-35, eat_y-30, 70,60);
}else{
rect = new Rectangle(eat_x-50, eat_y-43, 100,87);
}
return rect;
}
//被吃鱼消失
public void eatenFish_bye(){
for(int i=0;i<StartBg.eatenfish_list.size();i++){
EatenFish eatenfish = StartBg.eatenfish_list.get(i);
//判断两个矩形区域是否相交
if(getRectangle().intersects(eatenfish.getRectangle()) || eatenfish.getRectangle().intersects(getRectangle())){
StartBg.eatenfish_list.remove(eatenfish);
StartBg.music.playEatMusic();
count++;
}
}
}
}
Music:游戏运行时的背景声音、气泡产生的声音、吃鱼时的声音
java一种简单的音乐播放方法:(包 java.applet.AudioClip)
AudioClip shot=Applet.newAudioClip(Music.class.getClassLoader().getResource("音乐路径"));
缺点:只能播放wav格式的音乐
import java.applet.Applet;
import java.applet.AudioClip;
public class Music{
private AudioClip shot,shot1,shot2,shot3;
public void playBgMusic(){
shot=Applet.newAudioClip(Music.class.getClassLoader().getResource("music/startMusic.wav"));
shot.loop();
}
public void playBubblesMusic(){
shot2=Applet.newAudioClip(Music.class.getClassLoader().getResource("music/bubbles.wav"));
shot2.play();
}
public void playEatMusic(){
shot1=Applet.newAudioClip(Music.class.getClassLoader().getResource("music/bite3.wav"));
shot1.play();
}
public void playMusic(){
shot3=Applet.newAudioClip(Music.class.getClassLoader().getResource("music/wave2.wav"));
shot3.play();
}
}
GetImage: 获取游戏背景图片,在DrawStart中调用
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
public class GetImage {
//得到窗体的工具包
public Toolkit tool = Toolkit.getDefaultToolkit();
//得到开始界面图片
Image start_1 = tool.getImage(GetImage.class.getResource("start_1.png"));
Image start_2 = tool.getImage(GetImage.class.getResource("start_2.png"));
Image main_bg_1 = tool.getImage(GetImage.class.getResource("mainbg.png"));
DrawStart StartBg = null;
//通过构造方法传递窗体对象
public GetImage(DrawStart StartBg){
this.StartBg = StartBg;
}
//画游戏开始时的图片
public void startBackground(Graphics g){
g.drawImage(start_1, 0, 0,StartBg.getWidth(),StartBg.getHeight(), StartBg);
}
//画加载时的背景
public void loadBackground(Graphics g){
g.drawImage(main_bg_1, 0, 0,StartBg.getWidth(),StartBg.getHeight(), StartBg);
}
}
MyMouseListener:通过将主角鱼的坐标设为静态的,然后在鼠标移动方发上实现“画直线”的方法就可以实现对主角鱼的拖动
public class MyMouseListener implements java.awt.event.MouseListener,java.awt.event.MouseMotionListener{
@SuppressWarnings("unused")
private int x1,y1,x2,y2;
// 鼠标按键在组件上单击(按下并释放)时调用。
public void mouseClicked(java.awt.event.MouseEvent e){
}
// 鼠标进入到组件上时调用。
public void mouseEntered(java.awt.event.MouseEvent e) {
}
// 鼠标离开组件时调用。
public void mouseExited(java.awt.event.MouseEvent e) {
}
//按压
public void mousePressed(java.awt.event.MouseEvent e) {
x1 = e.getX();
y1 = e.getY();
}
// 鼠标按钮在组件上释放时调用。
public void mouseReleased(java.awt.event.MouseEvent e) {
}
//鼠标按下并拖动时调用
public void mouseDragged(java.awt.event.MouseEvent e){
x2 = e.getX();
y2 = e.getY();
Fish.eat_x=x2;
Fish.eat_y=y2;
Fish.list.add(x2);
x1 = x2;
y1 = y2;
}
//鼠标光标在组件上按下并移动时调用
public void mouseMoved(java.awt.event.MouseEvent e){
}
}
游戏相关图片:
这个游戏的实现最主要的是掌握多线程的思想
实现游戏难点:气泡、被吃的鱼的随机生成和鱼的随机游动,这个关系到整个画面是否有活跃
游戏的升级及鱼的变动,改动鱼之后相应的参数都要改变
鱼游动方向的判断,由于是用的静态变量,所以用的是队列存取X坐标,取出来比较实现的效果不是很好
功能还在进一步实现过程中,希望能多收到点建议!