简单坦克大战

简单坦克大战

一.游戏思路:
1.首先建立物体的定义类,在建立坦克定义类,子弹定义类,铁,墙,水等定义类分别继承基类物体定义类;建立xml文件用来存储坦克与子弹每种类型的每种等级,同时也存储每个关卡的障碍物;定义类中的数据全都来自xml中存储数据,所以还需要建立相对应的节点类型的类
2,.然后建立物体类,给物体添加所有其他物体子类的所有属性和方法;
每个物体都有位置,定义,方向,场景,类型,队伍;之后创建坦克,
子单等继承物体
3.坦克的移动以及坦克的发射子弹:敌方坦克移动改变方向可以每次move后用随机概率
nextDouble方法来绝定是否该变方向,用随机数来随机该变方向,
我方用键盘来判断是否移动与改变方向,敌方发射子弹用move步数来判断,我方用键盘来判读
4.在建立场景类,场景类是画板,用来画所有物体,同时场景实现接口键盘监听和建立一个线程,在场景里添加一个Vector物体类集合在paint方法中画物体,在线程里面每睡眠40秒后就移动和发射子弹
以及物体与物体之间的碰撞;物体碰撞:以每个物体的中心与中心之间的距离判断,如果在范围类就是碰撞了进行碰撞处理
5.建立窗口,在窗口中添加一个主菜单:”菜单”以及四个分菜单:新游戏,退出游戏,继续游戏,暂停,窗口实现动作监听,用setActionCommand方法来判别4个功能

二.曾经错处:
1.总是坦克,子弹等物体都是分别创建一个集合来遍历,画,让基类物体
几乎成了摆设

