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

2015/4/27

How to get objects to fly in formation

1
2
wabuilderman wabuilderman

2015/4/27

#
My game, space admiral, has you be able to control ships. I want these fighters to fly in a v-formation. My current code works and allows a single fighter to head towards a point. What doesn't work is the V-formation. How would I do this?
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
/**
 * Write a description of class Ships here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class Ships extends Player
{
    public int maxSpeed;
    public int fireRate = 20;
    public GreenfootImage turnLeftPic;
    public GreenfootImage turnRightPic;
    public GreenfootImage origPic;
    public int Xoffset = 0;
    public int Yoffset = 0;
    private int i=0;
    /**
     * Act - do whatever the Ships 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 void Shoot(int x, int y, Ships obj, int rate)
    {
        x+=Xoffset;
        y+=Yoffset;
        TurnToPoint(x,y,obj);
        i++;
        if(i>rate)
        {
            Bullets b = new Laser_Bolt(obj.getRotation());
            getWorld().addObject(b, obj.getX(), obj.getY());
            i = 0;
        }
    }
    public void TurnToPoint(int x, int y,Ships obj)
    {
        int prevRot = obj.getRotation();
        obj.turnTowards(x,y);
        int newRot = obj.getRotation();
        obj.setRotation(prevRot);
        if(prevRot<0)
        {
            prevRot+=360;
        }
        if(newRot<0)
        {
            newRot+=360;
        }
        if(prevRot != newRot)
        {
        if(whichWay(prevRot,newRot))
        {
            obj.setRotation(prevRot + 1);
            obj.setImage(obj.turnLeftPic);
        }
        else if(!whichWay(prevRot,newRot))
        {
            obj.setRotation(prevRot - 1);
            obj.setImage(obj.turnRightPic);
        }}
        if(Math.abs(prevRot - newRot)<10)
        {
            obj.setImage(obj.origPic);
        }
    }
    
    public void GoToPoint(int x, int y,Ships obj)
    {
        x+=Xoffset;
        y+=Yoffset;
        TurnToPoint(x,y,obj);
        double distX = Math.abs(obj.getpX() - x);
        double distY = Math.abs(obj.getpY() - y);
        double dist = Math.sqrt((distX*distX)+(distY*distY));
        if(dist>30)
        {
            if((dist/100)>obj.maxSpeed)
            {
                obj.move(obj,obj.maxSpeed, obj.getRotation());
            }
            else
            {
                obj.move(obj,(dist/100), obj.getRotation());
            }
        }
    }
    
    public boolean whichWay(int pr, int nr)
    {
        //if turning right is closer, return true, else, return false
        int ab = Math.abs(pr-nr);
        if(pr>nr)
        {
            if(ab>180){return true;} else {return false;}
        }
        if(nr>pr)
        {
            if(ab>180){return false;} else {return true;}
        }

        //if it exactly oppositite, just turn.
        return false;
    }
}
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class Fighters here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class Fighters extends Ships
{
    int turn = 0;
    /**
     * Act - do whatever the Fighters 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 void FighterFlight(Fighters obj)
    {
        int i=0;
        while(getWorld().getObjects(Fighters.class).size()>i)
        {
            Fighters o = (Fighters) getWorld().getObjects(Fighters.class).get(i);
            if ((i & 1) == 0 ){
                o.Xoffset=i*50;
                o.Yoffset=i*50;
            } else {
                o.Xoffset=-i*50;
                o.Yoffset=i*50;
            }
            i++;
        }
    }
}
danpost danpost

2015/4/27

#
I suggest that you have the fighters move with respect to the center of the formation. Maybe have an invisible actor to be at the center point and have it be the user-controlled object. Have this center actor control the location/rotation of the ships within its formation (it would be best to have it keep references to the ships in its formation; however, you could use 'getObjectInRange' or something similar to acquire those references). Any change in rotation or location will require all ships in its formation to be repositioned (moving all to the center location and setting the rotations to that of the center actor, then moving each some distance away from the center location at different angles. Something like this at the end of the act method of the center actor (this is for 3 ships in the formation):
int n = 0;
for (Object obj : getObjectsInRange(100, Ship.class))
{
    Actor ship = (Actor) obj;
    ship.setLocation(getX(), getY());
    ship.setRotation(getRotation()+120*n);
    ship.move(80);
    ship.turn(240*n);
    n++;
}
lordhershey lordhershey

2015/4/27

#
V Formation I made points that follow the leader just to see how I would do it - I use a leader that has 4 following points - but a completely invisible structure that the children latch to would be best.
wabuilderman wabuilderman

2015/4/27

#
Ok, I understand what your saying, but the way I want it, I want each of the fighters to remain independent. I am just wondering how I would get the point to be turned in relation to the direction the leader is coming from. I.e. if rotation of the initial fighter is 90, rotate the target pattern by 90. I was just wondering how to do this. I did not necessarily want the fighters to have to be a "Group Entity" where they are all controlled by just one pivotal axis, rather instead, their target is a V formation, therefore, they would turn in a more realistic, organized fashion.
wabuilderman wabuilderman

2015/4/27

#
*FYI, Question is still open*
danpost danpost

2015/4/28

#
The formation will still need to be controlled as a group; it just will not be a 'set to final location' type of control. It will be a 'progress to final location' type of control. The fighters will still be able to act independently of each other, similar to the V Formation demo provided by lordhershey.
wabuilderman wabuilderman

2015/4/28

#
Ok, I tried to do lordhersheys method, but I did something wrong. It won't even run. Here is my Heiarchy: SuperiorActor - Enemy - Player -Ships -Fighters -X1_Scorpio -FollowingPointFighter -Squadron -SquadronLeader -SquadronFollower Here is the Ships:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class Ships here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class Ships extends Player
{
    public int maxSpeed;
    public int fireRate = 20;
    public GreenfootImage turnLeftPic;
    public GreenfootImage turnRightPic;
    public GreenfootImage origPic;
    
    public GreenfootImage turnLeftPicD;
    public GreenfootImage turnRightPicD;
    public GreenfootImage origPicD;
    
    public GreenfootImage turnLeftPicL;
    public GreenfootImage turnRightPicL;
    public GreenfootImage origPicL;
    
    public int Xoffset = 0;
    public int Yoffset = 0;
    private int i=0;
    /**
     * Act - do whatever the Ships 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 void Shoot(int x, int y, Ships obj, int rate)
    {
        x+=Xoffset;
        y+=Yoffset;
        TurnToPoint(x,y,obj);
        i++;
        if(i>rate)
        {
            Bullets b = new Laser_Bolt(obj.getRotation());
            getWorld().addObject(b, obj.getX(), obj.getY());
            i = 0;
        }
    }
    public void TurnToPoint(int x, int y,Ships obj)
    {
        int prevRot = obj.getRotation();
        obj.turnTowards(x,y);
        int newRot = obj.getRotation();
        obj.setRotation(prevRot);
        if(prevRot<0)
        {
            prevRot+=360;
        }
        if(newRot<0)
        {
            newRot+=360;
        }
        if(prevRot != newRot)
        {
        if(whichWay(prevRot,newRot))
        {
            obj.setRotation(prevRot + 1);
            obj.setImage(obj.turnLeftPicD);
        }
        else if(!whichWay(prevRot,newRot))
        {
            obj.setRotation(prevRot - 1);
            obj.setImage(obj.turnRightPicD);
        }}
        if(Math.abs(prevRot - newRot)<10)
        {
            obj.setImage(obj.origPicD);
        }
    }
    
    public void GoToPoint(int x, int y,Ships obj)
    {
        x+=Xoffset;
        y+=Yoffset;
        TurnToPoint(x,y,obj);
        double distX = Math.abs(obj.getpX() - x);
        double distY = Math.abs(obj.getpY() - y);
        double dist = Math.sqrt((distX*distX)+(distY*distY));
        if(dist>30)
        {
            if((dist/100)>obj.maxSpeed)
            {
                obj.move(obj,obj.maxSpeed, obj.getRotation());
            }
            else
            {
                obj.move(obj,(dist/100), obj.getRotation());
            }
        }
    }
    
    public boolean whichWay(int pr, int nr)
    {
        //if turning right is closer, return true, else, return false
        int ab = Math.abs(pr-nr);
        if(pr>nr)
        {
            if(ab>180){return true;} else {return false;}
        }
        if(nr>pr)
        {
            if(ab>180){return false;} else {return true;}
        }

        //if it exactly oppositite, just turn.
        return false;
    }
}
Here is the Fighters:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class Fighters here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class Fighters extends Ships
{
    int turn = 0;
    boolean isFollower = false;
    /**
     * Act - do whatever the Fighters 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 void FighterFlight(Fighters obj)
    {
        int i=0;
        int x=0;
        while(getWorld().getObjects(Fighters.class).size()>i)
        {
            Fighters f = (Fighters) getWorld().getObjects(Fighters.class).get(i);
            if(i==0&&getWorld().getObjects(SquadronLeader.class).size()==0)
            {
                getWorld().addObject(new SquadronLeader(f),f.getX(),f.getY());
            }else if (i>0 && f.isFollower() == false)
            {
                getWorld().addObject(new SquadronFollower(f),f.getX(),f.getY());
                f.setFollower(true);
            }
            i++;
        }
    }
    public boolean isFollower()
    {
        return isFollower;
    }
    public void setFollower(boolean f)
    {
        isFollower = f;
    }
}
Here is the X1_Scorpio:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class X1_Scorpio here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class X1_Scorpio extends Fighters
{ 
    int i = 0;
    public X1_Scorpio()
    {
        maxSpeed = 1;
        maxSpeed = 15;
        turnLeftPic = new GreenfootImage("images/shaded pixel fighter Turn1.png");
        turnRightPic = new GreenfootImage("images/shaded pixel fighter Turn2.png");
        origPic = getImage();
        origPicD = darken(origPic);
        origPicL = lighten(origPic);
        turnLeftPicD = darken(turnLeftPic);
        turnLeftPicL = lighten(turnLeftPic);
        turnRightPicD = darken(turnRightPic);
        turnRightPicL = lighten(turnRightPic);
        setImage(origPicD);
    }
    
    /**
     * Act - do whatever the X1_Scorpio wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public void act() 
    {
        if(i<1)
        {
            SetP();
            i++;
        }
        MoveWith();
        FighterFlight(this);
        ApplyLight();
        ApplyP();
    }    
}
Here is the SquadronLeader:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class SquadronLeader here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class SquadronLeader extends Squadron
{
    FollowingPointFighter[] fp = null;
    public Fighters me;
    public SquadronLeader(Fighters m)
    {
        me = m;
    }
    /**
     * Act - do whatever the SquadronLeader 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 void addedToWorld(World world)
    {
        fp = new FollowingPointFighter[4];
        for(int i = 0 ; i < 4 ; i++)
        {
            fp[i] = new FollowingPointFighter(this,i);
            getWorld().addObject(fp[i],this.getX(),this.getY());
        }
    }
}
Here is the SquadronFollower:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
import java.util.List;
/**
 * Write a description of class SquadronFollower here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class SquadronFollower extends Squadron
{
    public FollowingPointFighter fp = null;
    public Fighters me;
    public SquadronFollower(Fighters m)
    {
        me = m;
    }
    //public Follower(FollowPoint fp)
    //{
    //    this.fp = fp;
    //}
    
    int distSq(int x,int y)
    {
        int xx = getX();
        int yy = getY();
        
        return((xx - x)*(xx - x) + (yy - y)*(yy - y));
    }
    
    public void act() 
    {
        int x;
        int y;
        int rot = 0;
        
        try
        {
            x = fp.getX();
            y = fp.getY();
        }
        catch(Exception e)
        {
            //Look for a follow point that is not attached or
            //touching anything meaning there is a missing man and we can
            //follow that node - or alternativly become a leader ourselves
            //with 4 orphanes following nodes.
            
            //Find an empty Node
            fp = null;
            
            World w = getWorld();
            List<FollowingPointFighter> fpts = w.getObjects(FollowingPointFighter.class);
            
            for(FollowingPointFighter fp : fpts)
            {
                if(fp.follower == null)
                {
                    fp.follower = this;
                    this.fp = fp;
                    break;
                }
            }
            
            return;
        }
        
        
        
        if(distSq(x,y) < 5)
        {
            setRotation(fp.getRotation());
            return;
        }
        
        int dist = (int)Math.sqrt(distSq(x,y));
        
        turnTowards(x,y);
        move(dist < 10 ? dist : 10);
    }       
}
Oh, and here is a seperate "Controling" class called Camera:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
import java.util.List;
/**
 * Write a description of class Camera here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class Camera extends Actor
{
    int moveX;
    int moveY;
    int i = 0;
    
    /**
     * Act - do whatever the Camera wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public void act() 
    {
        moveX = 0;
        moveY = 0;
        boolean turnPossible = false;
        if(Greenfoot.isKeyDown("w"))
        {
            moveY -= 2;
        }
        if(Greenfoot.isKeyDown("a"))
        {
            moveX -= 2;
        }
        if(Greenfoot.isKeyDown("s"))
        {
            moveY += 2;
        }
        if(Greenfoot.isKeyDown("d"))
        {
            moveX += 2;
        }
        if(Greenfoot.isKeyDown("f"))
        {
            moveAllToPoint();
            turnPossible = true;
        }
        if(Greenfoot.isKeyDown("1")&&i<10)
        {
            getWorld().addObject(new X1_Scorpio(),
            Greenfoot.getRandomNumber(getWorld().getWidth()),
            Greenfoot.getRandomNumber(getWorld().getHeight()));
            i++;
        }
        if(Greenfoot.isKeyDown("space"))
        {
            fireAllAtPoint();
            turnPossible = true;
        }
        if(turnPossible == false)
        {
            //AllShipsStraighten;
        }
    } 
    
    public int getMovementX()
    {
        return moveY;
    }
    
    public int getMovementY()
    {
        return moveX;
    }
    
    public void moveAllToPoint()
    {
        List<Ships> fleet = getWorld().getObjects(SquadronLeader.class);
        int i = 0;
        while(i<fleet.size())
        {
            fleet.get(i).GoToPoint(getWorld().getWidth()/2,getWorld().getHeight()/2, fleet.get(i));
            i++;
        }
    }
    public void fireAllAtPoint()
    {
        List<Ships> fleet = getWorld().getObjects(Ships.class);
        int i = 0;
        while(i<fleet.size())
        {
            fleet.get(i).Shoot(getWorld().getWidth()/2,getWorld().getHeight()/2, fleet.get(i),fleet.get(i).fireRate);
            i++;
        }
    }
}
When I try to run this.... It just comes up with a white screen. Nothing works. I end up having to restart Greenfoot. Can someone tell me where I went wrong? Am I putting in this system in the wrong way?
danpost danpost

2015/4/28

#
Are you saying it compiles okay; and the world prepares itself without incident -- but when you start the scenario the white screen appears?
wabuilderman wabuilderman

2015/4/29

#
Yeah. That's exactly what happened. It's happened someother times when I try to do too much without testing. probably several mistakes at work.
danpost danpost

2015/4/29

#
wabuilderman wrote...
Yeah. That's exactly what happened. It's happened someother times when I try to do too much without testing. probably several mistakes at work.
The 'while' loop in the 'FighterFlight method' of the Fighters class looks suspect. You are adding Fighter objects to the world while trying to use the size (which is therefore increasing) as a limit for exiting the loop.
wabuilderman wabuilderman

2015/4/29

#
Ah! Now I see. Thankyou. I'll let you know if it solves it.
wabuilderman wabuilderman

2015/4/29

#
Yeah, it worked. Thank you.
danpost danpost

2015/5/6

#
I tried my own hand at it. My end result is here.
wabuilderman wabuilderman

2015/5/7

#
Ok, well, I tried putting in your system, but yet again, I have issues porting. Here are the changed classes:
public class Wingman extends Squadron
{
    public static int count; // counts the number of instances created from this class
    
    private int id; // identification number of this instance
    public Ships me;
    public Ships L;
    
    public Wingman(Ships f, Ships l)
    {
        me = f;
        L = l;
        id = count;
        count++;
    }

    public void act()
    {
        // get rotation of leader
        int r = L.getRotation();
        // save current location
        int x = me.getX();
        int y = me.getY();
        // determine where we should be
        me.setLocation(L.getX(), L.getY());
        me.setRotation(r);
        me.move(-(id/2+1)*80);
        me.move(me,-(id/2+1)*40, r+90*(1-2*(id%2)));
        int destX = me.getX();
        int destY = me.getY();
        // move back to saved current location
        me.setLocation(x, y);
        // adjust speed toward that of leader
        if (L.speed > me.speed) me.speed++;
        if (L.speed < me.speed) me.speed--;
        // move
        me.move(me.speed);
        // move toward where we should be
        me.turnTowards(destX, destY);
        if (Math.hypot(x-destX, y-destY) > 2) me.move(100*(id/2+1));
        // set rotation to that of leader
        me.setRotation(r);
        // set image to that of leader
        me.setImage(L.getImage());
    }
}
A method from the "Ships" class
public void GoToPoint(int x, int y,Ships obj)
    {
        //if(getObjectsInRange(10, Ships.class) == obj)
        //{
            x+=Xoffset;
            y+=Yoffset;
            TurnToPoint(x,y,obj);
            double distX = Math.abs(obj.getpX() - x);
            double distY = Math.abs(obj.getpY() - y);
            double dist = Math.sqrt((distX*distX)+(distY*distY));
            if(dist>30)
            {
                if((dist/100)>obj.maxSpeed)
                {
                    obj.move(obj,obj.maxSpeed, obj.getRotation());
                    obj.speed = obj.maxSpeed;
                }
                else
                {
                    obj.move(obj,(dist/100), obj.getRotation());
                    obj.speed = (int) dist/100;
                }
            }
        //}
        
    }
and I simply put in the proper information for spawning (i.e. the new "me" value and the "L" value)
danpost danpost

2015/5/7

#
Sorry, but I cannot look over this one right now. I have things to do and people to see. Will return later on.
There are more replies on the next page.
1
2