教你用JAVA写个小游戏[通俗易懂]
大家好,又见面了,我是你们的朋友全栈君。
上周上课的时候老师让用Java写个小程序,我本想写一个经典的飞机大战游戏来着,可以后来突发奇想就写成了这个
一、整体思路
- 继承窗体类,复写窗体刷新
- 添加按键监听
- 游戏结束界面
- 王思聪类和热狗类 移动轨迹计算
- 判断碰撞 音乐播放
- 不断刷新窗体 处理细节
二、编码
1.图片
首先你要找到图片,可以百度一张,然后用ps切开,再找一张背景图片就搞定了
你还需要一个加载图片的工具类,可以使用getResource得到图片的URL路径,然后使用java自带的工具类ImageIO来读取图片
public class GameUtil {
public static Image getImage(String path){
URL url=GameUtil.class.getClassLoader().getResource(path);
BufferedImage img=null;
try {
img = ImageIO.read(url);
} catch (IOException e) {
e.printStackTrace();
}
return img;
}
}
2.窗体
写一个类来继承窗体,为其设置宽高,位置,关闭设置,可否缩放大小
复写它的更新和绘画方法,以后要在里面写绘画思聪和热狗和碰撞判断逻辑
为其添加按键监听事件,在这里处理按键的点击和释放,以此来实现思聪的移动
public void launchFrame(){
setSize(width,height);
setResizable(false);
setLocation(200,20);
setVisible(true);
addKeyListener(new KeyMoniter());
addWindowListener(new WindowAdapter(){
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
@Override
public void paint(Graphics graphics) {}
@Override
public void update(Graphics g){}
class KeyMoniter extends KeyAdapter{
@Override
public void keyPressed(KeyEvent e) {
//按键按下
}
@Override
public void keyReleased(KeyEvent e) {
//按键抬起
}
}
3.思聪和热狗
首先要有一个位置,还要能移动,其实也就是不断的计算位置和把图片画上去的过程
定义一些思聪的属性,并在构造方法中初始化这些属性
boolean left,right,down,up;
public int x,y,width,height;
Image img ;
public Plane(String img_path,int x, int y){
this.img = GameUtil.getImage(img_path);
this.x = x;
this.y = y;
width = img.getWidth(null);
height = img.getWidth(null);
live = true;
}
把思聪画上去
public void draw(Graphics g){
if(live){
g.drawImage(img, x, y, null);
move();
}
}
接下来最重要的就是计算思聪的位置了,为什么要把位置计算写到画思聪的方法里呢?主要是考虑这样的一种情况,如果你把方法计算写到按键按下或者释放里面,那么你想移动思聪的位置就得疯狂按键盘,要想长按按键来控制移动就要吧移动方法写到画思聪的方法里面,然后用按键的按下和释放来控制是否移动。
移动的时候还要考虑到边界的情况
public void move(){
if(left&&x>=10){
x -= 10;
}
if(up&&y>=30){
y -= 10;
}
if(right&&x<=FeiJiGame.width-60){
x += 10;
}
if(down&&y<=FeiJiGame.height -60){
y += 10;
}
}
public void KeyPressedControlDirection(KeyEvent e){
int key_code = e.getKeyCode();
if(key_code == 37){
left = true;
}
if(key_code == 38){
up = true;
}
if(key_code == 39){
right = true;
}
if(key_code == 40){
down = true;
}
}
public void KeyRelasedControlDirection(KeyEvent e){
int key_code = e.getKeyCode();
if(key_code == 37){
left = false;
}
if(key_code == 38){
up =false;
}
if(key_code == 39){
right = false;
}
if(key_code == 40){
down = false;
}
}
最后提供两个方法来改写思聪的生存
对于热狗类就简单多了,就是让它不断的跑,不需要响应按键事件
定义一些属性和在构造方法中初始化
double speed=15;
double degree;
public double x,y;
public int width,height;
Image img;
public Bullet(String img_path){
img=GameUtil.getImage(img_path);
degree = Math.random()*Math.PI*2;
x=FeiJiGame.width/2;
y=FeiJiGame.height/2;
width = 10;
height = 10;
}
随机的degree的用途是让它们的初始方向不同,使用sin和cos函数来控制热狗的移动,同时也要注意边界
public void draw(Graphics g){
g.drawImage(img, (int)x, (int)y, null);
x += speed*Math.cos(degree);
y += speed*Math.sin(degree);
if(x>FeiJiGame.width-width||x<width){
degree=Math.PI-degree;
}
if(y>FeiJiGame.height-height||y<height){
degree=-degree;
}
}
4.碰撞检测和音乐播放
在java的awt里面有一个矩形类可以判断两个矩形是否有重叠部分,有重叠说明就碰撞上了
Rectangle bulletRectangle = new Rectangle((int)bullet.x,(int)bullet.y,bullet.width,bullet.height);
Rectangle planeRectangle = new Rectangle(plane.x,plane.y,plane.width,plane.height);
boolean collide= bulletRectangle.intersects(planeRectangle);
音乐播放可以使用第三方的库,jl-1.0.1.jar,因为可能连续吃到热狗,所以需要多线程播放音乐
class MusicPlayer implements Runnable{
@Override
public void run() {
try {
new Player(new FileInputStream(FeiJiGame.class.getClassLoader().getResource("raw/music.mp3").getPath().substring(1))).play();
} catch (Exception e) {
e.printStackTrace();
}
}
}
5.完成
剩下的就是窗体的刷新,这个可以开一个线程来做
class PaintThread extends Thread {
@Override
public void run() {
while(!Thread.currentThread().isInterrupted()){
repaint();
try {
Thread.sleep(40);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
游戏右上方要显示现在的游戏时间,结束也要显示一些文字信息,写了一个工具类
使用font控制字体,graphics.setFont设置字体,drawString画上去
public void printInfo(Graphics g,String message,int size,int x,int y){
g.setColor(Color.white);
Font f = new Font("宋体",Font.BOLD,size);
g.setFont(f);
g.drawString(message, x,y);
}
游戏结束时显示一些信息,根据时间判断给出等级
private void gameOver(Graphics graphics) {
printInfo(graphics,"GAME OVER",80,270,300);
int survivalTime = (int)(endTime.getTime()-starTime.getTime())/1000;
printInfo(graphics,"吃热狗时间:"+survivalTime+"秒",40,300,400);
switch(survivalTime/10){
case 1:
printInfo(graphics,"独孤求败",50,350,500);
break;
case 2:
printInfo(graphics,"登堂入室",50,350,500);
break;
case 3:
printInfo(graphics,"小有成就",50,350,500);
break;
default:
printInfo(graphics,"初入江湖",50,350,500);
break;
}
paintThread.interrupt();
}
在初始化窗体时要添加热狗和开始重绘线程,开始计时
for(int i=0;i<15;i++){
Bullet bullet = new Bullet("images/hotdog.png");
bulletList.add(bullet);
}
starTime = new Date();
endTime = new Date();
paintThread=new PaintThread();
paintThread.start();
复写绘画和更新
@Override
public void paint(Graphics graphics) {
graphics.drawImage(bg, 0, 0, null);
plane.draw(graphics);
endTime = new Date();
if(gameState){
for(int i=0;i<bulletList.size();i++){
Bullet bullet=bulletList.get(i);
bullet.draw(graphics);
Rectangle bulletRectangle = new Rectangle((int)bullet.x,(int)bullet.y,bullet.width,bullet.height);
Rectangle planeRectangle = new Rectangle(plane.x,plane.y,plane.width,plane.height);
boolean collide= bulletRectangle.intersects(planeRectangle);
if(collide){
if (bulletList.size()!=0){
executorService.execute(musicPlayer);
bulletList.remove(i);
if (bulletList.size()==0){
gameState = false;
}
}
}
}
}else {
endTime = new Date();
gameOver(graphics);
paintThread.interrupt();
}
int count_time = (int)(endTime.getTime()-starTime.getTime())/1000;
printInfo(graphics,"你已经吃了"+count_time+"秒",20,750,50);
}
Image ImageBuffer = null;
Graphics GraImage = null;
@Override
public void update(Graphics g){
ImageBuffer = createImage(this.getWidth(), this.getHeight());
GraImage = ImageBuffer.getGraphics();
paint(GraImage);
GraImage.dispose();
g.drawImage(ImageBuffer, 0, 0, this);
}
在按键监听里面调用思聪的按键按下和释放方法
class KeyMoniter extends KeyAdapter{
@Override
public void keyPressed(KeyEvent e) {
plane.KeyPressedControlDirection(e);
}
@Override
public void keyReleased(KeyEvent e) {
plane.KeyRelasedControlDirection(e);
}
}
最后启动游戏
public static void main(String[] args) {
FeiJiGame game = new FeiJiGame();
game.loadGame();
}
github:https://github.com/s15603333319/SiCongEatHotDog
csdn:https://download.csdn.net/download/qq_37482202/11084561
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/158956.html原文链接:https://javaforall.cn
相关文章
- java发送邮件代码[通俗易懂]
- java删除文件目录及文件_Java删除文件,目录
- java贪吃蛇小游戏(详解)[通俗易懂]
- 编写java判断闰年_用Java程序判断是否是闰年的简单实例[通俗易懂]
- JAVA—— AJAX[通俗易懂]
- java冒泡排序概练_Java的冒泡排序[通俗易懂]
- java %08d_总结Java中String.format()的使用[通俗易懂]
- java是面向对象还是面向过程_Java面向对象编程和面向过程编程的区别[通俗易懂]
- 我的世界java版需要多少钱_我的世界Java版20w49a快照版[通俗易懂]
- java pfx 证书_Java将pfx证书转换为jks[通俗易懂]
- java开发常用四大框架_大牛经验!常用的5款Java框架汇总[通俗易懂]
- java开发常用四大框架_Java 后台开发框架[通俗易懂]
- java public interface_Java 接口interface的基础[通俗易懂]
- 手机版java编译器_Java编译器[通俗易懂]
- 解读Java中BigDecimal.ZERO.compareTo()的返回值含义[通俗易懂]
- java 特点_JAVA的几个重要特点[通俗易懂]
- java递归查询数据库数据[通俗易懂]
- java debug调试怎么用?[通俗易懂]
- JAVA遍历数组的三种方法_java遍历object数组
- java 事务嵌套_Java事务以及嵌套事务[通俗易懂]
- java反射 getMethod_JAVA 反射 getMethod() 和 invoke() 具体应用[通俗易懂]
- java如何打印菱形_JAVA输出菱形
- java 常量表达式,需要常量表达式? (Java switch语句)[通俗易懂]
- Java连接MySQL数据库的简单步骤(java如何连接mysql数据库)
- Linux下快速编写高效的Java代码(linux写java)
- Java与Oracle的连接方式(java连oracle)
- 实现基于Redis的分布式锁Java实现(redis锁java代码)