1.EatFish游戏开发过程
1. 游戏窗口创建
2. 添加背景图片
3. 启动封面
4. 启动页面的点击事件
5. 游戏开始的背景添加
6. 双缓存解决闪屏问题
7. 敌方鱼类的生成
8. 我方鱼的生成
9. 我方鱼和敌方鱼的碰撞检测
10. 游戏积分以及关卡的设置
游戏窗口的窗口创建
首先这个大鱼吃小鱼游戏在设计时就准备做成一个窗口游戏,并且准备采用Java进行开发,所以理所当然的想到了去使用Swing技术来支持开发。当然,现如今Swing也早就成为了时代的产物,逐渐被JavaJX替代了。由于时间以及难易程度的考虑,这里我们还是采用了Swing技术来开发这个游戏。
3. EatFish游戏中的5种状态
这里我们首先定义了一个static的对象state用来表示游戏状态,然后采用switch语句来判定每种游戏状态对应的窗口应该做什么事情。首先,state=0表示“游戏未开始”,state=1表示“游戏进行中”,state=2表示“游戏结束”,state=3表示“通关成功”,state=4表示“游戏暂停”。
我方鱼类和敌方鱼类的创建
敌方鱼类:
我方鱼类:
敌我方的鱼类本质其实就是一个个打的对象,我们要做的就是去创建它们对应的类然后生成相应的对象,然后通过createImage方法将这些鱼类的图片于对象进行绑定,然后我们看到的就是如上生动的鱼类了。此外,由于我方鱼类在向左向右移动时,以及敌方鱼类出现时都是有左右两个方向的,所以我们要提前准备好连个方向的动态图以及在代码中分别设计左右两个方向的鱼类对象。
我方鱼类的移动以及大小的变化
在工具类GameUtil中已经定义了UP、DOWM、LEFT、RIGHT,分别对应着键盘监听事件。我方鱼位置的变化由每次先前定义的speed以及当前位置决定。比如向右移动,点击一次“→”,我方鱼X坐标位置就加一个speed的大小。 在我方鱼吃到比自己等级小的鱼的时候,鱼的体积是应该变大的。这里是由给不同等级敌方鱼类的分数count决定的,当吃掉比自己等级低的鱼类后,会调用绘制自身的一个方法paintSelf(),由于参数中加了count的值,所以我方鱼的体积就会变大。
敌方鱼类的批量生成
首先敌方鱼类我们设计成了三种:海马、热带鱼、剑鱼。另外还有一种Boss鲨鱼(无视任何其他鱼类,实现通吃)。这里敌方鱼类的生成是和游戏难度等级挂钩的。当level=1时,我们让窗口内随机不断生成1级敌方鱼:海马。Level=2时,生成热带鱼。level=3时,生成剑鱼。Level=4时,生成鲨鱼。这里敌方鱼的生成借助了一个指针time,将他作为计数器,用来控制每过多久添加一条敌方鱼到敌方鱼的集合中。
鱼类的碰撞检测
鱼类碰撞检测是大鱼吃小鱼游戏中很关键的步骤,这里我们采用的是矩形碰撞检测的方法,即:通过获取鱼类自身矩形的方法,用于检测不同矩形之间是否相交了来判断鱼类碰撞。Java中有原生的Rectangle类,我们为每个鱼类生成一个可以返回Rectangle类的对象的方法即可。之后再通过Java中的intersects()方法去比较两个返回的Rectangle对象是否相交就可以判断出鱼类间是否碰撞了。在碰撞后,将等级小的鱼类位置坐标更新到窗口之外就达到了被吃掉的效果
8.项目代码
Bg类:
package com.shu;
import java.awt.*;
public class Bg {
void paintSelf(Graphics g , int fishLevel){
g.drawImage(GameUtils.bgimg,0,0,null);
switch (GameWin.state){
case 0:
GameUtils.drawWord(g,"开始",Color.red,80,700,500);
break;
case 1:
GameUtils.drawWord(g,"积分"+GameUtils.count,Color.ORANGE,50,200,120);
GameUtils.drawWord(g,"难度"+GameUtils.level,Color.ORANGE,50,600,120);
GameUtils.drawWord(g,"等级"+fishLevel,Color.ORANGE,50,1000,120);
break;
case 2:
GameUtils.drawWord(g,"游戏结束!!!",Color.red,50,600,400);
break;
case 3:
GameUtils.drawWord(g,"积分"+GameUtils.count,Color.ORANGE,50,200,120);
GameUtils.drawWord(g,"难度"+GameUtils.level,Color.ORANGE,50,600,120);
GameUtils.drawWord(g,"等级"+fishLevel,Color.ORANGE,50,1000,120);
GameUtils.drawWord(g ,"胜利",Color.red,80,700,500);
break;
case 4:
break;
default:
}
}
}
Enamy类:
package com.shu;
import java.awt.*;
public class Enamy
{
//定义图片
Image image;
//定义物体坐标
int x;
int y;
int width;
int height;
//移动速度
int speed;
//方向
int dir = 1;//1为向右 -1为向左
//类型
int type;
//分值
int count;
//绘制自身方法
public void paintSelf(Graphics g)
{
g.drawImage(image,x,y,width,height,null);
}
//获取自身矩形用于碰撞检测
public Rectangle getRec()
{
return new Rectangle(x,y,width,height);
}
}
//敌方鱼左类
class Enamy_1_L extends Enamy
{
Enamy_1_L()
{
this.x = -45;
this.y = (int)(Math.random()*700 + 100);
this.width = 45;
this.height = 69;
this.speed = 10;
this.count = 1;
this.type = 1;
this.image = GameUtils.enamyl_img;
}
}
//敌方鱼右类
class Enamy_1_R extends Enamy_1_L
{
Enamy_1_R()
{
this.x = 1400;
dir = -1;
this.image = GameUtils.enamyr_img;
}
}
class Enamy_2_L extends Enamy
{
Enamy_2_L()
{
this.x = -100;
this.y = (int)(Math.random()*700+100);
this.width = 100;
this.height = 100;
this.speed = 5;
this.count = 2;
this.type = 2;
this.image = GameUtils.enamyl_2img;
}
}
class Enamy_2_R extends Enamy_2_L
{
Enamy_2_R()
{
this.x = 1400;
dir = -1;
this.image = GameUtils.enamyr_2img;
}
}
class Enamy_3_L extends Enamy
{
Enamy_3_L()
{
this.x = -300;
this.y = (int)(Math.random()*700+100);
this.width = 300;
this.height = 150;
this.speed = 15;
this.count = 3;
this.type = 3;
this.image = GameUtils.enamyl_3img;
}
@Override
public Rectangle getRec()
{
return new Rectangle(x + 40, y + 30,width - 80,height +- 60);
}
}
class Enamy_3_R extends Enamy_3_L
{
Enamy_3_R()
{
this.x = 1400;
dir = -1;
this.image = GameUtils.enamyr_3img;
}
}
class Enamy_Boss extends Enamy
{
Enamy_Boss()
{
this.x = -1000;
this.y = (int)(Math.random()*700+100);
this.width = 170;
this.height = 170;
this.speed = 40;
this.count = 0;
this.type = 10;
this.image = GameUtils.bossimg;
}
}
GameUtils类:
package com.shu;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
public class GameUtils {
//方向
static boolean UP =false;
static boolean DOWN =false;
static boolean LEFT =false;
static boolean RIGHT =false;
//分数
static int count = 0;
//关卡等级
static int level = 0;
//敌方鱼类集合
public static List<Enamy> EnamyList = new ArrayList<>();
//背景图
public static Image bgimg = Toolkit.getDefaultToolkit().createImage("images/sea.jpg");
//敌方鱼类
public static Image enamyl_img = Toolkit.getDefaultToolkit().createImage("images/enemyFish/fish1_r.gif");
public static Image enamyr_img = Toolkit.getDefaultToolkit().createImage("images/enemyFish/fish1_l.gif");
public static Image enamyl_2img = Toolkit.getDefaultToolkit().createImage("images/enemyFish/fish2_r.png");
public static Image enamyr_2img = Toolkit.getDefaultToolkit().createImage("images/enemyFish/fish2_l.png");
public static Image enamyl_3img = Toolkit.getDefaultToolkit().createImage("images/enemyFish/fish3_r.png");
public static Image enamyr_3img = Toolkit.getDefaultToolkit().createImage("images/enemyFish/fish3_l.png");
public static Image bossimg = Toolkit.getDefaultToolkit().createImage("images/enemyFish/boss.gif");
//我方鱼类
public static Image MyFishimg_L = Toolkit.getDefaultToolkit().createImage("images/myFish/myfish_left.gif");
public static Image MyFishimg_R = Toolkit.getDefaultToolkit().createImage("images/myFish/myfish_right.gif");
//绘制文字的工具类
public static void drawWord(Graphics g,String str ,Color color,int size,int x, int y){
g.setColor(color);
g.setFont(new Font("仿宋",Font.BOLD,size));
g.drawString(str, x, y);
}
}
GameWin类:
package com.shu;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class GameWin extends JFrame {
/** 游戏状态 0未开始,1游戏中,2通关失败,3通关成功,4暂停,5重新开始*/
//定义游戏默认状态
static int state = 0;
Image offScreenImage;
//宽高
int width = 1440;
int height = 900;
double random;
//计数器
int time = 0;
//背景
Bg bg = new Bg();
//敌方鱼类
Enamy enamy;
//boss类
Enamy boss;
//是否生成boss
boolean isboss = false;
//我方鱼类
MyFish myFish = new MyFish();
public void launch(){
this.setVisible(true);
this.setSize(width,height);
this.setLocationRelativeTo(null);
//this.setResizable(false);
this.setTitle("大鱼吃小鱼");
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.addMouseListener(new MouseAdapter()
{
@Override
public void mouseClicked(MouseEvent e)
{
super.mouseClicked(e);
if(e.getButton() == 1 && state == 0)
{
state = 1;
repaint();
}
if(e.getButton() == 1 && state == 2 || state == 3)
{
reGame();
state = 1;
}
}
});
//键盘移动
this.addKeyListener(new KeyAdapter() {
@Override//按压
public void keyPressed(KeyEvent e) {
super.keyPressed(e);
//WASD
if (e.getKeyCode()==87){
GameUtils.UP = true;
}
if (e.getKeyCode()==83){
GameUtils.DOWN = true;
}
if (e.getKeyCode()==65){
GameUtils.LEFT = true;
}
if (e.getKeyCode()==68){
GameUtils.RIGHT = true;
}
if(e.getKeyCode() == 32)
{
if(state == 1)
{
state = 4;
GameUtils.drawWord(getGraphics(),"游戏暂停!!!",Color.red,50,600,400);
}
else if(state == 4) state = 1;
}
if(e.getKeyCode() == 75)//后路,按k 增加50积分
{
GameUtils.count += 50;
}
}
@Override//抬起
public void keyReleased(KeyEvent e)
{
super.keyPressed(e);
//WASD
if(e.getKeyCode() == 87)
{
GameUtils.UP = false;
}
if(e.getKeyCode() == 83)
{
GameUtils.DOWN = false;
}
if(e.getKeyCode() == 65)
{
GameUtils.LEFT = false;
}
if(e.getKeyCode() == 68)
{
GameUtils.RIGHT = false;
}
}
});
while(true)
{
repaint();
time ++;
try
{
Thread.sleep(40);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
public void paint(Graphics g)
{
//懒加载模式初始化对象 双缓存解决闪屏问题
offScreenImage = createImage(width,height);
Graphics gImage = offScreenImage.getGraphics();
bg.paintSelf(gImage,myFish.level);
//游戏状态
switch (state)
{
case 0:
break;
case 1:
myFish.paintSelf(gImage);
logic();
for(Enamy enamy:GameUtils.EnamyList)
{
enamy.paintSelf(gImage);
}
if(isboss)
{
boss.x = boss.x + boss.dir * boss.speed;
boss.paintSelf(gImage);
if(boss.x < 0)
{
gImage.setColor(Color.red);
gImage.fillRect(boss.x,boss.y,2400,boss.height/30);
}
}
break;
case 2:
for(Enamy enamy:GameUtils.EnamyList)
{
enamy.paintSelf(gImage);
}
if(isboss)
{
boss.paintSelf(gImage);
}
break;
case 3:
myFish.paintSelf(gImage);
break;
case 4:
return;
default:
}
g.drawImage(offScreenImage,0,0,null);
}
void logic()
{
//关卡难度
if(GameUtils.count<5)
{
GameUtils.level = 0;
GameUtils.level = 0;
myFish.level = 1;
}
else if(GameUtils.count<=15)
{
GameUtils.level = 1;
}
else if(GameUtils.count<=50)
{
GameUtils.level = 2;
myFish.level = 2;
}
else if(GameUtils.count <= 150)
{
GameUtils.level = 3;
myFish.level = 2;
}
else if(GameUtils.count <= 300)
{
GameUtils.level = 4;
myFish.level = 3;
}
else if(GameUtils.count > 300)
{
state = 3;//游戏胜利
}
random = Math.random();
//敌方鱼生成
switch (GameUtils.level)
{
case 4:
if(time % 60 == 0)
{
boss = new Enamy_Boss();
isboss = true;
}
case 3:
case 2:
if(time % 30 == 0)
{
if(random > 0.5)
{
enamy = new Enamy_3_L();
}
else
{
enamy = new Enamy_3_R();
}
GameUtils.EnamyList.add(enamy);
}
case 1:
if(time % 20 == 0)
{
if(random > 0.5)
{
enamy = new Enamy_2_L();
}
else
{
enamy = new Enamy_2_R();
}
GameUtils.EnamyList.add(enamy);
}
case 0:
if(time % 10 == 0)
{
if(random > 0.5)
{
enamy = new Enamy_1_L();
}
else
{
enamy = new Enamy_1_R();
}
GameUtils.EnamyList.add(enamy);
}
break;
default:
}
//移动方向
for(Enamy enamy:GameUtils.EnamyList)
{
enamy.x += enamy.dir * enamy.speed;
//和boss鱼类碰撞检测
if(isboss)
{
if(boss.getRec().intersects(enamy.getRec()))
{
enamy.x = -200;
enamy.y = -200;
}
if (boss.getRec().intersects(myFish.getRec()))
state = 2;
}
//我方鱼与敌方鱼碰撞检测
if(myFish.getRec().intersects(enamy.getRec()))
{
if(myFish.level >= enamy.type)
{
enamy.x = -200;
enamy.y = -200;
GameUtils.count = GameUtils.count + enamy.count;
}
else //我方鱼被高级鱼吃掉
{
state = 2;
}
}
}
}
//重新开始
void reGame()
{
GameUtils.EnamyList.clear();
time = 0;
myFish.level = 1;
GameUtils.count = 0;
myFish.x = 700;
myFish.y = 500;
myFish.width = 50;
myFish.height = 50;
boss = null;
isboss = false;
}
public static void main(String[] args) {
GameWin gameWin = new GameWin();
gameWin.launch();
}
}
MyFish类:
package com.shu;
import java.awt.*;
public class MyFish {
//图片
Image img = GameUtils.MyFishimg_L;
//坐标
int x = 700;
int y = 500;
int width = 50;
int height = 50;
//移动速度
int speed = 20;
//等级
int level = 1;
void logic()
{
if(GameUtils.UP)
{
y = y - speed;
}
if(GameUtils.DOWN)
{
y = y + speed;
}
if(GameUtils.LEFT)
{
x = x - speed;
img = GameUtils.MyFishimg_L;
}
if(GameUtils.RIGHT)
{
x = x + speed;
img = GameUtils.MyFishimg_R;
}
}
//绘制自身的方法
public void paintSelf(Graphics g)
{
logic();
g.drawImage(img,x,y,width + GameUtils.count,height + GameUtils.count,null);
}
//获取自身矩形的方法,用于碰撞检测
public Rectangle getRec()
{
return new Rectangle(x,y,width + GameUtils.count,height + GameUtils.count);
}
}
9.项目素材
10.项目运行结果演示