DEADSOFTWARE

5d18755c590feb3ebbf9df3071cc96a32da8fa66
[cavedroid.git] / core / src / ru / deadsoftware / cavedroid / game / mobs / Mob.java
1 package ru.deadsoftware.cavedroid.game.mobs;
3 import com.badlogic.gdx.Gdx;
4 import com.badlogic.gdx.graphics.Color;
5 import com.badlogic.gdx.graphics.g2d.SpriteBatch;
6 import com.badlogic.gdx.math.MathUtils;
7 import com.badlogic.gdx.math.Rectangle;
8 import com.badlogic.gdx.math.Vector2;
9 import com.badlogic.gdx.utils.Timer;
10 import ru.deadsoftware.cavedroid.game.GameItemsHolder;
11 import ru.deadsoftware.cavedroid.game.model.dto.SaveDataDto;
12 import ru.deadsoftware.cavedroid.game.model.item.InventoryItem;
13 import ru.deadsoftware.cavedroid.game.world.GameWorld;
14 import ru.deadsoftware.cavedroid.misc.Saveable;
16 import javax.annotation.CheckForNull;
17 import java.util.Collections;
18 import java.util.List;
20 /**
21 * Mob class.
22 */
23 public abstract class Mob extends Rectangle implements Saveable {
25 private static final float DAMAGE_TINT_TIMEOUT_S = 0.5f;
26 private static final Color DAMAGE_TINT_COLOR = new Color(0xff8080ff);
28 private static final float HIT_RANGE = 8f;
30 protected static int ANIMATION_SPEED = 360;
32 public enum Type {
33 MOB,
34 FALLING_BLOCK
35 }
37 public enum Direction {
39 LEFT(0, -1),
40 RIGHT(1, 1);
42 private final int index;
43 private final int basis;
45 /**
46 * Index for this direction (left = 0, right = 1)
47 */
48 public final int getIndex() {
49 return index;
50 }
52 /**
53 * Basis for this direction (left = -1, right = 1)
54 */
55 public final int getBasis() {
56 return basis;
57 }
59 Direction(int index, int basis) {
60 this.index = index;
61 this.basis = basis;
62 }
63 }
65 private class ResetTakeDamageTask extends Timer.Task {
67 @Override
68 public void run() {
69 mTakingDamage = false;
70 }
71 }
73 protected Vector2 mVelocity;
74 protected Type mType;
75 protected int mAnimDelta = ANIMATION_SPEED;
76 protected float mAnim;
78 protected Direction mDirection;
79 protected boolean mDead;
80 protected boolean mCanJump;
81 protected boolean mFlyMode;
83 protected int mMaxHealth;
84 protected int mHealth;
86 private boolean mTakingDamage = false;
87 @CheckForNull private ResetTakeDamageTask mResetTakeDamageTask = null;
89 /**
90 * @param x in pixels
91 * @param y in pixels
92 * @param width in pixels
93 * @param height in pixels
94 * @param mDirection Direction in which mob is looking
95 */
96 protected Mob(float x, float y, float width, float height, Direction mDirection, Type type, int maxHealth) {
97 super(x, y, width, height);
98 mVelocity = new Vector2(0, 0);
99 mCanJump = false;
100 mDead = false;
101 this.mDirection = mDirection;
102 this.mType = type;
103 this.mMaxHealth = maxHealth;
104 this.mHealth = mMaxHealth;
107 protected static Direction randomDir() {
108 return MathUtils.randomBoolean(.5f) ? Direction.LEFT : Direction.RIGHT;
111 private boolean isAnimationIncreasing() {
112 return mAnim > 0 && mAnimDelta > 0 || mAnim < 0 && mAnimDelta < 0;
115 private void checkHealth() {
116 mHealth = MathUtils.clamp(mHealth, 0, mMaxHealth);
118 if (mHealth <= 0) {
119 kill();
123 protected final void updateAnimation(float delta) {
124 final float velocityMultiplier = (Math.abs(getVelocity().x) / getSpeed());
125 final float animMultiplier = (velocityMultiplier == 0f ? 1f : velocityMultiplier) * delta;
126 final float maxAnim = 60f * (velocityMultiplier == 0f ? 1f : velocityMultiplier);
128 if (mVelocity.x != 0f || Math.abs(mAnim) > mAnimDelta * animMultiplier) {
129 mAnim += mAnimDelta * animMultiplier;
130 } else {
131 mAnim = 0;
134 if (mAnim > maxAnim) {
135 mAnim = maxAnim;
136 mAnimDelta = -ANIMATION_SPEED;
137 } else if (mAnim < -maxAnim) {
138 mAnim = -maxAnim;
139 mAnimDelta = ANIMATION_SPEED;
142 if (mVelocity.x == 0f && isAnimationIncreasing()) {
143 mAnimDelta = -mAnimDelta;
147 /**
148 * @return The X coordinate of a mob in blocks
149 */
150 public final int getMapX() {
151 return (int) (x + (getWidth() / 2)) / 16;
154 /**
155 * @return The Y coordinate of mob's upper edge in blocks
156 */
157 public final int getUpperMapY() {
158 return (int) (y / 16);
161 /**
162 * @return The Y coordinate if mob's vertical center in blocks
163 */
164 public final int getMiddleMapY() {
165 return (int) (y + (getHeight() / 2)) / 16;
168 /**
169 * @return The Y coordinate of mob's legs in blocks
170 */
171 public final int getLowerMapY() {
172 return (int) (y + getHeight()) / 16;
175 public final float getWidth() {
176 return width;
179 public final float getHeight() {
180 return height;
183 /**
184 * @return Integer representing a direction in which mob is looking, where 0 is left and 1 is right
185 */
186 public final Direction getDirection() {
187 return mDirection;
190 public final boolean looksLeft() {
191 return mDirection == Direction.LEFT;
194 public final boolean looksRight() {
195 return mDirection == Direction.RIGHT;
198 /**
199 * Switches direction in which mob is looking
200 */
201 protected final void switchDir() {
202 mDirection = looksLeft() ? Direction.RIGHT : Direction.LEFT;
205 public final boolean isDead() {
206 return mDead;
209 public final float getAnim() {
210 return mAnim;
213 /**
214 * Set's mob's dead variable to true and nothing else. It doesn't delete the
215 */
216 public void kill() {
217 mDead = true;
220 public final void move(float delta) {
221 x += mVelocity.x * delta;
222 y += mVelocity.y * delta;
225 public final Vector2 getVelocity() {
226 return mVelocity;
229 protected final void setVelocity(Vector2 velocity) {
230 mVelocity = velocity;
233 public final boolean canJump() {
234 return mCanJump;
237 public final void setCanJump(boolean canJump) {
238 this.mCanJump = canJump;
241 public final boolean isFlyMode() {
242 return mFlyMode;
245 public final void setFlyMode(boolean flyMode) {
246 this.mFlyMode = flyMode;
249 public final Type getType() {
250 return mType;
253 public final void checkWorldBounds(GameWorld gameWorld) {
254 if (x + width / 2 < 0) {
255 x += gameWorld.getWidthPx();
257 if (x + width / 2 > gameWorld.getWidthPx()) {
258 x -= gameWorld.getWidthPx();
262 public final int getHealth() {
263 return mHealth;
266 public final int getMaxHealth() {
267 return mMaxHealth;
270 public final void attachToController(MobsController controller) {
271 controller.addMob(this);
274 public void damage(int damage) {
275 if (damage == 0) {
276 return;
279 if (damage < 0) {
280 Gdx.app.error(this.getClass().getSimpleName(), "Damage cant be negative!");
281 return;
284 if (mHealth <= Integer.MIN_VALUE + damage) {
285 mHealth = Integer.MIN_VALUE + damage;
288 mHealth -= damage;
289 checkHealth();
291 setTakingDamage(true);
294 public void heal(int heal) {
295 if (heal < 0) {
296 Gdx.app.error(this.getClass().getSimpleName(), "Heal cant be negative!");
297 return;
300 if (mHealth >= Integer.MAX_VALUE - heal) {
301 mHealth = Integer.MAX_VALUE - heal;
304 mHealth += heal;
305 checkHealth();
308 public Rectangle getHitBox() {
309 return new Rectangle(x - HIT_RANGE, y - HIT_RANGE, width + HIT_RANGE, height + HIT_RANGE);
312 public boolean isTakingDamage() {
313 return mTakingDamage;
316 public void setTakingDamage(boolean takingDamage) {
317 mTakingDamage = takingDamage;
319 if (takingDamage) {
320 if (mResetTakeDamageTask != null && mResetTakeDamageTask.isScheduled()) {
321 mResetTakeDamageTask.cancel();
322 } else if (mResetTakeDamageTask == null) {
323 mResetTakeDamageTask = new ResetTakeDamageTask();
326 Timer.schedule(mResetTakeDamageTask, DAMAGE_TINT_TIMEOUT_S);
330 protected Color getTintColor() {
331 return isTakingDamage() ? DAMAGE_TINT_COLOR : Color.WHITE;
334 public List<InventoryItem> getDrop(GameItemsHolder gameItemsHolder) {
335 return Collections.emptyList();
338 public abstract void draw(SpriteBatch spriteBatch, float x, float y, float delta);
340 public abstract void ai(GameWorld gameWorld, GameItemsHolder gameItemsHolder, MobsController mobsController, float delta);
342 public abstract void changeDir();
344 public abstract float getSpeed();
346 public abstract void jump();
348 @Override
349 public abstract SaveDataDto.MobSaveDataDto getSaveData();
351 public static Mob fromSaveData(SaveDataDto.MobSaveDataDto saveData) {
352 return MobSaveDataMapperKt.fromSaveData(saveData);