/*
* Copyright 2015 Daniel Dittmar
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package dan.dit.whatsthat.util.flatworld.mover;
import dan.dit.whatsthat.util.flatworld.collision.Hitbox;
/**
* Created by daniel on 01.06.15.
*/
public class HitboxJumpMover extends HitboxMover {
public static final int STATE_NOT_MOVING = 0;
public static final int STATE_JUMP_ASCENDING = 1;
public static final int STATE_JUMP_FALLING = 2;
public static final int STATE_LANDED = 3;
private int mState = STATE_NOT_MOVING;
private float mSpeedY;
private float mRemainingAscend;
private float mRemainingDescend;
private long mAscendDuration;
private long mJumpInProgressDuration;
private long mTotalDuration;
private float mAccelY;
/**
* Initializes a jump in the y direction that will last the given duration. Does nothing
* if the distance to move is zero. All direction signums can be changed to move in the opposite direction.
* Speed is constant, no acceleration is done.
* @param ascendY Ascending movement, that means a positive value will move negative y direction.
* @param descendY Descending movement after the ascending movement. A positive value will move in the positive y direction.
* @param duration The positive duration of the total jump. The fraction of ascending distance to total distance will be the time
* taken for ascension.
*/
public void initJump(float ascendY, float descendY, long duration) {
float distance = (Math.abs(ascendY) + Math.abs(descendY));
if (distance == 0.f) {
return;
}
if (duration <= 0L) {
throw new IllegalArgumentException("Jump duration illegal: " + duration);
}
mJumpInProgressDuration = 0L;
mTotalDuration = duration;
mRemainingAscend = ascendY;
mRemainingDescend = descendY;
mAscendDuration = (long) (Math.abs(ascendY / distance) * duration);
mSpeedY = -2 * ascendY * ONE_SECOND / mAscendDuration; // ensure that speed is zero at peak
mAccelY = Math.signum(ascendY) * Math.abs(mSpeedY) * ONE_SECOND / mAscendDuration;
mState = STATE_JUMP_ASCENDING;
}
@Override
public float getSpeed() {
return Math.abs(mSpeedY);
}
@Override
public float getAcceleration() {
return Math.abs(mAccelY);
}
public long getJumpDuration() {
return mJumpInProgressDuration;
}
@Override
public int getState() {
return mState;
}
@Override
public boolean update(Hitbox toMove, long updatePeriod) {
boolean stateChange = false;
float dy;
switch (mState) {
case STATE_JUMP_ASCENDING:
mJumpInProgressDuration += updatePeriod;
mSpeedY += mAccelY * updatePeriod / ONE_SECOND;
dy = mSpeedY * updatePeriod / ONE_SECOND;
dy = (mRemainingAscend + dy >= 0.f) ? dy : -mRemainingAscend;
mRemainingAscend += dy;
toMove.move(0.f, dy);
if (mJumpInProgressDuration >= mAscendDuration) {
toMove.move(0.f, -mRemainingAscend);
mRemainingAscend = 0.f;
mState = STATE_JUMP_FALLING;
mSpeedY = 0.f;
float descendTime = (mTotalDuration - mAscendDuration) / ONE_SECOND;
mAccelY = mRemainingDescend * 2 / (descendTime * descendTime);
stateChange = true;
}
break;
case STATE_JUMP_FALLING:
mJumpInProgressDuration += updatePeriod;
mSpeedY += mAccelY * updatePeriod / ONE_SECOND;
dy = mSpeedY * updatePeriod / ONE_SECOND;
dy = (mRemainingDescend - dy >= 0.f) ? dy : mRemainingDescend;
mRemainingDescend -= dy;
toMove.move(0.f, dy);
if (mJumpInProgressDuration >= mTotalDuration) {
toMove.move(0.f, mRemainingDescend);
mRemainingDescend = 0.f;
mState = STATE_LANDED;
mSpeedY = 0.f;
stateChange = true;
}
break;
}
return stateChange;
}
@Override
public boolean isMoving() {
return mState == STATE_JUMP_ASCENDING || mState == STATE_JUMP_FALLING;
}
public void stop() {
mState = STATE_NOT_MOVING;
}
}