寨子版植物大战僵尸总结

山寨版植物大战僵尸总结????? 最近做了一个简化版的山寨植物大战僵尸,虽然还有很多功能没有实现,但初步的

山寨版植物大战僵尸总结

????? 最近做了一个简化版的山寨植物大战僵尸,虽然还有很多功能没有实现,但初步的样子还是有了,下面就谈一下我的收获和遇到的问题吧。

????? 一、总体构架

??????????? 我的游戏主要实现了在主界面上以图片做背景,通过鼠标的点击控制,种植向日葵,豌豆,通过收获阳光获得武器,并通过豌豆的射击消灭僵尸。下面是我在各个功能实现上的想法。

??????????? [1]在有背景的界面上插入有图片的按钮。

??????????????? 这里主要涉及的是将流式布局设为空,然后使用setBounds组件。

// 设置模块panel = new MyPanel();Dimension paneldim = new Dimension(1026, 700);panel.setPreferredSize(paneldim);panel.setLayout(null);// 以绝对方式添加组件,须将容器panel布局置空this.add(panel);mainshow = new JLabel(Config.mainshow);// 背景图片大小:1026*700mainshow.setBounds(0, 0, 1026, 760);// 坐标从x=0,y=0开始,它将按背景图片大小来占据北部空间panel.add(mainshow);        //设置豌豆射手按钮peabutton = new JButton(Config.peaButton);// 图标按钮大小:60*90peabutton.setBounds(122, 6, 60, 90);peabutton.setActionCommand("peashooter");// 设置按钮动作监听命令peabutton.addActionListener(al);panel.add(peabutton);// peabutton在mainshow的范围内

?? 这样可以摆脱布局的干扰,防止背景图片把按钮挤到窗口之外。但是还会遇到按钮上的图片会被底层背景覆盖,只有当鼠标在上面点击时,图片才会闪现。

??????????? [2]在背景图片上插入记分牌。

????????????这个记分牌实际是一个文本输入框,我在输入框上插入图片,并将传入的数字设为变量,并改变了字体和颜色,也就和原版不相上下了。

??????

// 创建并设置文本域final Image CHAT_TEXT_IMAGE_BG = Config.num.getImage();    JTextField jl = new JTextField("   100"){        {            setOpaque(false);        }         public void paint(Graphics g) {            g.drawImage(CHAT_TEXT_IMAGE_BG, 0, 0, this);            super.paint(g);        }    };    jl.setBorder(new EtchedBorder());        jl.setForeground(Color.getHSBColor(0,0,0));//设置字体的颜色        jl.setFont(new Font(" ", Font.ROMAN_BASELINE, 20));//设置字体的形状和大小        jl.setBounds(29, 74, 67, 30);//设置文本框的位置和大小        panel.add(jl);

??????????? [3]在草地上画太阳花和豌豆射手

??????????????? 采用和五子棋一样的方法,将草地看成数组,给太阳花和射手定义不同的数字,给窗口添加鼠标监听器,当点击时为数组附上相应的数值,并根据数值进行重绘。

// 1.豌豆// -1.向日葵// 获取草地上中点的坐标for (int i = 0; i < Config.ROWS; i++) {for (int j = 0; j < Config.COLUMNS; j++) { x2 = Config.X + j * Config.plantwidth; y2 = Config.Y + i * Config.plantheight;// 得到离点击位置最近的草坪中点坐标if ((x1 > x2) && (x1 < (x2 + Config.plantwidth)) && (y1 > y2)&& (y1 < (y2 + Config.plantheight))) {try{                    if (Config.plant[i][j] == 0) {    if (PKUI.item.equalsIgnoreCase("peashooter")&&number>=100) {    check = 1;    } else if (PKUI.item.equalsIgnoreCase("sunflower")&&number>=50) {    check = -1;    }    putplant(i, j, check);    }}catch(Exception ef){ef.getStackTrace();}                }}}}/** * 画植物的方法 *  * @param i *            : * @param j * @param check *            ,植物,1;向日葵,2; */public void putplant(int i, int j, int check) {x = Config.X + j * Config.plantwidth;y = Config.Y + i * Config.plantheight;if (check == 1) {           g.drawImage(Config.peashooter.getImage(), x, y, Config.width,Config.height, null);// 启动豌豆线程peashooterThread thread = new peashooterThread(panel,x,y);thread.start();Config.pslist.add(thread);    number-=100;} else if (check == -1) {g.drawImage(Config.sunflower.getImage(), x, y, Config.width,Config.height, null);// 向日葵线程sunflawerThread thread = new sunflawerThread(panel,x,y);thread.start();number-=50;}// 标记二维数组Config.plant[i][j] = check;// 判断输赢

?

???????????? [4]多线程的控制

?????????????这是这个游戏采用最多的方法,每一种植物是一个线程,控制是否喷出豌豆或阳光,再用另一个线程控制豌豆和阳光尖端喷出的频率,僵尸的延时出场以及每隔一段时间出现一批,也是通过可控时间的线程TimerTask类实现的。在线程中要通过对死循环的控制来控制每种植物的出现,在其中我遇到的问题是绘制的僵尸及豌豆和阳光不停地闪烁,原因是在双缓冲中进行了重绘,在线程中又绘制了图片,绘制的多次重叠导致图片不断闪烁。只要将线程中的绘制图片取消就可以解决。

???????????? [5]双缓冲解决屏幕重绘时闪烁问题

?????????? 在主类中再定义一个内部类,实现双缓冲。

class MyPanel extends JPanel {private Image offScreenImage;Graphics gImage;// 重写update方法,先将窗体上的图形画在图片对象上,再一次性显示public void update(Graphics g) {if (offScreenImage == null) {// 截取窗体所在位置的图片offScreenImage = this.createImage(1026, 760);}// 获得截取图片的画布gImage = offScreenImage.getGraphics();// 获取画布的底色并且使用这种颜色填充画布(默认的颜色为黑色)Color c = Color.BLACK;gImage.setColor(c);gImage.fillRect(0, 0, 1026, 760); // 有清除上一步图像的功能,相当于gImage.clearRect(0,// 0, WIDTH, HEIGHT)// 将截下的图片上的画布传给重绘函数,重绘函数只需要在截图的画布上绘制即可,不必在从底层绘制paint(gImage);// 将接下来的图片加载到窗体画布上去,才能得到每次画的效果g.drawImage(offScreenImage, 0, 0, null);}public void paint(Graphics g) {// 在重绘函数中实现双缓冲机制offScreenImage = this.createImage(1026, 760);// 获得截取图片的画布gImage = offScreenImage.getGraphics();// 获取画布的底色并且使用这种颜色填充画布,如果没有填充效果的画,则会出现拖动的效果gImage.setColor(gImage.getColor());gImage.fillRect(0, 0, 1026, 760); // 有清楚上一步图像的功能,相当于gImage.clearRect(0,// 0, WIDTH, HEIGHT)// 调用父类的重绘方法,传入的是截取图片上的画布,防止再从最底层来重绘super.paint(gImage);gImage.drawImage(Config.mainshow.getImage(), 0, 0, 1026, 760, null);for (int i = 0; i < Config.ROWS; i++) {for (int j = 0; j < Config.COLUMNS; j++) {int x = Config.X + j * Config.plantwidth;int y = Config.Y + i * Config.plantheight;if (Config.plant[i][j] == 1) {gImage.drawImage(Config.peashooter.getImage(), x, y,null);} else if (Config.plant[i][j] == -1) {gImage.drawImage(Config.sunflower.getImage(), x, y,null);}}}// 绘制子弹for (int i = 0; i < Config.plist.size(); i++) {peaThread pt = Config.plist.get(i);gImage.drawImage(Config.pea.getImage(), pt.x, pt.y,Config.size, Config.size, null);//panel.repaint();}// 绘制太阳for (int i = 0; i < Config.sunlist.size(); i++) {sunfThread sf = Config.sunlist.get(i);gImage.drawImage(Config.sun.getImage(), sf.x, sf.y,100, Config.sun_width, null);}for (int i = 0; i < Config.suntlist.size(); i++) {suntThread sf = Config.suntlist.get(i);gImage.drawImage(Config.sun.getImage(), sf.x, sf.y,100, Config.sun_width, null);}           //绘制僵尸   for(int i = 0;i<Config.dlist.size();i++){   death2Thread df = Config.dlist.get(i);   gImage.drawImage(Config.death1.getImage(), df.x,df.y, null); //   if((j+1)==(3*i-2)){//   gImage.drawImage(Config.death1.getImage(), df.x,df.y, null);   //   }else if((j+1)==(3*i-1)){//   gImage.drawImage(Config.death2.getImage(), df.x,df.y, null); //   }else if((j+1)==3*i){//   gImage.drawImage(Config.death2.getImage(), df.x,df.y, null); //   }//   }//    death2Thread df = Config.dlist.get(i);//    gImage.drawImage(Config.death1.getImage(), df.x,df.y, null);//       }//for (int i = 0; i < Config.dlist.size(); i++) {////final death2Thread df = Config.dlist.get(i);//Runnable rb = new Runnable(){//int n=1;//public void run(){//while(true){//gImage.drawImage(new ImageIcon("death"+n+".png").getImage(), df.x--, df.y, null);//n++;//if(n>3){//n=1;//}//try {//Thread.sleep(1000);//} catch (InterruptedException e) {//e.printStackTrace();//}//}////}//};//new Thread(rb).start();//////}// 将接下来的图片加载到窗体画布上去,才能考到每次画的效果g.drawImage(offScreenImage, 0, 0, null);}}

?

???? [6]控制小球与僵尸碰撞时消去小球和僵尸

???????? 主要采用了线程监听类,当碰撞时,在存储的队列中移除对象即可。

?二、自己遇到的困难和需要解决的问题

?????? 1、图片交换来实现僵尸的动态行走,图片和移动的位置,以及线程所取得的图片未能很好的搭配到一起,所以这个功能没有实现。 2、点击相应的按钮后每种植物只能种植一次,这也是我接下来要解决的问题。

?????? 同时由于每一个线程都是一个类,所以类的繁多造成了传参的混乱,也给我的彼岸陈国成造成了不小的麻烦

?????? 最后也是最要提的一点就是,一定要把自己的项目及时备份,我的项目在第三天的时候,被自己误删了,不得不从头开始写,这耽误了我很多时间,也是给我一个教训,一定要备份。

?

?

?

?

?

?

?

?

?