首页 > 编程语言 >基于Java实现的坦克大战小游戏

基于Java实现的坦克大战小游戏

时间:2024-06-15 18:30:15浏览次数:15  
标签:tiles Java tileW int HOUSE 大战 MapTile 小游戏 public

选题目的和意义:

    随着人们精神文化生活的日益丰富,为了让我们在闲暇的时间多方面发展个人的兴趣爱好,为了更好地开发个人智力,游戏成为人们生活中不可缺少的一部分。游戏产业促动高科技技术不断升级,作为经济增长的一大支撑点,已经成为经济腾飞的“第四产业”。作为休闲游戏的起源应该追溯到早期的俄罗斯方块和坦克大战,坦克大战是童年经常玩的游戏,也是一款经典游戏。《坦克大战》游戏几乎家喻户晓,对我们80后90后而言,是童年最珍贵的回忆。此款游戏是一款以红白机为平台操作射击游戏,玩家可以控制自己的坦克,以歼灭对方的坦克,其操作方式及其简单,是一款男女老少皆宜的游戏。为了满足人们的个性化需求,使玩家在游戏的过程中,更能体验游戏本身的乐趣,也为了满足更好的用户体验。

1 环境要求

操作系统:Windows 7(SP1)以上

JAVA虚拟机:JDK1.8以上

开发环境:Eclipse(4.5以上)

2 角色设定

用户在系统中扮演的角色,以及可以执行的职责。

玩 家 操纵玩家坦克,与敌方坦克作战,同时保护本基地。敌方坦克随机移动,发射子弹。

3 设定玩家(玩家一,玩家二,即一个人玩还是两个人玩),我方坦克的方向和子弹由用户控制,所有墙块都可以打碎,但是铁墙是打不碎的,草地不能阻止坦克和子弹的前进,河流能阻止坦克前进,但是不能阻止子弹前进。我方基地被毁则游戏结束,自己的坦克被毁游戏也结束,唯一赢得方式是消灭所有的敌方坦克,则可以进入下一关。一关比一关的难度大,通过地图来实现。

Wall:

Visible:

git提交截图

关键代码

Map类

1.GameMap

public class GameMap {

    public static final int MAP_X = Tank.RADIUS*3;
    public static final int MAP_Y = Tank.RADIUS*3 + GameFrame.titleBarH;
    public static final int MAP_WIDTH = Constant.FRAME_WIDTH-Tank.RADIUS*6;
    public static final int MAP_HEIGHT = Constant.FRAME_HEIGHT-Tank.RADIUS*8-GameFrame.titleBarH;

    //地图元素块的容器
    private List<MapTile> tiles = new ArrayList<>();

    //大本营
    private TankHouse house;

    public GameMap() {}
    /**
     * 初始化地图元素块,level : 第几关
     */
    public void initMap(int level){
        tiles.clear();
        try {
            loadLevel(level);
        } catch (Exception e) {
            e.printStackTrace();
        }

        //初始化大本营
        house = new TankHouse();
        addHouse();
    }

    /**
     * 加载关卡信息
     * @param level
     */
    private void loadLevel(int level) throws Exception{
        //获得关卡信息类的唯一实例对象
        LevelInof levelInof = LevelInof.getInstance();
        levelInof.setLevel(level);

        Properties prop = new Properties();
        prop.load(new FileInputStream("level/lv_"+level));
        //将所有的地图信息都加载进来
        int enemyCount = Integer.parseInt(prop.getProperty("enemyCount"));
        //设置敌人数量
        levelInof.setEnemyCount(enemyCount);

        //0,1 对敌人类型解析
        String[] enemyType = prop.getProperty("enemyType").split(",");
        int[] type = new int[enemyType.length];
        for (int i = 0; i < type.length; i++) {
            type[i] = Integer.parseInt(enemyType[i]);
        }
        //设置敌人类型
        levelInof.setEnemyType(type);
        //关卡难度
        //如果没有设计游戏难度,那么就当默认的处理
        String levelType = prop.getProperty("levelType");
        levelInof.setLevelType(Integer.parseInt(levelType==null? "1" : levelType));

        String methodName = prop.getProperty("method");
        int invokeCount = Integer.parseInt(prop.getProperty("invokeCount"));
        //把实参都读取到数组中来。
        String[] params = new String[invokeCount];
        for (int i = 1; i <=invokeCount ; i++) {
            params[i-1] = prop.getProperty("param"+i);
        }
        //使用读取到的参数,调用对应的方法。
        invokeMethod(methodName,params);
    }

