Steeringbehavior Java

SteeringBehavior.java

multiverse/src/multiverse/mars/behaviors

package multiverse.mars.behaviors;
 
import java.util.*;
 
import multiverse.msgsys.*;
import multiverse.server.objects.*;
import multiverse.server.math.*;
import multiverse.server.util.*;
import multiverse.server.engine.*;
import multiverse.server.plugins.MobManagerPlugin;
 
// Class: SteeringBehavior
// Auth: Sara Pickell
// Should be used to maintain separation, alignment and cohesion.
// Version 1 uses the messages from entering and exiting the radius
// Future versions should handle on spawn and be limited to a certain
// template.
// It's unknown whether the first version will even work.
 
public class SteeringBehavior extends Behavior implements MessageCallback, Runnable {
    public SteeringBehavior(){
        super();
        mrange = 8000;
    }
 
    // constructor when given spawn data
    public SteeringBehavior(SpawnData spawn, int sep, int align, int coh){
        super();
        // get the range of the spawn radius.
        mrange = spawn.getSpawnRadius();
        // get the relative amounts of separation, alignment and cohesion.
        separation = sep;
        alignment = align;
        cohesion = coh;
 
    }
 
    int mrange;
    int separation = 0;
    int alignment = 0;
    int cohesion = 0;
 
    // initialize the message filtering crap
    public void initialize() {
        super.initialize();
        //This filter lets through only messages that occur when something steps into
        //someone's reaction radius, and only when that someone is this mob.
        // SP, I copied this from a tutorial. I understand what it's doing.
        // I still don't feel entirely comfortable with the MV message architecture, though.
        SubjectFilter filter = new SubjectFilter(obj.getOid());
        filter.addType(ObjectTracker.MSG_TYPE_NOTIFY_REACTION_RADIUS);
        eventSub = Engine.getAgent().createSubscription(filter, this);
 
    }
 
    long eventSub = 0;
    boolean activated;
 
    // override the activate method.
    // adds debug logging and gets a tracker for stuff within range
    @Override
    public void activate() {
        Log.debug("FactionBehavior.activate: adding reaction radius for mob");
        // Tells the manager to send messages when something comes within mrange units of this mob
        MobManagerPlugin.getTracker(obj.getInstanceOid()).addReactionRadius(obj.getOid(), mrange);
        activated = true;
        run();
 
    }
 
    @Override
    public void deactivate() {
        // we lock down the thread and turn it off
        lock.lock();
        try 
        {
            activated = false;
            // if we're still subscribed for events cancel the sub
            if (eventSub != 0) 
            {
                Engine.getAgent().removeSubscription(eventSub);
                eventSub = 0;
            }
        }
        finally 
        {
            // use finally to be absolutely sure we unlock the thread
            lock.unlock();
        }
 
    }
 
    // override the handleMessage method
    // we'll be doing some debug logging and locking the thread
    @Override
    public void handleMessage(Message msg, int arg1) {
        if (Log.loggingDebug)
               Log.debug("Received a Steering message: " + msg.getMsgType());
        lock.lock();
        try {
            // if we aren't activated, don't even bother trying
            if (activated == false) {
                return ;
            }
            if (msg.getMsgType().equals(ObjectTracker.MSG_TYPE_NOTIFY_REACTION_RADIUS)) {
                // if we have the message, do something freaky weird
                ObjectTracker.NotifyReactionRadiusMessage message = 
                                 (ObjectTracker.NotifyReactionRadiusMessage)msg;
                // set a long to hold the subject id
                // sometimes you still need to use getSubject due
                // to it not always being treated like a long.
                // hell if I know why.
                long messageObjOid = message.getSubject();
                // if we're logging our debug code, send out some info on the message
                    if (Log.loggingDebug)
                        Log.debug("Steering: Notify Reaction Radius Message Received"
                                                 + obj.getOid() 
                                                 + " msgObjOid " 
                                                 + messageObjOid 
                                                 + " msgOid " + messageObjOid);
                // if the object is ourself, we'll be ignoring it.
                if (obj.getOid().equals(message.getSubject())) {
                    return ;
                }
                else if (message.getInRadius() == false) {    // if it's an old object then it must be leaving our space
                    percobjs.remove(multiverse.server.objects.MVObject.getObject(message.getSubject()));
                    return ;
                }
                else if (message.getWasInRadius() == false) {    // if it's a new arrival, we'll want to handle it
                    // in this case handling it means adding it to
                    // a list of nearby objects
                    percobjs.add(multiverse.server.objects.MVObject.getObject(message.getSubject()));
                }
            }
        } 
        finally {
            lock.unlock();
        }
 
        return ;
 
    }
 
    List<MVObject> percobjs;
 
    // we need to run separation, cohesion, and alignment on our list
    @Override
    public void run() {
        lock.lock();
        try{
            Point tempPoint = new Point(separation());
            tempPoint.add(new Point(cohesion()));
            sendMessage(tempPoint, 2000);
        }
        finally {
            lock.unlock();
        }
 
    }
 
    // send a message
 
    protected void sendMessage(Point waypoint, int speed) {
        // I assume this is where tell the mob to actually perform the action
        Engine.getAgent().sendBroadcast(new BaseBehavior.GotoCommandMessage(obj, waypoint, speed));
    }
 
    // The separation() method is responsible for keeping things apart.
 
    public multiverse.server.math.MVVector separation(){
        MVVector SteeringForce = new MVVector(0, 0, 0);
        for(int a=0; a < percobjs.size(); ++a)
        {
            MVVector agentVect = new MVVector(percobjs.get(a).getCurrentLoc());
            MVObject o = new MVObject(obj.getOid());
            MVVector toAgent = agentVect.sub(o.getCurrentLoc());
 
            SteeringForce = SteeringForce.add(toAgent.normalize().getX()/toAgent.length(), 0, toAgent.normalize().getZ()/toAgent.length());
        }
        return SteeringForce;
    }
 
    // The alignment() method is responsible for keeping things moving in a single direction.
 
    public multiverse.server.math.MVVector alignment(){
        MVVector AverageHeading = new MVVector(0, 0, 0);
        float total = 0;
        for(int a=0; a < percobjs.size(); ++a)
        {
            MVVector agentVect = new MVVector(percobjs.get(a).getDirection());
            AverageHeading = AverageHeading.add(agentVect);
            ++total;
        }
        AverageHeading.setX(AverageHeading.getX()/total);
        AverageHeading.setZ(AverageHeading.getZ()/total);
        AverageHeading.setY(0);
        return AverageHeading;
    }
 
    // The cohesion() method is responsible for keeping things together.
 
    public multiverse.server.math.MVVector cohesion(){
        MVVector CenterMass = new MVVector(0, 0, 0);
        float total = 0;
        for(int a=0; a < percobjs.size(); ++a)
        {
            MVVector agentVect = new MVVector(percobjs.get(a).getCurrentLoc());
            CenterMass = CenterMass.add(agentVect);
            ++total;
        }
        CenterMass.setX(CenterMass.getX()/total);
        CenterMass.setZ(CenterMass.getZ()/total);
        CenterMass.setY(0);
        return CenterMass;
    }
 
    private static final long serialVersionUID = 1L;
}
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License