Package games.stendhal.client.entity

Source Code of games.stendhal.client.entity.ActiveEntity

/* $Id: ActiveEntity.java,v 1.35 2010/11/23 16:58:33 kiheru Exp $ */
/***************************************************************************
*                   (C) Copyright 2003-2010 - Stendhal                    *
***************************************************************************
***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************/
package games.stendhal.client.entity;

import games.stendhal.client.GameObjects;
import games.stendhal.common.Direction;
import marauroa.common.game.RPObject;

/**
* An entity that has movement and direction.
*/
public abstract class ActiveEntity extends Entity {
  /** Epsilon value used for coordinate change checks. */
  private static final double EPSILON = 0.001;
  /**
   * Direction property.
   */
  public static final Property PROP_DIRECTION = new Property();

  /**
   * Speed property.
   */
  public static final Property PROP_SPEED = new Property();

  /**
   * The current [facing] direction.
   */
  private Direction direction;

  /** The current speed of this entity horizontally (tiles?/sec). */
  private double dx;

  /** The current speed of this entity vertically (tiles?/sec) . */
  private double dy;

  /**
   * Create an active (moving) entity.
   */
  ActiveEntity() {
    direction = Direction.DOWN;
    dx = 0.0;
    dy = 0.0;
  }

  //
  // ActiveEntity
  //

  /**
   * Get the direction.
   *
   * @return The direction.
   */
  public Direction getDirection() {
    return direction;
  }

  /**
   * The entity has stopped motion.
   */
  protected void onStop() {
  }

  /**
   * Set the direction.
   *
   * @param direction
   *            The direction.
   */
  protected void setDirection(final Direction direction) {
    this.direction = direction;
  }

  /**
   * Determine if this entity is not moving.
   *
   * @return <code>true</code> if not moving.
   */
  public boolean stopped() {
    return (dx == 0.0) && (dy == 0.0);
  }

  /**
   * Compares to floating point values.
   *
   * @param d1
   *            first value
   * @param d2
   *            second value
   * @param diff
   *            acceptable diff
   * @return true if they are within diff
   */
  private static boolean compareDouble(final double d1, final double d2,
      final double diff) {
    return Math.abs(d1 - d2) < diff;
  }

  /**
   * calculates the movement if the server an client are out of sync. for some
   * milliseconds. (server turns are not exactly 300 ms) Most times this will
   * slow down the client movement
   *
   * @param clientPos
   *            the position the client has calculated
   * @param serverPos
   *            the position the server has reported
   * @param delta
   *            the movement based on direction
   * @return the new delta to correct the movement error
   */
  public static double calcDeltaMovement(final double clientPos,
      final double serverPos, final double delta) {
    final double moveErr = clientPos - serverPos;
    final double moveCorrection = (delta - moveErr) / delta;
    return (delta + delta * moveCorrection) / 2;
  }

  // When rpentity moves, it will be called with the data.
  protected void onMove(final int x, final int y, final Direction direction,
      final double speed) {

    double oldx = this.x;
    double oldy = this.y;
    this.dx = direction.getdx() * speed;
    this.dy = direction.getdy() * speed;

    if ((Direction.LEFT.equals(direction))
        || (Direction.RIGHT.equals(direction))) {
      this.y = y;
      if (compareDouble(this.x, x, 1.0)) {
        // make the movement look more nicely: + this.dx * 0.1
        this.dx = calcDeltaMovement(this.x + this.dx * 0.1, x,
            direction.getdx())
            * speed;
      } else {
        this.x = x;
      }
      this.dy = 0;
    } else if ((Direction.UP.equals(direction))
        || (Direction.DOWN.equals(direction))) {
      this.x = x;
      this.dx = 0;
      if (compareDouble(this.y, y, 1.0)) {
        // make the movement look more nicely: + this.dy * 0.1
        this.dy = calcDeltaMovement(this.y + this.dy * 0.1, y,
            direction.getdy())
            * speed;
      } else {
        this.y = y;
      }
    } else {
      // placing entities
      this.x = x;
      this.y = y;
    }

    // Call onPosition only if the entity actually moved. Also always call
    // on partial coordinates - those are always predicted rather than real
    // and thus should always be a result of prediction. However, the
    // client collision detection does not always agree with that of the
    // server, so relying on just the coordinate change checks can miss
    // entities stopping when they collide with each other.
    if (!compareDouble(this.x, oldx, EPSILON) || !compareDouble(this.y, oldy, EPSILON)
        || !compareDouble(oldx, (int) oldx, EPSILON)
        || !compareDouble(oldy, (int) oldy, EPSILON)) {
      onPosition(x, y);
    }
  }

  //
  // Entity
  //

  /**
   * Initialize this entity for an object.
   *
   * @param base
   *            The object.
   *
   * @see #release()
   */
  @Override
  public void initialize(final RPObject base) {
    double speed;

    super.initialize(base);

    if (base.has("dir")) {
      setDirection(Direction.build(base.getInt("dir")));
    }

    if (base.has("speed")) {
      speed = base.getDouble("speed");
    } else {
      speed = 0.0;
    }

    dx = direction.getdx() * speed;
    dy = direction.getdy() * speed;
  }

  /**
   * Update cycle.
   *
   * @param delta
   *            The time (in ms) since last call.
   */
  @Override
  public void update(final int delta) {
    super.update(delta);

    if (!stopped()) {
      final double step = (delta / 300.0);

      final double oldX = x;
      final double oldY = y;

      // update the location of the entity based on speeds
      x += (dx * step);
      y += (dy * step);

      if (GameObjects.getInstance().collides(this)) {
        x = oldX;
        y = oldY;
      } else {
        onPosition(x, y);
      }
    }
  }

  /**
   * Process attribute changes that may affect positioning. This is needed
   * because different entities may want to process coordinate changes more
   * gracefully.
   *
   * @param base
   *            The previous values.
   * @param diff
   *            The changes.
   */
  @Override
  protected void processPositioning(final RPObject base, final RPObject diff) {
    // Real movement case
    final int oldx = base.getInt("x");
    final int oldy = base.getInt("y");

    int newX = oldx;
    int newY = oldy;

    if (diff.has("x")) {
      newX = diff.getInt("x");
    }
    if (diff.has("y")) {
      newY = diff.getInt("y");
    }

    Direction temp_direction;

    if (diff.has("dir")) {
      temp_direction = Direction.build(diff.getInt("dir"));
      setDirection(temp_direction);
      fireChange(PROP_DIRECTION);
    } else if (base.has("dir")) {
      temp_direction = Direction.build(base.getInt("dir"));
      setDirection(temp_direction);
    } else {
      temp_direction = Direction.STOP;
    }

    double speed;

    if (diff.has("speed")) {
      speed = diff.getDouble("speed");
      fireChange(PROP_SPEED);
    } else if (base.has("speed")) {
      speed = base.getDouble("speed");
    } else {
      speed = 0;
    }

    onMove(newX, newY, temp_direction, speed);

    if ((Direction.STOP.equals(temp_direction)) || (speed == 0)) {
      dx = 0.0;
      dy = 0.0;

      x = newX;
      y = newY;

      onStop();
    }

    /*
     * Change in position?
     */
    if ((oldx != newX) && (oldy != newY)) {
      onPosition(newX, newY);
    }
  }
}
TOP

Related Classes of games.stendhal.client.entity.ActiveEntity

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.