    //根据方法的名字和参数调用对应的方法
    private void invokeMethod(String name,String[] params){
        for (String param : params) {
            //获得每一行的方法的参数,解析。
            String[] split = param.split(",");
            //使用一个int 数组保存解析后的内容
            int[] arr = new int[split.length];
            int i;
            for (i = 0; i < split.length-1; i++) {
                arr[i] = Integer.parseInt(split[i]);
            }
            //块之间的间隔是地图块的倍数
            final int DIS = MapTile.tileW ;

            //解析最后一个double值
            int dis = (int)(Double.parseDouble(split[i])*DIS);
            switch(name){
                case "addRow":
                    addRow(MAP_X+arr[0]*DIS,MAP_Y+arr[1]*DIS,
                            MAP_X+MAP_WIDTH-arr[2]*DIS,arr[3],dis);
                    break;
                case "addCol":
                    addCol(MAP_X+arr[0]*DIS,MAP_Y+arr[1]*DIS,
                            MAP_Y+MAP_HEIGHT-arr[2]*DIS,
                            arr[3],dis);
                    break;
                case "addRect":
                    addRect(MAP_X+arr[0]*DIS,MAP_Y+arr[1]*DIS,
                            MAP_X+MAP_WIDTH-arr[2]*DIS,
                            MAP_Y+MAP_HEIGHT-arr[3]*DIS,
                            arr[4],dis);
                    break;
            }
        }
    }

    //将老巢的所有的元素块添加到地图的容器中
    private void addHouse(){
        tiles.addAll(house.getTiles());
    }

    /**
     * 某一个点确定的地图块。是否和 tiles 集合中的所有的块 有重叠的部分
     * @param tiles
     * @param x
     * @param y
     * @return 有重叠返回 true,否则 false
     */
    private boolean isCollide(List<MapTile> tiles, int x ,int y){
        for (MapTile tile : tiles) {
            int tileX = tile.getX();
            int tileY = tile.getY();
            if(Math.abs(tileX-x) < MapTile.tileW && Math.abs(tileY-y) < MapTile.tileW){
                return true;
            }
        }
        return false;
    }

    /**
     * 只对没有遮挡效果的块进行绘制
     * @param g
     */
    public void drawBk(Graphics g){
        for (MapTile tile : tiles) {
            if(tile.getType() != MapTile.TYPE_COVER)
                tile.draw(g);
        }
    }

    /**
     * 只绘制有遮挡效果的块
     * @param g
     */
    public void drawCover(Graphics g){
        for (MapTile tile : tiles) {
            if(tile.getType() == MapTile.TYPE_COVER)
                tile.draw(g);
        }
    }

    public List<MapTile> getTiles() {
        return tiles;
    }

    /**
     * 将所有的不可见的地图块从容器中移除
     */
    public void clearDestroyTile(){
        for (int i = 0; i < tiles.size(); i++) {
            MapTile tile = tiles.get(i);
            if(!tile.isVisible())
                tiles.remove(i);
        }
    }

    /**
     *往地图块容器中添加一行指定类型的地图块
     * @param startX 添加地图块的起始的x坐标
     * @param startY 添加地图块的起始的Y坐标
     * @param endX 添加地图块的结束的x坐标
     * @param type 地图块的类型
     * @param DIS 地图块之间的中心点的间隔 如果是块的宽度 意味着是连续的,
     *            如果大于块的宽度就是不连续的
     */
    public void addRow(int startX,int startY, int endX, int type, final int DIS){
        int count  = (endX - startX +DIS )/(MapTile.tileW+DIS);
        for (int i = 0; i <count ; i++) {
            MapTile tile = MapTilePool.get();
            tile.setType(type);
            tile.setX(startX + i * (MapTile.tileW+DIS));
            tile.setY(startY);
            tiles.add(tile);
        }
    }

