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

2018/10/4

Need help getting a projectile to change direction with an Actor

woopersnaper woopersnaper

2018/10/4

#
Hi, I really need some help with a school assignment I am doing. Any suggestions will be greatly appreciated! Basically I have a game where an Actor named Soldier X traverses maze-like levels and shoots zombies while navigating the maze. Everything seems to work okay until I code the shooting mechanics. Basically, while we have done "shooting" before, it was only with actors that moved on one axis at a time. Soldier X, however, has four different directions for shooting, and this has for some reason caused no end of complications and I am stumped. From my perspective, this code should work, however I haven't been programming for too long so I could most definitely be wrong. Here is the code for my Soldier X:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class SoldierX here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class SoldierX extends Actor
{
    private GreenfootImage So1;
    private GreenfootImage So2;
    private GreenfootImage So3;
    private GreenfootImage So4;

    public SoldierX() {
        So1 = new GreenfootImage("Soldier X.png");
        So2 = new GreenfootImage("Soldier X down.png");
        So3 = new GreenfootImage("Soldier X right.png");
        So4 = new GreenfootImage("Soldier X left.png");
        
                
        if(Greenfoot.isKeyDown("Right") ||Greenfoot.isKeyDown("d")){
            setImage(So3);
        }
        
        if(Greenfoot.isKeyDown("Left") ||Greenfoot.isKeyDown("a")){
            setImage(So4);
        }
        
        if (Greenfoot.isKeyDown("Down") ||Greenfoot.isKeyDown("s")) {
            setImage(So2);
        }
        
        if (Greenfoot.isKeyDown("Up") ||Greenfoot.isKeyDown("w")) {
            setImage(So1);
        }
        setImage(So1);
    }
    public GreenfootImage getSo1() {
            return So1;
    }
    public GreenfootImage getSo2() {
            return So2;
    }
    public GreenfootImage getSo3() {
            return So3;
    }
    public GreenfootImage getSo4() {
            return So4;
    }
    
    public void move() {
        if(Greenfoot.isKeyDown("left") ||Greenfoot.isKeyDown("a")) {
            if (getImage() == So1) {
                setImage(So4);
            }
            
            if (getImage() == So2) {
                setImage(So4);
            }
            
            if (getImage() == So3) {
                setImage(So4);
            }
            else {
                setImage(So4);
            }
            setLocation(getX()-5,getY());
        }
        
        if(Greenfoot.isKeyDown("right") ||Greenfoot.isKeyDown("d")) {
            
            if (getImage() == So1) {
                setImage(So3);
            }
            
            if (getImage() == So2) {
                setImage(So3);
            }
            
            if (getImage() == So3) {
                setImage(So3);
            }
            else {
                setImage(So3);
            }
            setLocation(getX()+5,getY());
        }
        
        if(Greenfoot.isKeyDown("up") ||Greenfoot.isKeyDown("w")) {
            
            if (getImage() == So2) {
                setImage(So1);
            }
            
            if (getImage() == So3) {
                setImage(So1);
            }
            
            if (getImage() == So4) {
                setImage(So1);
            }
            else {
                setImage(So1);
            }
           setLocation(getX(),getY()-5);
        }
        
        if(Greenfoot.isKeyDown("down") ||Greenfoot.isKeyDown("s")) {
            
            if (getImage() == So1) {
                setImage(So2);
            }
            
            if (getImage() == So3) {
                setImage(So2);
            }
            
            if (getImage() == So4) {
                setImage(So2);
            }
            else {
                setImage(So2);
            }
            
            setLocation(getX(), getY()+5);
        }
    }
    public void edge() {
        if(isAtEdge()) {
            Greenfoot.setWorld(new LevelTwo());
        }
    }
    public void wall(){
        if (isTouching(Wall.class) || isTouching (WallHori.class)) {
            setLocation(92,509);
        }
    }
    public void shoot() {
        if (Greenfoot.isKeyDown("space")) {
            getWorld().addObject(new bullet(), getX()+2, getY() - 2);
            
        }
    }
    public void act() 
    {
        edge();
        move();
        wall();
        shoot();
    }    
}

