上次搞定了角色的行走以及角色与地图元素的碰撞检测问题,这次就在这个地图中加入第一个NPC吧..
首先,前面做地图的时候用的是三层的数组,第一层用来存放角色脚下的素材,第二层是和角色同一层次的素材,而第三层本来是准备用来存放角色上方的素材想云朵之类的,但是想了一下,还是算了,没必要做得那么的麻烦,那么第三层就用来存放NPC吧...
在游戏中加入一个NPC,可以用JAVA面向对象的思想,创建一个NPC类,游戏中的每一个npc都是这个类的一个对象,我们游戏对npc的操作便可以转化成为对这个类的操作了.但是如果是在游戏的代码中去实例化这个类的话,一旦npc对象多了代码就会变得特别的长,不方便我们进行后续的调试,所以最好是用一种文件格式将一个个的npc属性事先存放好,在游戏进行的过程中一旦遇到一个npc再从这个事先保存好的npc文件中读取其中的属性,这样我们要修改npc的属性也比较方便...
用什么格式好呢,一开始我想过直接用txt文件,不过txt好像有点难控制的样子,正好前段时间学过XML的解析,这里我选择了用XML来保存npc的信息,而java中解析xml的方法采用dom解析的方式,因为这样既可以读又可以写...
思路就这么多,下面开始做准备工作..
1.找到一个npc的图片,我开始找了很久纠结不知道用什么,后面偶然发现一个网站,这里面可以让你自己拼接一个像素的npc图像出来,这简直不能再棒(链接放上:http://www.icongenerators.net/pixelavatar.html)
我拼了一个这样的出来,不过这网站保存的图片背景是白色的,需要自己用PS把背景换成透明的
2.接着就是写npc属性的xml文件了,这里先暂时想到这么几个属性,后面用到其他的再加吧..
<?xml version="1.0" encoding="utf-8"?> <npc201> <name>逗逼</name> <hp>20</hp> <level>2</level> <exp>10</exp> <money>10</money> <islive>1</islive> <talk>我是大傻逼,哈哈哈哈</talk> </npc201>
3.再接下来就是在游戏中通过dom解析xml文件,得到这个npc对象了,得到这个对象之后,游戏程序怎么找到这个对象呢,这里因为一个npc是和第三层地图数组map3里面的值是一一对应的,所有在得到这个对象之后,可以将它与它对应的数组中的值,放入hashmap,这样就建立起了一一对应的关系.
首先写一个npc类:
package yy1020; public class NPC { //NPC的名字 String name; //血量 int hp; //等级 int level; //经验 int exp; //金钱 int money; //是否活着 1活着 0死了 int islive; //对话 String talk = "我是大傻逼!"; public NPC(String name,int hp,int level,int exp,int money,int islive,String talk) { this.name = name; this.hp = hp; this.level = level; this.exp = exp; this.money = money; this.islive = islive; this.talk = talk; } }
写一个从xml文件中获取npc对象的类
package yy1020; import java.util.HashMap; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class GetNPC { //用来将npc对象与map3数组中的值一一对应起来的hashmap static HashMap<Integer, NPC> map = new HashMap<Integer, NPC>(); public static void getnpc(int num){ //获得xml文件路径 String numstr = String.valueOf(num); String path = "npc\\npc"+numstr+".xml"; try{ //得到解析xml工厂对象 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); //通过工厂对象得到解析器对象 DocumentBuilder builder = factory.newDocumentBuilder(); //解析器对象解析xml文件,得到一个doc文件 Document doc = builder.parse(path); setNPC(doc,num); }catch(Exception e){ e.printStackTrace(); } } /** * 解析doc文件,从里面获得npc类 * @param doc */ public static void setNPC(Node doc,int num){ String name = ""; int hp=0; int level=0; int exp=0; int money=0; int islive=0; String talk=""; Node node = (Node) doc.getFirstChild(); System.out.println(node.getNodeName()); NodeList nodes = node.getChildNodes(); for(int i=0;i<nodes.getLength();i++){ Node n = nodes.item(i); String str = n.getNodeName(); if(n instanceof Element){ if(str.equals("name")){ name = n.getTextContent(); }else if(str.equals("hp")){ hp = Integer.parseInt(n.getTextContent()); }else if(str.equals("level")){ level = Integer.parseInt(n.getTextContent()); }else if(str.equals("exp")){ exp = Integer.parseInt(n.getTextContent()); }else if(str.equals("money")){ money = Integer.parseInt(n.getTextContent()); }else if(str.equals("islive")){ islive = Integer.parseInt(n.getTextContent()); }else if(str.equals("talk")){ talk = n.getTextContent(); } } } NPC npc = new NPC(name, hp, level, exp, money, islive, talk); //将生成的这个npc对象和num加入hashmap map.put(num, npc); System.out.println(npc.name); } }
4.要实现与npc的对话,必须要重新写一个对话框面板,在游戏中角色面对npc时按下g键,就弹出这个对话框(当然这个对话框是一直都存在的,只是不用的时候大小设置为0,用的时候再给他大小),框中显示npc的名字和npc所说的话。
这里需要对面板的按键监听器做一系列的处理,按下g的时候,首先由hashmap得到该npc对象,获取到npc的属性,然后让刷新线程里面游戏面板停止刷新改为刷新对话框面板,同时让对话框面板的大小正常化,里面显示出npc的名字和对话的内容.
对话暂时只做了和上方的npc对话的判断,其他方向都是同样的处理方式
对话框面板类:
package yy1020; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import javax.swing.JPanel; /** * 对话框面板 * @author yy * */ public class TalkPanel extends JPanel implements gameConfig{ static NPC npc; public TalkPanel() { init(); } public void init(){ this.setBounds(28, 500, 0, 0); this.setLayout(null); this.setOpaque(false);//设置面板透明 } @Override public void paint(Graphics g) { super.paint(g); if(npc!=null){ g.drawImage(talkbox.getImage(), 0, 0, 630, 130, null); g.setColor(Color.BLUE); Font font = new Font("黑体", 600, 25); g.setFont(font); g.drawString(npc.name+":", 30, 30); g.setColor(Color.GREEN); g.drawString(npc.talk, 60, 65); } } //显示对话面板 public void show(){ this.setPreferredSize(new Dimension(panelX, panelY)); } //隐藏对话面板 public void hide(){ this.setPreferredSize(new Dimension(0, 0)); } //得到正在对话的npc public static void gettalknpc(int num){ npc = GetNPC.map.get(num); } }
游戏窗体类(和前面版本基本相同,不过按键监听那里加了很多判断):
package yy1020; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JPanel; /** * 游戏主窗体 * @author yy * */ public class mainFrame extends JFrame implements gameConfig{ //游戏状态 1为行走 2为对话 static int tag = 1; //游戏面板 JPanel panel; //对话面板 JPanel tpanel; public mainFrame() { init(); } /** * 设置窗体 */ public void init(){ this.setTitle(title); this.setSize(frameX, frameY); this.setLayout(null); this.setDefaultCloseOperation(3); // //设置窗体无边框 // this.setUndecorated(true); //创建对话框面板 tpanel = settpanel(); //创建游戏面板 panel = setpanel(); this.add(tpanel); this.add(panel); this.setVisible(true); //安装键盘监听器 PanelListenner plis = new PanelListenner(); this.addKeyListener(plis); //启动人物移动线程 Player player = new Player(); player.start(); //启动刷新面板线程 UpdateThread ut = new UpdateThread(panel,tpanel); ut.start(); } /** * 设置游戏面板 */ public JPanel setpanel(){ JPanel panel = new MyPanel(); panel.setBounds(18, 5, panelX, panelY); // panel.setPreferredSize(new Dimension(panelX, panelY)); panel.setLayout(null); panel.setBackground(Color.black); return panel; } /** * 设置对话面板 * @return */ public JPanel settpanel(){ JPanel tpanel = new TalkPanel(); return tpanel; } /** * 内部游戏按键监听类 * @author yy * */ class PanelListenner extends KeyAdapter{ //当按键按下 public void keyPressed(KeyEvent e){ int code = e.getKeyCode(); if(tag==1){ switch (code) { case KeyEvent.VK_UP: Player.up = true; Player.towards = 1; break; case KeyEvent.VK_DOWN: Player.down = true; Player.towards = 2; break; case KeyEvent.VK_LEFT: Player.left = true; Player.towards = 3; break; case KeyEvent.VK_RIGHT: Player.right = true; Player.towards = 4; break; case KeyEvent.VK_G://按下了对话键 if(Player.towards==1){//角色朝着上 int num = ReadMapFile.map3[Player.y/elesize-1][Player.x/elesize]; if(num!=0){//上方有npc if(GetNPC.map.get(num)==null){ GetNPC.getnpc(num); TalkPanel.gettalknpc(num); } tag = 2; tpanel.setBounds(28, 500, 630, 150); tpanel.repaint(); System.out.println(1); } }else if(Player.towards==2){//角色朝着下 if(ReadMapFile.map3[Player.y/elesize+1][Player.x/elesize]!=0){//下方有npc tpanel.setBounds(28, 500, 630, 150); tag = 2;//进入对话模式 tpanel.repaint(); } }else if(Player.towards==3){//角色朝着左 if(ReadMapFile.map3[Player.y/elesize][Player.x/elesize-1]!=0){//左方有npc tpanel.setBounds(28, 500, 630, 150); tag = 2; tpanel.repaint(); } }else if(Player.towards==4){//角色朝着下 if(ReadMapFile.map3[Player.y/elesize][Player.x/elesize+1]!=0){//右方有npc tpanel.setBounds(28, 500, 630, 150); tag = 2; tpanel.repaint(); } } break; default: break; } }else if(tag==2){ if(code==KeyEvent.VK_G){ tag=1; tpanel.setBounds(28, 500, 0, 0); } } } //当按键释放 public void keyReleased(KeyEvent e){ if(tag==1){ int code = e.getKeyCode(); switch (code) { case KeyEvent.VK_UP: Player.up = false; Player.up1 = 0; break; case KeyEvent.VK_DOWN: Player.down = false; Player.down1 = 0; break; case KeyEvent.VK_LEFT: Player.left = false; Player.left1 = 0; break; case KeyEvent.VK_RIGHT: Player.right = false; Player.right1 = 0; break; default: break; } } } } /** * 自定义内部游戏面板类 * @author yy * */ class MyPanel extends JPanel{ @Override public void paint(Graphics g) { super.paint(g); //找到角色旁边的素材,上下左右各5格 for(int i=Player.getI()-6;i<=Player.getI()+6;i++){ for(int j=Player.getJ()-6;j<=Player.getJ()+6;j++){ //如果这一格没有超界 if(i>=0&&j>=0&&i<ReadMapFile.map1.length&&j<ReadMapFile.map1[0].length){ //画第一层元素 ImageIcon icon = GetMap.int2icon(ReadMapFile.map1[i][j]); g.drawImage(icon.getImage(), (Player.px-elesize/2)+((j-Player.getJ())*elesize)-(Player.mx%elesize), (Player.py-elesize/2)+((i-Player.getI())*elesize)-(Player.my%elesize), elesize, elesize, null); //第二层 if(ReadMapFile.map2[i][j]!=0){ ImageIcon icon2 = GetMap.int2icon(ReadMapFile.map2[i][j]); g.drawImage(icon2.getImage(), (Player.px-elesize/2)+((j-Player.getJ())*elesize)-(Player.mx%elesize), (Player.py-elesize/2)+((i-Player.getI())*elesize)-(Player.my%elesize), elesize, elesize, null); } //第三层 if(ReadMapFile.map3[i][j]!=0){ ImageIcon icon3 = GetMap.int2npc(ReadMapFile.map3[i][j]); g.drawImage(icon3.getImage(), (Player.px-elesize/2)+((j-Player.getJ())*elesize)-(Player.mx%elesize), (Player.py-elesize/2)+((i-Player.getI())*elesize)-(Player.my%elesize), elesize, elesize, null); } } } } // g.setColor(Color.black); // g.fillRect(0, 0, 50, 650); // g.fillRect(0, 0, 650, 50); // g.fillRect(600, 0, 50, 650); // g.fillRect(0, 600, 650, 50); Player.draw(g); //npc // g.drawImage(npc1.getImage(), 400, 400, 50, 50, null); //做一个黑色的图片,然后中间挖空一个圆,加上模糊效果,来模拟人的视野 g.drawImage(shadow2.getImage(), 0, 0, 650, 650, null); } } }
然后是面板刷新线程:
package yy1020; import javax.swing.JPanel; /** * 刷新游戏面板的线程类 * @author yy * */ public class UpdateThread extends Thread{ JPanel panel; JPanel tpanel; public UpdateThread(JPanel panel,JPanel tpanel) { this.panel = panel; this.tpanel = tpanel; } @Override public void run() { while(true){ if(mainFrame.tag==1){//如果是在走路状态就刷新游戏地图面板 panel.repaint(); }else if(mainFrame.tag==2){//如果是在对话的状态就刷新对话框面板 tpanel.repaint(); } try { Thread.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); } } } }
这样npc的引入以及和npc的对话就实现了,后面再多加入几个npc,对话里面加入选项以及任务系统,一个基本的模型就差不多了,额 = =! ,不对,这特么的玩家背包菜单都还没做,怪物都还没有,战斗系统也没有,存档也没弄,后面还有好多啊 0 0、学校就要考试了,伤不起啊....
总之这次就先做到这了,还是上个图玩玩:
然后是画质和帧数惨不忍睹的gif
代码放下面了,xml文件用的是相对路径不用改,只需要在test类改一下地图的路径就能运行了吧...
做到这里突然想起我的地图数据结构可能选择错了,如果当初选择的不是数组而是图的话,估计后期会好做很多,不过也不想改了,这个游戏就当是探路的吧 0 0、
相关推荐
### 基于JAVA的手机RPG游戏图形引擎的实现 #### 1. 引言 随着移动技术的迅速发展,手机游戏已经成为人们日常生活的重要组成部分。游戏引擎作为控制游戏运行的核心程序,在游戏开发中扮演着至关重要的角色。游戏...
开发者需要设计并构建游戏环境,包括地形、建筑、物品、NPC(非玩家角色)等元素,这些都可通过导入3D模型、纹理、光照等资源来实现。 2. **角色控制器**:RPG游戏中的角色需要有精细的移动和交互控制。这通常通过...
【标题】"JS写的RPG游戏代码"是一个基于JavaScript编程语言构建的角色扮演游戏(RPG)项目。这个游戏专业性高,玩家无需登录即可直接体验游戏,还可以通过留言板进行互动交流。 【描述】中提到的关键知识点包括: 1....
在IT行业中,RPG(Role-Playing Game)角色扮演游戏是一种深受玩家喜爱的游戏类型,它让玩家扮演虚构世界中的角色,通过探索、战斗、对话等互动元素来推进故事发展。本教程“RPG角色扮演游戏程序设计”旨在教授如何...
《空岛:Java中的RPG游戏》是一款个人项目,它展示了开发者使用Java编程语言构建一个角色扮演游戏(RPG)的能力。在这个项目中,我们将深入探讨Java语言在游戏开发中的应用,以及RPG游戏设计的基本元素。 1. **Java...
- **持久化数据**:使用序列化、XML或自定义格式保存游戏进度。 - **内存管理**:J2ME设备内存有限,需要谨慎处理游戏数据的存储和加载。 8. **网络功能** - **多玩家支持**:可能包含局域网对战或在线同步游戏...
在IT行业中,游戏开发是一项复杂而充满挑战的任务,特别是角色扮演游戏(RPG)类型,它通常需要丰富的剧情、复杂的系统和细腻的图形表现。这里我们关注的是一款使用C语言编写的RPG完整代码,它提供了多场景地图、...
在Android平台上开发一款角色扮演游戏(RPG)时,地图绘制是至关重要的部分。"android RPG地图绘制"这个主题主要涉及如何在原生Android环境中利用Tiled地图资源来创建丰富的游戏场景。Tiled是一款广泛使用的开源地图...
4. **角色控制器**:RPG游戏中的角色移动、跳跃、攻击等行为需要通过角色控制器实现。开发者需要编写或使用现成的角色控制器组件,确保角色能流畅地在3D环境中移动,并处理与环境的交互。 5. **动画系统**:Unity3D...
在RPG游戏中,这种交互性至关重要,因为它允许玩家与游戏环境进行多种互动,例如与NPC(非玩家角色)交谈、捡拾物品或触发事件。 描述中提到了"场景随人物移动",这是RPG游戏中的核心功能之一,通常称为“无缝地图...
RPG游戏通常包含角色创建、升级系统、剧情线和与环境或NPC(非玩家角色)的互动。 3. **代码**:表示这是关于源代码的分享,意味着你可以查看、学习、修改和扩展游戏的内部机制。 4. **Android**:进一步确认了游戏...
【C++ RPG Demo】是一个基于C++编程语言开发的角色扮演游戏(Role-Playing Game,简称RPG)演示项目。这个项目旨在展示如何利用C++来构建一个基础的RPG游戏框架,帮助开发者理解游戏开发的基本原理和技术。在RPG游戏...
2. **任务触发器**:当玩家达到特定条件,如到达某个地点、与NPC对话或完成其他任务时,任务触发器会启动。这需要在游戏世界中设置检查点和事件监听器。 3. **任务状态管理**:每个任务都有一个状态,如未接受、...
当我们谈论"RPG Delphi code"时,我们指的是使用Delphi语言来编写RPG游戏的源代码。这个主题涵盖了多个知识点,包括Delphi的基础、面向对象编程、游戏开发框架、图形渲染、音效处理、数据结构和算法等。 首先,...
在这个Java环境中,我们可以看到一个名为“RPG”的项目,可能是用Java语言编写的,用于创建简单的角色扮演游戏。 标题“RPG:小型RPG游戏库”暗示了这是一个专注于RPG游戏开发的库,可能包含了游戏逻辑、场景管理、...
开发者需要掌握Java或Kotlin语言,熟悉Android SDK,理解AndroidManifest.xml配置文件,以及Activity、Service、BroadcastReceiver等组件的工作原理。 2. **RPG游戏机制**:RPG游戏通常包含角色创建、升级系统、...
NPC-Generator是一款基于Java开发的角色扮演游戏(RPG)非玩家角色(NPC)生成工具,专为Pathfinder游戏系统设计。Pathfinder是一种广受欢迎的桌上角色扮演游戏,玩家在游戏中扮演各种角色,与NPC互动,进行冒险和...
JavaScript,也被称为JS,是一种广泛应用于网页和网络应用的编程语言,尤其在创建交互式用户界面方面具有显著优势。这个“js游戏源代码”压缩包集合了使用JavaScript编写的多种游戏,是学习JavaScript编程和游戏开发...