    /**
     * 往地图元素块容器中添加一列 元素。
     * @param startX  该列的起始x坐标
     * @param startY 该列的起始y坐标
     * @param endY  改了的结束y坐标
     * @param type 元素类型
     * @param DIS 相邻元素中心点的间距
     */
    public void addCol(int startX,int startY, int endY, int type, final int DIS){
        int count  = (endY - startY +DIS)/(MapTile.tileW+DIS);
        for (int i = 0; i <count ; i++) {
            MapTile tile = MapTilePool.get();
            tile.setType(type);
            tile.setX(startX );
            tile.setY(startY + i * (MapTile.tileW+DIS));
            tiles.add(tile);
        }
    }

    //对指定的矩形区域添加元素块
    public void addRect(int startX,int startY,int endX, int endY, int type, final int DIS){
        int rows = (endY-startY+DIS)/(MapTile.tileW+DIS);
        for (int i = 0; i <rows ; i++) {
            addRow(startX,startY+i*(MapTile.tileW+DIS),endX,type,DIS);
        }
    }


}

2.TankHouse

public class TankHouse {
    //老巢的xy坐标
    public static final int HOUSE_X = (Constant.FRAME_WIDTH-3*MapTile.tileW >> 1)+2;
    public static final int HOUSE_Y = Constant.FRAME_HEIGHT-2 *MapTile.tileW;

    //一共六块地图块
    private List<MapTile> tiles = new ArrayList<>();
    public TankHouse() {
        tiles.add(new MapTile(HOUSE_X,HOUSE_Y));
        tiles.add(new MapTile(HOUSE_X,HOUSE_Y+MapTile.tileW));
        tiles.add(new MapTile(HOUSE_X+MapTile.tileW,HOUSE_Y));

        tiles.add(new MapTile(HOUSE_X+MapTile.tileW*2,HOUSE_Y));
        tiles.add(new MapTile(HOUSE_X+MapTile.tileW*2,HOUSE_Y+MapTile.tileW));
        //有文字的块
        tiles.add(new MapTile(HOUSE_X+MapTile.tileW,HOUSE_Y+MapTile.tileW));
        //设置老巢地图块的类型
        tiles.get(tiles.size()-1).setType(MapTile.TYPE_HOUSE);
    }

    public  void draw(Graphics g){
        for (MapTile tile : tiles) {
            tile.draw(g);
        }
    }

    public List<MapTile> getTiles() {
        return tiles;
    }
}


3.MapTile

public class MapTile {

    public static final int TYPE_NORMAL = 0;
    public static final int TYPE_HOUSE = 1;
    public static final int TYPE_COVER = 2;
    public static final int TYPE_HARD = 3;


    public static int tileW = 40;
    public static int radius = tileW >> 1;
    private int type = TYPE_NORMAL;

    private static Image[] tileImg;
    static{
        tileImg = new Image[4];
        tileImg[TYPE_NORMAL] = MyUtil.createImage("res/tile.png");
        tileImg[TYPE_HOUSE] = MyUtil.createImage("res/house.png");
        tileImg[TYPE_COVER] = MyUtil.createImage("res/cover.png");
        tileImg[TYPE_HARD] = MyUtil.createImage("res/hard.png");

        if(tileW <=0){
            tileW = tileImg[TYPE_NORMAL].getWidth(null);
        }
    }

    //图片资源的左上角
    private int x,y;
    private boolean visible = true;

    public MapTile() {
    }

    public MapTile(int x, int y) {
        this.x = x;
        this.y = y;
        if(tileW <=0){
            tileW = tileImg[TYPE_NORMAL].getWidth(null);
        }
    }