Here is the code for the Bullet:
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 Actor
{
    /**
     * 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() 
    {
        fly();
    }    
    
    public void fly() {
       SoldierX s = new SoldierX();
       if (s.getImage().equals(s.getSo2())) {
           setRotation(180);
           setLocation(getX(), getY() + 5);
       }
       else if (s.getImage().equals(s.getSo3())) {
           setRotation(90);
           setLocation(getX() + 5, getY());
       }
       else if (s.getImage().equals(s.getSo4())) {
           setRotation(-90);
           setLocation(getX() - 5, getY());
       }
       else 
        setLocation(getX(), getY() - 5);
    }
}
The issue is that no matter what I've tried, the bullet only ever seems to go in one direction (The initial check). All other checks in the code don't seem to be working. I even tried coding the movement and rotation in the soldier class, but then I get static-referencing issues. Thanks again for any help, I could really use it!
Super_Hippo Super_Hippo

2018/10/4

#
Think of it how it would work in real-life. Would the bullet check anything from the Soldier? No, it just flies straight (ignoring gravity for simplicity). So the only code in the Bullet's act method should be for moving straight (and maybe checking for collision and moving out of world). So you don't need to get a reference to the soldier and checking its image. If this worked, your bullet would also turn around when the soldier turns around (after shooting) and this is probably not what is intended. Just ignoring the fact here, that you create a NEW soldier (line 21), so it isn't the same soldier as the one who shot the bullet in the first place. To the SoldierX: In the constructor (when the soldier is created), checking for keypresses won't work. In the movement code, don't constantly check which image is currently used before changing it. For shooting, usually the code is like:
Bullet b = new Bullet(); //create a new bullet object
getWorld().addObject(b, getX(), getY()); //add the object to the same world at the same position
b.setRotation(getRotation()); //set the rotation of the bullet to the rotation of the shooting object
b.move(2); //move the bullet a bit so it doesn't start in the middle of the shooter (optional)
In your case, without using rotations, you could check for the shooter's image and set the rotation of the bullet accordingly (right from the Soldier's code when adding it to the world).
danpost danpost

2018/10/5

#
There is also an issue with a stream of bullets instead of individual ones (a new one will be create for each act cycle the space key is held down. You will need a boolean field to track the state of the space key:
private boolean spaceDown;

private void shoot()
{
    if (spaceDown != Greenfoot.isKeyDown("space")) // change in key state?
    {
        spaceDown = !spaceDown;
        if (spaceDown) // key changed to down state?
        {
            Actor bullet = new Bullet();
            getWorld().addObject(bullet, getX(), getY());
            // etc.
        }
    }
}
Another improved would come from using an array for your images along with a field to track which image in the array is being used. By ordering the image in a clockwise fashion with 'right' first, you can use its value to turn a new bullet to its proper orientation. Also, you should determine the final facing direction of the soldier before changing its image or location. The key components would look something like this:
private GreenfootImage[] images = {
    new GreenfootImage("Soldier X right.png");
    new GreenfootImage("Soldier X down.png");
    new GreenfootImage("Soldier X left.png");
    new GreenfootImage("Soldier X.png");
};
private int imageNum;
private boolean spaceDown;

public SoldierX()
{
    setImage(images[imageNum]); // initial image (facing right)
}

public void move()
{
    int dx, dy;
    if (Greenfoot.isKeyDown("right") || Greenfoot.isKeyDown("d")) dx++;
    if (Greenfoot.isKeyDown("down") || Greenfoot.isKeyDown("s")) dy++;
    if (Greenfoot.isKeyDown("left") || Greenfoot.isKeyDown("a")) dx--;
    if (Greenfoot.isKeyDown("up") || Greenfoot.isKeyDown("w")) dy--;
    if (dx*dy != 0 || dx+dy == 0) return; // is there a conflict or no move? if so, do nothing
    imageNum = dx != 0 ? 1-dx :  2-dy;
    setImage(images[imageNum]);
    setRotatiion(imageNum*90);
    move(5);
    setRotation(0);
}

private void shoot()
{
    if (spaceDown != Greenfoot.isKeyDown("space")) // change in key state?
    {
        spaceDown = !spaceDown;
        if (spaceDown) // key changed to down state?
        {
            Actor bullet = new Bullet();
            getWorld().addObject(bullet, getX(), getY());
            bullet.setRotation(imageNum*90);
            bullet.move(5);
        }
    }
}
You need to login to post a reply.