一个简单的示例讲解游戏游戏编程原理。附示例源码(转)

一个简单的示例讲解游戏游戏编程原理。附示例源码(转)

房子到期了,刚搬家,网还没转过去,回去之后一个人只能看看广告,不想被电视台QJ,于是就在公司赖着蹭网、蹭空调。实在太无聊,刚好昨天和@zhzhxtrrk聊到了移动设备上的游戏开发,据说在国外美刀赚很凶的,于是乎就写个玩玩呗,度过漫漫长夜。。。

说实话不想装sdk,于是就java上了,上网down素材。。。。然后开始动工。

先简单介绍下游戏的原理吧。

一、重写jpanel的print方法,在这个方法里面做的事情:1.画障碍物(顶部的尖刺) 2.画地板队列中的所有地板 3.画人 4.画图血条等提示信息

二、新建一个线程,这个线程不停的循环,在这个线程中做的事情:1.更新地板的位置 2.随即生成新的地板 3.更新地板动画 4.删除已经在窗口外面的地板

      每次循环休眠一段时间,每个循环是一个时钟周期,不同的时钟周期做不同的事情(35个时钟周期生成一个地板,7个时钟周期更新一次地板动画)

效果图:

一个简单的示例讲解游戏游戏编程原理。附示例源码(转)_第1张图片

核心代码剖析:

view plain copy to clipboard print ?
  1. //重写PAINT方法   
  2.     public   void  paint(Graphics g) {  
  3.         g1.clearRect(0 0 300 400 );  
  4.   
  5.         //画顶部的尖刺   
  6.         for  ( int  i =  0 ; i <  300  /  15 ; i++) {  
  7.             g1.drawImage(chi, 15  * i,  30 null );  
  8.         }  
  9.         man.drawMan(g1);  
  10.         NFloor tempFloor = null ;  
  11.         //画所有地板   
  12.         for  ( int  i =  0 ; i < floorList.size(); i++) {  
  13.             tempFloor = (NFloor) floorList.get(i);  
  14.             tempFloor.drawFloor(g1);  
  15.         }  
  16.   
  17.         g1.setColor(Color.ORANGE);  
  18.         g1.setFont(new  Font( "Courier" , Font.BOLD,  20 ));  
  19.         g1.drawString("已经:"  + man.getFloor() +  "层" 10 60 );  
  20.         g1.drawString("血:" 10 85 );  
  21.           
  22.         g1.setColor(Color.RED);  
  23.         g1.fillRect(40 75 , man.getHealth(),  10 );  
  24.           
  25.         g1.setColor(Color.YELLOW);  
  26.         g1.fillRect(40 +man.getHealth(),  75 100 -man.getHealth(),  10 );  
  27.   
  28.         g.drawImage(buffimg, 0 0 this );  
  29.     }  
//重写PAINT方法 public void paint(Graphics g) { g1.clearRect(0, 0, 300, 400); //画顶部的尖刺 for (int i = 0; i < 300 / 15; i++) { g1.drawImage(chi, 15 * i, 30, null); } man.drawMan(g1); NFloor tempFloor = null; //画所有地板 for (int i = 0; i < floorList.size(); i++) { tempFloor = (NFloor) floorList.get(i); tempFloor.drawFloor(g1); } g1.setColor(Color.ORANGE); g1.setFont(new Font("Courier", Font.BOLD, 20)); g1.drawString("已经:" + man.getFloor() + "层", 10, 60); g1.drawString("血:", 10, 85); g1.setColor(Color.RED); g1.fillRect(40, 75, man.getHealth(), 10); g1.setColor(Color.YELLOW); g1.fillRect(40+man.getHealth(), 75, 100-man.getHealth(), 10); g.drawImage(buffimg, 0, 0, this); }

在画图方法中不需要关注任何信息,只需要获取需要画图的对象,然后调用对象的画图方法即可。这里图片的尖刺是画出来的,如果能在底部图上把这些直接画上也是可以的。这样做也有好处,我们可以在画布的四周全部布满尖刺,如果碰到尖刺就死亡,这个也是可以的。

view plain copy to clipboard print ?
  1. if  (floorList.size() <  10 ) {  
  2.                         num++;  
  3.                         int  floor_x = ( int ) (Math.random() * ( 300  -  100 ));  
  4.                         floorList.add(new  NFloor(floor_x,  400  + ( int ) (Math.random() *  3 ),  
  5.                             (int ) (Math.random() *  6 ), num));  
  6.                     }  
