当前位置:首页 > CN2资讯 > 正文内容

我的世界Java披风下载

1天前CN2资讯


成果展示

制作思路

第1步:发现类(对象)

人物-小丑: Buffoon 子弹-帽子:Missile 墙体:Wall 爆炸物:Explode

第2步:发现属性

小丑:宽和高,位置(x,y),移动速度 帽子:宽和高,位置(x,y),移动速度 墙体:宽和高,位置(x,y) 爆炸物:宽和高,位置(x,y)

第3步:发现方法

小丑:移动、攻击、人物撞边界 子弹:移动、子弹撞墙、子弹撞边界 爆炸物:消失

重难点分析

窗体如何创建

public class GameClient extends Frame

通过继承Frame类实现Java窗体

public class Frame extends Window implements MenuContainer

Frame类继承了Window类和MenuContainer接口

如何将图片加载到窗体里

步骤1:创建常用工具类CommonUtils,新建getImage方法实现将图片资源转换为Java对象

public class CommonUtils { /** * 读取图片资源, 转变为Java对象 Image * @param imgPath 图片路径 * @return Image对象 */ public static Image getImage(String imgPath) { ImageIcon imageIcon = new ImageIcon(imgPath); return imageIcon.getImage(); } }

步骤2:调用getImage方法添加对象图片

