java小游戏大鱼吃小鱼入门(15min写一个小游戏)

【mie haha的博客】转载请注明出处(万分感谢!):
https://blog.csdn.net/qq_40315080/article/details/82823954

写代码前分析下游戏的各个部分

1.游戏构成:
大鱼吃小鱼=主角鱼+其他各种鱼(自由鱼)+游戏按钮+游戏背景
2.游戏过程:
主角鱼遇到比自己小的鱼:吃掉–>自身size变大
主角鱼遇到比自己大的鱼:被吃掉–>自由鱼size变大,游戏结束

接下来开始写代码:

事前准备:
1.画图片(比如在网上下载了鱼的图片,想要在界面上画不同的鱼,而不是画什么简单的○,□):举例格式如下:

Toolkit tool = Toolkit.getDefaultToolkit();

Image myfishshape = tool.getImage(Fish.class.getResource("myfish_zheng.png"));

首先显示游戏的界面:

界面中需要有主角鱼,一堆自由鱼,游戏按钮和游戏背景
这里主角鱼和自由鱼其实都是鱼,只是主角鱼受鼠标控制,游的速度不同,可以把所有的鱼看成一个整体队列,这样写很方便

```public class Framefish extends JFrame {
	
	//当前画布的画笔
	Graphics g;
    //画布里所有要移动的小?
    ArrayList<Fish> list = new ArrayList<Fish>();
	
	//函数名字不能叫show
	public void showui(){
		
		//设置窗体
		this.setTitle("大鱼吃小鱼");
		this.setSize(1200,1000);
		this.setLocationRelativeTo(null);
		this.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
		this.setBackground(Color.white);
		FlowLayout flow = new FlowLayout();
		this.setLayout(flow);
	   
		//设置按钮
		Dimension demension = new Dimension(80,80);
	    JButton button1 = new JButton("开始");
	    JButton button2 = new JButton("暂停");
	    JButton button3 = new JButton("结束");
	    JButton button4 = new JButton("恢复");
	    button1.setPreferredSize(demension);
	    button2.setPreferredSize(demension);
	    button3.setPreferredSize(demension);
	    button4.setPreferredSize(demension);
	    this.add(button1);
	    this.add(button2);
	    this.add(button3);
	    this.add(button4);
	    //按钮添加监听器,实现开始暂停恢复结束
	    buttonlisenenr bl = new buttonlisenenr(this,this.list,this.paopaolist);
	    button1.addActionListener(bl);
	    button2.addActionListener(bl);
	    button3.addActionListener(bl);
	    button4.addActionListener(bl);
	    
	    //设置窗体可见
		this.setVisible(true);
		g=this.getGraphics();
	
	}

鱼队列中的每一条鱼都有游的速度,大小的区别,同时这些鱼需要判断是否被吃掉获吃掉其他鱼,并且要出现在屏幕上(即被画下来),在屏幕上游动(即变化位置运动)对这些属性进行定义,创建鱼类:

public class Fish {

// 出现的位置和本身的大小
int x, y, size, speedx, speedy;
// 在次画布上画下,再把次画布画在界面上
Graphics g;
Framefish frame;

// 在鱼队列的生成中对每一个生成的小鱼初始化
public Fish(int x, int y, int speedx, int speedy, int size, Graphics g, Framefish frame) {
	this.x = x;
	this.y = y;
	this.speedx = speedx;
	this.speedy = speedy;
	this.size = size;
	this.g = g;
	this.frame = frame;
}

// 还活着就画下来,否则马上把这条鱼从队列中移除
public  void draw(Graphics g,ArrayList<Fish> list) {

		}

// 从队列中第一个鱼开始判断,大的鱼吃掉小的鱼
public void eat(ArrayList<Fish> list) {
	
}

// 每条鱼都有横纵速度,只要再界面内就继续移动,但不一定画出
public void move(ArrayList<Fish> list) {

}

}

上面的Fish类中用来画下鱼的draw函数,用来判断鱼吃掉或被吃掉的函数eat函数,用来让鱼游动起来的函数move都没有写内容,接下来将它们一一补全:

最简单的move函数用来使鱼游动:即不断变化鱼的位置x,y,每条鱼都有自己的速度,只要x按照speedx移动,y按照speedy移动即可,主角鱼例外,它只受鼠标控制,自己没有速度,即初始速度为0

public void move(ArrayList<Fish> list) {
			if (this.x>=0 && this.x+this.size<= frame.getWidth())
				x = x + speedx;
			if (this.y >= 0 && this.y+this.size<= frame.getHeight())
				y = y + speedy;
	}

画鱼其实是把鱼图案放在一个矩形内,将这个矩形画下(g.drawImage(图片名称,矩形左上角横坐标x,矩形左上角纵坐标y,矩形长,矩形宽,位置【一般写为null即可】)(因为试想按照鱼的不规则轮廓来画太困难了,我没有找到这样的方法),在画鱼的时候如果这条鱼按照速度已经游出了界面,这条鱼就不再出现在屏幕中,不再考虑这条鱼,就把这条鱼从所有要出现的鱼列中删掉(这里使用list.remove()来删除),这样就避免出现在看不到的界面外还在进行大鱼吃小鱼而游戏者却因为看不到被吃鱼的过程只看到吃鱼结果而莫名其妙的情况。

    Toolkit tool = Toolkit.getDefaultToolkit();
	Image myfishshape = tool.getImage(Fish.class.getResource("myfish_zheng.png"));
	Image myfishshape_to_right = tool.getImage(Fish.class.getResource("myfish_fan.png"));
	Image fishshape1 = tool.getImage(Fish.class.getResource("knewfish1.png"));
	Image fishshape2 = tool.getImage(Fish.class.getResource("koufish3.png"));
	Image fishshape4 = tool.getImage(Fish.class.getResource("knewfish4.png"));


// 还活着就画下来,否则马上把这条鱼从队列中移除
	public  void draw(Graphics g,ArrayList<Fish> list) {
		if (this.size > 0) {
			// 不是我的鱼
			if (this != list.get(0)) {
				//超出画面就删掉这个鱼
				if(this.x+this.size>=frame.getWidth())list.remove(this);
				else if(this.y+this.size>=frame.getHeight())list.remove(this);
				else if (this.size <= 60)
				g.drawImage(fishshape1, x, y, size-10, size-10, null);
				else if (this.size > 60 && this.size <= 120)
				g.drawImage(fishshape2, x, y, size+20, size+20, null);
				else if (this.size > 120)
				g.drawImage(fishshape4, x, y, size, size, null);
				System.out.println(this.size);
			}
			//是我的鱼
			else if (this == list.get(0)){
					g.drawImage(myfishshape, x, y, size, size, null);
		} 
		else if (this.size <= 0&&this!=list.get(0))
		{
			list.remove(this);
		}
	}

接下来就是游戏的关键–判断鱼是吃掉其他鱼还是被其他鱼吃掉。每一时刻,每条在屏幕上出现的鱼,都可以吃其他鱼或者被吃掉(假设没有无敌鱼),对每条鱼,都需要判断它与屏幕上其他所有鱼的size关系:(注意:只需要统一判断每条鱼能否吃掉其他的鱼即可,被吃掉的鱼删掉不再考虑)

public void eat(ArrayList<Fish> list) {
		 //Music musiceat = new Music();
		System.out.println(">>>>>"+list.size());
		for (int i = 0; i < list.size(); i++) {
			// 矩形相交就判断size
			Fish fish1 = this;
			Fish fish2 = list.get(i);
			if (fish1 != fish2
					&& ((fish1.x >= fish2.x && fish1.x <= fish2.x + fish2.size && fish1.y >= fish2.y
							&& fish1.y <= fish2.y + fish2.size)
					|| (fish1.x >= fish2.x && fish1.x <= fish2.x + fish2.size && fish1.y + fish1.size >= fish2.y
							&& fish1.y + fish1.size <= fish2.y + fish2.size)
					|| (fish1.x + fish1.size >= fish2.x && fish1.x + fish1.size <= fish2.x + fish2.size
							&& fish1.y >= fish2.y && fish1.y <= fish2.y + fish2.size)
					|| (fish1.x + fish1.size >= fish2.x && fish1.x + fish1.size <= fish2.x + fish2.size
							&& fish1.y + fish1.size >= fish2.y && fish1.y + fish1.size <= fish2.y + fish2.size))) {

				if (fish1.size > fish2.size) {
					fish1.size += fish2.size / 4;
					fish2.size = 0;
					//musiceat.playEatMusic();
				} else if (fish1.size < fish2.size) {
					fish2.size += fish1.size / 4;
					fish1.size = 0;
					 //musiceat.playEatMusic();
				}
			}
		}
	}

判断能否吃掉其他的鱼时,因为画鱼其实是画鱼图案所在的矩形,所以只需要判断两个矩形是否相交(在纸上稍稍画一下,可以发现只有4种情况,列举一下即可),如果相交就大的吃掉小的,所画矩形的大小可表示鱼的size(drawImage函数的第3,4个参数)。

每条鱼都已经写好,现在只需把所有这些鱼都放进一个队列里面,让它们隔一段时间就出现一个即可,此时需要用线程来控制鱼出现的速度(如果不用线程控制,所有的鱼将同时出现,屏幕上全都是鱼,影响游戏效果)

public class FishList extends Thread{

	ArrayList<Fish> list;
	Graphics g;
	Framefish frame;
	Random random;
	int sleeptime = 2000;
	
	public FishList(Graphics g,Framefish frame,ArrayList<Fish> list){
		this.g=g;
		this.frame=frame;
		this.list=list;
		random = new Random();
	}
	
	public void run(){
		while(Framefish.over==0&&true){
			//设置其他鱼的各种参数随机,创建鱼,加入鱼队列
			//从左边产生,最小size=20,最大size=200
			int x=0;
			int y=random.nextInt(800)+20;
			int speedx=random.nextInt(40)+20;
			int speedy=random.nextInt(5)+0;
			int size=random.nextInt(200)+20;
			Fish fish = new Fish(x,y,speedx,speedy,size,g,frame);
			list.add(fish);
			
			
			//慢慢产生,每休眠3000时添加一条鱼
			try {
				Thread.sleep(sleeptime);//休眠3000
			} catch (InterruptedException e) {
			}
		}
	}
}

以上在产生每条鱼时借用了随机数random来使鱼在随机位置,以随机速度游动。

这样所有的自由鱼在产生时都有了自己的初始位置,速度,可以游动了,但主角鱼还需要鼠标来控制,在鼠标监听器中写鼠标控制主角鱼的方法:

public class mouselisener extends MouseAdapter{

	Graphics g;
	Frame frame;
	Fish myfish;
	ArrayList<Fish> list;
	float x,y;

	public mouselisener(Graphics g, Frame mf, ArrayList<Fish> list) {
		this.g = g;
		this.frame = mf;
		this.list = list;
		this.myfish = list.get(0);
	}

	public void mouseClicked(MouseEvent e) {}

	public void mouseDragged(MouseEvent e) {}

	public void mouseEntered(MouseEvent e) {}

	public void mouseExited(MouseEvent e) {}

	public void mouseMoved(MouseEvent e) {
		myfish.x = e.getX();
		myfish.y = e.getY();
	}

	public void mousePressed(MouseEvent e) {}

	public void mouseReleased(MouseEvent e) {}

	public void mouseWheelMoved(MouseWheelEvent e) {}

	public void actionPerformed(ActionEvent e) {}

}

现在,所有的鱼都已经就绪,它们都可以按照需要进行活动(移动,吃鱼或被吃)了,但它们都是只能在某一时刻完成,游戏需要的效果是让这些鱼连续地游动,产生类似动画的效果,这就需要间隔很短的时间就在屏幕上画一次所有的鱼,时间越短,画面越连贯(视觉暂留),这同样需要用线程控制【注意:每隔一段时间画一次所有的鱼,之前所画的鱼如果不擦掉,那么你将看到鱼运动的“轨迹”(一条线),而不是动画的感觉,这就需要画所有的鱼时,把底层的背景图片画布也再画一次,这样就覆盖了之前所画的鱼的痕迹,就不会出现一条线的情况了】—它有名字哒:次画布方法

public class Threadfish extends Thread{

	Graphics g;
	Frame frame;
	ArrayList<Fish> list;
	public static boolean start = false,pause = false;
	
	public Threadfish(Graphics g,Frame frame,ArrayList<Fish> list,ArrayList<PaoPao> paopaolist){
		this.g=g;
		this.frame=frame;
		this.list=list;
		this.paopaolist=paopaolist;
	}
	
	public void run(){
		
		//创建次画布
		Image im = frame.createImage(frame.getWidth(),frame.getHeight());
		Graphics g2 = im.getGraphics();
		Toolkit tool = Toolkit.getDefaultToolkit();
		Image fishbackground= tool.getImage(Fish.class.getResource("sea.png"));
		
		if(start){
			System.out .println("222");
			while(pause){
				
			g2.drawImage(fishbackground,0,0,frame.getWidth(), frame.getHeight(),0,0,400,400,null);
			
			for(int i=0;i<list.size();i++){
				Fish fish = list.get(i);
				fish.draw(g2,list);
				
				fish.eat(list);
				
				fish.move(list);
			}
			
			try {
				Thread.sleep(60);
			} catch (InterruptedException e) {
				
			}
			
			g.drawImage(im,0,0,frame);
			if(list.get(0).size<=0){
				String a = new String("game over");
				g.setFont(new Font("", Font.BOLD, 50));
				g.drawString(a,500,500);
				//Toolkit toolfalse = Toolkit.getDefaultToolkit();
				//image FALSE= toolfalse.getImage(Fish.class.getResource("fish.gif"));
				//g.drawImage(FALSE, 600,600,200,200,null);
				Framefish.over=1;
				start=false;pause=false;
			}
			else if(list.get(0).size>=180){
				String a = new String("胜利");
				g.setFont(new Font("", Font.BOLD, 50));
				g.drawString(a,500,500);
				start=false;pause=false;
			}
		}
	}	
	}
}

好的,一切就绪,已经把所有的步骤都统一在了线程Threadfish中,只需要在main函数中启动即可啦:

	public static void main(String[] args){
	
	//创建界面,界面出现
	Framefish frame = new Framefish();
	frame.showui(); 
	
	//产生自己的鱼,初始size=60
	Random random = new Random(); 
	Fish myfish = new Fish(600,600,0,0,60,frame.g,frame);
	frame.list.add(myfish);
	
	//界面添加鼠标监听器
	mouselisener ml = new mouselisener(frame.g,frame,frame.list);
	System.out.println(frame.list.size());
	frame.addMouseMotionListener(ml);
	frame.addMouseListener(ml);
	
	//产生鱼队列
	FishList fishlist = new FishList(frame.g,frame,frame.list);
	fishlist.start();
	
	Threadfish threadfish = new Threadfish(frame.g,frame,frame.list,frame.paopaolist);
	threadfish.start();
	
}

大鱼吃小鱼简易版完成!
运行图片:
在这里插入图片描述
(以上代码中有借线程开始,结束,暂停,恢复的实现,没有细说,感兴趣的朋友可以看下一篇)
ps:如果你还想加入音乐,想让主角鱼的头方向像4399小游戏里那样随你的鼠标移动而变化,想加入一些小效果使游戏背景看起来更自然逼真,可以看看下一篇

仍在入门,写得匆忙,若有错误,欢迎指出

  • 37
    点赞
  • 262
    收藏
    觉得还不错? 一键收藏
  • 34
    评论
/*主框架类*/ import java.awt.*; import java.awt.event.*; import javax.swing.*; public class MyJFrame extends JFrame { private static final long serialVersionUID = 1L; public MyJFrame()//构造方法 { init();//自定义方法1 setVisible(true);//可见 } private void init()//自定义方法 { Toolkit tlk = Toolkit.getDefaultToolkit(); Image tittle = tlk.getImage("pho/最小化.png");//添加最小化图标 setIconImage(tittle); setUndecorated(true);//不启用标题栏 MyJPanel jpanel=new MyJPanel(); setContentPane(jpanel);//作用类似于add() setSize(1200,700);//设置窗口大小 setResizable(false);//不可改变大小 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭 setLocationRelativeTo(null);//窗口出现在桌面中间 /*******把鼠标隐藏*****/ Toolkit tool = Toolkit.getDefaultToolkit(); Image mouse=tool.getImage("pho/mouse.png");//给鼠标加一张透明的图片 Cursor cursor = tool.createCustomCursor(mouse,new Point(),null); setCursor(cursor); addKeyListener((KeyListener) new MyKeyAdapter());//设置键盘监听,用来退出游戏 } private class MyKeyAdapter extends KeyAdapter//键盘监听适配器 { public void keyPressed(KeyEvent e) { super.keyPressed(e); int event = e.getKeyCode();//接受键盘事件 if(event == KeyEvent.VK_ESCAPE)//按ESC退出 { int result = JOptionPane.showConfirmDialog(null, "是否退出游戏", "提示", JOptionPane.OK_CANCEL_OPTION); if(result == JOptionPane.OK_OPTION)//点击确定退出 { System.exit(0); } } } } }
好的,我可以为您提供一个简单的 Java 大鱼吃小鱼游戏的示例代码,您可以根据需要进行修改和优化。 ```java import java.awt.Color; import java.awt.Graphics; import java.awt.Point; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.ArrayList; import java.util.List; import java.util.Random; import javax.swing.JFrame; import javax.swing.JPanel; public class FishGame extends JPanel implements KeyListener, Runnable { // 游戏界面大小 private static final int WIDTH = 500; private static final int HEIGHT = 500; // 食物数量 private static final int FOOD_COUNT = 50; // 鱼的大小 private static final int FISH_SIZE = 30; // 食物的大小 private static final int FOOD_SIZE = 10; // 鱼的速度 private static final int FISH_SPEED = 5; // 鱼的坐标 private int fishX = WIDTH / 2; private int fishY = HEIGHT / 2; // 食物的列表 private List<Point> foodList = new ArrayList<Point>(); // 是否结束游戏 private boolean gameOver = false; public FishGame() { // 设置游戏窗口大小 setPreferredSize(new java.awt.Dimension(WIDTH, HEIGHT)); // 添加键盘监听器 addKeyListener(this); // 初始化食物列表 initFoodList(); // 启动游戏线程 new Thread(this).start(); } @Override public void paint(Graphics g) { // 清空画布 g.clearRect(0, 0, WIDTH, HEIGHT); // 绘制食物 for (Point food : foodList) { g.setColor(Color.RED); g.fillOval(food.x, food.y, FOOD_SIZE, FOOD_SIZE); } // 绘制鱼 g.setColor(Color.BLUE); g.fillOval(fishX, fishY, FISH_SIZE, FISH_SIZE); // 绘制游戏结束信息 if (gameOver) { g.setColor(Color.BLACK); g.drawString("Game Over!", WIDTH / 2 - 30, HEIGHT / 2); } } private void initFoodList() { // 随机生成食物的坐标 Random random = new Random(); for (int i = 0; i < FOOD_COUNT; i++) { int x = random.nextInt(WIDTH - FOOD_SIZE); int y = random.nextInt(HEIGHT - FOOD_SIZE); foodList.add(new Point(x, y)); } } private void moveFish(int dx, int dy) { // 计算鱼的新坐标 int newX = fishX + dx; int newY = fishY + dy; // 判断是否超出边界 if (newX < 0 || newX > WIDTH - FISH_SIZE || newY < 0 || newY > HEIGHT - FISH_SIZE) { return; } // 判断是否与食物碰撞 for (Point food : foodList) { if (newX + FISH_SIZE > food.x && newX < food.x + FOOD_SIZE && newY + FISH_SIZE > food.y && newY < food.y + FOOD_SIZE) { foodList.remove(food); break; } } // 更新鱼的坐标 fishX = newX; fishY = newY; // 判断是否游戏结束 if (foodList.size() == 0) { gameOver = true; } } @Override public void keyPressed(KeyEvent e) { switch (e.getKeyCode()) { case KeyEvent.VK_UP: moveFish(0, -FISH_SPEED); break; case KeyEvent.VK_DOWN: moveFish(0, FISH_SPEED); break; case KeyEvent.VK_LEFT: moveFish(-FISH_SPEED, 0); break; case KeyEvent.VK_RIGHT: moveFish(FISH_SPEED, 0); break; } } @Override public void keyReleased(KeyEvent e) { } @Override public void keyTyped(KeyEvent e) { } @Override public void run() { while (!gameOver) { try { Thread.sleep(50); repaint(); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { JFrame frame = new JFrame("Fish Game"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); FishGame game = new FishGame(); frame.add(game); frame.pack(); frame.setResizable(false); frame.setVisible(true); game.requestFocus(); } } ``` 这个示例代码中,我们使用 Java Swing 框架实现了一个简单的游戏窗口,并在其中绘制了一个蓝色的鱼和一些红色的食物。通过键盘上下左右键控制鱼的移动,当鱼与食物发生碰撞时,食物会消失,直到所有的食物都被吃掉,游戏结束。
评论 34
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值