【Java小游戏】小球躲避游戏 图片轮播爆炸效果、边缘反弹、计时功能

功能

Java开发的小球躲避小游戏。通过上下左右按键控制小球移动,小球移动的方向包括:横向、纵向、斜向,小球具有初始生命值。小球通过移动来躲避炮弹,当小球碰到炮弹时,产生爆炸的动画效果。

使用双缓冲方式解决闪烁问题。

注释很全面,速度、初始子弹数量都可以通过全局变量修改。适合入门学习使用。

运行效果

目录结构

【Java小游戏】小球躲避游戏 图片轮播爆炸效果、边缘反弹、计时功能_第1张图片

代码

全部代码都在博客里,整个项目文件已经上传至:CSDN下载

MyGameFrame.java

package cn.sxt.game;

import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Date;

import javax.swing.JFrame;

public class MyGameFrame extends Frame
{

	// 双缓冲 解决闪烁问题
	private Image offScreenImage = null;

	public void update(Graphics g)
	{
		if (offScreenImage == null)
			offScreenImage = this.createImage(Constant.GAME_WIDTH, Constant.GAME_HEIGHT);// 这是游戏窗口的宽度和高度
		Graphics gOff = offScreenImage.getGraphics();
		paint(gOff);
		g.drawImage(offScreenImage, 0, 0, null);
	}

	Image bg = GameUtil.getImage("image/bg.jpg");
	Image planeImg = GameUtil.getImage("image/plane.png");
	Plane plane = new Plane(planeImg, 250, 250, Constant.PLANE_SPEED);
	Shell shell[] = new Shell[Constant.SHELL_NUM];
	{
		for (int i = 0; i < Constant.SHELL_NUM; i++)
		{
			shell[i] = new Shell();
		}
	}

	Explode explode = new Explode(0, 0);
	Date startTime = new Date();
	Date endTime;
	int period;// 持续时间

	@Override
	public void paint(Graphics g)// 自动被调用,g相当于一支画笔
	{
		super.paint(g);

		g.drawImage(bg, 0, 0, null);// 画背景

		plane.drawItSelf(g);// 画飞机
		// 画炮弹
		for (int i = 0; i < Constant.SHELL_NUM; i++)
		{
			shell[i].draw(g);

			// 检测是否飞机和炮弹相接触
			boolean touch = shell[i].getRect().intersects(plane.getRect());
			if (touch)
			{
				Constant.LIFE--;

				plane.live = false;
				explode.x = plane.x;
				explode.y = plane.y;

				System.out.println("碰到了!");
				explode.count %= 16;
				explode.Draw(g);

				endTime = new Date();
				period = (int) (endTime.getTime() - startTime.getTime()) / 1000;// 计算时间差

				Font f = new Font("宋体", Font.BOLD, 20);
				g.setFont(f);
				g.setColor(Color.WHITE);
				g.drawString("(" + period + "秒)剩余生命值:" + Constant.LIFE, (int) plane.x, (int) plane.y);
			}
		}
	}

	// 键盘监听
	class KeyMonitor extends KeyAdapter
	{
		@Override
		public void keyPressed(KeyEvent e)// 按下键
		{
			// TODO Auto-generated method stub
			super.keyPressed(e);// 38按向上 40按向下 37按向左 39按向右
			plane.KeyDown(e);
		}

		@Override
		public void keyReleased(KeyEvent e)// 抬起键
		{
			// TODO Auto-generated method stub
			super.keyReleased(e);
			plane.KeyUp(e);
		}
	}

