/*
Copyright 2006 by Daniel Kuebrich
Licensed under the Academic Free License version 3.0
See the file "LICENSE" for more information
*/
// Class Bot
package sim.app.keepaway;
import java.awt.*;
import sim.portrayal.*;
import sim.util.*;
import sim.engine.*;
public /*strictfp*/ class Bot extends Entity implements Steppable
{
private static final long serialVersionUID = 1;
public Bot( final double x, final double y, Color c)
{
super(x,y,2,c);
}
public void draw(Object object, final Graphics2D g, final DrawInfo2D info )
{
// draw the circle
super.draw(object, g,info);
// draw our line as well
final double width = info.draw.width * radius * 2;
final double height = info.draw.height * radius * 2;
g.setColor(Color.white);
double d = velocity.angle();
g.drawLine((int)info.draw.x,
(int)info.draw.y,
(int)(info.draw.x) + (int)(width/2 * /*Strict*/Math.cos(d)),
(int)(info.draw.y) + (int)(height/2 * /*Strict*/Math.sin(d)));
}
public MutableDouble2D tempVector = new MutableDouble2D();
public MutableDouble2D getForces( final Keepaway keepaway)
{
sumVector.setTo(0,0);
Bag objs = keepaway.fieldEnvironment.getNeighborsWithinDistance(new Double2D(loc.x, loc.y), 100);
double dist = 0;
//http://www.martinb.com/physics/dynamics/collision/twod/index.htm
double mass1;
double mass2;
for(int x=0; x<objs.numObjs; x++)
{
if(objs.objs[x] != this)
{
dist = ((Entity)objs.objs[x]).loc.distance(loc);
if((((Entity)objs.objs[x]).radius + radius)*1.25 > dist) // collision!
{
// 10% chance of kicking the ball, if it's a ball
// and kicking is not especially interesting.. its just accelerated impact
if(objs.objs[x] instanceof Ball && keepaway.random.nextDouble() < .1)
{
tempVector.subtract(((Entity)objs.objs[x]).loc, loc);
tempVector.normalize().multiplyIn(2.0);
((Entity)objs.objs[x]).velocity.addIn(tempVector);
}
else // else just ram it...
{ // shouldnt matter what type of object collision occurrs with
tempVector.x = 0;
tempVector.y = 0;
mass1 = mass - ((Entity)objs.objs[x]).mass;
mass1 /= (mass + ((Entity)objs.objs[x]).mass);
mass2 = 2 * ((Entity)objs.objs[x]).mass;
mass2 /= (mass + ((Entity)objs.objs[x]).mass);
// self = object a
tempVector.x = velocity.x * mass1 + ((Entity)objs.objs[x]).velocity.x * mass2;
tempVector.y = velocity.y * mass1 + ((Entity)objs.objs[x]).velocity.y * mass2;
// collided object = object
((Entity)objs.objs[x]).bump.x = velocity.x * mass2 - ((Entity)objs.objs[x]).velocity.x * mass1;
((Entity)objs.objs[x]).bump.y = velocity.y * mass2 - ((Entity)objs.objs[x]).velocity.y * mass1;
velocity.x = tempVector.x;
velocity.y = tempVector.y;
}
}
else if(objs.objs[x] instanceof Ball)
{
// if we didn't hit the ball, we want to go towards it
tempVector.subtract(((Entity)objs.objs[x]).loc, loc);
tempVector.resize(0.5);
sumVector.addIn(tempVector);
}
}
}
// bump forces
sumVector.addIn(bump);
bump.x = 0;
bump.y = 0;
return sumVector;
}
public void step( final SimState state )
{
Keepaway keepaway = (Keepaway)state;
// get force
final MutableDouble2D force = getForces(keepaway);
// acceleration = f/m
accel.multiply(force, 1/mass); // resets accel
// v = v + a
velocity.addIn(accel);
capVelocity();
// L = L + v
newLoc.add(loc,velocity); // resets newLoc
// is new location valid?
if(isValidMove(keepaway, newLoc))
loc = newLoc;
keepaway.fieldEnvironment.setObjectLocation(this, new Double2D(loc));
}
}