if (floorList.size() < 10) { num++; int floor_x = (int) (Math.random() * (300 - 100)); floorList.add(new NFloor(floor_x, 400 + (int) (Math.random() * 3), (int) (Math.random() * 6), num)); }

地板的生成:地板队列(floorList)小于10的时候(表明同事出现的地板不超过10个),随即生成一个NFloor,X坐标为(int) (Math.random() * (300 - 100))因为画布宽度为300,地板为100,所以我们不能让地板的最右边超出画布,所以就是300-100之间的随机数。请看下图X的取值原理

一个简单的示例讲解游戏游戏编程原理。附示例源码(转)_第2张图片

view plain copy to clipboard print ?
  1. //RUN 方法   
  2.     public   void  run() {  
  3.         int  count =  0 ;  
  4.         int  num =  0 ;  
  5.         while  ( true ) {  
  6.             if  (!man.isDie()) {  
  7.                 //更新地板的位置   
  8.                 for  (NFloor floor : floorList) {  
  9.                     floor.setY(floor.getY() - floor.getSpeed());  
  10.                 }  
  11.                   
  12.                   
  13.                 //生成新地板,35个周期生成一个   
  14.                 if  (count %  35  ==  0 ) {  
  15.                     if  (floorList.size() <  10 ) {  
  16.                         num++;  
  17.                         int  floor_x = ( int ) (Math.random() * ( 300  -  100 ));  
  18.                         floorList.add(new  NFloor(floor_x,  400  + ( int ) (Math.random() *  3 ),  
  19.                             (int ) (Math.random() *  6 ), num));  
  20.                     }  
  21.                       
  22.                     count = 0 ;  
  23.                 }  
  24.                   
  25.                 if (count %  7  ==  0 ){  
  26.                     //更新地板动画   
  27.                     for  (NFloor floor : floorList) {  
  28.                         floor.update();  
  29.                     }  
  30.                 }  
  31.                   
  32.                 count++;  
  33.   
  34.                 //删除地板   
  35.                 for  (Iterator<NFloor> it =  this .floorList.iterator(); it.hasNext();) {  
  36.                     NFloor floor = (NFloor) it.next();  
  37.                     if  (floor.getY() <  40 ) {  
  38.                         it.remove();  
  39.                     }  
  40.                 }  
  41.   
  42.                 //重画   
  43.                 repaint();  
  44.             }else {  
  45.                 //清空数据   
  46.                 floorList.removeAllElements();  
  47.                 count = 0 ;  
  48.                 num = 0 ;  
  49.                 man.setHealth(100 );  
  50.             }  
  51.   
  52.             try  {  
  53.                 Thread.sleep(20 );  
  54.             } catch  (InterruptedException e) {  
  55.                 e.printStackTrace();  
  56.             }  
  57.         }  
  58.     }  
//RUN 方法 public void run() { int count = 0; int num = 0; while (true) { if (!man.isDie()) { //更新地板的位置 for (NFloor floor : floorList) { floor.setY(floor.getY() - floor.getSpeed()); } //生成新地板,35个周期生成一个 if (count % 35 == 0) { if (floorList.size() < 10) { num++; int floor_x = (int) (Math.random() * (300 - 100)); floorList.add(new NFloor(floor_x, 400 + (int) (Math.random() * 3), (int) (Math.random() * 6), num)); } count = 0; } if(count % 7 == 0){ //更新地板动画 for (NFloor floor : floorList) { floor.update(); } } count++; //删除地板 for (Iterator<NFloor> it = this.floorList.iterator(); it.hasNext();) { NFloor floor = (NFloor) it.next(); if (floor.getY() < 40) { it.remove(); } } //重画 repaint(); }else{ //清空数据 floorList.removeAllElements(); count = 0; num = 0; man.setHealth(100); } try { Thread.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); } } }

新启动的这个线程中会控制时钟周期(每次时钟周期休眠一段时间,这个值可以看效果订),每个时钟都会更新地板的位置,地板位置的计算公式:x坐标不 变(地板X轴始终是不变的)y=y-speed(Y轴的坐标会每次以一定的速度减少,看到的效果就是地板在不停的上升)。同时每35个时钟周期会随即生成 一个地板。