public Vector<ObjectScene> list = new Vector<ObjectScene>();
 for (int i = 0; i < list.size(); i++) {
                ObjectScene object = list.get(i);
                object.drawColor(g);//给自己添加颜色
                object.drawMySelf(g);//画自己
for (int i = 0; i < list.size(); i++) {
                    step = 0;
                    ObjectScene objecti = list.get(i);
                    objecti.launchBullet();
                    ArrayList<ObjectScene> colision = new ArrayList<ObjectScene>();    //物体碰撞后集合
                    for (int j = 0; j < list.size(); j++) {
                        ObjectScene objecctj = list.get(j);
                        if (objecti != objecctj && judecolision(objecti, objecctj)) {
                            if (objecti.type == TypeUtil.TANK && objecctj.type == TypeUtil.TANK) {    //tupe类型
                                objecti.move();
                            }
                        }
                    }
                    objecti.move();
                    for (int j = 0; j < list.size(); j++) {
                        ObjectScene objecctj = list.get(j);
                        if (objecti != objecctj && judecolision(objecti, objecctj)) {
                            colision.add(objecctj);
                        }

这里写图片描述
解决问题:在父类里面添加上所有子类的抽象方法,同时在父类里面添加一个int类型的类别变量和一个枚主类型队伍类,这样遍历的时候可以辨别敌我坦克子弹,墙,铁等

2.坦克与坦克碰撞后可以相互穿过去,坦克死亡刚出现新塔克时,相撞在一起不能移动了,只能该变方向

这里写图片描述
这里写图片描述

for (int i = 0; i < list.size(); i++) {
                    step = 0;
                    ObjectScene objecti = list.get(i);
                    objecti.launchBullet();//发射子弹
                    ArrayList<ObjectScene> colision = new ArrayList<ObjectScene>();
                    /*
                    *这个for循环是判断死了一个坦克,生成新的有没有重跌部份
                    */
                    for (int j = 0; j < list.size(); j++) {
                        ObjectScene objecctj = list.get(j);
                        if (objecti != objecctj && judecolision(objecti, objecctj)) {
                            if (objecti.type == TypeUtil.TANK && objecctj.type == TypeUtil.TANK) {
                                objecti.move();
                            }
                        }
                    }
                    objecti.move();
                    for (int j = 0; j < list.size(); j++) {
                        ObjectScene objecctj = list.get(j);
                        if (objecti != objecctj && judecolision(objecti, objecctj)) {
                            colision.add(objecctj);
                        }
                    }
                    colision(objecti, colision);
public void colision(ObjectScene objecti, ArrayList<ObjectScene> colision) {
        for (ObjectScene so : colision) {
            switch (objecti.type) {
            case TypeUtil.TANK:
                switch (so.type) {
                case TypeUtil.TANK:
                    objecti.back();
                    break;
                case TypeUtil.TIE:
                case TypeUtil.QIANG:
                case TypeUtil.WATER:
                    if (step == 0) {//step是防止碰到2个,会掉用2次move
                        objecti.back();
                        step++;
                    }
                    break;

解决方法:既然有移动的方法那吗就有后退的方法,当坦克碰到障碍物或者坦克的时候就后退到原来位置,先判断如果坦克死了以后重新出来的坦克与一个坦克重合一部份,那么就在前面先判断撞没撞,如果撞了就move一下;判断完后在move

3.键盘控制:因为一个建盘监听按下一个建后在按下另一个建,这样前面一个建就不执行了而是执行下一个建,这样就不能一边走一边发射子弹了
这里写图片描述

ArrayList<String> set = new ArrayList<>();

    @Override
    public void keyReleased(KeyEvent e) {
        set.remove(e.getKeyCode() + "");//松建就删除
    }

    @Override
    public void keyPressed(KeyEvent e) {
        String str = e.getKeyCode() + "";//按键添加
        if (!set.contains(str)) {
            set.add(str);
        }
    }

    private void anJianSet() {
        String pausex = null;
        String fangxiang = null;
        String zidan = null;
        for (String s : set) {
            switch (s) {
            case KeyEvent.VK_A + "":
            case KeyEvent.VK_W + "":
            case KeyEvent.VK_S + "":
            case KeyEvent.VK_D + "":
                fangxiang = s;//只要是控制方向就选最后一个
            case KeyEvent.VK_J + "":
                zidan = s;
            case KeyEvent.VK_P + "":
                pausex = s;
            }
        }
        if (zidan != null && !pause) {
            anJianZhiXin(zidan);
        }
        if (fangxiang != null && !pause) {
            anJianZhiXin(fangxiang);
        } else if (fangxiang == null) {
            ismytankMove = false;
        }
        if (pausex != null) {
            anJianZhiXin(pausex);
        }
    }

    private void anJianZhiXin(String s) {
        int code = Integer.parseInt(s);
        switch (code) {
        case KeyEvent.VK_W:
            mytank.fx = Fangxiang.Shang;
            ismytankMove = true;
            break;
        case KeyEvent.VK_S:
            mytank.fx = Fangxiang.Xia;
            ismytankMove = true;
            break;
        case KeyEvent.VK_A:
            mytank.fx = Fangxiang.Zuo;
            ismytankMove = true;
            break;
        case KeyEvent.VK_D:
            mytank.fx = Fangxiang.You;
            ismytankMove = true;
            break;
        case KeyEvent.VK_J:
            ismytankBullet = true;
            break;
        case KeyEvent.VK_P:
            pause = !pause;
        }
    }

解决方法:建立一个ArrayList集合·,当按下一个键盘就添加这个键盘,
当松开这个键盘就删除这个键盘,遍历ArrayList这个集合,这样就可以
多个键盘同时操作,但方向又只能执行一个,所以anJianSet这个方法中
在遍历一次,让只要是控制方向的键盘就只能执行最后一个

4.坦克移动方向的改变,不会如何控制和该变方向

if (RandomUtil.randomjd(0.155) && steep >//steep控制多少步后才执行 
Config.DITANK_GUAI_WAN_STEEP) {
                int r = (int) (Math.random() * 4);
                fx = Fangxiang.parse(r);
                steep = 0;
            }
public class RandomUtil {
    private static final Random rand = new Random();
     /*
     *nextDouble范围:0-1.0
     *反回随机double是否小于我的传入double
     */
    public static boolean randomjd(double time) {
        return rand.nextDouble() <= time;
    }
}
public enum Fangxiang {
    Shang(0, 0, -1), Xia(1, 0, 1), Zuo(2, -1, 0), You(3, 1, 0);

    public int dirction;
    public int xsudu;
    public int ysudu;

    Fangxiang(int dirction, int xsudu, int ysudu) {
        this.dirction = dirction;
        this.xsudu = xsudu;
        this.ysudu = ysudu;
    }

    public static Fangxiang parse(int id) {
        for (Fangxiang f : values()) {
            if (f.dirction == id) {
                return f;
            }
        }
        return null;
    }
}

解决方法:创建一个随机概率工具,在枚主类型中创建一个方向的办法
它会跟据传入的int而反回相对应的方向类,从而改变敌坦克的方向

5.在坦克类型定义中,每能够实现最后一个子节点中的level对应一个坦克定义

public final int typeId;
    public final HashMap<Integer, TankDefine> level_define;

    private TankTypeDefine(int typeId, HashMap<Integer, TankDefine> level_define) {
        this.typeId = typeId;
        this.level_define = level_define;
    }

    public static TankTypeDefine parse(Element root) {
        int typeId = Integer.parseInt(root.getAttribute("typeId"));
        HashMap<Integer, TankDefine> level_defines = new HashMap<>();// HashMap的初始化
        ArrayList<Element> proList = XmlReader.parseElements(root, "property");// 将tank节点的所有property子节点加入proList集合
        for (Element ele : proList) {
            TankDefine tankDefine = TankDefine.parse(ele);
            level_defines.put(tankDefine.level, tankDefine);// 以tank节点的属性level为建,tankDefine为值
        }
        return new TankTypeDefine(typeId, level_defines);
    }

解决方法:在坦克定义和坦克类型定义中,坦克类型定义和塔克类型中独有的属性必须要对应xml相对应节点的属性,坦克类型定义中HashMap中的建存坦克定义中的level

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值