Holy crap Batman! It's the beginnings of refactoring the basic puzzle

stuff into Narya.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@2876 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2003-11-26 01:42:34 +00:00
parent 0601c94e42
commit 54eaddb27d
53 changed files with 9395 additions and 0 deletions
@@ -0,0 +1,237 @@
//
// $Id: DropBlockSprite.java,v 1.1 2003/11/26 01:42:34 mdb Exp $
package com.threerings.puzzle.drop.client;
import java.awt.Rectangle;
import com.threerings.puzzle.Log;
/**
* The drop block sprite represents a block of multiple pieces that can be
* rotated to any of the four cardinal compass directions. As such, it
* may span multiple columns or rows depending on its orientation. The
* block has a "central" piece around which it rotates, with the other
* pieces referred to as "external" pieces.
*/
public class DropBlockSprite extends DropSprite
{
/**
* Constructs a drop block sprite and starts it dropping.
*
* @param view the board view upon which this sprite will be displayed.
* @param col the column of the central piece.
* @param row the row of the central piece.
* @param orient the orientation of the sprite.
* @param pieces the pieces displayed by the sprite.
*/
public DropBlockSprite (
DropBoardView view, int col, int row, int orient, int[] pieces)
{
super(view, col, row, pieces, 0);
_orient = orient;
}
/**
* Constructs a drop block sprite and starts it dropping.
*
* @param view the board view upon which this sprite will be displayed.
* @param col the column of the central piece.
* @param row the row of the central piece.
* @param orient the orientation of the sprite.
* @param pieces the pieces displayed by the sprite.
* @param renderOrder the rendering order of the sprite.
*/
public DropBlockSprite (
DropBoardView view, int col, int row, int orient, int[] pieces,
int renderOrder)
{
super(view, col, row, pieces, 0, renderOrder);
_orient = orient;
}
// documentation inherited
protected void init ()
{
super.init();
setOrientation(_orient);
}
/**
* Returns an array of the row numbers containing the block pieces.
* The first index is the row of the central piece. The array is
* cached and re-used internally and so the caller should make their
* own copy if they care to modify it.
*/
public int[] getRows ()
{
return _rows;
}
/**
* Returns an array of the column numbers containing the block pieces.
* The first index is the column of the central piece. The array is
* cached and re-used internally and so the caller should make their
* own copy if they care to modify it.
*/
public int[] getColumns ()
{
return _cols;
}
/**
* Returns the bounds of the block in board piece coordinates. The
* bounds rectangle is cached and re-used internally and so the caller
* should make their own copy if they care to modify it.
*/
public Rectangle getBoardBounds ()
{
return _dbounds;
}
/**
* Returns the row the external piece is located in.
*/
public int getExternalRow ()
{
return _erow;
}
/**
* Returns the column the external piece is located in.
*/
public int getExternalColumn ()
{
return _ecol;
}
// documentation inherited
public void setColumn (int col)
{
super.setColumn(col);
updateDropInfo();
}
// documentation inherited
public void setRow (int row)
{
super.setRow(row);
updateDropInfo();
}
// documentation inherited
public void setBoardLocation (int row, int col)
{
super.setBoardLocation(row, col);
updateDropInfo();
}
/**
* Updates the sprite image offset to reflect the direction in which
* the external piece is hanging.
*/
public void setOrientation (int orient)
{
super.setOrientation(orient);
int edx = 0, edy = 0;
if (orient == NORTH) {
edy = -1;
} else if (orient == WEST) {
edx = -1;
}
// update the sprite image offset
setRowOffset(edy);
setColumnOffset(edx);
// update the external piece position and drop block bounds
updateDropInfo();
}
// documentation inherited
public void toString (StringBuffer buf)
{
super.toString(buf);
buf.append(", erow=").append(_erow);
buf.append(", ecol=").append(_ecol);
}
/**
* Re-calculates the external piece position and bounds of the drop
* block.
*/
protected void updateDropInfo ()
{
// update the external piece location
_erow = calculateExternalRow();
_ecol = calculateExternalColumn();
// update the piece row and column arrays
_rows[0] = _row;
_rows[1] = _erow;
_cols[0] = _col;
_cols[1] = _ecol;
// calculate the drop block board bounds
int maxrow = Math.max(_row, _erow);
int mincol = Math.min(_col, _ecol);
int bpwid, bphei;
if (_orient == NORTH || _orient == SOUTH) {
bpwid = 1;
bphei = 2;
} else {
bpwid = 2;
bphei = 1;
}
// create the bounds rectangle if necessary
_dbounds.setBounds(mincol, maxrow, bpwid, bphei);
}
/**
* Returns the row the external piece is located in based on the
* current central piece location and sprite orientation.
*/
protected int calculateExternalRow ()
{
if (_orient == NORTH) {
return (_row - 1);
} else if (_orient == SOUTH) {
return (_row + 1);
} else {
return _row;
}
}
/**
* Returns the column the external piece is located in based on the
* current central piece location and sprite orientation.
*/
protected int calculateExternalColumn ()
{
if (_orient == WEST) {
return (_col - 1);
} else if (_orient == EAST) {
return (_col + 1);
} else {
return _col;
}
}
/** The drop block bounds in board coordinates. */
protected Rectangle _dbounds = new Rectangle();
/** The drop block piece rows. */
protected int[] _rows = new int[2];
/** The drop block piece columns. */
protected int[] _cols = new int[2];
/** The external piece location in board coordinates. */
protected int _ecol, _erow;
}
@@ -0,0 +1,370 @@
//
// $Id: DropBoardView.java,v 1.1 2003/11/26 01:42:34 mdb Exp $
package com.threerings.puzzle.drop.client;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.util.Iterator;
import com.samskivert.swing.Label;
import com.threerings.media.image.Mirage;
import com.threerings.media.sprite.Sprite;
import com.threerings.yohoho.client.YoUI;
import com.threerings.puzzle.util.PuzzleContext;
import com.threerings.puzzle.Log;
import com.threerings.puzzle.client.PuzzleBoardView;
import com.threerings.puzzle.client.ScoreAnimation;
import com.threerings.puzzle.data.Board;
import com.threerings.puzzle.data.PuzzleConfig;
import com.threerings.puzzle.drop.data.DropBoard;
import com.threerings.puzzle.drop.data.DropConfig;
import com.threerings.puzzle.drop.data.DropPieceCodes;
/**
* The drop board view displays a drop puzzle game in progress for a
* single player.
*/
public abstract class DropBoardView extends PuzzleBoardView
implements DropPieceCodes
{
/** The color used to render normal scoring text. */
public static final Color SCORE_COLOR = Color.white;
/** The color used to render chain reward scoring text. */
public static final Color CHAIN_COLOR = Color.yellow;
/**
* Constructs a drop board view.
*/
public DropBoardView (PuzzleContext ctx, int pwid, int phei)
{
super(ctx);
// save off piece dimensions
_pwid = pwid;
_phei = phei;
// determine distance to float score animations
_scoreDist = 2 * _phei;
}
/**
* Initializes the board with the board dimensions.
*/
public void init (PuzzleConfig config)
{
DropConfig dconfig = (DropConfig)config;
// save off the board dimensions in pieces
_bwid = dconfig.getBoardWidth();
_bhei = dconfig.getBoardHeight();
super.init(config);
}
/**
* Returns the width in pixels of a single board piece.
*/
public int getPieceWidth ()
{
return _pwid;
}
/**
* Returns the height in pixels of a single board piece.
*/
public int getPieceHeight ()
{
return _phei;
}
/**
* Called by the {@link DropSprite} to populate <code>pos</code> with
* the screen coordinates in pixels at which a piece at <code>(col,
* row)</code> in the board should be drawn. Derived classes may wish
* to override this method to allow specialised positioning of
* sprites.
*/
public void getPiecePosition (int col, int row, Point pos)
{
pos.setLocation(col * _pwid, (row * _phei) - _roff);
}
/**
* Called by the {@link DropSprite} to get the dimensions of the area
* that will be occupied by rendering a piece segment of the given
* orientation and length whose bottom-leftmost corner is at
* <code>(col, row)</code>.
*/
public Dimension getPieceSegmentSize (int col, int row, int orient, int len)
{
if (orient == NORTH || orient == SOUTH) {
return new Dimension(_pwid, len * _phei);
} else {
return new Dimension(len * _pwid, _phei);
}
}
/**
* Dirties the rectangle encompassing the piece segment with the given
* direction and length whose bottom-leftmost corner is at <code>(col,
* row)</code>.
*/
public void dirtySegment (int dir, int col, int row, int len)
{
int x = _pwid * col, y = (_phei * row) - _roff;
int wid = (dir == VERTICAL) ? _pwid : len * _pwid;
int hei = (dir == VERTICAL) ? _phei * len : _phei;
_remgr.invalidateRegion(x, y, wid, hei);
}
/**
* Dirties the rectangle encompassing the specified piece in the
* board.
*/
public void dirtyPiece (int col, int row)
{
_remgr.invalidateRegion(_pwid * col, (_phei * row) - _roff,
_pwid, _phei);
}
/**
* Dirties a rectangular region of pieces.
*/
public void dirtyPieces (int xx, int yy, int width, int height)
{
_remgr.invalidateRegion(xx*_pwid, yy*_phei, width*_pwid, height*_phei);
}
/**
* Returns the image used to display the given piece at coordinates
* <code>(0, 0)</code> with an orientation of {@link #NORTH}. This
* serves as a convenience routine for those puzzles that don't bother
* rendering their pieces differently when placed at different board
* coordinates or in different orientations.
*/
public Mirage getPieceImage (int piece)
{
return getPieceImage(piece, 0, 0, NORTH);
}
/**
* Returns the image used to display the given piece at the specified
* column and row with the given orientation.
*/
public abstract Mirage getPieceImage (
int piece, int col, int row, int orient);
// documentation inherited
public void setBoard (Board board)
{
// when a new board arrives, we want to remove all drop sprites
// so that they don't modify the new board with their old ideas
for (Iterator iter = _actionSprites.iterator(); iter.hasNext(); ) {
Sprite s = (Sprite) iter.next();
if (s instanceof DropSprite) {
// remove it from _sprites safely
iter.remove();
// but then use the standard removal method
removeSprite(s);
}
}
super.setBoard(board);
_dboard = (DropBoard)board;
}
/**
* Creates a new drop sprite used to animate the given pieces falling
* in the specified column.
*/
public DropSprite createPieces (int col, int row, int[] pieces, int dist)
{
return new DropSprite(this, col, row, pieces, dist);
}
/**
* Creates and returns an animation which makes use of a label sprite
* that is assigned a path that floats it a short distance up the
* view, with the label initially centered within the view.
*
* @param score the score text to display.
* @param color the color of the text.
*/
public ScoreAnimation createScoreAnimation (String score, Color color)
{
return createScoreAnimation(
score, color, MEDIUM_FONT_SIZE, 0, _bhei - 1, _bwid, _bhei);
}
/**
* Creates and returns an animation showing the specified score
* floating up the view, with the label initially centered within the
* view.
*
* @param score the score text to display.
* @param color the color of the text.
* @param fontSize the size of the text; a value between 0 and {@link
* #getPuzzleFontSizeCount} - 1.
*/
public ScoreAnimation createScoreAnimation (
String score, Color color, int fontSize)
{
return createScoreAnimation(
score, color, fontSize, 0, _bhei - 1, _bwid, _bhei);
}
/**
* Creates and returns an animation showing the specified score
* floating up the view.
*
* @param score the score text to display.
* @param color the color of the text.
* @param x the left coordinate in board coordinates of the rectangle
* within which the score is to be centered.
* @param y the bottom coordinate in board coordinates of the
* rectangle within which the score is to be centered.
* @param width the width in board coordinates of the rectangle within
* which the score is to be centered.
* @param height the height in board coordinates of the rectangle
* within which the score is to be centered.
*/
public ScoreAnimation createScoreAnimation (
String score, Color color, int x, int y, int width, int height)
{
return createScoreAnimation(
score, color, MEDIUM_FONT_SIZE, x, y, width, height);
}
/**
* Creates and returns an animation showing the specified score
* floating up the view.
*
* @param score the score text to display.
* @param color the color of the text.
* @param fontSize the size of the text; a value between 0 and {@link
* #getPuzzleFontSizeCount} - 1.
* @param x the left coordinate in board coordinates of the rectangle
* within which the score is to be centered.
* @param y the bottom coordinate in board coordinates of the
* rectangle within which the score is to be centered.
* @param width the width in board coordinates of the rectangle within
* which the score is to be centered.
* @param height the height in board coordinates of the rectangle
* within which the score is to be centered.
*/
public ScoreAnimation createScoreAnimation (String score, Color color,
int fontSize, int x, int y,
int width, int height)
{
// create the score animation
ScoreAnimation anim =
createScoreAnimation(score, color, fontSize, x, y);
// position the label within the specified rectangle
Dimension lsize = anim.getLabel().getSize();
Point pos = new Point();
centerRectInBoardRect(
x, y, width, height, lsize.width, lsize.height, pos);
anim.setLocation(pos.x, pos.y);
return anim;
}
/**
* Populates <code>pos</code> with the most appropriate screen
* coordinates to center a rectangle of the given width and height (in
* pixels) within the specified rectangle (in board coordinates).
*
* @param bx the bounding rectangle's left board coordinate.
* @param by the bounding rectangle's bottom board coordinate.
* @param bwid the bounding rectangle's width in board coordinates.
* @param bhei the bounding rectangle's height in board coordinates.
* @param rwid the width of the rectangle to position in pixels.
* @param rhei the height of the rectangle to position in pixels.
* @param pos the point to populate with the rectangle's final
* position.
*/
protected void centerRectInBoardRect (
int bx, int by, int bwid, int bhei, int rwid, int rhei, Point pos)
{
getPiecePosition(bx, by + 1, pos);
pos.x += (((bwid * _pwid) - rwid) / 2);
pos.y -= ((((bhei * _phei) - rhei) / 2) + rhei);
// constrain to fit wholly within the board bounds
pos.x = Math.max(Math.min(pos.x, _bounds.width - rwid), 0);
}
/**
* Rotates the given drop block sprite to the specified orientation,
* updating the image as necessary. Derived classes that make use of
* block dropping functionality should override this method to do the
* right thing.
*/
public void rotateDropBlock (DropBlockSprite sprite, int orient)
{
// nothing for now
}
// documentation inherited
public void paintBetween (Graphics2D gfx, Rectangle dirtyRect)
{
gfx.translate(0, -_roff);
renderBoard(gfx, dirtyRect);
renderRisingPieces(gfx, dirtyRect);
gfx.translate(0, _roff);
}
// documentation inherited
public Dimension getPreferredSize ()
{
int wid = _bwid * _pwid;
int hei = _bhei * _phei;
return new Dimension(wid, hei);
}
/**
* Renders the row of rising pieces to the given graphics context.
* Sub-classes that make use of board rising functionality should
* override this method to draw the rising piece row.
*/
protected void renderRisingPieces (Graphics2D gfx, Rectangle dirtyRect)
{
// nothing for now
}
/**
* Sets the board rising offset to the given y-position.
*/
protected void setRiseOffset (int y)
{
if (y != _roff) {
_roff = y;
_remgr.invalidateRegion(_bounds);
}
}
/** The drop board. */
protected DropBoard _dboard;
/** The piece dimensions in pixels. */
protected int _pwid, _phei;
/** The board rising offset. */
protected int _roff;
/** The board dimensions in pieces. */
protected int _bwid, _bhei;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,23 @@
//
// $Id: DropPanel.java,v 1.1 2003/11/26 01:42:34 mdb Exp $
package com.threerings.puzzle.drop.client;
import com.threerings.puzzle.data.BoardSummary;
/**
* Puzzles using the drop services need implement this interface to
* display drop puzzle related information.
*/
public interface DropPanel
{
/**
* Sets the next block to be displayed.
*/
public void setNextBlock (int[] pieces);
/**
* Updates the board summary display for the given player.
*/
public void setSummary (int pidx, BoardSummary summary);
}
@@ -0,0 +1,566 @@
//
// $Id: DropSprite.java,v 1.1 2003/11/26 01:42:34 mdb Exp $
package com.threerings.puzzle.drop.client;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Shape;
import com.samskivert.util.ObserverList;
import com.threerings.util.DirectionUtil;
import com.threerings.media.image.Mirage;
import com.threerings.media.sprite.Sprite;
import com.threerings.media.tile.TileManager;
import com.threerings.puzzle.Log;
/**
* The drop sprite is a sprite that displays one or more pieces falling
* toward the bottom of the board.
*/
public class DropSprite extends Sprite
{
/**
* Constructs a drop sprite and starts it dropping.
*
* @param view the board view upon which this sprite will be displayed.
* @param col the column of the sprite.
* @param row the row of the bottom-most piece.
* @param pieces the pieces displayed by the sprite.
* @param dist the distance the sprite is to drop in rows.
*/
public DropSprite (
DropBoardView view, int col, int row, int[] pieces, int dist)
{
this(view, col, row, pieces, dist, -1);
}
/**
* Constructs a drop sprite and starts it dropping.
*
* @param view the board view upon which this sprite will be displayed.
* @param col the column of the sprite.
* @param row the row of the bottom-most piece.
* @param pieces the pieces displayed by the sprite.
* @param dist the distance the sprite is to drop in rows.
* @param renderOrder the render order.
*/
public DropSprite (
DropBoardView view, int col, int row, int[] pieces, int dist,
int renderOrder)
{
_view = view;
_col = col;
_row = row;
_pieces = pieces;
_dist = (dist == 0) ? 1 : dist;
_orient = NORTH;
_unit = _view.getPieceHeight();
setRenderOrder(renderOrder);
}
// documentation inherited
protected void init ()
{
super.init();
// size the bounds to fit our pieces
updateBounds();
// set up the piece location
setBoardLocation(_row, _col);
// calculate vertical render offset based on the number of pieces
setRowOffset(-(_pieces.length - 1));
}
/**
* Returns the remaining number of columns to drop.
*/
public int getDistance ()
{
return _dist;
}
/**
* Returns the column the piece is located in.
*/
public int getColumn ()
{
return _col;
}
/**
* Returns the row the piece is located in.
*/
public int getRow ()
{
return _row;
}
/**
* Returns the pieces the sprite is displaying.
*/
public int[] getPieces ()
{
return _pieces;
}
/**
* Returns the velocity of this sprite.
*/
public float getVelocity ()
{
return _vel;
}
/**
* Sets the row and column the piece is located in.
*/
public void setBoardLocation (int row, int col)
{
_row = row;
_col = col;
updatePosition();
}
/**
* Sets the column the piece is located in.
*/
public void setColumn (int col)
{
_col = col;
updatePosition();
}
/**
* Set the row the piece is located in.
*/
public void setRow (int row)
{
_row = row;
updatePosition();
}
/**
* Sets the column offset of the sprite image.
*/
public void setColumnOffset (int count)
{
_offx = count;
updateRenderOffset();
updateRenderOrigin();
}
/**
* Sets the row offset of the sprite image.
*/
public void setRowOffset (int count)
{
_offy = count;
updateRenderOffset();
updateRenderOrigin();
}
/**
* Sets the pieces the sprite is displaying.
*/
public void setPieces (int[] pieces)
{
_pieces = pieces;
}
/**
* Sets the velocity of this sprite. The time at which the current
* row was entered is modified so that the sprite position will remain
* the same when calculated using the new velocity since the piece
* sprite may have its velocity modified in the middle of a row
* traversal.
*/
public void setVelocity (float velocity)
{
// bail if we've already got the requested velocity
if (_vel == velocity) {
return;
}
if (_rowstamp > 0) {
// get our current distance along the row
long now = _view.getTimeStamp();
float pctdone = getPercentDone(now);
// revise the current row entry time to account for the new velocity
float travpix = pctdone * _unit;
long msecs = (long)(travpix / velocity);
_rowstamp = now - msecs;
}
// update the velocity
_vel = velocity;
}
/**
* Starts the piece dropping toward the next row.
*/
public void drop ()
{
// Log.info("Dropping piece [piece=" + this + "].");
// drop one row by default
if (_dist <= 0) {
_dist = 1;
}
if (_stopstamp > 0) {
// we're dropping from a stand-still
long delta = _view.getTimeStamp() - _stopstamp;
_rowstamp += delta;
_stopstamp = 0;
} else {
// we're continuing a previous drop, so make use of any
// previously existing time
_rowstamp = _endstamp;
}
}
/**
* Returns true if this drop sprite is dropping, false if it has been
* {@link #stop}ped or has not yet been {@link #drop}ped.
*/
public boolean isDropping ()
{
return (_stopstamp == 0) && (_rowstamp != 0);
}
/**
* Stops the piece from dropping.
*/
public void stop ()
{
if (_stopstamp == 0) {
_stopstamp = _view.getTimeStamp();
// Log.info("Stopped piece [piece=" + this + "].");
}
}
/**
* Puts the drop sprite into (or takes it out of) bouncing
* mode. Bouncing mode is used to put the sprite into limbo after it
* lands but before we commit the landing, giving the user a last
* moment change move or rotate the piece. While the sprite is
* "bouncing" it will be rendered one pixel below it's at rest state.
*/
public void setBouncing (boolean bouncing)
{
if (_bouncing = bouncing) {
// if we've activated bouncing, shift the sprite slightly to
// illustrate its new state
shiftForBounce();
// to prevent funny business in the event that we were a long
// ways past the end of the row when we landed, we warp the
// sprite back to the exact point of landing for the purposes
// of the bounce and any subsequent antics
_endstamp = _rowstamp = _view.getTimeStamp();
// Log.info("Adjusted rowstap due to bounce " +
// "[time=" + _endstamp + "].");
}
}
/**
* Returns true if this sprite is bouncing.
*/
public boolean isBouncing ()
{
return _bouncing;
}
/**
* Updates the sprite's location to illustrate that it is currently in
* the "bouncing" state.
*/
protected void shiftForBounce ()
{
setLocation(_ox, _srcPos.y+1);
}
// documentation inherited
public boolean inside (Shape shape)
{
return shape.contains(_bounds);
}
/**
* Returns a value between <code>0.0</code> and <code>1.0</code>
* representing how far the piece has moved toward the next row
* as of the given time stamp.
*/
public float getPercentDone (long timestamp)
{
// if we've never been ticked and so haven't yet initialized our
// row start timestamp, just let the caller know that we've not
// traversed our row at all
if (_rowstamp == 0) {
return 0.0f;
}
long msecs = Math.max(0, timestamp - _rowstamp);
float travpix = msecs * _vel;
float pctdone = (travpix / _unit);
// Log.info("getPercentDone [timestamp=" + timestamp +
// ", rowstamp=" + _rowstamp + ", msecs=" + msecs +
// ", travpix=" + travpix + ", pctdone=" + pctdone +
// ", vel=" + _vel + "].");
return pctdone;
}
// documentation inherited
public void paint (Graphics2D gfx)
{
// get the column and row increment based on the sprite's orientation
int oidx = _orient/2;
int incx = ORIENT_DX[oidx];
int incy = ORIENT_DY[oidx];
// determine offset from the start of each actual row and column
int dx = _ox - _srcPos.x, dy = _oy - _srcPos.y;
int pcol = _col, prow = _row;
for (int ii = 0; ii < _pieces.length; ii++) {
// ask the board for the render position of this piece
_view.getPiecePosition(pcol, prow, _renderPos);
// draw the piece image
paintPieceImage(gfx, ii, pcol, prow, _orient,
_renderPos.x + dx, _renderPos.y + dy);
// increment the target column and row
pcol += incx;
prow += incy;
}
}
/**
* Paints the specified piece with the supplied parameters.
*/
protected void paintPieceImage (Graphics2D gfx, int pieceidx,
int col, int row, int orient, int x, int y)
{
Mirage image = _view.getPieceImage(_pieces[pieceidx], col, row, orient);
image.paint(gfx, x, y);
}
// documentation inherited
public void tick (long timestamp)
{
super.tick(timestamp);
// initialize our rowstamp if we haven't done so already
if (_rowstamp == 0) {
_rowstamp = timestamp;
}
// if we're bouncing or paused, do nothing here
if (_bouncing || _stopstamp > 0) {
return;
}
PieceMovedOp pmop = null;
// figure out how far along the current board coordinate we should be
float pctdone = getPercentDone(timestamp);
if (pctdone >= 1.0f) {
// note that we've reached the next row
advancePosition();
// update remaining drop distance
_dist--;
// calculate any remaining time to be used
long used = (long)(_unit / _vel);
_endstamp = _rowstamp + used;
_rowstamp = _endstamp;
// update our percent done because we've moved down a row
pctdone -= 1.0;
// inform observers that we've reached our destination
pmop = new PieceMovedOp(this, timestamp, _col, _row);
}
// Log.info("Drop sprite tick [dist=" + _dist + ", pctdone=" + pctdone +
// ", row=" + _row + ", col=" + _col + "].");
// constrain the sprite's position to the destination row
pctdone = Math.min(pctdone, 1.0f);
// calculate the latest sprite position
int nx = _srcPos.x + (int)((_destPos.x - _srcPos.x) * pctdone);
int ny = _srcPos.y + (int)((_destPos.y - _srcPos.y) * pctdone);
// only update the sprite's location if it actually moved
if (_ox != nx || _oy != ny) {
setLocation(nx, ny);
}
// lastly notify our observers if we made it to the next row
if (pmop != null) {
_observers.apply(pmop);
}
}
/**
* Called when the sprite has finished traversing its current row to
* advance its board coordinates to the next row.
*/
protected void advancePosition ()
{
setRow(_row + 1);
// Log.info("Moved to row " + _row);
}
// documentation inherited
public void fastForward (long timeDelta)
{
if (_rowstamp > 0) {
_rowstamp += timeDelta;
}
}
// documentation inherited
public void toString (StringBuffer buf)
{
super.toString(buf);
buf.append(", orient=").append(DirectionUtil.toShortString(_orient));
buf.append(", row=").append(_row);
buf.append(", col=").append(_col);
buf.append(", offx=").append(_offx);
buf.append(", offy=").append(_offy);
buf.append(", dist=").append(_dist);
}
/**
* Updates internal pixel coordinates used when the piece is moving.
*/
protected void updatePosition ()
{
_view.getPiecePosition(_col, _row, _srcPos);
_view.getPiecePosition(_col, _row+1, _destPos);
setLocation(_srcPos.x, _srcPos.y);
}
// documentation inherited
public void setOrientation (int orient)
{
invalidate();
super.setOrientation(orient);
updateBounds();
invalidate();
}
/**
* Updates the bounds for this sprite based on the sprite display
* dimensions in the view.
*/
protected void updateBounds ()
{
Dimension size = _view.getPieceSegmentSize(
_col, _row, _orient, _pieces.length);
_bounds.width = size.width;
_bounds.height = size.height;
}
/**
* Adjusts our render origin such that our location is not in the
* upper left of the sprite's rendered image but is in fact offset by
* some number of rows and columns.
*/
protected void updateRenderOffset ()
{
_oxoff = -(_view.getPieceWidth() * _offx);
_oyoff = -(_view.getPieceHeight() * _offy);
}
/** Used to dispatch {@link DropSpriteObserver#pieceMoved}. */
protected static class PieceMovedOp implements ObserverList.ObserverOp
{
public PieceMovedOp (DropSprite sprite, long when, int col, int row)
{
_sprite = sprite;
_when = when;
_col = col;
_row = row;
}
public boolean apply (Object observer)
{
if (observer instanceof DropSpriteObserver) {
((DropSpriteObserver)observer).pieceMoved(
_sprite, _when, _col, _row);
}
return true;
}
protected DropSprite _sprite;
protected long _when;
protected int _col, _row;
}
/** The default piece velocity. */
protected static final float DEFAULT_VELOCITY = 30f/1000f;
/** The time at which we started the current row. */
protected long _rowstamp;
/** The time at which we reached the end of the previous row. */
protected long _endstamp;
/** The time at which we were stopped en route to our next row. */
protected long _stopstamp;
/** The board view upon which this sprite is displayed. */
protected DropBoardView _view;
/** The unit distance the sprite moves to reach the next row. */
protected int _unit;
/** The screen coordinates of the top-left of the row currently
* occupied by the sprite. */
protected Point _srcPos = new Point();
/** The screen coordinates of the top-left of the row toward which the
* sprite is falling. */
protected Point _destPos = new Point();
/** The piece render position; used as working data when determining
* where to render each piece in the sprite. */
protected Point _renderPos = new Point();
/** The number of rows remaining to drop. */
protected int _dist;
/** The piece velocity. */
protected float _vel = DEFAULT_VELOCITY;
/** The offsets in columns or rows at which the piece is rendered. */
protected int _offx, _offy;
/** The current piece location in the board. */
protected int _row, _col;
/** The pieces this sprite is displaying. */
protected int[] _pieces;
/** Indicates that the drop sprite is bouncing; see {@link
* #setBouncing}. */
protected boolean _bouncing;
// used to compute the column and row increment while rendering the
// sprite's pieces based on its orientation
// W N E S
protected static final int[] ORIENT_DX = { -1, 0, 1, 0 };
protected static final int[] ORIENT_DY = { 0, -1, 0, 1 };
}
@@ -0,0 +1,16 @@
//
// $Id: DropSpriteObserver.java,v 1.1 2003/11/26 01:42:34 mdb Exp $
package com.threerings.puzzle.drop.client;
/**
* Provides notifications for drop puzzle specific stuff.
*/
public interface DropSpriteObserver
{
/**
* Called when the drop sprite has moved completely to the specified
* board coordinates.
*/
public void pieceMoved (DropSprite sprite, long when, int col, int row);
}
@@ -0,0 +1,93 @@
//
// $Id: NextBlockView.java,v 1.1 2003/11/26 01:42:34 mdb Exp $
package com.threerings.puzzle.drop.client;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JComponent;
import javax.swing.border.Border;
import com.threerings.media.image.Mirage;
import com.threerings.util.DirectionCodes;
/**
* The next block view displays an image representing the next drop block
* to appear in the game.
*/
public class NextBlockView extends JComponent
implements DirectionCodes
{
/**
* Constructs a next block view.
*/
public NextBlockView (DropBoardView view, int pwid, int phei, int orient)
{
// save things off
_view = view;
_pwid = pwid;
_phei = phei;
_orient = orient;
// configure the component
setOpaque(false);
}
/**
* Sets the pieces displayed by the view.
*/
public void setPieces (int[] pieces)
{
_pieces = pieces;
repaint();
}
// documentation inherited
public void paintComponent (Graphics g)
{
super.paintComponent(g);
// draw the pieces
Graphics2D gfx = (Graphics2D)g;
if (_pieces != null) {
Dimension size = getSize();
int xpos = (_orient == VERTICAL) ? 0 : (size.width - _pwid);
int ypos = (_orient == VERTICAL) ? (size.height - _phei) : 0;
for (int ii = 0; ii < _pieces.length; ii++) {
Mirage image = _view.getPieceImage(_pieces[ii]);
image.paint(gfx, xpos, ypos);
if (_orient == VERTICAL) {
ypos -= _phei;
} else {
xpos -= _pwid;
}
}
}
}
// documentation inherited
public Dimension getPreferredSize ()
{
int wid = (_orient == VERTICAL) ? _pwid : (2 * _pwid);
int hei = (_orient == VERTICAL) ? (2 * _phei) : _phei;
return new Dimension(wid, hei);
}
/** The drop board view from which we obtain piece images. */
protected DropBoardView _view;
/** The pieces displayed by this view. */
protected int[] _pieces;
/** The piece dimensions in pixels. */
protected int _pwid, _phei;
/** The view orientation; one of {@link #HORIZONTAL} or {@link
* #VERTICAL}. */
protected int _orient;
}