这是一款经典小游戏,大鱼吃小鱼,玩家操控小鱼从小吃到大,直面Boss的挑战,全方面的代码解析,适合新手第一款的项目实战
⭐本项目演示地址⭐
⭐资源图片源代码私信博主⭐
项目的完整结构图:
游戏效果图:
源代码如下:
游戏窗口类完整代码:
package game;
import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class FishFrame extends Frame {
public static final int GAME_WIDTH = 1200;//游戏窗口的宽
public static final int GAME_HEIGHT = 800;//游戏窗口的高
private Image offScreenImage = null;//在paint方法进行画图前保存图画,以便一次画出,消除双缓冲现象
public static Random r = new Random();//创建一个随机数生成器
private boolean isStart = false;//判断游戏是否开始的变量
MyFish myFish = new MyFish(GAME_WIDTH/2, GAME_HEIGHT/2, this);//创建一条我的小鱼
List<EnemyFish> fishList_Left = new ArrayList<EnemyFish>();//装小鱼的集合
List<EnemyFish> fishList_Right = new ArrayList<EnemyFish>();//装小鱼的集合
/**
* 画出图片
*/
public void paint(Graphics g) {
/*
* 通过isStart变量判断游戏是否开始,没有开始的话画出欢迎界面
*/
if(!isStart){
draw_welcome(g);
return;
}
//画出我方小鱼,如果我方小鱼吃掉了敌军小鱼会有GOOD字样显示
myFish.draw(g);
if(myFish.eatFishs(fishList_Left) || myFish.eatFishs(fishList_Right)){
for(int i = 0; i < 5; i++){
g.drawString("GOOD!", myFish.x, myFish.y);
}
}
//设置我方小鱼可以被吃掉
myFish.beEaten(fishList_Left);
myFish.beEaten(fishList_Right);
//画出敌方小鱼
for(int i = 0; i < fishList_Left.size(); i++) {
EnemyFish e = fishList_Left.get(i);
e.draw(g);
}
for(int i = 0; i < fishList_Right.size(); i++) {
EnemyFish e = fishList_Right.get(i);
e.draw(g);
}
//画出当前小鱼数量和当前玩家积分字样
g.setFont(new Font("宋体", Font.BOLD, 25));
g.drawString("fish account : " + (fishList_Left.size()+fishList_Right.size()), 10, 50);
g.drawString("you scores : " + myFish.scores, 10, 70);
if(myFish.scores > 380) {
g.drawString("你以为你真的能变成一条肥鱼吃遍天下吗? Too Young! Too Simple!", 200, 350);
}
//当我方小鱼阵亡时写出GAME OVER字样
if(!myFish.live){
g.setColor(Color.RED);
g.setFont(new Font("宋体", Font.BOLD, 70));
g.drawString("GAME OVER!!!", 300, 400);
}
}
/**
* 画出欢迎界面
* @param g
*/
private void draw_welcome(Graphics g) {
g.setColor(Color.RED);
g.setFont(new Font("宋体", Font.BOLD, 75));
g.drawString("Welcome to the FishGame!!!", 100, 150);
g.setFont(new Font("宋体", Font.BOLD, 40));
g.setColor(Color.YELLOW);
g.drawString("How to play:", 200, 350);
g.drawString("press W,A,S,D to move,", 200, 400);
g.drawString("you can eat the samller ones,", 200, 450);
g.drawString("but be careful to the big ones.", 200, 500);
g.drawString("The boss is waiting for you, Let's go!", 200, 600);
g.drawString("Press Enter to start...", 200, 650);
}
/**
* 游戏初始化
*/
private void launchFrame() {
this.setLocation(50, 50);//设置游戏窗口的位置
this.setSize(GAME_WIDTH, GAME_HEIGHT);//设置游戏窗口的宽高
this.setVisible(true);//设置游戏窗口可见
this.setResizable(false);//设置游戏窗口大小不可改变
this.setTitle("FishGame");//设置游戏窗口标题
this.addWindowListener(new WindowAdapter() {//添加窗口监听
public void windowClosing(WindowEvent e) {//匿名内部类监听窗口关闭事件
System.exit(0);//窗口关闭游戏退出
}
});
this.addKeyListener(new KeyMonitorForStart());//添加键盘监听,看游戏是否开始
this.addKeyListener(new KeyMonitor());//添加键盘监听
new Thread(new RepaintThread()).start();//创建重画线程对象进行重画
new Thread(new AddFishFromLeft(this)).start();//添加向右移动的小鱼
new Thread(new AddFishFromRight(this)).start();//添加向左移动的小鱼
//通过当前积分改变我方小鱼的移动速度
changeMyFishSpeedByScores();
}
/**
* 根据积分改变稍微提高小鱼的速度
*/
private void changeMyFishSpeedByScores() {
//先获取当前MyFish的积分
int score = this.myFish.scores;//根据积分设置MyFish的速度
if(score >= 0 && score <50) {
addSpeed();
}else if(score >= 50 && score < 100) {
addSpeed();
}else if(score >= 100 && score < 200){
addSpeed();
}else{
addSpeed();
addSpeed();
}
}
/**
* 提高速度
*/
private void addSpeed() {
myFish.xSpeed++;
myFish.ySpeed++;
}
/**
* 设置游戏背景
*/
private void drawBackground(Graphics g) {
Toolkit tk = Toolkit.getDefaultToolkit();//拿到当前系统默认的Toolkit
Image background = tk.getImage(this.getClass()
.getClassLoader().getResource("images/background/sea.jpg"));
g.drawImage(background, 0, 0, null);
}
/**
* 消除双缓冲现象
*/
public void update(Graphics g) {
if(null == offScreenImage) {//判断offScreenImage是否为空,为空则创建一张准备图片
offScreenImage = this.createImage(GAME_WIDTH, GAME_HEIGHT);
}
Graphics og = offScreenImage.getGraphics();
drawBackground(og);
paint(og);//执行paint方法,把要画的图片画到缓冲的offScreenImage上
g.drawImage(offScreenImage, 0, 0, null);//在屏幕上画出offScreenImage
}
/**
* 重画的线程类
*
*/
class RepaintThread implements Runnable{
public void run() {
while(true) {
repaint();//启动线程后进行重画
try {
Thread.sleep(30);//每隔50毫秒重画一次
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/*
* 键盘监听内部类,用于改变鱼的位移,让鱼动起来
*/
class KeyMonitor extends KeyAdapter{
public void keyPressed(KeyEvent e) {
myFish.keyPressed(e);
}
public void keyReleased(KeyEvent e) {
myFish.keyRelease(e);
}
}
/*
* 键盘监听,监听是否按下了回车键,按下回车键设置isStart为true,游戏开始
*/
class KeyMonitorForStart extends KeyAdapter{
public void keyPressed(KeyEvent e) {
int key = e.getExtendedKeyCode();
if(key == KeyEvent.VK_ENTER){
isStart = true;
}
}
}
public static void main(String[] args) {
FishFrame fishFrame = new FishFrame();//创建本类对象
fishFrame.launchFrame();//加载游戏
}
}
敌人鱼类:
package game;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.util.Random;
/**
* 敌方小鱼类
*
*/
public class EnemyFish extends GameObject {
public MyFish OurEnemy;//敌军小鱼的敌人就是玩家的小鱼,用于判断是否能吃掉玩家的小鱼
private Image image;//小鱼自己的图片
/**
* 加载敌军小鱼的图片
*/
private static Random r = new Random();
public static Image[] images = null;
public static Toolkit tk = Toolkit.getDefaultToolkit();
static {
images = new Image[] {
tk.createImage(EnemyFish.class.getClassLoader().getResource("images/enemyFish/fish1_l.gif")),
tk.createImage(EnemyFish.class.getClassLoader().getResource("images/enemyFish/fish2_l.gif")),
tk.createImage(EnemyFish.class.getClassLoader().getResource("images/enemyFish/fish3_l.gif")),
tk.createImage(EnemyFish.class.getClassLoader().getResource("images/enemyFish/fish1_r.gif")),
tk.createImage(EnemyFish.class.getClassLoader().getResource("images/enemyFish/fish2_r.gif")),
tk.createImage(EnemyFish.class.getClassLoader().getResource("images/enemyFish/fish3_r.gif")),
tk.createImage(EnemyFish.class.getClassLoader().getResource("images/enemyFish/boss.gif"))
};
}
public EnemyFish(int x, int y, int width, int height,
FishFrame ff, Direction dir, int speed, MyFish OurEnemy, Image image) {
super();
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.ff = ff;
this.dir = dir;
this.xSpeed = speed;
this.OurEnemy = OurEnemy;
this.image = image;
}
/**
* 画出小鱼的方法
* @param g
*/
public void draw(Graphics g) {
if(!live) {
if(dir.equals(Direction.R)){
ff.fishList_Left.remove(this);//如果小鱼死亡就从容器中移除
}else{
ff.fishList_Right.remove(this);//如果小鱼死亡就从容器中移除
}
return;//小鱼死亡则不再画出
}
g.drawImage(image, x, y, width, height, null);//画出自己的图片
move();//小鱼位置变化
}
/**
* 小鱼移动的方法
*/
private void move() {
if(dir.equals(Direction.L)) {
x -= xSpeed;//如果小鱼的方向是朝左的,x坐标递减向左移动
}else {
x += xSpeed;//否则向右移动
}
//小鱼如果走出边界则判断为死亡
if(dir.equals(Direction.R)){
if(x > ff.GAME_WIDTH) this.live = false;//向右的小鱼,如果x坐标大于窗口宽度则死亡
}else{
if(x < 0) this.live = false;//向左的小鱼,如果x坐标小于窗口宽度则死亡
}
}
}
作者:KJ.JK
本文仅用于交流学习,未经作者允许,禁止转载,更勿做其他用途,违者必究。