This site requires JavaScript, please enable it in your browser!
Greenfoot back
ProgramTheWorld
ProgramTheWorld wrote ...

2014/6/5

Bullets go right through enemies some of the time and other times they kill the enemies. Help!

ProgramTheWorld ProgramTheWorld

2014/6/5

#
Ok so I am working on a tower defense game, and ive got towers that shoot at the enemies. My problem is when the tower shoots at the enemies, sometimes it will kill them, and other times it will just go right through them and the tower will get stuck trying to kill the enemy which cant be killed (since the bullets go right through it). I've been working on this for hours and I can't figure out what i'm doing wrong! thanks! let me know if theres anything anyone needs to better understand the problem. ps all my unit types (Infantry, Medium, Speedy, Ultra, Heavy) all inherit from an empty class called Enemy so I can easily check if an actor is an enemy pps all my tower types (Ice, Gun, Bomb) inherit from the Tower class ppps all my towers are the same except for different values for damage and rate of fire etc.; same with units, they are all the same except for health etc. this is my code in class Tower.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public Enemy target(int range){
        if(field==null){field=(Field)getWorld();}
        List<Enemy> enemies= getObjectsInRange(range,Enemy.class);
        if(enemies.size()==0){
            return null;
        }
        double dist=field.getDist(this,enemies.get(0));
        closest=enemies.get(0);
        for(Enemy e:enemies){
            double newdist=field.getDist(this,e);
            if(newdist<dist){
                dist=newdist;
                closest=e;
            }
        }
        //turnTowards(closest.getX(),closest.getY());
        return closest;
    }
    public Double getTargetDist(Enemy enemy){
        if(field==null){field=(Field)getWorld();}
        if(enemy!=null){
            double dist=field.getDist(this,enemy);
            return dist;
        }
        return null;
    }
    public Double getClosestTargetDist(int range){
        Enemy e=target(range);
        if(e==null)return null;
        Double dist=(Double)getTargetDist(target(range));
        return dist;
    }
    public HashMap getAllEnemies(){
        if(field==null){field=(Field)getWorld();}
        List<Enemy> b= field.getObjects(Enemy.class);
        for(Enemy x:b){
            enemyMap.put(x,getTargetDist(x));
        }
        return enemyMap;
    }
