一、项目简介
- 《大鱼吃小鱼》是一种基于Java技术的简单游戏,可以在桌面应用程序中运行。玩家扮演着一个生活在海洋中的鱼类,在游戏过程中需要不断地吃掉比自己体积小的鱼来成长,并要躲避比自己体积大的鱼的攻击,以避免被吃掉。游戏的界面主要由一个海底场景和多个鱼组成。每条鱼都有自己的身体大小和速度属性,根据这些属性可以判断出鱼之间的大小关系,从而实现吃或被吃的游戏规则。当玩家的鱼体积增长到一定程度后,也可以去捕捉身体比自己小的其他鱼类。在进行游戏时,玩家可以使用键盘控制自己的鱼移动等,通过不断地提高自己的技能和策略,最终成为海洋之王。
二、项目采用技术
- 变量、数据类型、判断语句、循环结构、类的继承、简单窗口创建、图形图片绘制、键盘事件、双缓存技术。
三、功能需求分析
1、游戏界面
- 游戏需要一个逼真的海底场景,以及多个不同种类的鱼等海洋生物。每个游戏元素需要有相应的图片或动画效果,以增加游戏的可玩性。此外,游戏还需要有控制面板、得分牌等辅助信息。
2、鱼类属性
- 每条鱼都需要具备相应的属性,包括体积大小、速度等,同时还要考虑成长和食物等因素对其属性的影响。
3、鱼类操作
- 玩家需要能够操纵自己控制的鱼类进行移动、食用其他鱼类、升级等操作。
鱼类操作
4、AI系统设计
- 游戏中的AI系统需要考虑多个因素来设置敌方鱼类的行为,如视野、移动方式等,以及逃脱策略 。除此之外,还设计了一些特殊的“BOSS”型角色,增加游戏难度。
5、结束游戏
- 玩家碰到比自己等级高的鱼被吃掉,游戏失败。
四、项目核心代码
1、双缓存技术解决闪烁问题(S)
Image offScreenImage;
//循环调用
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);
}
}
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);
}
2、关卡难度变化(S)
package fish;
void logic() {
//关卡难度
if(GameUtils.count<5) {
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=3;
}else if(GameUtils.count<=300) {
GameUtils.level=4;
myFish.level=3;
}else if(GameUtils.count>300) {
state=3;
}
3、设置游戏状态(S)
package fish;
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);
}
}
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:
}
4、随机生成鱼(S)
package fish;
//生成鱼
random=Math.random();
switch(GameUtils.level) {
case 4:
if(time%60==0) {
if(random>0) {
boss=new Enamy_Boss();
isboss=true;
}
}
case 3:
if(time%10==0) {
if(random>0.5) {
enamy=new EnamyLeft();
}else {
enamy=new EnamyRight();
}
GameUtils.EnamyList.add(enamy);
}
case 2:
if(time%30==0) {
if(random>0.5) {
enamy=new EnamyLeft3();
}else {
enamy=new EnamyRight3();
}
GameUtils.EnamyList.add(enamy);
}
case 1:
if(time%20==0) {
if(random>0.5) {
enamy=new EnamyLeft2();
}else {
enamy=new EnamyRight2();
}
GameUtils.EnamyList.add(enamy);
}
case 0:
if(time%10==0) {
if(random>0.5) {
enamy=new EnamyLeft();
}else {
enamy=new EnamyRight();
}
GameUtils.EnamyList.add(enamy);
}
break;
default:
}
5、登录界面逻辑实现(S)
@Override
public void mouseClicked(MouseEvent m) {
if (m.getSource() == loginButton){
System.out.println("用户点击登录按钮");
String name = UserjTextField.getText();
String paw = passwordField.getText();
//获取验证码
String codeInput = code.getText();
UserInfo user = new UserInfo(name,paw);
System.out.println("用户输入的用户名为:"+name);
System.out.println("用户输入的密码为:"+paw);
if (codeInput.length() == 0 && name.length() !=0 && paw.length() !=0){
System.out.println("用户验证码为空!");
showDialog("验证码不能为空!");
String code = CodeUtil.Create(5);//创建一个5位长度的随机验证码
rightCode.setText(code);
}else if (name.length() ==0 || paw.length() == 0){
System.out.println( "用户名或者密码为空");
showDialog("用户名或者密码为空");
String code = CodeUtil.Create(5);
rightCode.setText(code);
//判断输入的验证码与生成的验证码是否相同
} else if (!codeInput.equalsIgnoreCase(rightCode.getText())) {
showDialog("验证码输入错误");
String code = CodeUtil.Create(5);
rightCode.setText(code);
}else if(contains(user)){
System.out.println("用户输入账号正确,登录成功!");
//关闭登陆界面
this.setVisible(false);
new Game();
}else {
System.out.println("用户名或密码错误");
showDialog("用户名或密码错误");
String code = CodeUtil.Create(5);
rightCode.setText(code);
}
}
//更换验证码
if(m.getSource() == rightCode){
System.out.println("更换验证码!");
String code = CodeUtil.Create(5);
rightCode.setText(code);
}
//进入注册页面
if(m.getSource() == enrollButton){
System.out.println("用户注册");
this.dispose();
new Register();
}
}
//鼠标长按
@Override
public void mousePressed(MouseEvent m) {
if (m.getSource() == loginButton){
loginButton.setIcon(new ImageIcon("......\\FeedingFrenzy\\image\\login\\登录按下.png"));
}else if (m.getSource() == enrollButton){
enrollButton.setIcon(new ImageIcon("......\\FeedingFrenzy\\image\\login\\注册按下.png"));
} //显示查看密码
else if (m.getSource() == seelabel){
seelabel.setIcon(new ImageIcon("......\\FeedingFrenzy\\image\\login\\显示密码按下.png"));
passwordField.setEchoChar((char)0);
}
}
//松开按钮
@Override
public void mouseReleased(MouseEvent m) {
if (m.getSource() == loginButton){
loginButton.setIcon(new ImageIcon("......\\FeedingFrenzy\\image\\login\\登录按钮.png"));
}else if (m.getSource() == enrollButton){
enrollButton.setIcon(new ImageIcon("......\\FeedingFrenzy\\image\\login\\注册按钮.png"));
} else if (m.getSource() == seelabel){
seelabel.setIcon(new ImageIcon("......\\FeedingFrenzy\\image\\login\\显示密码.png"));
passwordField.setEchoChar('*');
}
}
6、鱼的碰撞检测(D)
package fish;
//我方鱼与敌方鱼碰撞检测
if(myFish.getRec().intersects(enamy.getRec())) {
if(myFish.level>=enamy.type) {
System.out.println("碰撞了");
enamy.x=-200;
enamy.y=-200;
GameUtils.count=GameUtils.count+enamy.count;
}else {
state=2;
}
}
7、创建鱼类(D)
package fish;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
public class Enamy {
//图片
Image img;
//物体坐标
int x;
int y;
int width;
int height;
//移动速度
int speed;
//方向:从左向右1,从左向右-1
int dir=1;
//类型
int type;
//分值
int count;
//绘制自身方法
public void paintSelf(Graphics g) {
g.drawImage(img, x, y, width, height,null);
}
//获取自身矩形用于碰撞
public Rectangle getRec() {
return new Rectangle(x,y,width,height);
}
}
public class Enamy_Boss extends Enamy {
Enamy_Boss(){
this.x=-1000;
this.y=(int)(Math.random()*700+100);
this.width=340;
this.height=340;
this.speed=100;
this.count=0;
this.type=10;
this.img=GameUtils.bossing;
}
}
public class EnamyLeft extends Enamy{
EnamyLeft(){
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.img=GameUtils.enamyl1;
}
}
public class EnamyRight extends Enamy{
EnamyRight(){
this.x=1400;
dir=-1;
this.y=(int)(Math.random()*700+100);
this.width=45;
this.height=69;
this.speed=10;
this.count=1;
this.type=1;
this.img=GameUtils.enamyr1;
}
}
//省略其他地方子鱼类
8、用户信息(D)
储存用户信息,核对用户信息,创建用户类
public static ArrayList<UserInfo> userInfoArrayList = new ArrayList<>();
{
userInfoArrayList.add(new UserInfo("hangman","123456"));
for (UserInfo userInfo : userInfoArrayList) {
System.out.println("用户信息:"+userInfo.getName()+" "+userInfo.getPaw());
System.out.println("--------------------------------------------");
}
}
public boolean contains(UserInfo userInfo){
//for增强
for (UserInfo rightuser : userInfoArrayList) {
//集合user
if (userInfo.getName().equals(rightuser.getName()) && userInfo.getPaw().equals(rightuser.getPaw())) {
//相同则通过进行下一步
return true;
}
}
return false;
}
public class UserInfo {
private String name;
private String paw;
public UserInfo(String name, String paw) {
this.name = name;
this.paw = paw;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPaw() {
return paw;
}
public void setPaw(String paw) {
this.paw = paw;
}
}
9、控制鱼的移动方向(L)
package fish;
//定义移动方向
for(Enamy enamy:GameUtils.EnamyList) {
enamy.x=enamy.x+enamy.dir*enamy.speed;
if(isboss) {
if(boss.getRec().intersects(getBounds())) {
enamy.x=-200;
enamy.y=-200;
}
if(boss.getRec().intersects(myFish.getRec())) {
state=2;
}
}
10、绘制文字(L)
package fish;
import java.awt.Color;
import java.awt.Graphics;
public class Bg {
public void paintSelf(Graphics g,int fishLevel) {
g.drawImage(GameUtils.background, 0, 0,null);
switch(GameWin.state) {
case 0:
GameUtils.drawWord(g, "开始", Color.GREEN, 80,700,500);
break;
case 1:
GameUtils.drawWord(g, "积分"+GameUtils.count, Color.ORANGE, 50,200,120);
GameUtils.drawWord(g, "难度"+GameUtils.level, Color.ORANGE, 80,600,120);
GameUtils.drawWord(g, "等级"+fishLevel, Color.ORANGE, 80,1000,120);
break;
case 2:
GameUtils.drawWord(g, "积分"+GameUtils.count, Color.ORANGE, 50,200,120);
GameUtils.drawWord(g, "难度"+GameUtils.level, Color.ORANGE, 80,600,120);
GameUtils.drawWord(g, "等级"+fishLevel, Color.ORANGE, 80,1000,120);
GameUtils.drawWord(g, "失败", Color.RED,80,700,500);
break;
case 3:
GameUtils.drawWord(g, "积分"+GameUtils.count, Color.ORANGE, 50,200,120);
GameUtils.drawWord(g, "难度"+GameUtils.level, Color.ORANGE, 80,600,120);
GameUtils.drawWord(g, "等级"+fishLevel, Color.ORANGE, 80,1000,120);
GameUtils.drawWord(g, "胜利", Color.RED, 80,700,500);
break;
case 4:
break;
default:
}
}
}
11、添加工具类(L)
package fish;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
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 background=Toolkit.getDefaultToolkit().createImage("D:\\eclipse\\FeedingFrenzy\\image\\Ocean.jpg");
//敌方鱼类
public static Image enamyl1=Toolkit.getDefaultToolkit().createImage("D:\\eclipse\\FeedingFrenzy\\image\\Enamy1.png");
public static Image enamyr1=Toolkit.getDefaultToolkit().createImage("D:\\eclipse\\FeedingFrenzy\\image\\Enamy1.png");
public static Image enamyl2=Toolkit.getDefaultToolkit().createImage("D:\\eclipse\\FeedingFrenzy\\image\\Enamy2.png");
public static Image enamyr2=Toolkit.getDefaultToolkit().createImage("D:\\eclipse\\FeedingFrenzy\\image\\Enamy2.png");
public static Image enamyl3=Toolkit.getDefaultToolkit().createImage("D:\\eclipse\\FeedingFrenzy\\image\\Enamy3.jpg");
public static Image enamyr3=Toolkit.getDefaultToolkit().createImage("D:\\eclipse\\FeedingFrenzy\\image\\Enamy3.jpg");
public static Image bossing=Toolkit.getDefaultToolkit().createImage("D:\\eclipse\\FeedingFrenzy\\image\\Enamy4.jpg");
//我方鱼类
public static Image MyfishimgR=Toolkit.getDefaultToolkit().createImage("D:\\eclipse\\FeedingFrenzy\\image\\myfish.jpg");
public static Image MyfishimgL=Toolkit.getDefaultToolkit().createImage("D:\\eclipse\\FeedingFrenzy\\image\\myfish.jpg");
//绘制文字的工具类
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);
}
}
12、登录界面设置(L)
package fish;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import java.awt.event.*;
import java.util.ArrayList;
public class LoginJFrame extends JFrame {
public LoginJFrame() {
this.setSize(488,430);
this.setTitle("大鱼吃小鱼 登陆");
this.setAlwaysOnTop(true);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(1);
this.setVisible(true);
}
JTextField UserjTextField = new JTextField();//用户名输入框
JPasswordField passwordField = new JPasswordField();//用户密码输入框
JTextField code = new JTextField();//验证码输入框
JButton loginButton = new JButton();//登录按钮
JButton enrollButton = new JButton();//注册按钮
JLabel seelabel = new JLabel();
//验证码区域
JLabel rightCode = new JLabel();
public void initView() {
//添加用户名标签
JLabel UserjLabel = new JLabel(new ImageIcon("......\\PinTu\\image\\login\\用户名.png"));
UserjLabel.setBounds(100, 140, 47, 17);
this.getContentPane().add(UserjLabel);
//添加输入框
UserjTextField.setBounds(195, 134, 200, 30);
this.getContentPane().add(UserjTextField);
//添加密码标签
JLabel PawjLabel = new JLabel(new ImageIcon("E:\\JavaProject\\PinTu\\image\\login\\密码.png"));
PawjLabel.setBounds(110, 200, 32, 16);
this.getContentPane().add(PawjLabel);
//添加密码输入框
passwordField.setBounds(195, 195, 200, 30);
passwordField.setEchoChar('*');
this.getContentPane().add(passwordField);
//密码显示
seelabel.setIcon(new ImageIcon("......\\PinTu\\image\\login\\显示密码.png"));
seelabel.setBounds(400,195,50,30);
seelabel.addMouseListener((MouseListener) this);
this.getContentPane().add(seelabel);
//验证码提示
JLabel codeText = new JLabel(new ImageIcon("......\\PinTu\\image\\login\\验证码.png"));
codeText.setBounds(100, 256, 50, 30);
this.getContentPane().add(codeText);
//验证码的输入框
code.setBounds(195, 256, 100, 30
五、系统演示操作视频或者主要功能截图
鱼类操作
六、团队成员负责模块
团队成员 | 负责模块 | 个人博客 | 代码行数 |
宋佳敏 | 搭建窗口,控制游戏状态,设置游戏模式,登录界面逻辑实现 | http://t.csdn.cn/zPjUh | 284 |
邓书勤 | 创建鱼相关类,鱼的碰撞检测,添加用户信息 | http://t.csdn.cn/fSIi9 | 243 |
刘晟珲 | 添加工具类,设置画笔,控制鱼的移动方向,登录页面设置 | http://t.csdn.cn/T0wBL | 238 |
七、项目git地址
地址:https://github.com/s-jm21/FeedingFrenzy
八、团队成员git提交记录截图
宋佳敏:
邓书勤:
刘晟珲 :