初学嘛) ,不过总的来讲这个程序仍是颇有意思的。这里我从新再整理了一下,但愿能帮助到其余想要开发相似程序的朋友,共同进步!
晒一下效果图:java
哈,仍是有模有样的。左边是本身写的冒险岛,右边是真的冒险岛。
毕竟也是个游戏,方向键能够控制人物移动,而后能够攻击,能够打怪,升级,作任务。网络
先说一下素材,有一个专门提供冒险岛素材的纸娃娃系统,冒险岛中各类素材均可以从这个网站中获取:
http://www.maplesimulator.com/programs/bannedstory多线程
游戏中显示出这样的界面效果,能够用PS中的图层来理解,所谓图层就是含有文字或图形等元素的胶片,一张张按顺序叠放在一块儿,组合起来造成页面的最终效果。函数
而这个胶片,就是JAVA中的容器JPanel。JPanel能够设置背景图片,也能够多个JPanel放置于一个JPanel中,就拿游戏下方的状态条来讲:
整个状态条就是一个JPanel,咱们就新建一个状态条类测试
public class StatusBar extends JPanel
而后让他继承JPanel。
咱们给这个JPanel设置这样的一个背景:
给JPanel设置背景的方法是重写JPanel的paint函数,看下面代码应该很清楚。字体
public void paint(Graphics g){ g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\状态条\\状态条.png"),0,0,this); }
接着,在这个JPanel上还要显示等级的数字、血条、蓝条、经验条,以及一个系统按钮(不过其实这个按钮并不属于StatusBar类,咱们只是让他显示在这个位置)。
这些都是StatusBar类的成员。咱们只须要在固定的位置将相应的成员显示就能够了。
先说这个显示等级的数字,很显然就是一个JLabel嘛,不过我用的不是JLabel。
依旧是在paint函数中,加入这样一段:动画
g.setColor(Color.WHITE); g.setFont(new Font(Font.DIALOG_INPUT, Font.BOLD, 25));//设置字体 g.drawString(Integer.toString(lv), 50,38);//等级
直接把字画在JPanel上的相应位置就能够了,颜色、字体、大小、字的内容、横纵坐标,就这些参数。能够查看API文档,这里就不细说。网站
血条蓝条经验条,这三个条条是大部分网络游戏都有的东西,主要用来直观的显示玩家状态,拿血条举例子,看最前面的效果图,当前血量800,总血量1000,因此血条的长度就是整个血槽的4/5,这样一想,用进度条这种组件去实现血条蓝条是很可行的,然而我查了才发现,JAVA中(至少是标准库吧。。)并无进度条这个组件,因此仍是要本身去实现它。
仍是在paint函数中:this
g.setColor(Color.RED); //血条 g.fillRect(141, 23, (int)((double)hp/allhp*length), 15); g.setColor(Color.BLUE); //蓝条 g.fillRect(340, 23, (int)((double)mp/allmp*length), 15); g.setColor(Color.YELLOW); //经验条 g.fillRect(539, 23, (int)((double)exp/allexp*length), 15);
根据当前血量和总血量的比例去绘制相应长度相应颜色的矩形,这样一来动态的血条蓝条经验条的主体部分就完成了,咱们还须要在上面显示具体的血量和血总量:
有了前面绘制等级的经验,咱们使用g.drawString函数就能够了,不过为了显示的美观吗,咱们还须要考虑一些问题,文字的显示是与血条右边对其的,而绘制文字的参数中提供的参数是这样的一组x,y并不能符合咱们右对其的要求。
因此我用了另一种很机智(shabi)的方法:spa
//数字比例6.7619 /[比例3 String hptxt="["+Integer.toString(hp)+"/"+Integer.toString(allhp)+"]"; int hptxtnuml=Integer.toString(hp).length()+Integer.toString(allhp).length();//血量数字显示的数字长度 int hptxtx=272-(int)(hptxtnuml*6.7619);//相应横坐标 String mptxt="["+Integer.toString(mp)+"/"+Integer.toString(allmp)+"]"; int mptxtnuml=Integer.toString(mp).length()+Integer.toString(allmp).length();//蓝量数字显示的数字长度 int mptxtx=471-(int)(mptxtnuml*6.7619);//相应横坐标 String exptxt="["+Integer.toString(exp)+"/"+Integer.toString(allexp)+"]"; int exptxtnuml=Integer.toString(exp).length()+Integer.toString(allexp).length();//蓝量数字显示的数字长度 int exptxtx=670-(int)(exptxtnuml*6.7619);//相应横坐标
先把要绘制的字符串准备好,而后计算一下文本长度(这个长度是指真的长度。。显示出来要几个坐标。。别问我怎么测得,我用尺子量的。。),最后换算出相应的坐标绘制。
至此,状态条的显示就完成了。在个人设计中,人物的属性(血,蓝,经验,等级,攻击力等)是直接放在状态条类里做为成员变量的,换句话说,你玩游戏玩的不是那我的物,你的全部数据都不存在人物的类里,而是存在状态条类里,人物攻击力高,一下秒掉怪物,那只是配合着状态条里的属性显示给玩家看而已~
咱们先把状态条放到一边,待会再来用它。
如今咱们要实现方向键控制人物移动。
依旧是前面图层的思想,人物也是一个图层。咱们建立一我的物类:
public class Obj extends JPanel
先来分析一下人物的动做,人物有个朝向,脸朝左,脸朝右,站着不动的时候有站着不动的姿式,走路的时候有走路的姿式,按上键若是能抓到绳子,有爬绳子的姿式,按下有趴着的姿式。因此Obj类中须要有一个变量来控制人物的状态,(向左走、向右走、向左趴下等):
private int zhuangtai=2;//人物状态
而后在绘制背景图片的时候,switch(zhuangtai)来决定该绘制哪张图片就能够了。
咱们能够写一个设置状态的函数,以便控制人物的时候使用:
public void setzhuangtai(int a)//设置状态 { zhuangtai=a; }
这里说明一下,人物站立的时候,并非一张静止的图片,而是提早准备好的GIF图像,站立的时候显示的就是天然摆手的动画分镜头以下:
固然若是不想使用GIF图像的话,能够新建一个线程,专门在站立状态控制人物摆手动画的切换。
相似攻击的动画显示也是如此。
咱们如今先来设想一下控制人物移动的思路:
首先人物这个图层(JPanel)是显示在窗口上的,主类继承JFream
而后人物做为主类的成员,就和建立一个JButton同样的写法
private Obj ren=new Obj(0,0);//建立角色
用两个整形变量x,y来表明人物的坐标
接下来就是将,xy做为参数使用setBounds函数设置人物的显示坐标以及显示大小。
对主窗口注册键盘监听和触发事件:
咱们按下方向键后,好比说方向右键,调用Obj类中的setzhuangtai函数,修改人物状态,再将x+5 (这个值本身定,值越大移动的越快)接着再次使用setBounds从新设置人物的显示坐标。而后调用repaint进行重绘。
这样就能够实现人物的移动了。我这里没有附具体代码,由于我不是这样写的。。(噗!!)
在实际测试中,这样去实现人物移动会引入一个很麻烦的问题——当你设置了游戏地图以后,控制人物移动会出现背景跟不上人物,有残影的情形,具体的解决方案是使用双缓冲技术,不过我有另外的思路解决了这个问题,何乐而不为呢:
人物移动的时候,人物这个图层后面的背景老是拖着以前的背景,使得显示着很不协调,个人解决方案是设置人物这个图层的大小的时候,让他充满整个屏幕,这样的话,人物移动时,背景就是整个屏幕,而不用考虑旧背景的残影问题了。不过这样设计的话,人物移动的方式就要改变了,不能再是移动人物类的对象在主窗口中显示的位置,由于人物类的对象在主窗口中已是全屏显示了,不能再改变,改变的只能是人物的图片,在人物类的这个JPanel中内部的位置。因此x,y这个坐标也是存于人物类中。
private int zhuangtai=2;//人物状态 //屏幕坐标 private int x; private int y; public void setzhuangtai(int a)//设置状态 { zhuangtai=a; } public void setxy(int m_x,int m_y) { x=m_x; y=m_y; } //人物在屏幕中移动 public void movex(int m_x) { x+=m_x; } public void movey(int m_y) { y+=m_y; }
显示的地方就经过x和y的值来调整位置,不过仍是有一个地方要注意,显示图片时的坐标参数是指以左上角为起点的,可是每一张图片的大小都不同,因此若是不加换算的话就会出现这样的问题:
人物的显示坐标天然是要以脚为坐标,因此咱们对于每一张图都要测定它的偏移(很幸运的是纸娃娃系统能够直接导出偏移的值),而后显示的时候根据偏移去计算换算后的坐标。
paint函数以下:
public void paint(Graphics g)
{ switch(zhuangtai) { case 0:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\主角\\走路\\向右走0.png"),x-15,y-68,this);break; case 1:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\主角\\走路\\向右走1.png"),x-15,y-68,this);break; case 2:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\主角\\走路\\向右走2.png"),x-15,y-68,this);break; case 3:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\主角\\走路\\向右走3.png"),x-15,y-68,this);break; case 4:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\主角\\走路\\向左走0.png"),x-76,y-68,this);break; case 5:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\主角\\走路\\向左走1.png"),x-76,y-68,this);break; case 6:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\主角\\走路\\向左走2.png"),x-76,y-68,this);break; case 7:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\主角\\走路\\向左走3.png"),x-76,y-68,this);break; case 8:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\主角\\站立\\面朝右站.gif"),x-40,y-86,this);break; case 9:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\主角\\站立\\面朝左站.gif"),x-24,y-86,this);break; case 10:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\主角\\跳跃\\向右跳.png"),x-40,y-90,this);break; case 11:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\主角\\跳跃\\向左跳.png"),x-25,y-90,this);break; case 12:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\主角\\趴下\\面朝左趴下.png"),x-106,y-40,this);break; case 13:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\主角\\趴下\\面朝右趴下.png"),x,y-40,this);break; case 14:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\技能\\轻舞飞扬\\左\\0.png"),x-165,y-110,this);break; case 15:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\技能\\轻舞飞扬\\左\\1.png"),x-165,y-110,this);break; case 16:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\技能\\轻舞飞扬\\左\\2.png"),x-165,y-110,this);break; case 17:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\技能\\轻舞飞扬\\左\\3.png"),x-165,y-110,this);break; case 18:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\技能\\轻舞飞扬\\左\\4.png"),x-165,y-110,this);break; case 19:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\技能\\轻舞飞扬\\左\\5.png"),x-165,y-110,this);break; case 20:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\技能\\轻舞飞扬\\左\\6.png"),x-165,y-110,this);break; case 21:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\技能\\轻舞飞扬\\左\\7.png"),x-165,y-110,this);break; case 22:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\技能\\轻舞飞扬\\左\\8.png"),x-165,y-110,this);break; case 23:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\技能\\轻舞飞扬\\右\\0.png"),x-115,y-110,this);break; case 24:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\技能\\轻舞飞扬\\右\\1.png"),x-115,y-110,this);break; case 25:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\技能\\轻舞飞扬\\右\\2.png"),x-115,y-110,this);break; case 26:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\技能\\轻舞飞扬\\右\\3.png"),x-115,y-110,this);break; case 27:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\技能\\轻舞飞扬\\右\\4.png"),x-115,y-110,this);break; case 28:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\技能\\轻舞飞扬\\右\\5.png"),x-115,y-110,this);break; case 29:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\技能\\轻舞飞扬\\右\\6.png"),x-115,y-110,this);break; case 30:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\技能\\轻舞飞扬\\右\\7.png"),x-115,y-110,this);break; case 31:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\技能\\轻舞飞扬\\右\\8.png"),x-115,y-110,this);break; case 32:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\图片素材\\主角