`

【纯JAVA语言做个RPG游戏】2.游戏界面及角色移动的基本实现

阅读更多

    继上次做的地图编辑器,我大致的做了一个4000X4000的游戏地图数组,不过只画了一部分,以后要加什么新东西继续编辑这个地图就行了,保存在了一个文件中.

    现在便可以继续下一步,做出游戏的大致界面了.

    现在的2D游戏界面常见的大致有两种形式:

    1.一种是地图在游戏窗体上固定,人在地图中走动(也就是人相对屏幕移动了);

    2.而另一种则是游戏人物位置固定,游戏的地图在移动,这样看起来也是人物移动了。

    前一种方式地图的大小都给限定死了,不能超出屏幕,要显示大地图的话,通常都是将一个大地图分成若干个区域,然后通过设置门或者传送阵之类的进行整个地图的切换。而后者则没有限定地图的大小,人物可以安逸的走到任意大小地图的任意一个角落。

    当然也有一些游戏是将上面两种模式结合起来了,比如人物走到超过某一个位置时,就开始移动地图,这种混合的模式比较广泛的应用于卷轴式游戏中,例如冒险岛,dnf之类的.

    这里我选择的是第二种形式,因为我觉得将地图分区太麻烦了,用前面做的地图编辑器一次性做一张大的地图更省事。

    那么,首先确定好任务的位置在游戏窗体的正中央,游戏的地图数组是一个二维数组,游戏地图不会小于我们的游戏窗体,所以游戏窗体在任意的一个时刻显示的都仅仅是一个游戏地图的一部分(我们在游戏窗体上显示的时候,仅仅需要读取和操作地图二维数组的一部分值就够了)。

    我们如何来知道目前该显示哪一片地图数组中的内容到游戏面板上呢?这就要靠我们控制的角色了,通过上下左右控制角色相对整张地图的坐标,我们可以将整个游戏面板区域看作是我们操作的角色的视野,通过角色相对与整张地图的坐标,来得到角色相对地图数组的位置(即角色在数组中的i,j),这样就可以找到角色i,j旁边的一系列数组元素了。

    当然,只照上面那样做的话,游戏的画面就会是一格一格动的,因为一个数组元素代表的是一个正方形的图片,角色的视野元素每变一次都至少一变化了一排的元素,不可能说只变化2分之一或者3分之一排的元素,这样画面就是按元素格移动,而不是像素点,看起来就会很恶心,一点都不流畅,要让游戏的画面按像素点移动该怎么做呢?

    首先,还是和前面一样的思维,按照角色相对数组的坐标,找出角色位置旁边的数组元素,但在显示这些元素的时候就不能通过角色相对数组的坐标来画了,要用角色相对地图的坐标来画。由于角色相对地图的坐标变化是连续的,所以这样画出来的图像也是连续的.

 

下面上代码:

1.首先写一个游戏界面和元素的配置接口,其他类需要用到一些这里面的基本配置信息时只需实现这个接口。

/**
 * 游戏配置接口
 * @author yy
 *
 */
public interface gameConfig {
	//游戏主窗体名字
	String title = "场景移动小游戏";
	//游戏主窗体的大小
	int frameX = 700;
	int frameY = 700;
	//游戏面板大小
	int panelX = 650;
	int panelY = 650;
	//游戏素材大小
	int elesize = 50;
	//人物大小
	int playersize = 50;
	//------------[游戏素材]----------
	//-----第一层
	ImageIcon icon0 = new ImageIcon("000空白.png");
	ImageIcon icon1 = new ImageIcon("001草地.png");
	ImageIcon icon2 = new ImageIcon("002地砖.png");
	ImageIcon icon3 = new ImageIcon("003召泽地板副本.png");
	ImageIcon icon100 = new ImageIcon("100红树.png");
	ImageIcon icon101 = new ImageIcon("101绿树.png");
	ImageIcon icon102 = new ImageIcon("102绿竹.png");
	ImageIcon icon103 = new ImageIcon("103高绿树.png");
	ImageIcon icon150 = new ImageIcon("150岩浆.png");
	
	
	//镜头
//	ImageIcon shadow = new ImageIcon("镜头阴影.png");
	ImageIcon shadow2 = new ImageIcon("镜头阴影2.png");
	
	
	
}

 

2.写一个类用来读取之前做好的游戏地图数组文件(读入的顺序和前面写入时一样):

/**
 * 读入地图文件
 * @author yy
 *
 */
public class ReadMapFile {
	//定义静态的三个数组,用来保存从地图文件中读取到的三个地图数组
	static int[][] map1;
	static int[][] map2;
	static int[][] map3;
	/**
	 * 读入地图
	 * @param path 地图文件位置
	 */
	static void readfile(String path){
		try{
			//从path路径下的地图文件中得到文件输入流
			FileInputStream fis = new FileInputStream(path);
			//将文件输入流包装成基本数据输入流
			DataInputStream dis = new DataInputStream(fis);
			//按保存时候的顺序依次读出地图文件中的三个地图数组
			int i = dis.readInt();
			int j = dis.readInt();
			map1 = new int[i][j];
			map2 = new int[i][j];
			map3 = new int[i][j];
			for(int ii=0;ii<i;ii++){
				for(int jj=0;jj<j;jj++){
					map1[ii][jj] = dis.readInt();
					map2[ii][jj] = dis.readInt();
					map3[ii][jj] = dis.readInt();
				}
			}
			dis.close();
			fis.close();
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}

3.写一个玩家类,来确定玩家在游戏地图中的位置(角色位移偏移量对50求余,用来补充两个元素之间的间隔无法连续显示的间隙,从而达成像素点移动)。

/**
 * 角色类
 * @author yy
 *
 */
public class Player extends Thread implements gameConfig{
	//角色中点相对游戏面板的位置(在游戏中是不变的)
	static int px = panelX/2;
	static int py = panelY/2;
	//角色中点在整张地图中的位置(设置人最开始中点的位置一定要是一个元素中心的位置,要不然这种移动就会出问题 - -!)
	static int x = 25;
	static int y = 25;
	//角色的偏移量(实现像素点移动关键的部分)
	static int mx = 0;
	static int my = 0;
	//角色的步长
	static int step = 1;
	//角色是否移动
	static boolean up = false;
	static boolean down = false;
	static boolean left = false;
	static boolean right = false;
	@Override
	public void run() {
		while(true){
			move();
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 角色移动的方法
	 */
	public void move(){
		if(up){
			//改变角色在地图中的位置
			y=y-step;
			//改变角色移动相对于固定元素点的偏移量
			my=my-step;
		}
		if(down){
			y=y+step;
			my=my+step;
		}
		if(left){
			x=x-step;
			mx=mx-step;
		}
		if(right){
			x=x+step;
			mx=mx+step;
		}
	}
	//得到角色在数组中的位置I
	public static int getI(){
		return (y-(playersize/2))/50;
	}
	//得到角色在数组中的位置J
	public static int getJ(){
		return (x-(playersize/2))/50;
	}
}

4.一个工具类,用来让程序能用过读取到数组中的int数据,找到相匹配的元素图片对象。

/**
 * 游戏面板通过读取数组中的int来匹配到相应的元素图片方法类
 * @author yy
 *
 */
public class GetMap implements gameConfig{
	//通过数字匹配图片
		static ImageIcon int2icon(int num){
			if(num==0){
				return icon0;
			}else if(num==1){
				return icon1;
			}else if(num==2){
				return icon2;
			}else if(num==3){
				return icon3;
			}else if(num==100){
				return icon100;
			}else if(num==101){
				return icon101;
			}else if(num==102){
				return icon102;
			}else if(num==103){
				return icon103;
			}else if(num==150){
				return icon150;
			}
			return null;
		}
}

 

5.写一个游戏窗体类,游戏就在这个窗体上运行。

    (1)一个窗体上放一个游戏面板,这个游戏面板需要我们自己写一个MyPanel类继承JPanel,重写里面的paint方法,在这paint方法里面通过数组画地图,用来更新游戏的地图信息,这样就可以保证面板repaint的时候,地图一直存在。再用一个刷新线程来不停的对面板进行刷新;

    (2)然后对窗体安装按键监听器,目前只监听负责移动的上下左右按键,来实现人物的移动,当然这里也可以认为是控制地图的移动,因为这是相对的(物理学相对运动 (=@__@=) ),至于怎么提升移动的流畅度也是通过线程处理的,http://y-1746119035.iteye.com/blog/2094687以前已经考虑过了..

/**
 * 游戏主窗体
 * @author yy
 *
 */
public class mainFrame extends JFrame implements gameConfig{
	//游戏面板
	JPanel panel;
	
	public mainFrame() {
		init();
		
	}
	/**
	 * 设置窗体
	 */
	public void init(){
		this.setTitle(title);
		this.setSize(frameX, frameY);
		this.setLayout(new FlowLayout());
		this.setDefaultCloseOperation(3);
		//创建游戏面板
		panel = setpanel();
		
		this.add(panel);
		this.setVisible(true);
		//安装键盘监听器
		PanelListenner plis = new PanelListenner();
		this.addKeyListener(plis);
		
		//启动人物移动线程
		Player player = new Player();
		player.start();
		
		//启动刷新面板线程
		UpdateThread ut = new UpdateThread(panel);
		ut.start();
	}
	
	/**
	 * 设置游戏面板
	 */
	public JPanel setpanel(){
		JPanel panel = new MyPanel();
		panel.setPreferredSize(new Dimension(panelX, panelY));
		panel.setLayout(null);
		panel.setBackground(Color.black);
		
		return panel;
	}
	
	/**
	 * 内部游戏按键监听类
	 * @author yy
	 *
	 */
	class PanelListenner extends KeyAdapter{
		//当按键按下
		public void keyPressed(KeyEvent e){
			int code = e.getKeyCode();
			switch (code) {
			case KeyEvent.VK_UP:
				Player.up = true;
				break;
			case KeyEvent.VK_DOWN:
				Player.down = true;
				break;
			case KeyEvent.VK_LEFT:
				Player.left = true;
				break;
			case KeyEvent.VK_RIGHT:
				Player.right = true;
				break;

			default:
				break;
			}
		}
		//当按键释放
		public void keyReleased(KeyEvent e){
			int code = e.getKeyCode();
			switch (code) {
			case KeyEvent.VK_UP:
				Player.up = false;
				break;
			case KeyEvent.VK_DOWN:
				Player.down = false;
				break;
			case KeyEvent.VK_LEFT:
				Player.left = false;
				break;
			case KeyEvent.VK_RIGHT:
				Player.right = false;
				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);
						//第二层
						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);
						//第三层
						ImageIcon icon3 = GetMap.int2icon(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);
			
			//由于暂时还没弄好游戏角色的移动图,所以角色先用一个黑色的小球代替一下....  = =!
			g.fillOval(Player.px-elesize/2, Player.py-elesize/2, elesize, elesize);
			//个人的一个小想法,做一个黑色的图片,然后中间挖空一个圆,加上模糊效果,来模拟人的视野
			g.drawImage(shadow2.getImage(), 0, 0, 650, 650, null);
		}
	}
}

 6.补充上面的面板刷新线程类(注意游戏面板刷新线程的休眠时间一定要是最小的,且其他休眠时间是它的整数倍)

public class UpdateThread extends Thread{
	JPanel panel;
	public UpdateThread(JPanel panel) {
		this.panel = panel;
	}
	
	@Override
	public void run() {
		while(true){
			panel.repaint();
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
}

 7.最后再来个启动类,来启动程序(首先读取到地图数组,再打开窗口)

/**
 * 开始游戏
 * @author yy
 *
 */
public class test {
	public static void main(String[] args) {
		//首先从地图文件中读入地图数组
		ReadMapFile.readfile("D:\\mygame\\map\\map1.map");
		//用读到的地图数组创建游戏窗体,开始游戏
		mainFrame mf = new mainFrame();
	}
}

 

 

这样下来,一个游戏基本的框架便完成了,接下来的任务便是加入碰撞处理部分了..

运行这个程序(焦点离开那个小黑球吧,那是人物角色的替代品  = =!):



 试了一下啊,转化的gif画质简直惨不忍睹,不过还是发上来试试,gif图中有卡顿,实际程序中是没有的,虽然我不知道iteye是否能支持gif...⊙﹏⊙‖∣°....

源代码丢下面了,有兴趣的可以一起玩玩...
 搞到这个点,我特么也是醉了....还好明天没课└(^o^)┘

 

 


 

 

 

 

  • 大小: 398.8 KB
  • 大小: 708.2 KB
9
1
分享到:
评论
13 楼 L冬萤 2017-04-23  
这个走到边界会报错,还有不加那个视角阴影,旁边的地图加载不是很流畅
12 楼 wuzhongzangyue 2016-11-30  
真棒
11 楼 wangminlomt5 2016-11-05  
我想问地图有多大?怎么无限行走的,没有终点吗?用第一章的代码我改了下打开地图发现很多没有显示出来,不是2000*2000的啊~
10 楼 szk 2016-05-29  
9 楼 白千方 2016-03-23  
你好,我想问一下,可以将图像数组保存为文件,然后读取吗?
8 楼 hers 2015-10-23  
小豆包一只,问一下,你给的那个map压缩包怎么打开
7 楼 xsbird 2014-10-30  
Y_1746119035 写道
xsbird 写道
map1.map 地图呢?

额  - -!,一开始忘记传了。我做后面的检验碰撞时把这个地图覆盖了,现在没了...等后面我把碰撞和角色行走都弄好一起传吧...

ok,楼主神勇。
6 楼 Y_1746119035 2014-10-27  
xsbird 写道
map1.map 地图呢?

额  - -!,一开始忘记传了。我做后面的检验碰撞时把这个地图覆盖了,现在没了...等后面我把碰撞和角色行走都弄好一起传吧...
5 楼 xsbird 2014-10-27  
map1.map 地图呢?
4 楼 Y_1746119035 2014-10-27  
紫梦飘逸 写道
看到你,我也是醉了,

我也醉了,~ (*+﹏+*)~
3 楼 Y_1746119035 2014-10-27  
LinApex 写道
加油, 娃子。

多谢鼓励, (=^ω^=)~~
2 楼 紫梦飘逸 2014-10-26  
看到你,我也是醉了,
1 楼 LinApex 2014-10-26  
加油, 娃子。

相关推荐

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

    在本教程中,我们将深入探讨如何使用纯Java语言制作角色扮演游戏(RPG)并利用XML文件导入非玩家角色(NPC)以及实现与NPC的交互。这个项目不仅涵盖了基础的Java编程,还涉及到游戏开发中的重要概念,如数据结构、...

    【纯JAVA语言做RPG游戏】3.地图碰撞检测和角色行走的实现

    在开发一款RPG(角色扮演游戏)时,地图碰撞检测和角色行走的实现是核心功能之一。这个主题将探讨如何使用纯Java语言来处理这些问题。首先,我们要理解地图碰撞检测是确保角色不能穿过非通行区域,而角色行走则涉及...

    Github基于Java的Rpg游戏

    【标题】:“Github基于Java的Rpg游戏”指的是在GitHub上可以找到的一种使用Java编程语言开发的角色扮演游戏(Role-Playing Game,简称RPG)。这种类型的游戏通常包含丰富的剧情、角色发展和互动元素,而通过使用...

    JavaRPG-游戏

    《JavaRPG-游戏》是一款基于Java编程语言开发的角色扮演游戏,体现了Java在游戏开发领域的应用。游戏虽然简单,但包含了游戏设计的基本要素,如角色、环境、交互等,展现了Java在构建复杂逻辑和实时交互系统方面的...

    初学java时做的RPG游戏

    在初学者阶段,使用Java开发一个RPG(角色扮演游戏)是一个很好的学习项目,因为它涵盖了多种编程概念和技术。在这个过程中,开发者通常会接触到图形用户界面(GUI)、事件处理、多线程以及基本的游戏逻辑。让我们...

    java写的RPG小游戏

    Java编写的RPG小游戏是一款基于Java编程语言开发的角色扮演游戏(Role-Playing Game,简称RPG)。这类游戏通常包含丰富的故事情节、角色设定、任务系统和战斗机制,为玩家提供沉浸式的游戏体验。在Java环境下,...

    JAVA RPG 游戏 控制上下左右

    通过以上技术,我们可以构建一个基本的JAVA RPG游戏,使玩家能够自由控制角色在游戏世界的上下左右移动。实际开发中,还需要考虑更多的细节,如游戏保存和加载、音效和音乐、AI控制的敌人行为等。总之,Java提供了...

    JAVARPG小游戏

    Java RPG小游戏是一款基于Java开发的移动平台游戏,利用了Java ME(Micro Edition)技术栈,专为手机设备设计。此游戏具有完整的功能模块,包括LOGO展示、菜单系统、角色控制、地图滚动以及场景切换,为玩家提供了一...

    java 课程设计大作业 写的一个RPG游戏(代码+文档)

    这是一个基于Java语言的课程设计项目,它涉及到游戏开发,特别是角色扮演游戏(RPG)的实现。这个项目不仅包含了源代码,还有相关的实验报告和指导文档,对于学习Java编程和游戏开发的学生来说,是一个非常有价值的...

    RPG_Game.rar_Eclipse_RPG_rpg game java

    6. **学习资源**:此RPG游戏项目不仅是一个可玩的产品,也是一个学习资源,展示了如何用Java语言在移动设备上实现RPG游戏的开发流程和技术。对于想要学习游戏开发或Java ME的初学者,这个项目是一个很好的实践案例。...

    用Java写一款简单的RPG游戏

    在本文中,我们将深入探讨如何使用Java编程语言来开发一款简单的角色扮演游戏(RPG)。Java是一种广泛使用的面向对象的语言,适合构建复杂的游戏架构。我们将会涵盖以下几个关键知识点: 1. **面向对象编程**:Java...

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

    综上所述,基于JAVA的手机RPG游戏图形引擎的实现涉及多个方面的技术细节,包括MIDP中的关键API介绍、游戏引擎的整体架构设计以及地图数据文件的具体实现等。通过合理设计和优化,可以显著提高游戏的性能表现,为玩家...

    Java RPG游戏:古代传说开源源代码

    《Java RPG游戏:古代传说开源源代码》是一个基于Java编程语言开发的角色扮演游戏(RPG)项目,它的开源特性为开发者提供了一个学习和探索游戏开发的宝贵资源。通过分析和研究这个项目的源代码,我们可以深入理解Java...

    java游戏 rpg

    8. **技术实现**:在Java平台上开发RPG游戏,开发者可能会用到Java Swing或JavaFX图形库来创建游戏界面,使用Java的多线程技术来处理游戏逻辑和用户输入,以及使用面向对象的设计原则来构建游戏对象和系统。...

    java RPG小游戏

    在本项目中,"java RPG小游戏" 是一个利用Java编程语言开发的角色扮演游戏(RPG)应用,它展示了软件设计中的两种重要模式:模型-视图-控制器(MVC)架构和面向对象(OO)编程技术。以下是这两个核心知识点的详细...

    精选_基于Java实现的RPG小游戏_源码打包

    在本资源中,我们拥有一个名为“精选_基于Java实现的RPG小游戏_源码打包”的压缩包,其中包含了一个使用Java编程语言开发的角色扮演游戏(RPG)游戏源代码。这个项目是为学习和理解Java编程,特别是游戏开发方面提供...

    一款RPG游戏源代码

    4. **游戏逻辑**:RPG游戏的源代码会包含角色、敌人、物品、地图、战斗系统等核心模块的实现,开发者需要理解游戏设计和算法。 5. **数据结构与算法**:游戏中可能用到各种数据结构(如数组、链表、栈、队列、图)...

    用Swing写的一个RPG游戏

    《用Swing写的一个RPG游戏》是一款基于Java Swing库开发的角色扮演游戏(Role-Playing Game,简称RPG)。Swing是Java提供的一种用于构建桌面应用的GUI(图形用户界面)工具包,它允许开发者创建丰富的交互式用户界面...

Global site tag (gtag.js) - Google Analytics