this is my code in class Bullet( it also inherits from the smooth mover class found in the Asteroids tutorial. I also have the vector class properly placed in my program)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
public int damage;
    public double speedDamage;
    public double x;
    public double y;
    public double origx;
    public double origy;
    public double dist;
    public int range;
    private Field field;
    public Counter counter;
    public Enemy e;
    public Bullet(){}
    public Bullet(double x,double y,int rotation, int range,int damage,double speedDamage){
        this(new Vector(0,(double)0),rotation);
        setLocation(x,y);
        origx=x;
        origy=y;
        this.x=x;
        this.y=y;
        this.range=range;
        this.damage=damage;
        this.speedDamage=speedDamage;
    }
    public Bullet(Vector speed, int rotation){
        super(speed);
        setRotation(rotation);
        addForce(new Vector(rotation,15));
        //Greenfoot.playSound("energyGun.wav");
    }
    /**
     * Act - do whatever the Bullet wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public void act()
    {
        field=(Field)getWorld();
        counter=field.getCounter();
        this.dist=Math.sqrt((Math.pow((this.x-origx),2))+(Math.pow((this.y-origy),2)));
        if(this.dist>this.range){
            getWorld().removeObject(this);
        }
        else{
            move();
            this.x=getExactX();
            this.y=getExactY();
            checkHit();
        }
    }
    public void checkHit(){
        e= (Enemy)getOneIntersectingObject(Enemy.class);
        if(e!=null){
            if(e instanceof Infantry){
                Infantry i=(Infantry)e;
                i.update(this.damage,this.speedDamage);
                counter.addMoney(i.bonus);
            }
            else if(e instanceof Speedy){
                Speedy s=(Speedy)e;
                s.update(this.damage,this.speedDamage);
                counter.addMoney(s.bonus);
            }
            else if(e instanceof Medium){
                Medium m=(Medium)e;
                m.update(this.damage,this.speedDamage);
                counter.addMoney(m.bonus);
            }
            else if(e instanceof Heavy){
                Heavy h=(Heavy)e;
                h.update(this.damage,this.speedDamage);
                counter.addMoney(h.bonus);
            }
            else if(e instanceof Ultra){
                Ultra u=(Ultra)e;
                u.update(this.damage,this.speedDamage);
                counter.addMoney(u.bonus);
            }
            getWorld().removeObject(this);
        }
    }
this is the Infantry class code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class Infantry extends Enemy
{
    public boolean isHit=false;
    public double speed;
    public int bonus;
    public int health;
    public Infantry(){
        this(5.0,5,10);
    }
    public Infantry(double speed,int bonus,int health){
        this.speed=speed;
        this.bonus=bonus;
        this.health=health;
    }
    public void update(int damage,double speed){
        this.speed-=speed;
        this.health-=damage;
        if(this.health<=0){
            Field field=(Field)getWorld();
            getWorld().removeObject(this);
            field.setScore();
        }
        else if(this.speed<=0){
            this.speed=1;
        }
    }
    /**
     * Act - do whatever the Infantry wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public void act()
    {
        // Add your action code here.
    }
    public double getSpeed(){return this.speed;}
    public int getBonus(){return this.bonus;}
    public int getHealth(){return this.health;}
}
this is the gun class code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
public class Gun extends Tower
{
    public int level;
    public double rate;
    public int nextPrice;
    public int range;
    public int damage;
    public int speedDamage=0;
    private double reloadDelayCount;
    private static final double[] rates={7.0,5.0,3.0};
    private static final int[] prices={10,15,30};
    private static final int[] ranges={50,70,90};
    private static final int[] damages={5,10,20};
    public Counter counter;
    /**
     * When first creating an Gun tower, this is called.
     * gives default values for rate, nextPrice, range, and damage amount
     */
    public Gun(){
        this(0);
    }
     
    /**
     * Gun Constructor
     *
     * @param rate The rate the tower fires at
     * @param nextPrice The price of purchase
     * @param range The range of fire
     * @param damage The amount the tower decreases unit health
     */
    public Gun(int level){
        update(level);
        this.reloadDelayCount=this.rate;
    }
    public void upgrade(){
        counter=getCounter();
        if(counter.canAfford(this.nextPrice)){
            counter.removeMoney(this.nextPrice);
            if((this.level==1)||(this.level==2)){
                this.level++;
                update(this.level);
            }
        }
    }
    private void update(int level){
        this.level=level;
        if(this.level==3){this.nextPrice=1000000000;}
        else if(this.level==0){this.level++;}
        this.nextPrice=prices[Math.min(2,this.level)];
        this.rate=rates[this.level-1];
        this.range=ranges[this.level-1];
        this.damage=damages[this.level-1];
        this.speedDamage=0;
    }
    public int getLevel(){return this.level;}
    public double getRate(){return this.rate;}
    public int getPrice(){return this.nextPrice;}
    public int getlvlPrice(int level){return prices[Math.max(0,Math.min(2,(level-1)))];}
    public int getRange(){return this.range;}
    public int getDamage(){return this.damage;}
    public int getSpeedDamage(){return this.speedDamage;}
    public void fire(){
        if(reloadDelayCount>=this.rate*5){
            Bullet bullet=new Bullet((double)getX(),(double)getY(),getRotation(),getRange(),getDamage(),getSpeedDamage());
            getWorld().addObject(bullet,getX(),getY());
            bullet.move();
            reloadDelayCount=0;
        }
    }
    /**
     * Act - do whatever the Gun wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public void act()
    {
        Enemy atarget=target(this.range);
        if(atarget!=null){
            turnTowards((int)atarget.getExactX(),(int)atarget.getExactY());
            fire();
        }
        reloadDelayCount++;
    }
}
ProgramTheWorld ProgramTheWorld

2014/6/5

#
oh and also the units inherit from the smooth mover class
danpost danpost

2014/6/5

#
One thing that is or may become a problem is that your Ice, Gun, and Bomb classes should not extend Tower. If you cannot say the ObjectA is a specific type of ObjectB, then ObjectA should not extend the ObjectB class. (Ice is NOT a tower of any type; Gun is not a tower of any type, and Bomb is not a tower of any type. You probably have the same problem with what class your Bullet class extends. All of these should probably extends either Actor or SmoothMover (probably all extending SmoothMover, except for the Gun class, which should extending Actor).
ProgramTheWorld ProgramTheWorld

2014/6/5

#
but they are towers. sorry if that was confusing.
danpost danpost

2014/6/5

#
ProgramTheWorld wrote...
but they are towers. sorry if that was confusing.
So, Ice is really 'IceTower', Gun is really 'GunTower' and Bomb is really 'BombTower' (as if the names were incomplete)? What class does your Bullet class extend?
ProgramTheWorld ProgramTheWorld

2014/6/5

#
exactly. the bullet class extends the smooth mover class the hierarchy is this: World ---field Actor ---SmoothMover ------Bullet ------Enemy ---------Heavy ---------Speedy ---------Ultra ---------Infantry ---------Medium ---IceButton ---GunButton ---BombButton ---ScoreBoard ---NextLevelButton ---Counter ---Tower ------Gun ------Ice ------Bomb Vector the (towername)Button classes are initialized in the world and you drag them to create the towers. the nextlevelbutton starts the next wave of enemies. the counter is your money. the scoreboard is the number of enemies destroyed and appears after the game is over.
danpost danpost

2014/6/5

#
The 'update' method of the Infantry class does not look right. You set speed and health to zero by subtracting those values from themselves, then the object gets removed (because health is zero) -- the 'else' part will never execute. When is this method called and from where?
all my unit types (Infantry, Medium, Speedy, Ultra, Heavy) all inherit from an empty class called Enemy so I can easily check if an actor is an enemy
Why is the Enemy class empty? You should put the common fields and methods in it INSTEAD of in each of the subclasses. If the subclasses have different values for them, you can set them in their individual constructors (which you seem to already be doing via constructor arguments to bring the values in.
You need to login to post a reply.