【纯J***A语言做个RPG游戏】2.游戏界面及角色移动的基本实现 - 推酷
【纯J***A语言做个RPG游戏】2.游戏界面及角色移动的基本实现
继上次做的地图编辑器,我大致的做了一个的游戏地图数组,不过只画了一部分,以后要加什么新东西继续编辑这个地图就行了,保存在了一个文件中.
&&& 现在便可以继续下一步,做出游戏的大致界面了.
现在的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){
//从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 =
static boolean down =
static boolean left =
static boolean right =
public void run() {
while(true){
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
* 角色移动的方法
public void move(){
//改变角色在地图中的位置
//改变角色移动相对于固定元素点的偏移量
if(right){
//得到角色在数组中的位置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;
5.写一个游戏窗体类,游戏就在这个窗体上运行。
(1)一个窗体上放一个游戏面板,这个游戏面板需要我们自己写一个MyPanel类继承JPanel,重写里面的paint方法,在这paint方法里面通过数组画地图,用来更新游戏的地图信息,这样就可以保证面板repaint的时候,地图一直存在。再用一个刷新线程来不停的对面板进行刷新;
(2)然后对窗体***按键***器,目前只***负责移动的上下左右按键,来实现人物的移动,当然这里也可以认为是控制地图的移动,因为这是相对的(物理学相对运动
& (=@__@=) &
),至于怎么提升移动的流畅度也是通过线程处理的,
以前已经考虑过了..
* 游戏主窗体
* @author yy
public class mainFrame extends JFrame implements gameConfig{
//游戏面板
public mainFrame() {
* 设置窗体
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);
* 内部游戏按键***类
* @author yy
class PanelListenner extends KeyAdapter{
//当按键按下
public void keyPressed(KeyEvent e){
int code = e.getKeyCode();
switch (code) {
case KeyEvent.VK_UP:
Player.up =
case KeyEvent.VK_DOWN:
Player.down =
case KeyEvent.VK_LEFT:
Player.left =
case KeyEvent.VK_RIGHT:
Player.right =
//当按键释放
public void keyReleased(KeyEvent e){
int code = e.getKeyCode();
switch (code) {
case KeyEvent.VK_UP:
Player.up =
case KeyEvent.VK_DOWN:
Player.down =
case KeyEvent.VK_LEFT:
Player.left =
case KeyEvent.VK_RIGHT:
Player.right =
* 自定义内部游戏面板类
* @author yy
class MyPanel extends JPanel{
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{
public UpdateThread(JPanel panel) {
this.panel =
public void run() {
while(true){
panel.repaint();
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^)┘
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致J***A推荐游戏
J***A热门游戏
03月26日01月03日11月19日11月06日10月31日09月18日09月18日08月09日08月09日08月09日
益智类小游戏,通过在各点之间画线,四条线能形成一个四方形的盒...
08月09日08月02日07月03日06月18日06月06日05月31日05月31日05月27日05月27日05月27日
控制一直猴子去收集香蕉、宝石、水果等,然后放到篮子里。当然你...
08月06日08月02日06月21日06月14日05月27日05月21日05月20日05月03日05月03日05月03日
经典的对对碰玩法,将三个或三个以上的宝石连接一起,即可消除。
11月06日08月08日08月06日08月05日07月30日07月25日07月25日07月24日07月22日07月19日
非常独特创新的塔防游戏,会有各种不同能力的龙,去升级,然后移...
04月11日09月18日07月03日06月21日05月25日04月20日04月16日04月08日04月07日03月29日
09月18日09月18日07月25日07月19日07月19日07月17日07月17日07月17日07月05日07月04日
是不是很羡慕其他平台的跑酷游戏,而java平台上的跑酷就是渣...
09月22日08月05日05月31日05月20日04月18日03月25日03月21日03月05日01月22日12月15日
英文版,伪3D的效果,用来消磨时间吧。
09月22日09月22日05月14日04月11日04月09日01月28日01月15日11月01日10月12日09月20日
这种棋牌类,游戏的AI一定要高,否则没有挑战性也就没有乐趣。...
08月02日08月02日07月22日07月17日06月21日06月18日06月09日05月27日05月20日05月10日
以前有玩过,但依然很喜欢,阴暗的场景,恐怖的气氛,胆小勿下哦...
07月22日07月05日06月18日06月14日06月09日05月20日04月30日04月28日04月15日04月15日
战棋游戏,走格子,三国背景,还有剧情,个人感觉还不错,略有难...
06月27日06月18日06月04日05月10日05月06日10月24日10月10日10月05日08月14日08月12日
横板过关,游戏画面卡通风格,整体比较普通,没有太多亮点,打分...
10月09日09月18日08月09日08月09日08月09日08月02日08月02日08月02日07月25日07月25日2010年5月 Java大版内专家分月排行榜第一2010年2月 Java大版内专家分月排行榜第一2010年1月 Java大版内专家分月排行榜第一2010年1月 Oracle大版内专家分月排行榜第一2009年12月 Java大版内专家分月排行榜第一2009年12月 Oracle大版内专家分月排行榜第一
2010年2月 Oracle大版内专家分月排行榜第三
2010年5月 Java大版内专家分月排行榜第一2010年2月 Java大版内专家分月排行榜第一2010年1月 Java大版内专家分月排行榜第一2010年1月 Oracle大版内专家分月排行榜第一2009年12月 Java大版内专家分月排行榜第一2009年12月 Oracle大版内专家分月排行榜第一
2010年2月 Oracle大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。