开始
我们先在这里创建五个java文件,后面创建一个文件夹存储图片,我就按照这几个文件作用展开描述
bg.java
package common;
import common.game_pic;
import java.awt.Color;
import java.awt.Graphics;
public class bg {
public void paintself(Graphics g)
{
g.drawImage(game_pic.bgimgage, 0,0 ,1440,900,null);
switch (newgame.state) {
case 0: {
game_pic.drawworld(g, "开始", Color.red, 80 , 500, 600);
// System.out.println("");
}
case 1:{
game_pic.drawworld(g, "积分"+game_pic.score,Color.orange, 50 , 300, 120);
game_pic.drawworld(g, "难度"+game_pic.level, Color.red, 50 , 600, 120);
game_pic.drawworld(g, "等级"+myfish.level, Color.red, 50 , 100, 120);
}
}
}
}
代码解释
先看看这些包
import java.awt.Color;
import java.awt.Graphics;,这两个是图像类
在bg.java中我们主要是实现一开始的背景加载功能,而又在类中创建一个paintself方法,这是为后面加载图像提供简便的实现。我们可以看到实现的是
public void paintself(Graphics g)
g.drawImage(game_pic.bgimgage, 0,0 ,1440,900,null);
switch (newgame.state) {
case 0: {
game_pic.drawworld(g, "开始", Color.red, 80 , 500, 600);
// System.out.println("");
}
case 1:{
game_pic.drawworld(g, "积分"+game_pic.score,Color.orange, 50 , 300, 120);
game_pic.drawworld(g, "难度"+game_pic.level, Color.red, 50 , 600, 120);
game_pic.drawworld(g, "等级"+myfish.level, Color.red, 50 , 100, 120);
这里传入的是Graphics g,这个是绘制图像的,一开始的时候加载我们的背景图像
然后呢在switch (newgame.state)来判断newgame.state,就是游戏现在的状态,一般游戏的时候前面都是有开始的画面
game_pic.drawworld(g, "开始", Color.red, 80 , 500, 600);
然后又安装一个公共的方法,这个主要是为了便于绘制文字
case 1:{
game_pic.drawworld(g, "积分"+game_pic.score,Color.orange, 50 , 300, 120);
game_pic.drawworld(g, "难度"+game_pic.level, Color.red, 50 , 600, 120);
game_pic.drawworld(g, "等级"+myfish.level, Color.red, 50 , 100, 120);
}
game_pic.java
package common;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
public class game_pic {
//分数统计
static int score=0;
//敌方鱼类集合
public static List<fish> enny_l=new ArrayList<fish>();//List<ennamy_l>: 这指定了变量的类型。List 是一个接口,它提供了操作对象集合(特别是序列)的方法。尖括
//号 <> 中的 ennamy_l 是一个泛型参数,它告诉编译器这个列表只能包含 ennamy_l 类型的对象。
//背景图类
public static Image bgimgage=Toolkit.getDefaultToolkit().createImage("D:\\programing\\javaide\\new_game\\src\\picture\\sea.png");
//敌方鱼类
public static Image dirmgage1=Toolkit.getDefaultToolkit().createImage("D:\\programing\\javaide\\new_game\\src\\picture\\fish_l.png");
public static Image dirmgager=Toolkit.getDefaultToolkit().createImage("D:\\programing\\javaide\\new_game\\src\\picture\\fish_r.png");
public static Image myfish_l=Toolkit.getDefaultToolkit().createImage("D:\\programing\\javaide\\new_game\\src\\picture\\fissl.gif");
public static Image myfish_r=Toolkit.getDefaultToolkit().createImage("D:\\programing\\javaide\\new_game\\src\\picture\\fissr.gif");
public static Image ffdir=Toolkit.getDefaultToolkit().createImage("D:\\programing\\javaide\\new_game\\src\\picture\\fish3.png");
public static Image ffdil=Toolkit.getDefaultToolkit().createImage("D:\\programing\\javaide\\new_game\\src\\picture\\fiss3.png");
public static Image bossImage=Toolkit.getDefaultToolkit().createImage("D:\\programing\\javaide\\new_game\\src\\picture\\boss.png");
static boolean up=false;
static boolean down=false;
static boolean left=false;
static boolean right=false;
//关卡等级设置,到了积分就设置不同的关卡难度
static int level=0;
//绘制文字的工具类
public static void drawworld (Graphics g,String str,Color color,int size,int x,int y) {
g.setColor(color);
g.setFont(new Font("仿宋", Font.BOLD,60));
g.drawString(str,x,y);
}
}
/*
在Java中,这段代码是创建并初始化一个静态`Image`对象的实例。这个对象`bgimage`被设置为使用`Toolkit`类加载并创建的一个图像。下面是对代码的逐行解释:
- `public static Image bgimage`: 这是在一个类中声明一个名为`bgimage`的公共静态变量,它的类型是`Image`。`Image`是AWT(Abstract Window Toolkit)包中的一个类,用于表示图像数据。
- `Toolkit.getDefaultToolkit()`: `Toolkit`类是一个抽象类,它提供了一种抽象的方式来处理本地图形和用户输入。`getDefaultToolkit()`是一个静态方法,它返回当前平台默认的工具包实例。
- `.createImage('image/sea.png')`: `createImage`是`Toolkit`类的一个方法,用于创建一个图像。它接受一个图像文件的路径作为参数。在这个例子中,路径是`'image/sea.png'`,这意味着它试图加载当前工作目录下`image`文件夹中的`sea.png`文件。
所以,整行代码的意思是:
声明一个名为`bgimage`的静态`Image`变量,并将其初始化为通过默认工具包加载的位于`image`文件夹中的`sea.png`文件。
不过,这段代码有几个潜在的问题:
1. 单引号`'`通常用于字符字面量。在Java中,字符串应该使用双引号`"`。因此,正确的路径应该是`"image/sea.png"`。
2. `createImage`方法可能不会立即加载图像,它可能返回一个异步加载的图像。因此,在使用图像之前,你可能需要确保图像已经完全加载。
3. 如果`sea.png`文件不存在或者路径不正确,`createImage`方法将返回一个不包含任何图像数据的`Image`对象。
正确的代码应该是:
```java
public static Image bgimage = Toolkit.getDefaultToolkit().createImage("image/sea.png");
```
在使用`bgimage`之前,你可能还需要确保图像已经加载完毕。这可以通过实现`ImageObserver`接口或使用`MediaTracker`类来实现。
*/
在这个java中主要实现的对于一些公共属性的封装
bgimgage=
dirmgage1=
dirmgager=
myfish_l=T
myfish_r=T
ffdir=Tool
ffdil=Tool
bossImage,对这些图片加载显现
up=fa
down=
left=
right这是对上下左右的实现逻辑
public static void drawworld (Graphics g,String str,Color color,int size,int x,int y) {
g.setColor(color);
g.setFont(new Font("仿宋", Font.BOLD,60));
g.drawString(str,x,y);
}
}这个是封装了g.drawString方法,不然的话每次都要写几遍
fish.java
package common;
import java.awt.*;
import common.game_pic;
public class fish {
//定义图片
Image img;
//定义坐标
int x;
int y;
int width;
int height;
//移动速度
int speed;
//方向定义
int dir=1;
//类型
int type;
//分值
int count;
//距离,用于检测自身
//距离,用于碰撞检测
public Rectangle getrec () {
return new Rectangle(x,y,width,height);//就相当于是返回一个对象
}
public void paintself(Graphics g ) {
g.drawImage(img,x,y,null);//背景面
}}
//敌方鱼左边的鱼
class ennamy_l extends fish{
// ennamy_l(){
//
// }构造方法
public ennamy_l() {
// TODO Auto-generated constructor stub
this.x=5;
this.y = (int)(Math.random() * 700 + 100);
this.width=45;
this.height=69;
this.speed=10;
this.count=5;
this.img=game_pic.dirmgage1;
}
}
class ennamy_r extends fish{
public ennamy_r() {
// TODO Auto-generated constructor stub
this.x=1400;
dir=-1;
this.y = (int)(Math.random() * 700 + 100);
this.width=45;
this.height=69;
this.speed=10;
this.count=5;
this.img=game_pic.dirmgager;
}
}
class ennamy_3 extends fish {
public ennamy_3() {
// TODO Auto-generated constructor stu() {
// TODO Auto-generated constructor stub
this.x=5;
this.y = (int)(Math.random() * 700 + 100);
this.width=45;
this.height=69;
this.speed=15;
this.type=2;
this.img=game_pic.ffdir;
}
@Override
public Rectangle getrec () {
return new Rectangle(x+40,y+30,width+5,height+5);//就相当于是返回一个对象
}
}
class ennamy_3r extends fish {
// TODO Auto-generated constructor stu() {
// TODO Auto-generated constructor stub
public ennamy_3r() {
// TODO Auto-generated constructor stu() {
// TODO Auto-generated constructor stub
this.x=1400;
this.y = (int)(Math.random() * 700 + 100);
this.width=45;
this.height=69;
this.speed=15;
this.type=2;
this.dir=-1;
this.img=game_pic.ffdil;
}
@Override
public Rectangle getrec () {
return new Rectangle(x+40,y+30,width+5,height+5);//就相当于是返回一个对象
}
}
class enn_bos extends fish{
public enn_bos() {
this.x=-1000;
this.y = (int)(Math.random() * 700 + 100);
this.width=340;
this.height=340;
this.speed=20;
this.type=10;
this.img=game_pic.bossImage;
// TODO Auto-generated constructor stub
}
}
在这里是我们的fish类,把这几个敌方的鱼构建
我们先创建一个公共鱼类,这个公共鱼类是敌方鱼类共有的
public class fish {
//定义图片
Image img;
//定义坐标
int x;
int y;
int width;
int height;
//移动速度
int speed;
//方向定义
int dir=1;
//类型
int type;
//分值
int count;
//距离,用于检测自身
//距离,用于碰撞检测
public Rectangle getrec () {
return new Rectangle(x,y,width,height);//就相当于是返回一个对象
}
public void paintself(Graphics g ) {
g.drawImage(img,x,y,null);//背景面
}}
所以后面我们把那些敌方类都继承到这个敌方公共类
敌法类
class ennamy_l extends fish{
// ennamy_l(){
//
// }构造方法
public ennamy_l() {
// TODO Auto-generated constructor stub
this.x=5;
this.y = (int)(Math.random() * 700 + 100);
this.width=45;
this.height=69;
this.speed=10;
this.count=5;
this.img=game_pic.dirmgage1;
}
}
然后又是类继承
class ennamy_r extends fish{
public ennamy_r() {
// TODO Auto-generated constructor stub
this.x=1400;
dir=-1;
this.y = (int)(Math.random() * 700 + 100);
this.width=45;
this.height=69;
this.speed=10;
this.count=5;
this.img=game_pic.dirmgager;
}
}
class ennamy_3 extends fish {
public ennamy_3() {
// TODO Auto-generated constructor stu() {
// TODO Auto-generated constructor stub
this.x=5;
this.y = (int)(Math.random() * 700 + 100);
this.width=45;
this.height=69;
this.speed=15;
this.type=2;
this.img=game_pic.ffdir;
}
@Override
public Rectangle getrec () {
return new Rectangle(x+40,y+30,width+5,height+5);//就相当于是返回一个对象
}
}
这样我们在需要不同等级下的不同敌方类的时候生成不同的鱼子
在boss类构建时class enn_bos extends fish{
public enn_bos() {
this.x=-1000;
this.y = (int)(Math.random() * 700 + 100);
this.width=340;
this.height=340;
this.speed=20;
this.type=10;
this.img=game_pic.bossImage;
// TODO Auto-generated constructor stub
}
}
然后又是myfish,即我自己的鱼类
myfish.java
package common;
import java.awt.*;
import common.game_pic;
public class myfish {
Image img=game_pic.myfish_l;
//坐标
int x=700;
int y=500;
int width=50;
int height=50;
//速度
int speed=20;
//等级
static int level=3;
public void paintself(Graphics g) {
logic();//判断下是哪个图片,后面再更改
g.drawImage(img,x,y,width+game_pic.score,height+game_pic.score,null);
}
public void logic() {
if (game_pic.up) {//错误消息 "Cannot make a static reference to the non-static field game_pic.up" 表示您正在尝试在一个静态上下文中引用一个非静态字段 game_pic.up。在 Java 中,静态成员(方法或变量)可以在没有类实例的情况下直
//接访问,但是非静态成员必须通过类的实例来访问。
y=y-speed;
}
if (game_pic.down) {//错误消息 "Cannot make a static reference to the non-static field game_pic.up" 表示您正在尝试在一个静态上下文中引用一个非静态字段 game_pic.up。在 Java 中,静态成员(方法或变量)可以在没有类实例的情况下直
//接访问,但是非静态成员必须通过类的实例来访问。
y=y+speed;
}
if (game_pic.left) {//错误消息 "Cannot make a static reference to the non-static field game_pic.up" 表示您正在尝试在一个静态上下文中引用一个非静态字段 game_pic.up。在 Java 中,静态成员(方法或变量)可以在没有类实例的情况下直
//接访问,但是非静态成员必须通过类的实例来访问。
x=x-speed;
img=game_pic.myfish_l;
}
if (game_pic.right) {//错误消息 "Cannot make a static reference to the non-static field game_pic.up" 表示您正在尝试在一个静态上下文中引用一个非静态字段 game_pic.up。在 Java 中,静态成员(方法或变量)可以在没有类实例的情况下直
//接访问,但是非静态成员必须通过类的实例来访问。
x=x+speed;
img=game_pic.myfish_r;
}
if (newgame.state==3) {
x=700;
y=500;
}
}
//检测矩形的方法,用碰撞检测
public Rectangle setRec() {
return new Rectangle(x,y,width+game_pic.score,height+game_pic.score);
}
}
我们在这个类中也是又paintself方法的
public void paintself(Graphics g) {
logic();//判断下是哪个图片,后面再更改
g.drawImage(img,x,y,width+game_pic.score,height+game_pic.score,null);
}
因为我们的鱼是要上下左右移动的,所以我们用logic来判断下
public void logic() {
if (game_pic.up) {//错误消息 "Cannot make a static reference to the non-static field game_pic.up" 表示您正在尝试在一个静态上下文中引用一个非静态字段 game_pic.up。在 Java 中,静态成员(方法或变量)可以在没有类实例的情况下直
//接访问,但是非静态成员必须通过类的实例来访问。
y=y-speed;
}
if (game_pic.down) {//错误消息 "Cannot make a static reference to the non-static field game_pic.up" 表示您正在尝试在一个静态上下文中引用一个非静态字段 game_pic.up。在 Java 中,静态成员(方法或变量)可以在没有类实例的情况下直
//接访问,但是非静态成员必须通过类的实例来访问。
y=y+speed;
}
if (game_pic.left) {//错误消息 "Cannot make a static reference to the non-static field game_pic.up" 表示您正在尝试在一个静态上下文中引用一个非静态字段 game_pic.up。在 Java 中,静态成员(方法或变量)可以在没有类实例的情况下直
//接访问,但是非静态成员必须通过类的实例来访问。
x=x-speed;
img=game_pic.myfish_l;
}
if (game_pic.right) {//错误消息 "Cannot make a static reference to the non-static field game_pic.up" 表示您正在尝试在一个静态上下文中引用一个非静态字段 game_pic.up。在 Java 中,静态成员(方法或变量)可以在没有类实例的情况下直
//接访问,但是非静态成员必须通过类的实例来访问。
x=x+speed;
img=game_pic.myfish_r;
}
if (newgame.state==3) {
x=700;
y=500;
}
},这里我们是用左右键的左右图片表达这种看法。而上下是用y的上下实现。那么
public Rectangle setRec() {
return new Rectangle(x,y,width+game_pic.score,height+game_pic.score);
}是用于碰撞检测的
new game.java
package common;
import javax.swing.Timer;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Iterator;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
public class newgame extends JFrame {
int width=1440;
int height=900;
//游戏状态
static int state=0;
bg bgg=new bg();
Image offimagescreen;
//敌方鱼类装载
fish ennFish,boss;
//随机生成鱼的数量,速度不要太快,控制生成
double random;
int time=0;//记录重绘次数
fish enfis;
myfish myfis=new myfish();
boolean isbooss=false;
public void launch() {
this.setVisible(true);
this.setSize(width,height);
this.setLocationRelativeTo(null);//如果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();//重新绘制
/*总的来说,repaint 方法属于 Component 类,这是所有Swing组件的父类。因此,所有继承自 Component 类的Swing组件,
* 如 JButton, JPanel, JFrame 等,都有 repaint 方法。repaint 是Swing组件更新显示的一个关键方法,用于确保用户界面能够反映组件的最新状态。
* repaint() 调用的位置是正确的,它位于状态改变之后,这样就可以确保组件在状态改变后能够重新绘制自己,以反映新的状态。
*/
}
if (e.getButton()==1&&state==2||state==3) {
regame();
}
}}
);
//键盘移动
this.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
super.keyPressed(e);
if (e.getKeyCode()==87) {
game_pic.up=true;
}
if (e.getKeyCode()==83) {
game_pic.down=true;
}
if (e.getKeyCode()==65) {
game_pic.left=true;
}
if (e.getKeyCode()==68) {
game_pic.right=true;
}
//空格键实现暂停功能
if (e.getKeyCode()==32) {
//用switch实现转换
switch (state) {
case 1:
state=4;
//这个时候进行提示语
game_pic.drawworld(getGraphics(), "游戏暂停", Color.red, 50, 600, 400);
break;
case 4 :
state=1;
}
}
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
super.keyReleased(e);
if (e.getKeyCode()==87) {
game_pic.up=false;
}
if (e.getKeyCode()==83) {
game_pic.down=false;
}
if (e.getKeyCode()==65) {
game_pic.left=false;
}
if (e.getKeyCode()==68) {
game_pic.right=false;
}
}
});//在Java中,this.addKeyListener(new KeyAdapter() { }); 这行代码是用于为当前组件(通常是窗口或者面板)添加键盘事件监听器。这里使用了KeyAdapter类,它是一个适配器类,用于简化键盘事件监听器的实现,因为
//它为KeyListener接口中的所有方法提供了空实现。
Timer tim=new Timer(100, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
time++;
// TODO Auto-generated method stub
repaint();
}
} );
tim.start();
// while (true) {
// repaint();
// try {
// Thread.sleep(400);
// } catch (InterruptedException e1) {
// // TODO Auto-generated catch block
// e1.printStackTrace();
// }}
}
/*
* DO_NOTHING_ON_CLOSE:当用户试图关闭窗口时,不执行任何操作。这通常用于在关闭窗口之前需要确认的情况。
HIDE_ON_CLOSE:当用户试图关闭窗口时,只隐藏窗口,但不会终止程序。这是 JFrame 的默认操作。
DISPOSE_ON_CLOSE:当用户试图关闭窗口时,会释放窗口的资源并隐藏窗口。如果所有窗口都被dispose,程序将结束。
EXIT_ON_CLOSE:当用户试图关闭窗口时,会退出应用程序。这通常用于程序的主窗口。
*/
@Override
public void paint(Graphics g) {
// super.paint(g);//createImage(width, height) 是一个方法调用,它创建了一个指定宽度和高度的空图像缓冲区。这个方
//法可以在 Component 类中找到,因此任何从 Component 继承的类(比如 Applet 或 JPanel)都可以使用这个方法。
if (offimagescreen == null) {
offimagescreen = createImage(width, height);
}
Graphics gimage=offimagescreen.getGraphics();//Graphics gimage = offimagescreen.getGraphics(); 这行代码是用来获取之前
//创建的屏幕外图像缓冲区(offimagescreen)的Graphics对象,这样你就可以在这个图像上进行绘制操作了
// 调用父类的paint方法来确保其他组件也被绘制
// 确保图像已经被加载
// 正确的方式是使用静态变量
// try {
g.drawImage(game_pic.bgimgage,0,0,null);//这个是绘制底板,缓存区域
//
//
//
// } catch (Exception e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
switch (state) {
case 0:
bgg.paintself(gimage);//背景面这些是将底板都加到缓存区域上
//
// gimage.setColor(Color.pink);//设置笔为粉红
// // gimage/设置字体
// gimage.setFont(new Font("仿宋", Font.BOLD,60));
// gimage.drawString("hello world",700,500);
break;
case 1:
bgg.paintself(gimage);
//定义分数
// gimage.setColor(Color.red);
// gimage.setFont(new Font("仿宋", Font.BOLD,60));
// String str = "开始!"+game_pic.score; // 示例文本
// int x = 200; // 示例 x 坐标
// int y = 120; // 示例 y 坐标
//
// gimage.drawString(str, x, y);
logic();//加载
// System.out.println(ennFish.x);
// ennFish.x+=30;
myfis.paintself(gimage);
// 取出小鱼
for (fish enl:game_pic.enny_l) {
enl.paintself(gimage);
}
if (isbooss) {
boss.x=boss.x+boss.dir*boss.speed;
boss.paintself(gimage);
}
break;
//
/*
* 在这个例子中,fruits 是一个包含三个字符串的数组。增强型 for 循环将遍历数组中的每个元素,并且每次迭代都将当前元素赋值给变量 fruit。然后,可以在循环体内使用 fruit 变量。
以下是增强型 for 循环的一般语法:
for (声明语句 : 表达式) {
// 循环体
}
声明语句:用于声明一个局部变量,该变量的类型必须与集合中元素的类型相同,或者是可以兼容的类型。
表达式:这个表达式必须是一个数组或者是一个实现了 Iterable 接口的集合。
增强型 for 循环在处理集合时非常方便,因为它简化了代码并减少了出错的可能性(比如索引越界错误)。不过,它也有一些限制,比如你不能在循环中使用索引来访问元素,也不能直接修改集合的结构(比如添加或删除元素)。如果需要这
*/
// System.out.println(ennFish.x);
// break;
case 2:
game_pic.drawworld(gimage,"失败",Color.orange,50,700,500);
if (isbooss) {
boss.paintself(gimage);
}
break;
case 3:
myfis.paintself(gimage);
gimage.setColor(Color.red);
gimage.setFont(new Font("仿宋", Font.BOLD,60));
gimage.drawString("积分"+game_pic.score, 200, 500);
gimage.drawString("胜利", 600, 500);
break;
case 4:
return;
}
g.drawImage(offimagescreen,0,0,null);//这里将所有缓存的一次加载到图片上
// g.drawImage(game_pic.dirmgage1,0,0,null);
}
void logic() {
//将添敌方小鱼添加到队列中
//管卡难度逻辑判断
if (game_pic.score<20) {
myfis.level=1;
}
// else if ( game_pic.score<100 &&game_pic.score>20) {
//
// game_pic.level=1;
// myfis.level=2;
//
//
// }
// else if (game_pic.score<50) {
//
// game_pic.level=2;
// myfis.level=2;
else if (game_pic.score>20) {
game_pic.level=2;
myfis.level=4;
}else if (game_pic.score>300) {
state=3;//游戏胜利并显示胜利
}
random=Math.random();//随机概率
//来看时间判断
switch (game_pic.level) {
case 4:
if(time%160==0) {
if (random<0.5) {
boss=new enn_bos();
isbooss=true;
}
}
break;
case 0:{
if(time%11==0) {
if (random<0.5) {
enfis=new enn_bos();
}
else {
enfis=new ennamy_r();
} //需要不同等级生成不同的鱼
game_pic.enny_l.add(enfis) ;
}}break;
case 1:{
if (time%20==0) {
System.out.println(game_pic.level);
if (random>0.5) {
enfis=new ennamy_3();
}
else {
enfis=new ennamy_3r();
}
game_pic.enny_l.add(enfis) ;
}
}
break;
//对每个鱼的添加移动,有移动方向
}
for (fish enl:game_pic.enny_l) {
enl.x=enl.x+enl.dir*enl.speed;
//我方鱼类与对方鱼类进行碰撞检测
if (isbooss) {
if (boss.getrec().intersects(enl.getrec())) {
enl.x=-200;
enl.y=-200;
}
if (boss.getrec().intersects((myfis.setRec()))) {
state=2;
}
}
if (myfis.setRec().intersects(enl.getrec())) {
if (myfish.level>=enl.type) {
enl.x=-200;
enl.y=-200;//通过坐标实现消失
game_pic.score=game_pic.score+enl.count;
}
else {
state=2;
}
//这里判断
// System.out.println("开始判断了");
}
//获取两个的交集
}
}//对于鱼类批量出来的
/*
* 在Java Swing中,paint 方法通常不需要手动调用,因为它是自动调用的。当你创建一个窗口(例如 JFrame)并设置为可见时,Swing 的绘图系统会在必要时调用 paint 方法来绘制组件。
在你提供的代码中,paint 方法被覆盖了,这意味着当Swing框架决定需要重绘窗口时(例如,窗口首次显示、窗口大小改变、窗口被遮挡后又重新显示等),它会自动调用这个方法。
*/
public void regame() {
game_pic.enny_l.clear();
time=0;
myfis.level=1;
game_pic.score=0;
myfis.x=700;
myfis.y=500;
myfis.width=50;
myfis.height=50;
boss=null;
isbooss=false;
}
public static void main(String[] args) {
newgame gamewine=new newgame();
gamewine.launch();
}
}
在这里的时候是我们主要实现的
先导入包
package common;
import javax.swing.Timer;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Iterator;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
我们这些导入的类有awt,有事件触发
这里的一个总类是
public class newgame extends JFrame {
JFrame,
int width=1440;
int height=900;
//游戏状态
先初次加载这些类
static int state=0;
bg bgg=new bg();
Image offimagescreen;
//敌方鱼类装载
fish ennFish,boss;
//随机生成鱼的数量,速度不要太快,控制生成
double random;
int time=0;//记录重绘次数
fish enfis;
myfish myfis=new myfish();
boolean isbooss=false;
public void launch() {
this.setVisible(true);
this.setSize(width,height);
this.setLocationRelativeTo(null);//如果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();//重新绘制
/*总的来说,repaint 方法属于 Component 类,这是所有Swing组件的父类。因此,所有继承自 Component 类的Swing组件,
* 如 JButton, JPanel, JFrame 等,都有 repaint 方法。repaint 是Swing组件更新显示的一个关键方法,用于确保用户界面能够反映组件的最新状态。
* repaint() 调用的位置是正确的,它位于状态改变之后,这样就可以确保组件在状态改变后能够重新绘制自己,以反映新的状态。
*/
}
if (e.getButton()==1&&state==2||state==3) {
regame();
}
}}
);
//键盘移动
this.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
super.keyPressed(e);
if (e.getKeyCode()==87) {
game_pic.up=true;
}
if (e.getKeyCode()==83) {
game_pic.down=true;
}
if (e.getKeyCode()==65) {
game_pic.left=true;
}
if (e.getKeyCode()==68) {
game_pic.right=true;
}
//空格键实现暂停功能
if (e.getKeyCode()==32) {
//用switch实现转换
switch (state) {
case 1:
state=4;
//这个时候进行提示语
game_pic.drawworld(getGraphics(), "游戏暂停", Color.red, 50, 600, 400);
break;
case 4 :
state=1;
}
}
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
super.keyReleased(e);
if (e.getKeyCode()==87) {
game_pic.up=false;
}
if (e.getKeyCode()==83) {
game_pic.down=false;
}
if (e.getKeyCode()==65) {
game_pic.left=false;
}
if (e.getKeyCode()==68) {
game_pic.right=false;
}
}
});//在Java中,this.addKeyListener(new KeyAdapter() { }); 这行代码是用于为当前组件(通常是窗口或者面板)添加键盘事件监听器。这里使用了KeyAdapter类,它是一个适配器类,用于简化键盘事件监听器的实现,因为
//它为KeyListener接口中的所有方法提供了空实现。
Timer tim=new Timer(100, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
time++;
// TODO Auto-generated method stub
repaint();
}
} );
tim.start();
// while (true) {
// repaint();
// try {
// Thread.sleep(400);
// } catch (InterruptedException e1) {
// // TODO Auto-generated catch block
// e1.printStackTrace();
// }}
}
我们这里是一个主要实现方法
然后其他判断方法
// super.paint(g);//createImage(width, height) 是一个方法调用,它创建了一个指定宽度和高度的空图像缓冲区。这个方
//法可以在 Component 类中找到,因此任何从 Component 继承的类(比如 Applet 或 JPanel)都可以使用这个方法。
if (offimagescreen == null) {
offimagescreen = createImage(width, height);
}
Graphics gimage=offimagescreen.getGraphics();//Graphics gimage = offimagescreen.getGraphics(); 这行代码是用来获取之前
//创建的屏幕外图像缓冲区(offimagescreen)的Graphics对象,这样你就可以在这个图像上进行绘制操作了
// 调用父类的paint方法来确保其他组件也被绘制
// 确保图像已经被加载
// 正确的方式是使用静态变量
// try {
g.drawImage(game_pic.bgimgage,0,0,null);//这个是绘制底板,缓存区域
//
//
//
// } catch (Exception e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
switch (state) {
case 0:
bgg.paintself(gimage);//背景面这些是将底板都加到缓存区域上
//
// gimage.setColor(Color.pink);//设置笔为粉红
// // gimage/设置字体
// gimage.setFont(new Font("仿宋", Font.BOLD,60));
// gimage.drawString("hello world",700,500);
break;
case 1:
bgg.paintself(gimage);
//定义分数
// gimage.setColor(Color.red);
// gimage.setFont(new Font("仿宋", Font.BOLD,60));
// String str = "开始!"+game_pic.score; // 示例文本
// int x = 200; // 示例 x 坐标
// int y = 120; // 示例 y 坐标
//
// gimage.drawString(str, x, y);
logic();//加载
// System.out.println(ennFish.x);
// ennFish.x+=30;
myfis.paintself(gimage);
// 取出小鱼
for (fish enl:game_pic.enny_l) {
enl.paintself(gimage);
}
if (isbooss) {
boss.x=boss.x+boss.dir*boss.speed;
boss.paintself(gimage);
}
break;
//
/*
* 在这个例子中,fruits 是一个包含三个字符串的数组。增强型 for 循环将遍历数组中的每个元素,并且每次迭代都将当前元素赋值给变量 fruit。然后,可以在循环体内使用 fruit 变量。
以下是增强型 for 循环的一般语法:
for (声明语句 : 表达式) {
// 循环体
}
声明语句:用于声明一个局部变量,该变量的类型必须与集合中元素的类型相同,或者是可以兼容的类型。
表达式:这个表达式必须是一个数组或者是一个实现了 Iterable 接口的集合。
增强型 for 循环在处理集合时非常方便,因为它简化了代码并减少了出错的可能性(比如索引越界错误)。不过,它也有一些限制,比如你不能在循环中使用索引来访问元素,也不能直接修改集合的结构(比如添加或删除元素)。如果需要这
*/
// System.out.println(ennFish.x);
// break;
case 2:
game_pic.drawworld(gimage,"失败",Color.orange,50,700,500);
if (isbooss) {
boss.paintself(gimage);
}
break;
case 3:
myfis.paintself(gimage);
gimage.setColor(Color.red);
gimage.setFont(new Font("仿宋", Font.BOLD,60));
gimage.drawString("积分"+game_pic.score, 200, 500);
gimage.drawString("胜利", 600, 500);
break;
case 4:
return;
}
g.drawImage(offimagescreen,0,0,null);//这里将所有缓存的一次加载到图片上
// g.drawImage(game_pic.dirmgage1,0,0,null);
同样是逻辑判断
void logic() {
//将添敌方小鱼添加到队列中
//管卡难度逻辑判断
if (game_pic.score<20) {
myfis.level=1;
}
// else if ( game_pic.score<100 &&game_pic.score>20) {
//
// game_pic.level=1;
// myfis.level=2;
//
//
// }
// else if (game_pic.score<50) {
//
// game_pic.level=2;
// myfis.level=2;
else if (game_pic.score>20) {
game_pic.level=2;
myfis.level=4;
}else if (game_pic.score>300) {
state=3;//游戏胜利并显示胜利
}
random=Math.random();//随机概率
//来看时间判断
switch (game_pic.level) {
case 4:
if(time%160==0) {
if (random<0.5) {
boss=new enn_bos();
isbooss=true;
}
}
break;
case 0:{
if(time%11==0) {
if (random<0.5) {
enfis=new enn_bos();
}
else {
enfis=new ennamy_r();
} //需要不同等级生成不同的鱼
game_pic.enny_l.add(enfis) ;
}}break;
case 1:{
if (time%20==0) {
System.out.println(game_pic.level);
if (random>0.5) {
enfis=new ennamy_3();
}
else {
enfis=new ennamy_3r();
}
game_pic.enny_l.add(enfis) ;
}
}
break;
//对每个鱼的添加移动,有移动方向
}
for (fish enl:game_pic.enny_l) {
enl.x=enl.x+enl.dir*enl.speed;
//我方鱼类与对方鱼类进行碰撞检测
if (isbooss) {
if (boss.getrec().intersects(enl.getrec())) {
enl.x=-200;
enl.y=-200;
}
if (boss.getrec().intersects((myfis.setRec()))) {
state=2;
}
}
if (myfis.setRec().intersects(enl.getrec())) {
if (myfish.level>=enl.type) {
enl.x=-200;
enl.y=-200;//通过坐标实现消失
game_pic.score=game_pic.score+enl.count;
}
else {
state=2;
}
//这里判断
// System.out.println("开始判断了");
}
//获取两个的交集
}
}//对于鱼类批量出来的
又实现重新开始的功能
public void regame() {
game_pic.enny_l.clear();
time=0;
myfis.level=1;
game_pic.score=0;
myfis.x=700;
myfis.y=500;
myfis.width=50;
myfis.height=50;
boss=null;
isbooss=false;
}
main方法总类,总类的实现
public static void main(String[] args) {
newgame gamewine=new newgame();
gamewine.launch();
}
}
这里我们来解释一下
流程
launch类加载
int width=1440;
int height=900;
//游戏状态
static int state=0;
bg bgg=new bg();
Image offimagescreen;
//敌方鱼类装载
fish ennFish,boss;
//随机生成鱼的数量,速度不要太快,控制生成
double random;
int time=0;//记录重绘次数
fish enfis;
myfish myfis=new myfish();
boolean isbooss=false;。将这些初始属性加载下
调用launch方法。launch方法中
this.setVisible(true);
this.setSize(width,height);
this.setLocationRelativeTo(null);//如果setLocationRelativeTo的参数是null,
//则窗口会相对于整个屏幕居中显示。如果参数是一个特定的组件
this.setResizable(false);//设置可调解大小的
this.setTitle("这是一个长久项目");
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);先把窗口初步设置下,然后增加监听事件this.addMouseListener(new MouseAdapter() {,在个里面是对state的一个判断,重新绘制,因为图像是要变化的
键盘事件的监听
this.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
super.keyPressed(e);
if (e.getKeyCode()==87) {
game_pic.up=true;
}
if (e.getKeyCode()==83) {
game_pic.down=true;
}
if (e.getKeyCode()==65) {
game_pic.left=true;
}
if (e.getKeyCode()==68) {
game_pic.right=true;
}
//空格键实现暂停功能
if (e.getKeyCode()==32) {
//用switch实现转换
switch (state) {
case 1:
state=4;
//这个时候进行提示语
game_pic.drawworld(getGraphics(), "游戏暂停", Color.red, 50, 600, 400);
break;
case 4 :
state=1;
}
}
}这里就是利用键盘上的不同对game_pic.left=实现更改,从而实现图片替换
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
super.keyReleased(e);
if (e.getKeyCode()==87) {
game_pic.up=false;
}
if (e.getKeyCode()==83) {
game_pic.down=false;
}
if (e.getKeyCode()==65) {
game_pic.left=false;
}
if (e.getKeyCode()==68) {
game_pic.right=false;
}
}这个就是放开按键后变化
实现定时重绘
Timer tim=new Timer(100, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
time++;
// TODO Auto-generated method stub
repaint();
}
} );
public void paint(Graphics g) {
方法,双缓存图片机制实现
if (offimagescreen == null) {
offimagescreen = createImage(width, height);
}
Graphics gimage=offimagescreen.getGraphics();//
switch (state) {
case 0:
bgg.paintself(gimage);//背景面这些是将底板都加到缓存区域上
//
// gimage.setColor(Color.pink);//设置笔为粉红
// // gimage/设置字体
// gimage.setFont(new Font("仿宋", Font.BOLD,60));
// gimage.drawString("hello world",700,500);
break;
case 1:
bgg.paintself(gimage);
//定义分数
// gimage.setColor(Color.red);
// gimage.setFont(new Font("仿宋", Font.BOLD,60));
// String str = "开始!"+game_pic.score; // 示例文本
// int x = 200; // 示例 x 坐标
// int y = 120; // 示例 y 坐标
//
// gimage.drawString(str, x, y);
logic();//加载
// System.out.println(ennFish.x);
// ennFish.x+=30;
myfis.paintself(gimage);
// 取出小鱼
for (fish enl:game_pic.enny_l) {
enl.paintself(gimage);
}
if (isbooss) {
boss.x=boss.x+boss.dir*boss.speed;
boss.paintself(gimage);
}
break;
判断加载不同的鱼类,这里也有个logic判断
然后进行logic方法构建,通过
if (game_pic.score<20) {
myfis.level=1;对分数的不同更改myfis.level的变更,后面
switch (game_pic.level) {
case 4:
if(time%160==0) {
if (random<0.5) {
boss=new enn_bos();
isbooss=true;
}
}
break;
case 0:{
if(time%11==0) {
if (random<0.5) {再用来通过game_pic.level)困难程度实现鱼类变化
鱼类添加
if(time%11==0) {
if (random<0.5) {
enfis=new enn_bos();
}
else {
enfis=new ennamy_r();
} //需要不同等级生成不同的鱼
game_pic.enny_l.add(enfis) ;
是通过enny_l这里的原先指定的列表添加
for (fish enl:game_pic.enny_l) {
enl.x=enl.x+enl.dir*enl.speed;
//我方鱼类与对方鱼类进行碰撞检测
if (isbooss) {
if (boss.getrec().intersects(enl.getrec())) {
enl.x=-200;
enl.y=-200;
}
if (boss.getrec().intersects((myfis.setRec()))) {
state=2;
}}把列表中每个成员拿出来,把这些enl.x=enl.x+enl.dir*enl.speed;对其x进行x方面的移动,我们再到这里if (myfis.setRec().intersects(enl.getrec())) {。来和矩形判断接触的距离,这样的话我们就能够实现吃不吃。就这样
enl.x=-200;
enl.y=-200;//通过坐标实现消实现了它的消失。
我们的regame是重新开始,就是重置选分 public void regame() { game_pic.enny_l.clear(); time=0; myfis.level=1; game_pic.score=0; myfis.x=700; myfis.y=500; myfis.width=50; myfis.height=50; boss=null; isbooss=false; }