	// 多线程的使用 反复重画窗口,当经常使用一个类时,可以把调用它放入类作为被调用类的内部类,这样方便调用
	class PaintThread extends Thread
	{
		@Override
		public void run()
		{
			// TODO Auto-generated method stub
			super.run();
			while (true)
			{
				repaint();
				try
				{
					Thread.sleep(Constant.SLEEP);
				} catch (InterruptedException e)
				{
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

	}

	// 初始化窗口函数
	public void launchFrame()
	{
		this.setTitle("魔鬼鱼");
		this.setVisible(true);
		this.setSize(Constant.GAME_WIDTH, Constant.GAME_HEIGHT);// 窗口大小 这里有何神奇的bug 垮外界屏幕的时候窗口无法缩小
		this.setLocation(500, 500);// 窗口位置

		// 匿名内部类 安卓编程到处都是 用来在关闭窗口之后结束程序
		this.addWindowListener(new WindowAdapter()
		{
			@Override
			public void windowClosing(WindowEvent e)
			{
				System.exit(0);// 0表示正常结束 负数表示异常结束
			}
		});

		new PaintThread().start();// 启动重画窗口的线程

		addKeyListener(new KeyMonitor());// 添加键盘监听
	}

	public static void main(String[] args)// 使用alt / 组合件可以快速补全
	{
		MyGameFrame fr = new MyGameFrame();
		fr.launchFrame();
	}
}

Explode.java

package cn.sxt.game;

import java.awt.Graphics;
import java.awt.Image;

public class Explode
{
	double x, y;// 爆炸的坐标

	static Image[] imgs = new Image[16];// 使用static避免图像被反复加载

	static// 静态初始化块
	{
		for (int i = 0; i < 16; i++)
		{
			imgs[i] = GameUtil.getImage("image/explode/e" + (i + 1) + ".gif");
			imgs[i].getWidth(null);
		}
	}

	int count;// 当前显示的图片序号

	public void Draw(Graphics g)
	{
		if (count <= 15)//轮播16张图片
		{
			System.out.println("轮播16张图片");
			g.drawImage(imgs[count], (int) x, (int) y, null);
			count++;
		}
	}

	//构造器
	public Explode(double x, double y)
	{
		this.x = x;
		this.y = y;
	}
}

GameObject.java

package cn.sxt.game;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;


//包含游戏中物体的常用属性,物体继承于这个类即可
public class GameObject
{
	Image img;	//图像路径名称
	double x,y;	//位置坐标
	int speed;	//速度
	int width,height;	//宽高
	
	//画出自己
	public void drawItSelf(Graphics g)
	{
		g.drawImage(img, (int)x, (int)y, null);
	}
	
	//矩形用于做碰撞检测 返回物体所在矩形
	public Rectangle getRect()
	{
		return new Rectangle((int)x,(int)y,width,height);
	}

	//构造器
	public GameObject(Image img, double x, double y, int speed, int width, int height)
	{
		super();
		this.img = img;
		this.x = x;
		this.y = y;
		this.speed = speed;
		this.width = width;
		this.height = height;
	}
	
	//重载的构造器 方便调用
	public GameObject(Image img, double x, double y)
	{
		super();
		this.img = img;
		this.x = x;
		this.y = y;
	}

	//无参构造器
	public GameObject()
	{
		super();
	}
}

GameUtil.java

package cn.sxt.game;

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;

public class GameUtil
{
	private GameUtil()// 工具类最好将构造器私有化
	{

	}

	// 返回指定路径文件的图片对象
	public static Image getImage(String path)
	{
		BufferedImage bi = null;
		try
		{
			URL u = GameUtil.class.getClassLoader().getResource(path);
			bi = ImageIO.read(u);
		} catch (IOException e)
		{
			e.printStackTrace();
		}
		return bi;
	}
}

Constant.java(类似于全局变量)

package cn.sxt.game;

//用于存储常量
public class Constant
{
	public static final int GAME_WIDTH = 500;
	public static final int GAME_HEIGHT = 500;
	public static final int SHELL_NUM = 40;
	public static final int PLANE_SPEED = 5;
	public static final int SHELL_SPEED = 3;
	public static final int SLEEP = 50;
	public static int LIFE = 1000;
}

Plane.java (plane就是斜眼笑的图片)

package cn.sxt.game;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;

public class Plane extends GameObject // Plane类继承 GameObject类
{
	public boolean up, down, left, right;
	boolean live = true;

	public void drawItSelf(Graphics g)
	{
		//if (live)
		//{
			if (up)
				y -= speed;
			if (down)
				y += speed;
			if (left)
				x -= speed;
			if (right)
				x += speed;

			g.drawImage(img, (int) x, (int) y, null);
		//} else
		//{
		//	System.out.println("碰到了额");
		//}

	}

	public void KeyDown(KeyEvent e)
	{
		switch (e.getKeyCode())
		{
		case 38:
			up = true;
			System.out.println(e.getKeyCode() + "按向上");
			break;
		case 40:
			down = true;
			System.out.println(e.getKeyCode() + "按向下");
			break;
		case 37:
			left = true;
			System.out.println(e.getKeyCode() + "按向左");
			break;
		case 39:
			right = true;
			System.out.println(e.getKeyCode() + "按向右");
			break;
		default:
			System.out.println(e.getKeyCode() + "按无效键");
		}
	}

	public void KeyUp(KeyEvent e)
	{
		up = down = left = right = false;
		System.out.println(e.getKeyCode() + "按键抬起");
	}

	public Plane(Image img, double x, double y, int speed)
	{
		this.img = img;
		this.x = x;
		this.y = y;
		this.speed = speed;
		this.width = img.getWidth(null);// 获得图片宽度
		this.height = img.getHeight(null);// 获得图片高度
	}
}

Shell.java(子弹)

package cn.sxt.game;

import java.awt.Color;
import java.awt.Graphics;

//子弹
public class Shell extends GameObject
{
	double degree;// 角度
	int xflag = 1;
	int yflag = 1;

	public Shell()
	{
		// 坐标
		x = 100;
		y = 100;

		// 长宽
		width = 10;
		height = 10;

		// 速度
		speed = Constant.SHELL_SPEED;

		// 角度生成
		degree = Math.random() * Math.PI * 2;// 产生一个0~2π之间的随机数
	}

	// 画炮弹
	public void draw(Graphics g)
	{
		Color c = g.getColor();// 保存之前的颜色
		g.setColor(Color.yellow);

		g.fillOval((int) x, (int) y, width, height);// 填充炮弹

		if (x <= 20 || x >= Constant.GAME_WIDTH - 20)
		{
			xflag *= -1;
		}
		if (y <= 20 || y >= Constant.GAME_HEIGHT - 20)
		{
			yflag *= -1;
		}

		x += speed * Math.cos(degree) * xflag;
		y += speed * Math.sin(degree) * yflag;

		g.setColor(c);// 用完之后把颜色还原
	}
}

你可能感兴趣的:(Java)