    public void draw(Graphics g){
        if(!visible)
            return;

        if(tileW <=0){
            tileW = tileImg[TYPE_NORMAL].getWidth(null);
        }

        g.drawImage(tileImg[type],x,y,null);

    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public boolean isVisible() {
        return visible;
    }

    public void setVisible(boolean visible) {
        this.visible = visible;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    /**
     * 地图块和若干个子弹是否有碰撞
     * @param bullets
     * @return
     */
    public boolean isCollideBullet(List<Bullet> bullets){
        if(!visible || type == TYPE_COVER)
            return false;
        for (int i = 0; i < bullets.size(); i++) {
            Bullet bullet = bullets.get(i);
//        }
//        for (Bullet bullet : bullets) {
            int bulletX = bullet.getX();
            int bulletY = bullet.getY();
            boolean collide = MyUtil.isCollide(x + radius, y + radius, radius, bulletX, bulletY);
            if(collide){
                //子弹的销毁
                bullet.setVisible(false);
                BulletsPool.theReturn(bullet);
                return true;
            }
        }
        return false;
    }

    //判断当前的地图块是否是老巢
    public boolean isHouse(){
        return type == TYPE_HOUSE;
    }

    @Override
    public String toString() {
        return "MapTile{" +
                "x=" + x +
                ", y=" + y +
                ", visible=" + visible +
                '}';
    }
}


 

标签:tiles,Java,tileW,int,HOUSE,大战,MapTile,小游戏,public
From: https://blog.csdn.net/2301_81898675/article/details/139705985

相关文章

  • idea中给java程序传启动参数的说明
    一、idea中给java程序传启动参数的说明在idea中运行java程序时可以传递三种类型的参数:vm参数,环境变量参数,程序参数publicclassMyTest{publicstaticvoidmain(String[]args){//获取vmoptions传递的参数Stringparam1=System.getProperty("v......
  • 小吴讲故事之假如我有100w(java生成pdf文档,一页A4多条数据)
    故事背景各位码农们好!我是在社会接受练习时长2年半的java练习生,大家也可以叫我小卡拉米吴!最近在项目中遇到一个需求,就是有关于pdf文件生成的,具体需求如下。到了小卡拉米吴讲故事的时间了:事情是这样的。小吴是一名普通的码农,和野原广志一样,但不是小组长,生活除了工作就是回......
  • java设计模式之-工厂模式
    工厂模式是一种创建对象的设计模式,它通过将对象的实例化过程封装在一个工厂类中,从而实现对象的创建和使用的解耦。它属于创建型模式的一种,可以帮助我们更加灵活地创建对象。工厂模式主要解决的问题是在对象的创建过程中,如果直接在代码中使用new关键字来创建对象,会导致代码的耦合......
  • Java——变量作用域和生命周期
    一、作用域1、作用域简介在Java中,作用域(Scope)指的是变量、方法和类在代码中的可见性和生命周期。理解作用域有助于编写更清晰、更高效的代码。2、作用域块作用域(BlockScope):块作用域是指在大括号{}内定义的变量的作用域。变量只在其定义的块内可见和有效,包括循环、条件......
  • java1
    在继承中,创建子类对象,访问成员方法的规则: 创建的对象是谁,就优先用谁,没有再向上找 注意:无论是成员变量还是成员方法, 如果没有都是向上找父类,不会向下找子类继承的特点:子类可以拥有父类的内容,此处子类还可以拥有自己独有的内容(成员变量和方法) 定义继承的格式:(至少需要......
  • 第六站:Java橙——JavaFX的动感舞台
    JavaFX入门案例:创建一个基础UI应用JavaFX允许开发者使用Java语言来设计和实现富客户端应用程序,这些应用程序具有高度互动的用户界面(UI),支持2D和3D图形,以及媒体播放等特性。下面,我们将通过一个简单的案例来展示如何使用JavaFX创建一个基本的UI应用,包括UI设计、构建场景图、......
  • 认识 Java 里的线程和方法
    Thread和Runnable的区别Thread才是Java里对线程的唯一抽象,Runnable只是对任务(业务逻辑)的抽象。Thread可以接受任意一个Runnable的实例并执行启动线程的方式有:1、XextendsThread;,然后X.start2、XimplementsRunnable;然后交给Thread运行永远都只有thread.star......
  • Linux下Java环境安装
    Linux下open-jdk1.8安装教程一.下载安装包Javadownload下载后上传到服务器二.安装1.解压安装包tar-zxvfjdk-8u341-linux-x64.tar.gz2.配置环境变量在/etc/profile文件中,新增Java的环境变量vi/etc/profileexportJAVA_HOME=/usr/local/jdk/jdk1.8.0_341export......
  • Java接口的介绍与使用,多态的介绍与使用
    第一章.接口1.接口的介绍2.接口的定义以及使用1.接口:是一个引用数据类型,是一种标准,规则2.关键字:a.interface接口publicinterface接口名{}b.implements实现实现类implements接口名{}3.接口中可以定义的成员:a.jdk7以及之......
  • Java习题
    1.题目使用Java的输入、输出流将一个文本文件的内容按行读出,每读出一行就顺序添加行号,并写入到另一个文件中。代码及详细注释importjava.io.*;//导入JavaI/O库中的所有类publicclassE{//定义一个公共类Epublicstaticvoidmain(Stringargs[]){//主......