www.pudn.com > Bluegammon蓝牙的应用编程.rar > AbstractDicesAnim.java


// Copyright (c) 2005 Sony Ericsson Mobile Communications AB 
// 
// This software is provided "AS IS," without a warranty of any kind.  
// ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,  
// INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A  
// PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.  
// 
// THIS SOFTWARE IS COMPLEMENTARY OF JAYWAY AB (www.jayway.se) 
 
package bluegammon.gui.animation; 
 
 
import javax.microedition.lcdui.Graphics; 
import javax.microedition.m3g.Graphics3D; 
import javax.microedition.m3g.Transform; 
 
import bluegammon.Audio; 
import bluegammon.gui.BoardCanvas; 
import bluegammon.gui.Context3D; 
import bluegammon.logic.Rand; 
import bluegammon.logic.BoardMediator; 
 
 
/** 
 * An abstract animation of two dices - we do not have 
 * a case where we ever show only one dice. This is an 
 * general handler for rolling two dices that will have 
 * specified color and dice-value each. 
 *  
 * @author Peter Andersson 
 */ 
abstract public class AbstractDicesAnim extends Animation 
{ 
  /** Dice property index constants */ 
  protected static final int X = 0, Y = 1, Z = 2, 
  							DX = 3, DY = 4, DZ = 5, 
  							RX = 6, RY = 7, RZ = 8, 
  							DRZ = 9, 
  							WRX = 10, WRY = 11; 
  /** Z index where board is */ 
  protected static final float Z_ON_BOARD = -35f; 
  /** Gravity constant */ 
  protected static final float G = -0.05f; 
  /** X-axis rotation per dice value */ 
  protected static final float[] XROT = 
  { 0, 90, 0, 0, -90, 180 }; 
  /** Y-axis rotation per dice value */ 
  protected static final float[] YROT = 
  { 0, 0, 90, -90, 0, 0 }; 
  /** Physic properties for dice 1 */ 
  protected float[] diceProps1 = new float[12]; 
  /** Physic properties for dice 2 */ 
  protected float[] diceProps2 = new float[12]; 
  /** White dice 1 flag */ 
  protected boolean m_dice1White; 
  /** White dice 2 flag */ 
  protected boolean m_dice2White; 
  /** Values of dices */ 
  protected int m_dice1, m_dice2; 
  /** Current step in animation */ 
  protected int m_step; 
  /** The step from which both dices are still */ 
  protected int m_diceStillStep; 
  /** The time from which both dices are still */ 
  protected long m_diceStillTime; 
  /** Flag indicating if we played sound of dices hitting board */ 
  protected boolean m_playedSound = false; 
  /** Cached transform object */ 
  protected Transform m_trans = new Transform(); 
  /** Shadow rgb buffer */ 
  protected static int[] m_shadow = null; 
  /** Size of the dice in correspondance to the canvas */ 
  protected static int m_factor; 
 
  /** 
   * Initializes this animation, must be called before 
   * displaying any diceanimations. 
   * @param factor	The size factor of the dices, depends 
   * 				on the canvas size of the device. 
   */ 
  public static void init(int factor) 
  { 
    // Create semi transparant shadow as rgb buffer 
    m_factor = factor * 7; 
    m_shadow = Context3D.createShadowRGB(factor * 14, 1); 
  } 
   
  /** 
   * Called when the animation starts, resets the state of the sound. 
   */ 
  public void onStart() 
  { 
    m_playedSound = false; 
  } 
 
