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

2014/3/28

Problems with shooting objects.

Camaro Camaro

2014/3/28

#
Hi, currently I am working on a school project (grade 12) in which we are supposed to create a small game. My idea was something like the old DOS-Game "Sopwith" which some of you may know; you are flying a plane and have to shoot / bomb some ground targets. Until now, i managed to get a flying plane which shoots some bullets, crashes and explodes when you touch the world's borders, the ground or enemy buildings. Also, there is a complete world with hills, factorys, moving tanks and some other stuff. So far so good. When a bullet hits an enemy, it gets removed from the world. But as one bullet normally does not destroy a whole tank, i added a private int which should count the bullets which already hit it. Problems are: 1st the variable does not count down, ergo the enemy can not be destroyed. 2nd if I write "getWorld().removeObject(this);" to remove the bullet from the world after hitting a target the game stops, so i have to respawn it in a place where it cant do any damage (just an anoying problem)... Full bullet.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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
 
/**
 * Write a description of class bullet here.
 *
 * @author (your name)
 * @version (a version number or a date)
 */
public class bullet extends plane
{
    private int speed = -4;
    private int factory_life = 20;
    private int tank_life = 10;
    private int flak_life = 5;
    private int quarter_life = 20;
 
    /**
     * 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()
    {
        /**
         * spawne die Kugel beim Flugzeug und beschleunige sie in die aktuelle Richtung
         */
         
        Actor plane = getOneIntersectingObject(plane.class); 
        if(plane != null) { 
            setLocation(getX(), getY());
            setRotation(rotation);
            move(-4);
        
        else
        {
            move(-4);
            destroyEnemies();
 
            if(atWorldEdge())
            {
                setImage("blank.png");
                setLocation(100, 600);
                move(0);
                turn(180);
            }
 
            if (atGround())
            {
                setImage("blank.png");
                setLocation(100, 600);
                move(0);
                turn(180);
            
        }
    }
 
    /**
     * Wenn Gegner getroffen, Leben abziehen. Objekt verschwinden lassen, falls Leben = 0.
     */
    public void destroyEnemies() 
    {    
        Actor enemy = getOneIntersectingObject(factory.class); 
        if(enemy != null)   
        {  
            factory_life = factory_life - 1;
            if (factory_life==0)
            {
                getWorld().removeObject(enemy);
            }
            setImage("blank.png");
            setLocation(100, 600);
            move(0);
            turn(180);
        
 
        Actor enemy2 = getOneIntersectingObject(tank.class); 
        if(enemy2 != null)
        
            tank_life = tank_life - 1;
            if (tank_life==0)
            {
                getWorld().removeObject(enemy2);
            }
            setImage("blank.png");
            setLocation(100, 600);
            move(0);
            turn(180);
        
 
        Actor enemy3 = getOneIntersectingObject(flak.class); 
        if(enemy3 != null)
        
            flak_life = flak_life - 1;
            if (flak_life==0)
            {
                getWorld().removeObject(enemy3);
            }  
            setImage("blank.png");
            setLocation(100, 600);
            move(0);
            turn(180);
        
 
        Actor enemy4 = getOneIntersectingObject(quarter.class); 
        if(enemy4 != null)
        
            quarter_life = quarter_life - 1;
            if (quarter_life==0)
            {
                getWorld().removeObject(enemy4);
            }
            setImage("blank.png");
            setLocation(100, 600);
            move(0);
            turn(180);
        
    }  
}
If you want to see the whole game just ask and I'll upload it. Greetings from Berlin :)
danpost danpost

2014/3/28

#
The problem is that all your '_life' fields belong in their respective classes, not in the bullet class. Instance fields, as in the bullet class above, are destroyed along with the bullet when removed from the world and no references are kept on them. In other words, once there is no link between the bullet and the scenario, it is flagged for garbage collection (the bullet and all its instance fields). When a new bullet is created, it gets assigned all its instance fields in their initial state (the value in a field from one bullet does not carry over to the same field in another).
Camaro Camaro

2014/3/28

#
Thanks! Then i'll just let them disappear like before. I changed my factory.class to this:
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
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
 
/**
 * Write a description of class factory here.
 *
 * @author (your name)
 * @version (a version number or a date)
 */
public class factory extends KI
{
    private int factory_life = 20;
 
    /**
     * Act - do whatever the factory wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public void act()
    {
        Actor bullet = getOneIntersectingObject(bullet.class); 
        if(bullet != null)  
        {  
            if (factory_life == 0)
            {
                getWorld().removeObject(this);
            }
            else
            {
                factory_life = factory_life - 1;
            }
        }
    }
}
...and removed it in my bullet class. It doesn't work either... when i check the private int factory_life in the Object Inspector after shooting some rounds it still says 20 :( I did not understand the whole collision thing at all, still in learning process ;)
danpost danpost

2014/3/28

#
I think that one problem you are having is due to the fact that you are using the same name for the Actor object 'bullet' as the bullet class is named (classes, by convention, should begin with an uppercase letter). Try this:
1
2
3
4
5
6
public void act()
{
    Actor b = getOneIntersectingObject(bullet.class);
    if (b != null)
    // ect.
}
If that works, then that was the major problem. For the minor problem, the way you have the act method coded, your factory will take 21 hits before being destroyed. Twenty times the 'factory_life' field will be decremented and the twenty-first time will be the first time that the 'factory_life' check will be 'true' If ever you need to do something due to a counter reaching a specific number, perform that check immediately after changing the counter. For example:
1
2
count = count-1; // or 'count--;'
if (count == 0) // etc.
This is what I simplified your act method to:
1
2
3
4
5
6
7
8
9
public void act()
{
    Actor b = getOneIntersectingObject(bullet.class);
    if (b != null)
    {
        getWorld().removeObject(b);
        if (--factory_life == 0) getWorld().removeObject(this);
    }
}
I added the removal of the bullet here. You can remove the check for a factory in the bullet class. You can similar for the other actors a bullet can hit.
Camaro Camaro

2014/4/1

#
Well, I tried it but it won't destroy the factory, same as before. I also renamed all my classes to begin with an uppercase letter and changed all class names in code to begin with an uppercase letter, too. ;-) The simplyfied act method is nice, thank you!
danpost danpost

2014/4/1

#
I wonder if you have more than one factory on top of another. After you think your factory should be destroyed, 'Pause' the scenario and drag the factory around. See if there is not another one underneath the first one.
Camaro Camaro

2014/4/1

#
No, there is no second one after shooting the first factory, checked it. It's the last thing to do on my project, then the game will be complete... annoying. :-/
danpost danpost

2014/4/1

#
Change 'factory_life' from 'private' to 'public' access, run the scenario again; then after stopping, right click on the factory and 'Inspect' the value of 'factory_life'. Actually, stop and check its value several times on the way to 'destroying' the factory. Report back the values inspected.
Camaro Camaro

2014/4/1

#
Did it, factory_life stays 20 all the time, whether I hit it 2 or 40 times. Edit: Just... Wait... I forgot to delete some code from the bullet class, now I can destroy my enemies! Thanks for your help danpost :-)
danpost danpost

2014/4/1

#
Do you have code in the Bullet class to detect Factory objects (also?)?
Camaro Camaro

2014/4/1

#
I had ;-)
danpost danpost

2014/4/1

#
Camaro wrote...
I had ;-)
Does that mean you removed it and it works alright now? or, is that just letting me know it is there?
Camaro Camaro

2014/4/2

#
Removed it and it works alright now. ;-)
You need to login to post a reply.