同时我们会在每个时钟周期判断一个地板是否超过了画布,如果超过了就直接删除掉。

由于画板中有些地板是有动画效果的,所以需要每7个时钟周期更新一下地板的状态,做出动画效果floor.update()这个随后讲地板的时候在介绍

最后会掉一次repaint()把更新完成的数据重新在画布上画出来。

地板类:

view plain copy to clipboard print ?
  1. public   void  drawFloor(Graphics g1) {  
  2.         //貌似没有找到空心的资源,所以手动画之。。。   
  3.         if (style== 5 ){  
  4.             g1.setColor(Color.GRAY);  
  5.             g1.fillRect(x, y, width, heigth);  
  6.             return ;  
  7.         }  
  8.           
  9.         //其他类型的图片都在资源文件里面,这里只需要根据不同的style(地板类型)、donghua(地板的动画状态)来获取需要画的图片即可   
  10.         try  {  
  11.             img = ImageIO  
  12.                 .read(new  File(res.get(String.valueOf(style)).get(String.valueOf(donghua))));  
  13.         } catch  (IOException e) {  
  14.         }  
  15.           
  16.         g1.drawImage(img, x, y, null );  
  17.     }  
public void drawFloor(Graphics g1) { //貌似没有找到空心的资源,所以手动画之。。。 if(style==5){ g1.setColor(Color.GRAY); g1.fillRect(x, y, width, heigth); return; } //其他类型的图片都在资源文件里面,这里只需要根据不同的style(地板类型)、donghua(地板的动画状态)来获取需要画的图片即可 try { img = ImageIO .read(new File(res.get(String.valueOf(style)).get(String.valueOf(donghua)))); } catch (IOException e) { } g1.drawImage(img, x, y, null); }

每次画地板的时候根据地板的不同style(地板类型)、donghua(地板的动画状态)来获取需要画的图片,然后画到画布上。

view plain copy to clipboard print ?
  1. public   void  update() {  
  2.        //每次更新,获取到动画的状态,status计数器自增,statusNum为状态总数   
  3.        status = status + 1 ;  
  4.        //取模获取动画的循环状态   
  5.        donghua=status%statusNum;  
  6.        if (donghua== 0 ){  
  7.            status=0 ;  
  8.        }  
  9.    }  
public void update() { //每次更新,获取到动画的状态,status计数器自增,statusNum为状态总数 status = status + 1; //取模获取动画的循环状态 donghua=status%statusNum; if(donghua==0){ status=0; } }

每次获取不同的动画状态,供上面的方法在获取图片的时候获取不同的图片。

玩家类:

view plain copy to clipboard print ?
  1. public   void  drawMan(Graphics g) {  
  2.         //角色与顶端的碰撞处理   
  3.         if  (y <  40  || y >  400  || health <=  0 ) {  
  4.             isDie = true ;  
  5.         }  
  6.   
  7.         if  (!isDie) {  
  8.             for  ( int  i =  0 ; i < game.floorList.size(); i++) {  
  9.                 this .isManOnFloor =  false //初始化角色悬空   
  10.                 floor1 = (NFloor) game.floorList.get(i);  
  11.   
  12.                 //判断角色是否在地板上以及处理   
  13.                 if  (x >= floor1.getX() - MAN_WIDTH && x < floor1.getX() + floor1.width  
  14.                     && y >= floor1.getY() - MAN_HEIGHT  
  15.                     && y < floor1.getY() - MAN_HEIGHT + floor1.heigth) {  
  16.                     this .isManOnFloor =  true ;  
  17.                     floor = floor1.getNum();  
  18.                     ySpeed = floor1.getSpeed();  
  19.                     y = floor1.getY() - MAN_HEIGHT;  
  20.                     break ;  
  21.                 }  
  22.             }  
  23.   
  24.             //当人物落在地板上时对应的处理   
  25.             if  (isManOnFloor) {  
  26.                 if  (floor1 !=  null ) {  
  27.                     switch  (floor1.getStyle()) {  //判断落在的地板时什么类型,以及相应的处理方式   
  28.   
  29.                         case   0 //在刺板上,掉血一次   
  30.                             if  (!onDingChi) {  
  31.                                 health -= 20 ;  
  32.                             }  
  33.                             onDingChi = true ;  
  34.                             break ;  
  35.                         case   1 //左移动的板子,用户的速度左   
  36.                             xFloorSpeed = -1 ;  
  37.   
  38.                             break ;  
  39.                         case   2 //右移动的板子,用户的速度右   
  40.                             xFloorSpeed = 1 ;  
  41.                             break ;  
  42.                         case   3 //石头板子,不做处理   
  43.                             break ;  
  44.                         case   4 //跳板,让用户跳一下(板子上升太快,人下落太快,于是乎,出现狂跳现象)   
  45.                                 y -= 20 ;  
  46.                             break ;  
  47.                         case   5 //空心板,害人了。。把用户正常往下掉。   
  48.                             y = y + floor1.heigth;  
  49.                             break ;  
  50.                     }  
  51.                 }  
  52.             } else  {  
  53.                 //如果不是在板子上,清空板子上的状态   
  54.                 ySpeed = -4 ;  
  55.                 xFloorSpeed = 0 ;  
  56.                 onDingChi = false ;  
  57.             }  
  58.   
  59.             try  {  
  60.                 img = ImageIO.read(new  File( "Resources/ManStand.PNG" ));  
  61.             } catch  (IOException e) {  
  62.             }  
  63.   
  64.             //左右墙的处理   
  65.             if  (x >=  300  - MAN_WIDTH) {  
  66.                 x = 300  - MAN_WIDTH;  
  67.             }  
  68.             if  (x <=  0 ) {  
  69.                 x = 0 ;  
  70.             }  
  71.   
  72.             g.drawImage(img, x = x + xSpeed + xFloorSpeed, y = y - ySpeed, null );  
  73.         }  
  74.     }  
public void drawMan(Graphics g) { //角色与顶端的碰撞处理 if (y < 40 || y > 400 || health <= 0) { isDie = true; } if (!isDie) { for (int i = 0; i < game.floorList.size(); i++) { this.isManOnFloor = false; //初始化角色悬空 floor1 = (NFloor) game.floorList.get(i); //判断角色是否在地板上以及处理 if (x >= floor1.getX() - MAN_WIDTH && x < floor1.getX() + floor1.width && y >= floor1.getY() - MAN_HEIGHT && y < floor1.getY() - MAN_HEIGHT + floor1.heigth) { this.isManOnFloor = true; floor = floor1.getNum(); ySpeed = floor1.getSpeed(); y = floor1.getY() - MAN_HEIGHT; break; } } //当人物落在地板上时对应的处理 if (isManOnFloor) { if (floor1 != null) { switch (floor1.getStyle()) { //判断落在的地板时什么类型,以及相应的处理方式 case 0: //在刺板上,掉血一次 if (!onDingChi) { health -= 20; } onDingChi = true; break; case 1: //左移动的板子,用户的速度左 xFloorSpeed = -1; break; case 2: //右移动的板子,用户的速度右 xFloorSpeed = 1; break; case 3: //石头板子,不做处理 break; case 4: //跳板,让用户跳一下(板子上升太快,人下落太快,于是乎,出现狂跳现象) y -= 20; break; case 5: //空心板,害人了。。把用户正常往下掉。 y = y + floor1.heigth; break; } } } else { //如果不是在板子上,清空板子上的状态 ySpeed = -4; xFloorSpeed = 0; onDingChi = false; } try { img = ImageIO.read(new File("Resources/ManStand.PNG")); } catch (IOException e) { } //左右墙的处理 if (x >= 300 - MAN_WIDTH) { x = 300 - MAN_WIDTH; } if (x <= 0) { x = 0; } g.drawImage(img, x = x + xSpeed + xFloorSpeed, y = y - ySpeed, null); } }

在画玩家的时候会判断玩家1.是否还活着(没碰壁,血不为0) 2.玩家是否在地板上(在地板上根据不同的地板做出不同的人的坐标和速度的变化) 3.画人(根据坐标和速度来画)

好了到这里一个下100层的游戏已经搞定了。其实很简单,一个游戏就是不同的始终周期改变用户的位置,然后根据不同位置做出不同逻辑的判断。

好了就到这里吧。下次放出一个小的效验码破解的示例

最后附上源码

你可能感兴趣的:(一个简单的示例讲解游戏游戏编程原理。附示例源码(转))