  /** 
   * Initiates this animation. Specifies color and values for both dices. 
   * @param dice1White	True if left dice is white, false for black, 
   * @param dice2White	True if right dice is white, false for black, 
   * @param dice1Val	Left dice value, 1 to 6. 
   * @param dice2Val	Right dice value, 1 to 6. 
   */ 
  public AbstractDicesAnim(boolean dice1White, boolean dice2White, int dice1Val, int dice2Val) 
  { 
    m_dice1White = dice1White; 
    m_dice2White = dice2White; 
    m_dice1 = dice1Val; 
    m_dice2 = dice2Val; 
 
    // Initiate dice positions, vectors and rotations 
    int drz0, drz1; 
    BoardCanvas canvas = BoardCanvas.getInstance(); 
    diceProps1[X] = (canvas.getWidth() / 2 - m_factor); 
    diceProps1[DX] = (Rand.randomFloat() - 0.7f) * ((float) canvas.getWidth() / 200.0f); 
    diceProps1[Y] = canvas.getHeight() - m_factor; 
    diceProps1[DY] = -((float) canvas.getBoardHeight() / 150.0f) + 
    				  (Rand.randomFloat() - 2f) * ((float) canvas.getBoardHeight() / 400.0f); 
    diceProps1[Z] = -10f + 5f * Rand.randomFloat(); 
    diceProps1[DZ] = 0; 
    diceProps1[RX] = 180.0f * Rand.randomFloat(); 
    diceProps1[RY] = 180.0f * Rand.randomFloat(); 
    diceProps1[WRX] = XROT[dice1Val - 1]; 
    diceProps1[WRY] = YROT[dice1Val - 1]; 
    drz0 = (Rand.random() & 0xf) + 8; 
    drz1 = -(Rand.random() & 0xf) - 8; 
    if (-drz1 > drz0) drz0 = drz1; 
    diceProps1[DRZ] = drz0; 
 
    diceProps2[X] = (canvas.getWidth() / 2 + m_factor); 
    diceProps2[DX] = diceProps1[DX] +  
    				 (float)((Rand.randomFloat() + 1.5f) * canvas.getWidth() / 300.0f); 
    diceProps2[Y] = diceProps1[Y]; 
    diceProps2[DY] = -((float)canvas.getBoardHeight() / 150.0f) + 
        			  (Rand.randomFloat() - 2f) * ((float) canvas.getBoardHeight() / 400.0f); 
    diceProps2[Z] = -10f + 5f * Rand.randomFloat(); 
    diceProps2[DZ] = 0; 
    diceProps2[RX] = 180.0f * Rand.randomFloat(); 
    diceProps2[RY] = 180.0f * Rand.randomFloat(); 
    diceProps2[WRX] = XROT[dice2Val - 1]; 
    diceProps2[WRY] = YROT[dice2Val - 1]; 
    drz0 = (Rand.random() & 0xf) + 8; 
    drz1 = -(Rand.random() & 0xf) - 8; 
    if (-drz1 > drz0) drz0 = drz1; 
    diceProps2[DRZ] = drz0; 
 
    m_diceStillStep = -1; 
  } 
   
  public void paint(Graphics g) 
  { 
    Context3D c3d = Context3D.getInstance(); 
 
    int factor2 = m_factor * 2; 
 
    float x0 = diceProps1[X]; 
    float y0 = diceProps1[Y]; 
    float z0 = diceProps1[Z]; 
 
    float x1 = diceProps2[X]; 
    float y1 = diceProps2[Y]; 
    float z1 = diceProps2[Z]; 
 
    // Draw shadows 
    g.drawRGB(m_shadow, 0, factor2, 
        (int)(x0 - m_factor - c3d.toScreenCoordinateX(c3d.getShadowProjectionDeltaX(z0 - Z_ON_BOARD), z0)), 
        (int)(y0 - m_factor), factor2, factor2, true); 
    g.drawRGB(m_shadow, 0, factor2, 
        (int)(x1 - m_factor - c3d.toScreenCoordinateX(c3d.getShadowProjectionDeltaX(z1 - Z_ON_BOARD), z1)), 
        (int)(y1 - m_factor), factor2, factor2, true); 
 
    // Draw dices 
    Graphics3D g3d = c3d.bindScene(g); 
 
    // Dice 1 
    m_trans.setIdentity(); 
    m_trans.postTranslate(c3d.to3DCoordinateX(x0, Z_ON_BOARD), c3d.to3DCoordinateY( 
        y0, Z_ON_BOARD), z0); 
    // In air rotation 
    m_trans.postRotate(diceProps1[RX], 1, 0, 0); 
    m_trans.postRotate(diceProps1[RY], 0, 1, 0); 
    m_trans.postRotate(diceProps1[RZ], 0, 0, 1); 
    // Dice value rotation 
    m_trans.postRotate(diceProps1[WRX], 1, 0, 0); 
    m_trans.postRotate(diceProps1[WRY], 0, 1, 0); 
 
    g3d.render(	c3d.getDiceVertexBuffer(), 
        		c3d.getDiceIndexBuffer(), 
        		c3d.getDiceAppearance(m_dice1White), 
        		m_trans); 
 
    // Dice 2 
    m_trans.setIdentity(); 
    m_trans.postTranslate(c3d.to3DCoordinateX(x1, Z_ON_BOARD), 
        			c3d.to3DCoordinateY(y1, Z_ON_BOARD), 
        			z1); 
    // In air rotation 
    m_trans.postRotate(diceProps2[RX], 1, 0, 0); 
    m_trans.postRotate(diceProps2[RY], 0, 1, 0); 
    m_trans.postRotate(diceProps2[RZ], 0, 0, 1); 
    // Dice value rotation 
    m_trans.postRotate(diceProps2[WRX], 1, 0, 0); 
    m_trans.postRotate(diceProps2[WRY], 0, 1, 0); 
 
    g3d.render(	c3d.getDiceVertexBuffer(), 
		c3d.getDiceIndexBuffer(), 
		c3d.getDiceAppearance(m_dice2White), 
		m_trans); 
 
    g3d.releaseTarget(); 
 
  } 
 
