// // Nenya library - tools for developing networked games // Copyright (C) 2002-2012 Three Rings Design, Inc., All Rights Reserved // https://github.com/threerings/nenya // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation; either version 2.1 of the License, or // (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA package com.threerings.media.util; import java.awt.Color; import java.awt.Graphics2D; import com.samskivert.util.RandomUtil; /** * Bobble a Pathable. */ public class BobblePath implements Path { /** * Construct a bobble path that updates as often as possible. * * @param dx the variance in the x direction. * @param dy the variance in the y direction. * @param duration the duration to bobble, or -1 to bobble until stop() is called. */ public BobblePath (int dx, int dy, long duration) { this(dx, dy, duration, 1L); } /** * Construct a bobble path. * * @param dx the variance in the x direction. * @param dy the variance in the y direction. * @param duration the duration to bobble, or -1 to bobble until stop() is called. * @param updateFreq how often to update the Pathable's location. */ public BobblePath (int dx, int dy, long duration, long updateFreq) { _updateFreq = updateFreq; _duration = duration; setVariance(dx, dy); } /** * Set the variance of bobblin' in each direction. */ public void setVariance (int dx, int dy) { if ((dx < 0) || (dy < 0) || ((dx == 0) && (dy == 0))) { throw new IllegalArgumentException( "Variance values must be positive, and at least one must be non-zero."); } else { _dx = dx; _dy = dy; } } /** * Set a new update frequency. */ public void setUpdateFrequency (long freq) { _updateFreq = freq; } /** * Have the Pathable stop bobbling asap. */ public void stop () { // it will stop on the next tick.. _stopTime = 0L; } // documentation inherited from interface Path public void init (Pathable pable, long tickstamp) { _sx = pable.getX(); _sy = pable.getY(); // change the duration to a real stop time if (_duration == -1L) { _stopTime = Long.MAX_VALUE; } else { _stopTime = tickstamp + _duration; } _nextMove = tickstamp; } // documentation inherited from interface Path public boolean tick (Pathable pable, long tickStamp) { // see if we need to stop if (_stopTime <= tickStamp) { boolean updated = updatePositionTo(pable, _sx, _sy); pable.pathCompleted(tickStamp); return updated; } // see if it's time to move.. if (_nextMove > tickStamp) { return false; } // when bobbling, it's bad form to bobble into the same position int newx, newy; do { newx = _sx + RandomUtil.getInt(_dx * 2 + 1) - _dx; newy = _sy + RandomUtil.getInt(_dy * 2 + 1) - _dy; } while (! updatePositionTo(pable, newx, newy)); // and update the next time to move _nextMove = tickStamp + _updateFreq; return true; } // documentation inherited from interface Path public void fastForward (long timeDelta) { _stopTime += timeDelta; _nextMove += timeDelta; } // documentation inherited from interface Path public void paint (Graphics2D gfx) { // for debugging, show the bobble bounds gfx.setColor(Color.RED); gfx.drawRect(_sx - _dx, _sy - _dy, _dx * 2, _dy * 2); } // documentation inherited from interface public void wasRemoved (Pathable pable) { // reset the pathable to its initial location pable.setLocation(_sx, _sy); } /** * Update the position of the pathable or return false if it's already there. */ protected boolean updatePositionTo (Pathable pable, int x, int y) { if ((pable.getX() == x) && (pable.getY() == y)) { return false; } else { pable.setLocation(x, y); return true; } } /** The initial position of the pathable. */ protected int _sx, _sy; /** The variance we will bobble around that initial position. */ protected int _dx, _dy; /** How long we'll bobble. */ protected long _duration; /** How often we update the locations. */ protected long _updateFreq; /** The time at which we'll stop pathin'. */ protected long _stopTime; /** The time at which we'll next update the position of the pathable. */ protected long _nextMove = 0L; }