public class GameClient extends Frame { Image bg_image = CommonUtils.getImage("images/bg.png"); Image explode = CommonUtils.getImage("images/explode.png"); Image missile = CommonUtils.getImage("images/missile.png"); Image wall_h = CommonUtils.getImage("images/wall-h.png"); Image wall_v = CommonUtils.getImage("images/wall-v.png"); Image buffoon = CommonUtils.getImage("images/body/s-left.png");

步骤3:重写Framed的paint方法,实现窗体加载图片

@Override public void paint(Graphics g){ //画背景图 g.drawImage(bg_image,0,0,1100,700,this); //画小丑 g.drawImage(buffoon,300,200,80,80,this); //画爆炸物 g.drawImage(explode,800,400,90,90,this); //画原谅帽 g.drawImage(missile,300,300,60,60,this); //画横着的墙体 g.drawImage(wall_h,400,300,100,20,this); //画竖着的墙体 g.drawImage(wall_v,400,300,20,100,this);

Graphics类的drawImage方法需要提供Image类参数、窗体的x参数、窗体的y参数、Image类的宽度width、Image类的长度length以及observer(当转换了更多图像时要通知的对象)

对象移动的实现

指向标的地图,通常采用“上北下南,左西右东”的规则确定方向。移动的八个方向通常指的是北、东北、东、东南、南、西南、西、西北。因此在定义移动方向时用上、左、下、右、上右、下右、上左、下左来表示

小丑:移动 move<Orientation类传递方向参数> 'left向左' :x = x - this.speed; 'right向右' :x = x + this.speed; 'down向下' :y = y + this.speed; 'up向上' :y = y - this.speed; 'ur东北方向' : x = x + this.speed; y = y - this.speed; 'ul西北方向' : x = x - this.speed; y = y - this.speed; 'dr东南方向' : x = x + this.speed; y = y + this.speed; 'dl西南方向' : x = x - this.speed; y = y + this.speed;

窗体关闭的实现

public void start() { //窗体添加侦听方法 this.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { super.windowClosing(e); //退出游戏 System.exit(0); } });

WindowAdapter类
1.接收窗口事件的抽象适配器类。此类中的方法为空。此类存在的目的是方便创建侦听器对象。
2.扩展此类可创建 WindowEvent 侦听器并为所需事件重写该方法。(如果要实现 WindowListener 接口,则必须定义该接口内的所有方法。此抽象类将所有方法都定义为 null,所以只需针对关心的事件定义方法。
3.使用扩展的类可以创建侦听器对象,然后使用窗口的 addWindowListener 方法向该窗口注册侦听器。当通过打开、关闭、激活或停用、图标化或取消图标化而改变了窗口状态时,将调用该侦听器对象中的相关方法,并将 WindowEvent 传递给该方法。
windowAdapter监听器

按键事件触发的实现

this.addKeyListener(new KeyAdapter() { //键盘按下的时候出发 @Override public void keyPressed(KeyEvent e) { super.keyPressed(e); } //键盘松开 @Override public void keyReleased(KeyEvent e) { //获取被按下的键对应的数值,如,a:67,b:68 int keyCode = e.getKeyCode(); switch (keyCode){ case KeyEvent.VK_UP: System.out.println("向上走!!!"); buffoon.setDir("UP"); break; case KeyEvent.VK_DOWN: System.out.println("向下走"); buffoon.setDir("DOWN"); break; case KeyEvent.VK_RIGHT: System.out.println("向右走"); buffoon.setDir("RIGHT"); break; case KeyEvent.VK_LEFT: System.out.println("向左走!!"); buffoon.setDir("LEFT"); break; } buffoon.move(buffoon.getDir()); } });

按键触发的要点

要点一:‘new KeyAdapter()’ 新建一个按键事件的监听器,并通过addKeyListener()向主窗体注册该监听器;
要点二:重写KeyAdapter的方法,分别是KeyTyped(键入)、KeyPresdded(按下)、KeyReleased(释放)。这里我们只监听KeyPressed事件并重写该方法,实现对人物方向状态的改变;
要点三:KeyEvent e.getKeyCode返回的是按下按键对应的键值,参考KeyEvent的键值属性。Java 8在线API

创建对象Buffoon.move()方法

public void move(String dir){ switch (dir){ case "UP": this.y -= this.speed; setDir("STOP"); break; case "DOWN": this.y += this.speed; setDir("STOP"); break; case "RIGHT": this.x += this.speed; setDir("STOP"); break; case "LEFT": this.x -= this.speed; setDir("STOP"); break; }

每次监听到按键事件调用move方法实现buffoon对象的移动

对象移动的原理

对象移动的画面也叫动画,是在屏幕上显示一系列连续动画画面的一帧一帧的图形,然后在间隔很短的时间显示下一帧图形,如此反复,利用人眼的‘视觉暂留’现象主观感觉好像画面的物体在运动。
FPS(Frames Per Second),是每秒钟的帧数。一帧就是一幅静态画像,电影的播放速度是24FPS。帧数越多,所显示的动作就会越流畅。通常,要避免动作不流畅的最低是30FPS。FPS百度百科

动画移动的搬运工-线程(thread)

什么是线程 线程(thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

/** * 定义一个重新绘制画面的线程,相当于招一个工人专门去从事这项工作 */ public class RePaintThread implements Runnable{ @Override //线程操作的全都在run方法中 public void run() { while (true){ //每50毫秒 执行一次 try { Thread.sleep(20); //重新绘制图像 gameClient.repaint(); } catch (InterruptedException e) { e.printStackTrace(); } } }要点一:Runnable接口public class RePaintThread implements Runnable 使用实现接口 Runnable 的对象创建一个线程时,启动该线程将导致在独立执行的线程中调用对象的 run 方法。要点二:重写Run方法 方法 run 的常规协定是:它可能执行任何所需的动作。重新绘制图像gameClient.repaint();要点三:Thread.sleep—线程反复执行的时间间隔 1、使用’While(true)'构造死循环 2、在死循环中执行repaint()重绘图形方法 3、线程中断异常(InterruptedException)是当前线程被中断的表现之一。遇到这个异常时,如果你不知道如何处理,你应当向上抛出。

子弹发射的实现

Buffoon类

//子弹容器 private List<Missile> missileList=new ArrayList<Missile>(); //开火 public Missile fire(){ //人物在哪里,子弹就在哪发射 return new Missile(this.x,this.y,this.dir,this.gameClient); } //根据按键输入内容完成buffoon的动作 public void okDirPressed(int keyCode){ //TODO 确定方向 switch (keyCode){ case KeyEvent.VK_UP: this.setDir("UP"); UP=true; break; case KeyEvent.VK_DOWN: this.setDir("DOWN"); DOWN=true; break; case KeyEvent.VK_RIGHT: this.setDir("RIGHT"); RIGHT=true; break; case KeyEvent.VK_LEFT: this.setDir("LEFT"); LEFT=true; break; //打桩 case KeyEvent.VK_CONTROL: Missile missile=this.fire(); //将子弹扔到容器中; this.missileList.add(missile); //看看容器中有多少子弹 break;

Missile类

/** *通过构造器将buffoon开火生成的子弹参数传回给 missile类 */ public Missile(int x, int y,String missile_dir, GameClient gameClient) { this.x = x; this.y = y; //将人物的移动方向赋值给子弹 this.missile_dir=missile_dir; this.width = 80; this.height = 20; this.speed = 20; this.gameClient=gameClient; } //根据传回的方向参数给子弹一个发射方向,并在子弹超出窗口界限时,给出判断 public void move(){ if(missile_dir.equals("STOP")){ missile_dir="LEFT"; } switch (missile_dir){ case "UP": this.y -= this.speed; break; case "DOWN": this.y += this.speed; break; case "RIGHT": this.x += this.speed; break; case "LEFT": this.x -= this.speed; break; case "DR": this.x += this.speed; this.y +=this.speed; break; case "DL": this.x -= this.speed; this.y +=this.speed; break; case "UR": this.x += this.speed; this.y -=this.speed; break; case "UL": this.x -= this.speed; this.y -=this.speed; break; } if(x<190||y<40||x>800||y>420){ isout=false; } }

GameClient类

public void paint(Graphics g){ g.drawImage(BG_IMAGE,0,0,DataPropertiesUtils.CLIENT_WIDTH,DataPropertiesUtils.CLIENT_HEIGHT,this); buffoon.paint(g); explode.paint(g); wall_h.paintH(g); //画子弹 for (int i = 0; i < buffoon.getMissileList().size(); i++) { // 将容器中的子弹拿出来,画到屏幕上 Missile missile=buffoon.getMissileList().get(i); //根据子弹的边界判断控制子弹的运动和消失 if(missile.isIsout()){ missile.paint(g); missile.move(); }else{ //超出边界,用remove方法移除子弹对象; buffoon.getMissileList().remove(missile); } }


    你可能想看:

    扫描二维码推送至手机访问。

    版权声明:本文由皇冠云发布,如需转载请注明出处。

    本文链接:https://www.idchg.com/info/21817.html

    分享给朋友:

    “我的世界Java披风下载” 的相关文章

    VPS上如何彻底卸载Docker?一步步教你轻松完成卸载

    在VPS上卸载Docker之前,我们需要做一些准备工作,确保卸载过程顺利进行,同时避免数据丢失。这些步骤虽然简单,但非常重要,尤其是在处理生产环境时。 停止所有运行的容器 卸载Docker的第一步是停止所有正在运行的容器。如果不先停止容器,直接卸载可能会导致数据损坏或丢失。我们可以使用以下命令来停止...

    VPS在线测速:如何选择合适的虚拟专用服务器

    在现今的网络环境中,选择合适的VPS(虚拟专用服务器)是每位用户尤其是中小企业和开发者需要重点关注的事项之一。VPS在线测速的重要性体现在很多方面,尤其是在评估服务性能时,测速显得尤为关键。通过测速脚本,用户可以全面了解VPS的网络状况和系统性能,从而在购买时做出更明智的决策。 想象一下,你已经在选...

    CN2 VPS:选择优质虚拟专用服务器的最佳指南

    CN2 VPS概述 在如今的网络环境中,CN2 VPS(虚拟专用服务器)吸引了不少关注。简单来说,它是一种基于中国电信CN2线路的云服务器。CN2线路是中国电信提供的优质网络线路,拥有低延迟、高速度及良好的稳定性。对于那些希望搭建网站、进行外贸交易、跨境办公或者需要远程协作的人来说,CN2 VPS是...

    如何在Linux中指定DNS服务器设置教程

    在开始讨论如何在Linux系统中指定DNS之前,我们需要明白DNS服务器的作用与重要性。DNS,全称域名系统,是将人类易读的域名转换为计算机能够理解的IP地址的系统。想象一下,如果没有DNS,我们每次访问一个网站都得记住复杂的数字IP地址,那将是多么麻烦的一件事。因此,选择一个合适的DNS服务器,不...

    选择合适的SSH连接工具以提升远程管理效率和安全性

    在当今的网络环境中,SSH连接工具扮演着重要角色。简单来说,SSH连接工具是一种应用程序,用于通过SSH协议安全地连接和管理远程服务器。想想看,当我们需要与服务器进行交互、执行命令或者上传文件时,这些工具就变得尤为重要。 我记得第一次使用SSH连接工具的时候,是为了管理一台远程服务器。能够通过简单的...

    如何进行IP被墙检测及有效应对策略

    在我们日常上网的过程中,可能会遇到一些网站无法访问的情况。这时就有可能是我们的IP被墙了。那么,什么是IP被墙检测呢?简单来说,IP被墙检测是为了确认某个IP地址是否受到网络封锁的过程。它帮助用户判断是否存在网络限制,通常与地理位置、服务提供商或网络政策有关。 IP被墙的影响非常显著。如果某个服务或...