`

【纯java语言做RPG游戏】4.用XML导入NPC并与NPC对话

阅读更多

上次搞定了角色的行走以及角色与地图元素的碰撞检测问题,这次就在这个地图中加入第一个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、

 

 

  • 大小: 1.4 KB
  • 大小: 296.3 KB
  • 大小: 767.4 KB
9
1
分享到:
评论
7 楼 hers 2015-10-23  
那个map怎么用,放哪里啊,
6 楼 Y_1746119035 2014-11-08  
QuarterLifeForJava 写道
顶一个,不错,持续关注,期待战斗机制。

额....感谢支持...  - -!
5 楼 Y_1746119035 2014-11-08  
xc_wangwang 写道
楼主有兴趣可以看看这个http://david-game.iteye.com/blog/2087880
纯Java写的梦幻西游,基于OpenGL.用Swing写游戏性能问题太严重

看了下,那个没源代码,而且看起来好复杂的样子...我现在还只会写简单的  = =!
4 楼 xc_wangwang 2014-11-08  
楼主有兴趣可以看看这个http://david-game.iteye.com/blog/2087880
纯Java写的梦幻西游,基于OpenGL.用Swing写游戏性能问题太严重
3 楼 QuarterLifeForJava 2014-11-08  
顶一个,不错,持续关注,期待战斗机制。
2 楼 Y_1746119035 2014-11-08  
rex0654335 写道
功能实现的很好,但是如果一开始没有设计好整个架构的话,以后添加功能会很乱,代码粘合度太高。

嗯,确实啊....我现在每加一个功能都要对前面的一些代码修改来测试去的...没这方面的经验,需要自己摸索下  = =!
1 楼 rex0654335 2014-11-07  
功能实现的很好,但是如果一开始没有设计好整个架构的话,以后添加功能会很乱,代码粘合度太高。

相关推荐

    基于JAVA的手机RPG游戏图形引擎的实现

    ### 基于JAVA的手机RPG游戏图形引擎的实现 #### 1. 引言 随着移动技术的迅速发展,手机游戏已经成为人们日常生活的重要组成部分。游戏引擎作为控制游戏运行的核心程序,在游戏开发中扮演着至关重要的角色。游戏...

    unity3D RPG游戏开发包.zip

    开发者需要设计并构建游戏环境,包括地形、建筑、物品、NPC(非玩家角色)等元素,这些都可通过导入3D模型、纹理、光照等资源来实现。 2. **角色控制器**:RPG游戏中的角色需要有精细的移动和交互控制。这通常通过...

    JS写的RPG游戏代码

    【标题】"JS写的RPG游戏代码"是一个基于JavaScript编程语言构建的角色扮演游戏(RPG)项目。这个游戏专业性高,玩家无需登录即可直接体验游戏,还可以通过留言板进行互动交流。 【描述】中提到的关键知识点包括: 1....

    RPG角色扮演游戏程序设计

    在IT行业中,RPG(Role-Playing Game)角色扮演游戏是一种深受玩家喜爱的游戏类型,它让玩家扮演虚构世界中的角色,通过探索、战斗、对话等互动元素来推进故事发展。本教程“RPG角色扮演游戏程序设计”旨在教授如何...

    TheIsleOfNull:个人项目-Java中的RPG游戏

    《空岛:Java中的RPG游戏》是一款个人项目,它展示了开发者使用Java编程语言构建一个角色扮演游戏(RPG)的能力。在这个项目中,我们将深入探讨Java语言在游戏开发中的应用,以及RPG游戏设计的基本元素。 1. **Java...

    J2ME RPG游戏源码

    - **持久化数据**:使用序列化、XML或自定义格式保存游戏进度。 - **内存管理**:J2ME设备内存有限,需要谨慎处理游戏数据的存储和加载。 8. **网络功能** - **多玩家支持**:可能包含局域网对战或在线同步游戏...

    c写的rpg完整代码

    在IT行业中,游戏开发是一项复杂而充满挑战的任务,特别是角色扮演游戏(RPG)类型,它通常需要丰富的剧情、复杂的系统和细腻的图形表现。这里我们关注的是一款使用C语言编写的RPG完整代码,它提供了多场景地图、...

    android RPG地图绘制

    在Android平台上开发一款角色扮演游戏(RPG)时,地图绘制是至关重要的部分。"android RPG地图绘制"这个主题主要涉及如何在原生Android环境中利用Tiled地图资源来创建丰富的游戏场景。Tiled是一款广泛使用的开源地图...

    U3D单机RPG

    4. **角色控制器**:RPG游戏中的角色移动、跳跃、攻击等行为需要通过角色控制器实现。开发者需要编写或使用现成的角色控制器组件,确保角色能流畅地在3D环境中移动,并处理与环境的交互。 5. **动画系统**:Unity3D...

    flex游戏 rpg game

    在RPG游戏中,这种交互性至关重要,因为它允许玩家与游戏环境进行多种互动,例如与NPC(非玩家角色)交谈、捡拾物品或触发事件。 描述中提到了"场景随人物移动",这是RPG游戏中的核心功能之一,通常称为“无缝地图...

    魔塔游戏代码

    RPG游戏通常包含角色创建、升级系统、剧情线和与环境或NPC(非玩家角色)的互动。 3. **代码**:表示这是关于源代码的分享,意味着你可以查看、学习、修改和扩展游戏的内部机制。 4. **Android**:进一步确认了游戏...

    C++ rpg demo

    【C++ RPG Demo】是一个基于C++编程语言开发的角色扮演游戏(Role-Playing Game,简称RPG)演示项目。这个项目旨在展示如何利用C++来构建一个基础的RPG游戏框架,帮助开发者理解游戏开发的基本原理和技术。在RPG游戏...

    RPG脚本\仿网游多任务系统

    2. **任务触发器**:当玩家达到特定条件,如到达某个地点、与NPC对话或完成其他任务时,任务触发器会启动。这需要在游戏世界中设置检查点和事件监听器。 3. **任务状态管理**:每个任务都有一个状态,如未接受、...

    RPG delphi code

    当我们谈论"RPG Delphi code"时,我们指的是使用Delphi语言来编写RPG游戏的源代码。这个主题涵盖了多个知识点,包括Delphi的基础、面向对象编程、游戏开发框架、图形渲染、音效处理、数据结构和算法等。 首先,...

    RPG:小型RPG游戏库

    在这个Java环境中,我们可以看到一个名为“RPG”的项目,可能是用Java语言编写的,用于创建简单的角色扮演游戏。 标题“RPG:小型RPG游戏库”暗示了这是一个专注于RPG游戏开发的库,可能包含了游戏逻辑、场景管理、...

    Android RGP游戏源码

    开发者需要掌握Java或Kotlin语言,熟悉Android SDK,理解AndroidManifest.xml配置文件,以及Activity、Service、BroadcastReceiver等组件的工作原理。 2. **RPG游戏机制**:RPG游戏通常包含角色创建、升级系统、...

    NPC-Generator

    NPC-Generator是一款基于Java开发的角色扮演游戏(RPG)非玩家角色(NPC)生成工具,专为Pathfinder游戏系统设计。Pathfinder是一种广受欢迎的桌上角色扮演游戏,玩家在游戏中扮演各种角色,与NPC互动,进行冒险和...

    js游戏源代码

    JavaScript,也被称为JS,是一种广泛应用于网页和网络应用的编程语言,尤其在创建交互式用户界面方面具有显著优势。这个“js游戏源代码”压缩包集合了使用JavaScript编写的多种游戏,是学习JavaScript编程和游戏开发...

Global site tag (gtag.js) - Google Analytics