  public void next() 
  { 
    boolean hitGround = false; 
    hitGround =  updateDicePhysics(diceProps1); 
    hitGround |= updateDicePhysics(diceProps2); 
    if (hitGround && !m_playedSound) 
    { 
      m_playedSound = true; 
      if (Math.abs(diceProps1[DRZ]) + Math.abs(diceProps2[DRZ]) > 19*2) 
      { 
        Audio.playSound(Audio.DICES_LONG); 
      } 
      else 
      { 
        Audio.playSound(Audio.DICES_SHORT); 
      } 
    } 
    if (m_diceStillStep == -1) 
    { 
      if (isStill(diceProps1) && isStill(diceProps2)) 
      { 
        m_diceStillTime = System.currentTimeMillis(); 
        m_diceStillStep = m_step; 
      } 
    } 
    BoardCanvas.getInstance().requestRepaint(); 
    m_step++; 
  } 
 
  public boolean isFinished() 
  { 
    return (m_diceStillStep > 0 && (m_step > m_diceStillStep + 14 	|| 
        System.currentTimeMillis() > m_diceStillTime + 1500)) 		|| 
        BoardMediator.isGameFinished(); 
  } 
 
  public long getInterval() 
  { 
    return 20; 
  } 
 
  // Helpers 
 
  /** 
   * Updates the dices vectors and positions. If dice is on board, friction is 
   * applied. 
   */ 
  protected boolean updateDicePhysics(float[] diceProps) 
  { 
    boolean hitGround = false; 
    BoardCanvas canvas = BoardCanvas.getInstance(); 
    // Update position 
    diceProps[X] += diceProps[DX]; 
    diceProps[Y] += diceProps[DY]; 
 
    // Bounce against middle wall on board? 
    if (diceProps[Y] < (canvas.getBoardHeight() / 2 + m_factor) 
        && diceProps[DY] < 0) 
    { 
      diceProps[DY] = -diceProps[DY]; 
      diceProps[Y] = (canvas.getBoardHeight() / 2 + m_factor); 
    } 
 
    // in air 
    if (diceProps[Z] > Z_ON_BOARD) 
    { 
      diceProps[Z] += diceProps[DZ]; 
      diceProps[DZ] += G; 
      diceProps[RZ] += diceProps[DRZ]; 
 
      // boink 
      if (diceProps[Z] <= Z_ON_BOARD) 
      { 
        diceProps[DZ] = 0; 
        diceProps[Z] = Z_ON_BOARD; 
        hitGround = true; 
      } 
    } 
 
    // on board 
    else 
    { 
      // Decrease in air rotations 
      diceProps[RX] %= 360; 
      if (Math.abs(diceProps[RX]) < 13)	diceProps[RX] = 0; 
      else if (diceProps[RX] > 180)		diceProps[RX] += 12; 
      else if (diceProps[RX] < 180)		diceProps[RX] -= 12; 
 
      diceProps[RY] %= 360; 
      if (Math.abs(diceProps[RY]) < 13)	diceProps[RY] = 0; 
	  else if (diceProps[RY] > 180)		diceProps[RY] += 12; 
      else if (diceProps[RY] < 180)		diceProps[RY] -= 12; 
 
      // friction, positions and in air z-rotation 
      diceProps[DRZ] *= 0.95f; 
      if (Math.abs(diceProps[DRZ]) < 2)	diceProps[DRZ] = 0; 
      diceProps[RZ] += diceProps[DRZ]; 
      diceProps[DX] *= 0.95f; 
      if (Math.abs(diceProps[DX]) < 1)	diceProps[DX] = 0; 
      diceProps[DY] *= 0.95f; 
      if (Math.abs(diceProps[DY]) < 1)	diceProps[DY] = 0; 
    } 
    return hitGround; 
  } 
 
  /** 
   * Returns if a dice is still 
   *  
   * @param diceProps 	The dice properties 
   * @return true if dice is still 
   */ 
  protected boolean isStill(float[] diceProps) 
  { 
    return diceProps[Z] == Z_ON_BOARD & diceProps[DRZ] == 0; 
  } 
}