package sim.app.robots;
import java.awt.*;
import sim.physics2D.constraint.*;
import sim.engine.*;
import sim.physics2D.physicalObject.*;
import sim.physics2D.forceGenerator.ForceGenerator;
import sim.physics2D.util.*;
import sim.util.Bag;
import sim.util.Double2D;
public class Bot extends sim.robot2D.Robot implements Steppable, ForceGenerator
{
Can currentCan;
private PinJoint pj;
private Double2D canHome;
private double canHomeRadius = 20;
private ConstraintEngine objCE;
private Double2D botHome;
private double normalForce;
private int botState;
private final int HAVECAN = 1;
private final int APPROACHINGCAN = 2;
private final int RELEASINGCAN = 3;
private final int RETURNINGHOME = 4;
private final int SEARCHING = 5;
public Effector e1;
public Effector e2;
public Bot(Double2D pos, Double2D vel)
{
// vary the mass with the size
this.setPose(pos, new Angle(0));
this.setVelocity(vel);
this.setShape(new sim.physics2D.shape.Circle(10, Color.gray), 300);
this.setCoefficientOfFriction(.2);
this.setCoefficientOfStaticFriction(0);
this.setCoefficientOfRestitution(1);
this.normalForce = this.getMass();
currentCan = null;
canHome = new Double2D(50, 50);
botHome = pos;
botState = SEARCHING;
objCE = ConstraintEngine.getInstance();
}
public void step(SimState state)
{
Double2D position = this.getPosition();
Robots simRobots = (Robots)state;
simRobots.fieldEnvironment.setObjectLocation(this, new sim.util.Double2D(position.x, position.y));
// Find a can
if (botState == SEARCHING)
{
Bag objs = simRobots.fieldEnvironment.allObjects;
objs.shuffle(state.random);
for (int i = 0; i < objs.numObjs; i++)
{
if (objs.objs[i] instanceof Can)
{
currentCan = (Can)objs.objs[i];
if (currentCan.getPosition().y > 50 && currentCan.visible)
{
botState = APPROACHINGCAN;
break;
}
else
currentCan = null; // can is already home or has been picked
// up by another bot
}
}
if (currentCan == null)
botState = RETURNINGHOME;
}
}
public void addForce()
{
switch (botState)
{
case HAVECAN:
if (this.getPosition().y <= 40)
{
if (this.getVelocity().length() > 0.01 || this.getAngularVelocity() > 0.01)
this.stop();
else
{
objCE.unRegisterForceConstraint(pj);
botState = RELEASINGCAN;
objCE.removeNoCollisions(this, currentCan);
objCE.removeNoCollisions(e1, currentCan);
objCE.removeNoCollisions(e2, currentCan);
currentCan.visible = true;
}
}
else
this.goTo(new Double2D(this.getPosition().x, 40));
break;
case RELEASINGCAN:
// back out of can home
if (this.getPosition().subtract(currentCan.getPosition()).length() <= 30)
backup();
else
botState = SEARCHING;
break;
case APPROACHINGCAN:
if (currentCan.visible)
this.goTo(currentCan.getPosition());
else
botState = SEARCHING;
break;
case RETURNINGHOME:
if (this.getPosition().subtract(botHome).length() <= 30)
{
if (this.getOrientation().radians != 0)
this.faceTowards(new Angle(0));
else
stop();
}
else
this.goTo(botHome);
break;
}
}
public int handleCollision(PhysicalObject2D other, Double2D colPoint)
{
Double2D globalPointPos = this.getPosition().add(colPoint);
Double2D localPointPos = this.localFromGlobal(globalPointPos);
Angle colAngle = this.getAngle(localPointPos);
// Make sure the object is a can and that it is (roughly) between
// the effectors
if (other instanceof Can && botState == APPROACHINGCAN
&& (colAngle.radians < Math.PI / 8 || colAngle.radians > (Math.PI * 2 - Math.PI / 8)))
{
// Create a fixed joint directly at the center of the can
pj = new PinJoint(other.getPosition(), this, other);
objCE.registerForceConstraint(pj);
botState = HAVECAN;
objCE.setNoCollisions(this, other);
objCE.setNoCollisions(e1, other);
objCE.setNoCollisions(e2, other);
currentCan.visible = false;
return 2; // sticky collision
}
else
return 1; // regular collision
}
}