`
michaelzjy
  • 浏览: 3518 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
最近访客 更多访客>>
社区版块
存档分类
最新评论

从简化版贪吃蛇游戏的制作谈参数传递,多线程以及吐槽自己的代码优化、bug修改以及效率问题(妈妈说过题目要长才有人看。。。)

阅读更多

        这个贪吃蛇游戏从几周前开始讲五子棋的绘制的时候就开始着手做了,一开始觉得要做还是挺简单的,最多一两天就搞定了,毕竟功能单一,逻辑也简单,因此思路很清晰,但是实际上做到后来发现各种问题层出不穷,从坐标计算到内部逻辑关系,从日出到日落(闹哪样啊,这最后一句算是什么啊。。。)下面就边举例边吐槽吧。  

       

         首先是最简单的界面实现和监听器,很基础就不多说什么了,只有一个参数传递因为之前学习的时候没有做总结,所以就在这里补上。先上代码:

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Draw extends JFrame {
public static void main(String[] args) {
Draw d = new Draw();
d.initUI();
}
private void initUI() {
this.setTitle("Draw");
this.setSize(1360,760);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(3);
this.setVisible(true);
this.setVisible(true);
Graphics g2=this.getGraphics();
Graphics g3=this.getGraphics();
Graphics g4=this.getGraphics();
        //参数传递
MouseClick click=new MouseClick(g2,g3,g4);
this.addKeyListener(click);
}

 

 

       因为在这里创建的画布对象Graphics g2,g3,g4需要传递到监听器里面,所以就要把对象作为参数来传递,如代码中做了注释的那一行。另外,你也看到了我创建了三个画布对象,是因为最开始就打算做一个颜色渐深的贪吃蛇效果(如图),但是如果要每次运动时都要设置渐进的颜色很麻烦,所以把三个画布分别设置颜色就简单多啦。

       



 


     那么界面搞好后,就要实现贪吃蛇的运动啦。而正是实现贪吃蛇的运动花费了我99%的时间。下面先上是我做贪吃蛇这段时间整体思路的几个阶段的总体思维导图,以便大家能把下面要讲的的几个点串在一起。



 

 

1、既然是贪吃蛇,那么就要先让他动起来,所以就要设定他的运动轨迹以及触发他运动的监听器。因为最开始只知道鼠标监听器,所以就用了鼠标点击来触发,点一个点,贪吃蛇就根据事先设定好的运动规律(水平运动x个单位,竖直运动y个单位)来运动到指定位置。但后来一想既然是贪吃蛇,那就最好用键盘来触发,所以研究了半天得到键盘每个按键号码的方法是什么,以及应该是哪个方法里实现,最后几经波折终于搞好,下面是实现键盘监听的代码:

 

public class MouseClick implements KeyListener{
public Graphics g4;
public Graphics g3;
public Graphics g2;
public MouseClick(Graphics g4,Graphics g3,Graphics g2){
this.g4=g4;
this.g3=g3;
this.g2=g2;
}
//得到每个按键特有的号码
public void keyPressed(KeyEvent e) {
int c1=e.getKeyCode();
}
public void keyReleased(KeyEvent arg0) {
}
public void keyTyped(KeyEvent e) {
}
}

 

得到按键的号码后,就要按照按的是哪个是哪个键来分方向运动,以向上为例,代码

 

Y1=Y1-ra;
last2Y=last2Y-ra;
last1Y=last1Y-ra;
g4.fillOval(X1-r/2,last2Y-r/2,r,r);
g3.fillOval(X1-r1/2,last1Y-r1/2,r1,r1);
     g2.fillOval(X1-r2/2,Y1-r2/2,r2,r2);
     try{
     Thread.sleep(k);
     }
     catch(Exception ef){} 
     

 

 

但是后来想做的好看一些,就想要加上过渡效果,但是当时想到的方法很麻烦,就是转向之前贪吃蛇的运动有四种可能,所以就需要分情况来设定轨迹,一共16种情况,而且每种的轨迹都是不一样的,都需要单独设定,所以代码的长度一下子变成了原来的四倍。因此轨迹的调试占了很大头,而且一不小心就会出错。。。下面还是以向上为例:

private void up() {
g4.setColor(new Color(i,i,i));
g3.setColor(new Color(j,j,j));
g2.setColor(new Color(o,o,o));
if(c==39){
g4.clearRect(0, 0, 1400, 800);
g4.fillOval(X1-r/2,Y1-ra-r/2,r,r); 
g3.fillOval(X1-r1/2,Y1-r1/2,r1,r1);
g2.fillOval(last1X-r2/2,Y1-r2/2,r2,r2);
try{
Thread.sleep(k);
}
catch(Exception ef){}
g4.clearRect(0, 0, 1400, 800);
g4.fillOval(X1-r/2,Y1-2*ra-r/2,r,r);

g3.fillOval(X1-r1/2,Y1-ra-r1/2,r1,r1);
g2.fillOval(X1-r2/2,Y1-r2/2,r2,r2);
Y1=Y1;
last1Y=Y1-ra;
last2Y=last1Y-ra;

     try{
     Thread.sleep(k);
     }
     catch(Exception ef){}
    }
if(c==37){
g4.clearRect(0, 0, 1400, 800);

g4.fillOval(last2X-r/2,last2Y+ra-r/2,r,r);
     g2.fillOval(last1X-r2/2,last2Y+2*ra-r2/2,r2,r2);
     g3.fillOval(last2X-r1/2,last2Y+2*ra-r1/2,r1,r1);
     try{
     Thread.sleep(k);
     }
     catch(Exception ef){}
     g4.clearRect(0, 0, 1400, 800);

g4.fillOval(last2X-r/2,last2Y-r/2,r,r);
     g2.fillOval(last2X-r2/2,last2Y+2*ra-r2/2,r2,r2);
     g3.fillOval(last2X-r1/2,last2Y+ra-r1/2,r1,r1);
     last1X=last2X;
     X1=last2X;
     last2Y=last2Y;
     last1Y=last2Y+ra;
     Y1=last2Y+2*ra;
     try{
     Thread.sleep(k);
     }
     catch(Exception ef){}
    } 
if(c==40){
g4.clearRect(0, 0, 1400, 800);

g4.fillOval(X1-r/2,last1Y-r/2,r,r);
     g3.fillOval(X1-r1/2,Y1-r1/2,r1,r1);
     try{
     Thread.sleep(k);
     }
     catch(Exception ef){}
     g4.clearRect(0, 0, 1400, 800);
     g4.fillOval(X1-r/2,last2Y-r/2,r,r);
     g2.fillOval(X1-r2/2,Y1-r2/2,r2,r2);
     g3.fillOval(X1-r1/2,last1Y-r1/2,r1,r1);
     try{
     Thread.sleep(k);
     }
     catch(Exception ef){}
     
     g4.clearRect(0, 0, 1400, 800);

}


while(true)
{ 
int ty = this.type;
、 if(ty == 4)
{
g4.clearRect(0, 0, 1400, 800); 
Y1=Y1-ra;
last2Y=last2Y-ra;
last1Y=last1Y-ra;
g4.fillOval(X1-r/2,last2Y-r/2,r,r);
g3.fillOval(X1-r1/2,last1Y-r1/2,r1,r1);
     g2.fillOval(X1-r2/2,Y1-r2/2,r2,r2);
     try{
     Thread.sleep(k);
     }
     catch(Exception ef){} 
}
if(ty==1){
right();
}
if(ty==2){
left();
}
if(ty==3){
down();
}

 

 

 2、在辛辛苦苦的快耗费了所有的耐心的把轨迹搞出来后,可悲的发现让蛇能自己前进的循环在按了其他方向键的时候跳不出来,调试了半天也不行心情很沮丧,所以只能找胡哥(其实我最开始打的是总,不是哥,结果发的时候说胡*是敏感词。。。胡哥你做了什么现在怎么变敏感人物了哈哈)帮忙,胡哥说要等到学了多线程之后才可以,所以我满怀期待的等着学多线程的那天...

     实际上当时用单线程也能做出来,只是因为我的对象作为参数传值时没有传好,所以没有传进来,按键变化时循环里的值不变化,所以才挑不出来,这些是后来才知道的。。。

 

3、在学过了多线程之后,就开始用多线程实现

import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class MouseClick implements KeyListener{
int c;
int type;
public Graphics g4;
public Graphics g3;
public Graphics g2;
public MouseClick(Graphics g4,Graphics g3,Graphics g2){
this.g4=g4;
this.g3=g3;
this.g2=g2;
}
public void keyPressed(KeyEvent e) {
int c1=e.getKeyCode();
Duoxian dx=new DuoXian(g2,g3,g4,type,c);
if(c1==39){
type=1;
}
if(c1==37){
type=2;
}
if(c1==40){
type=3;
}
if(c1==38){
type=4;
}
dx.start();
c=c1; 
}
public void keyReleased(KeyEvent arg0) {
}
public void keyTyped(KeyEvent e) {
}
}

 

接着在run方法里设定当type为何值时运行何种方法,并定义这些将要实现的方法,up(),down()等这四个方法在这里就不写了,想看的话在上面有。

import java.awt.Color;
import java.awt.Graphics;
public class DuoXian extends Thread{
private int type;
private int c;
private Graphics g4;
private Graphics g3;
private Graphics g2;
public DuoXian(Graphics g4,Graphics g3,Graphics g2,int type,int c){
this.g4=g4;
this.g3=g3;
this.g2=g2;
this.type=type;
this.c=c;
}
int r=30,r1=22,r2=14;
int ra=(r+r1)/2,rc=(r1+r2)/2;
int X1=650,Y1=350;
int last1X=X1-ra,last1Y=Y1-ra,last2X=last1X-ra,last2Y=last1Y-ra;
int k=300;
int i=0,j=100,o=200;

public void run(){
if(type==1)
right();
if(type==2)
left();
if(type==3)
down();
if(type==4)
up();
}

 

 

4、运行之后发现还是有问题,每次变向后,原来的不消失而是继续运动,因此就形成了多个贪吃蛇一起运动,感觉好坑爹的感觉。。。之后又各种分析逻辑结构等都没找到原因,有种想死的冲动有木有。。。这么多天一直在搞这个其他的都放了结果最后没弄出来。。。

    走投无路之时去找了康哥,在给我反复查了好长时间之后终于发现了问题。。。就是按我原来所想,就是每次变向之后,原来的线程就会停止。但事实是不是这样的,每次变向之后都会新建一个线程,所以参数的改变不会影响到之前的线程,在他的帮助下我改进了我的代码,如下:

import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class MouseClick implements KeyListener{
int c;
int type;

public Graphics g4;
public Graphics g3;
public Graphics g2;
public MouseClick(Graphics g4,Graphics g3,Graphics g2){
this.g4=g4;
this.g3=g3;
this.g2=g2;
}
public void keyPressed(KeyEvent e) {
int c1=e.getKeyCode();
if(c1==39){
type=1;
}
if(c1==37){
type=2;
}
if(c1==40){
type=3;
}
if(c1==38){
type=4;
}

if(!m_bFirstChecked) //如果是第一次运行就启动线程
{
dx=new DuoXian(g2,g3,g4,type,c);
dx.start();
m_bFirstChecked = true;
}
else
{
dx.setTypeValue(type,c);
System.out.println(type);
}
c=c1; 
}
private DuoXian dx;
private boolean m_bFirstChecked = false;

public void keyReleased(KeyEvent arg0) {
}

public void keyTyped(KeyEvent e) {

}
}

 

 

     再经过最终的调试,终于做成了由方向键控制流畅运动的贪吃蛇。Bingo!

 

     好吧,题目里是承诺要写一些对自己的吐槽,结果把这些过程写下来之后发现已经没有吐槽的必要了,要吐的已经在上面都体现出来了~~~~以上就是我对于这一次“痛苦”经历的回顾及总结,下次吸取教训就好,再有这样的经历会再贴上来的,留着以后看看以前有多傻哈哈~~

  • 大小: 2.1 KB
  • 大小: 63.3 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics