这么多天的代码,才发现,写一个程序是真的不简单。但是能用一个小程序发挥自己手中代码的巨大作用,让 我也能做一个能玩的游戏出来,是一件很有成就感的事,前几天跟小伙伴们成立了一个四个人的小组,来做一个游戏,名字叫做---旅行钓鱼,名字看起来是挺搓的,但是做起来也真的是不简单,做了四天,我们小组的成员们才做出来百分之九十,还有一小部分没有做完,正在炉里加载中。。。其实就是我负责的那一部分
就是这么一个游戏,我负责的是渔船钓鱼的那一部分,现在还有把鱼拉起来没实现(就是把鱼拉起来,就是把鱼拉起来),好吧,现在进入正文,先介绍一下我自己写的东西,这个游戏的其他部分我也在完善,我会把游戏和游戏素材上传到我的百度网盘里面(iteye好像最多传10M的),一下全是干货(这个游戏的一部分干货),会持续更新
小伙伴们看了素材以后就知道我们做这个钓鱼的船和渔人大致需要怎么做了,制作这个游戏是肯定要用到多线程的,如果跟我一样还是新手,或者对线程不是特别了解的,推荐一个网址:http://www.ibm.com/developerworks/cn/education/java/j-threads/j-threads.html ,这里面讲的比较详细。素材里面的arm图片是连在一起的,游戏里当鱼钩在动的时候,手臂就在动,而这几个手臂动的图片都在同一个png图片上,所以我们需要做的就是,把这张图片拆分(就是每次只特点显示某一部分),这样就好了,还有一个难点就是如何画一个动态的鱼线,让它跟着鱼钩走,其实也很好解决,只是当时纠结我好一阵子,用frame的Graphics画就好了,前提是我们在做渔人这个类的时候用变量记录了鱼钩的坐标,并且实时的更新它。这里面主要用到的一个方法就是,得到缓冲图的画布之后,在画布上画图片的方法drawImage();这个方法好几种传递参数的方法,功能很强大,我们可以用这个方法来实现手臂的动态效果,.drawImage(Image img, int x, int y, ImageObserver observer),这个方法的连个int参数要注意,不是把图片画在画布的什么位置,而是吧画布放在图片的那个位置,两个int类型表示起始坐标。后面的一个参数可以不管它直接填null(我也不太清楚是干什么的),对了,在创建缓冲画布的时候,要用这个构造方法BufferedImage(int width, int height, int imageType)里面前两个int参数是代表缓冲图大小,后面一个代表缓冲图类型,我们要用透明的类型BufferedImage.TYPE_INT_ARGB,缓冲图的大小一定要对,要把arm图片平均分成几个部分才好。
接下来就是对钩子的处理,我设个坐标来记录钩子位置,这里面我是用键盘的上下左右来控制船和钩子的,当按下键的时候,钩子用正向速度下落,并同时更新Y坐标,X坐标就是可以用缓冲图在frame的画布中的坐标改变一下即可。
下面我把代码粘贴出来供大家参考
//Entity是游戏的一个公共积累,可以存一些公共属性和方法 public class FishHumen extends Entity{ //这个缓冲图在frame画布上的X坐标,钩子的Y坐标,手臂图像在图片上的X坐标 private int x = 0 , hookY = 120, armX = 0; //记录鱼钩是否撞击到鱼的标志 private boolean isHitHook = false; //穿运动的速度,鱼钩的Y轴速度 private static int speed = 0, speedY = 0; //用于传进来鱼的坐标判断是鱼钩是否撞击到鱼 private Fish fish; //构造方法,把鱼传进来 public FishHumen(Fish fish){ this.fish = fish; } //画图片的方法,这里面传件来的g 是frame的画布 public void draw(Graphics g){ //新建图片对象 ImageIcon body = new ImageIcon("fisherman/body1.png"); ImageIcon arm = new ImageIcon("fisherman/arm1.png"); ImageIcon head = new ImageIcon("fisherman/head1.png"); ImageIcon boat = new ImageIcon("boat/boatBack1.png"); ImageIcon boatEngine1 = new ImageIcon("boat/boatEngine1.png"); ImageIcon boatFront1 = new ImageIcon("boat/boatFront1.png"); ImageIcon boatPropeller = new ImageIcon("boat/boatPropeller.png"); //新建缓冲图对象,这里必须把缓冲图放在这个方法里面,每一次都创建,不然在手臂动的时候,上一次动的轨迹还在上面 //大家可以自行尝试一下 BufferedImage buff = new BufferedImage(180,156,BufferedImage.TYPE_INT_ARGB); //得到缓冲图的画布来画图片在上面 Graphics bg = buff.getGraphics(); //判断是否钓到鱼 isHit(fish); //把几张图片用适当的坐标画在画布上,其中arm的横坐标每次都改变,这个方法的两个int参数不是用画在画布上 的坐标 //是画布在图片上的坐标,就想我们用老式的胶片电影,是胶片(画布)在滚动,而不是前面放的镜头(图片)在动。 bg.drawImage(arm.getImage(), armX, 0, null); bg.drawImage(boat.getImage(), 0, 10, null); bg.drawImage(body.getImage(), 0, 0, null); bg.drawImage(boatEngine1.getImage(), 0, 0, null); bg.drawImage(boatPropeller.getImage(), 0, 0, null); bg.drawImage(head.getImage(), 0, 0, null); bg.drawImage(boatFront1.getImage(), 0, 10, null); //改变鱼钩位置的方法 hookPos(g); //这里面X坐标是用来改变渔人和船的位置的 g.drawImage(buff, x, 120, null); //不能让船超界 if(x <= 0 && speed < 0){ x = 0; } //判断钩子是否超出范围 if(hookY > 500 ){ speedY = -speedY; } if(hookY < 120){ speedY = 0; isHitHook = false; } //相撞就把钩子设为反方向让它返回 if(isHitHook){ speedY = -10; } x += speed; //判断图片和画布的相对位置当放到最后一张图片的时候再返回来 if(armX == -1080){ armX = 0; } //钩子在动的时候,鱼线就动 if(speedY != 0){ armX -= 180; } } //钩子位置的方法 public void hookPos(Graphics g){ BufferedImage hookbuf = new BufferedImage(30,50,BufferedImage.TYPE_INT_ARGB); ImageIcon hook = new ImageIcon("boat/hook.png"); hookbuf.getGraphics().drawImage(hook.getImage(), 0, 0, null); g.drawImage(hookbuf, x+160, hookY, null); //System.out.println(x+160+" 佛山热 "+ hookY); g.setColor(Color.black); g.drawLine(x+178, 120, x+178, hookY+10); //System.out.println(x+160+" "+ hookY); g.setColor(Color.black); // if(isHit(null)){ // speedY = -speedY; // }else hookY += speedY; } //是否碰到鱼 public void isHit(Fish fish){ int[] fx = fish.getChangeXLocation(),fy = fish.getChangeYLocation(); for(int i = 0;i < 10;++i){ if((fx[i] >= x+178 && fx[i] <= x+238 && fy[i] >= hookY + 4 && fy[i] <= hookY +50)){ isHitHook = true; //System.out.println("isHitHook"); } } }
剩下的就是在主frame类里面启动线程和添加键盘监听器了,那些代码我就不拿出来了,键盘监听器类可以继承KeyAdapter类就好
素材 以及原版游戏 百度网盘地址:http://pan.baidu.com/s/1pJ0TeaR