DEADSOFTWARE

CaveGame in kotlin
[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 org.jetbrains.annotations.Nullable;
11 import ru.deadsoftware.cavedroid.game.GameItemsHolder;
12 import ru.deadsoftware.cavedroid.game.model.dto.SaveDataDto;
13 import ru.deadsoftware.cavedroid.game.model.item.InventoryItem;
14 import ru.deadsoftware.cavedroid.game.world.GameWorld;
15 import ru.deadsoftware.cavedroid.misc.Saveable;
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;
88 @Nullable
89 private ResetTakeDamageTask mResetTakeDamageTask = null;
91 /**
92 * @param x in pixels
93 * @param y in pixels
94 * @param width in pixels
95 * @param height in pixels
96 * @param mDirection Direction in which mob is looking
97 */
98 protected Mob(float x, float y, float width, float height, Direction mDirection, Type type, int maxHealth) {
99 super(x, y, width, height);
100 mVelocity = new Vector2(0, 0);
101 mCanJump = false;
102 mDead = false;
103 this.mDirection = mDirection;
104 this.mType = type;
105 this.mMaxHealth = maxHealth;
106 this.mHealth = mMaxHealth;
109 protected static Direction randomDir() {
110 return MathUtils.randomBoolean(.5f) ? Direction.LEFT : Direction.RIGHT;
113 private boolean isAnimationIncreasing() {
114 return mAnim > 0 && mAnimDelta > 0 || mAnim < 0 && mAnimDelta < 0;
117 private void checkHealth() {
118 mHealth = MathUtils.clamp(mHealth, 0, mMaxHealth);
120 if (mHealth <= 0) {
121 kill();
125 protected final void updateAnimation(float delta) {
126 final float velocityMultiplier = (Math.abs(getVelocity().x) / getSpeed());
127 final float animMultiplier = (velocityMultiplier == 0f ? 1f : velocityMultiplier) * delta;
128 final float maxAnim = 60f * (velocityMultiplier == 0f ? 1f : velocityMultiplier);
130 if (mVelocity.x != 0f || Math.abs(mAnim) > mAnimDelta * animMultiplier) {
131 mAnim += mAnimDelta * animMultiplier;
132 } else {
133 mAnim = 0;
136 if (mAnim > maxAnim) {
137 mAnim = maxAnim;
138 mAnimDelta = -ANIMATION_SPEED;
139 } else if (mAnim < -maxAnim) {
140 mAnim = -maxAnim;
141 mAnimDelta = ANIMATION_SPEED;
144 if (mVelocity.x == 0f && isAnimationIncreasing()) {
145 mAnimDelta = -mAnimDelta;
149 /**
150 * @return The X coordinate of a mob in blocks
151 */
152 public final int getMapX() {
153 return (int) (x + (getWidth() / 2)) / 16;
156 /**
157 * @return The Y coordinate of mob's upper edge in blocks
158 */
159 public final int getUpperMapY() {
160 return (int) (y / 16);
163 /**
164 * @return The Y coordinate if mob's vertical center in blocks
165 */
166 public final int getMiddleMapY() {
167 return (int) (y + (getHeight() / 2)) / 16;
170 /**
171 * @return The Y coordinate of mob's legs in blocks
172 */
173 public final int getLowerMapY() {
174 return (int) (y + getHeight()) / 16;
177 public final float getWidth() {
178 return width;
181 public final float getHeight() {
182 return height;
185 /**
186 * @return Integer representing a direction in which mob is looking, where 0 is left and 1 is right
187 */
188 public final Direction getDirection() {
189 return mDirection;
192 public final boolean looksLeft() {
193 return mDirection == Direction.LEFT;
196 public final boolean looksRight() {
197 return mDirection == Direction.RIGHT;
200 /**
201 * Switches direction in which mob is looking
202 */
203 protected final void switchDir() {
204 mDirection = looksLeft() ? Direction.RIGHT : Direction.LEFT;
207 public final boolean isDead() {
208 return mDead;
211 public final float getAnim() {
212 return mAnim;
215 /**
216 * Set's mob's dead variable to true and nothing else. It doesn't delete the
217 */
218 public void kill() {
219 mDead = true;
222 public final void move(float delta) {
223 x += mVelocity.x * delta;
224 y += mVelocity.y * delta;
227 public final Vector2 getVelocity() {
228 return mVelocity;
231 protected final void setVelocity(Vector2 velocity) {
232 mVelocity = velocity;
235 public final boolean canJump() {
236 return mCanJump;
239 public final void setCanJump(boolean canJump) {
240 this.mCanJump = canJump;
243 public final boolean isFlyMode() {
244 return mFlyMode;
247 public final void setFlyMode(boolean flyMode) {
248 this.mFlyMode = flyMode;
251 public final Type getType() {
252 return mType;
255 public final void checkWorldBounds(GameWorld gameWorld) {
256 if (x + width / 2 < 0) {
257 x += gameWorld.getWidthPx();
259 if (x + width / 2 > gameWorld.getWidthPx()) {
260 x -= gameWorld.getWidthPx();
264 public final int getHealth() {
265 return mHealth;
268 public final int getMaxHealth() {
269 return mMaxHealth;
272 public final void attachToController(MobsController controller) {
273 controller.addMob(this);
276 public void damage(int damage) {
277 if (damage == 0) {
278 return;
281 if (damage < 0) {
282 Gdx.app.error(this.getClass().getSimpleName(), "Damage cant be negative!");
283 return;
286 if (mHealth <= Integer.MIN_VALUE + damage) {
287 mHealth = Integer.MIN_VALUE + damage;
290 mHealth -= damage;
291 checkHealth();
293 setTakingDamage(true);
296 public void heal(int heal) {
297 if (heal < 0) {
298 Gdx.app.error(this.getClass().getSimpleName(), "Heal cant be negative!");
299 return;
302 if (mHealth >= Integer.MAX_VALUE - heal) {
303 mHealth = Integer.MAX_VALUE - heal;
306 mHealth += heal;
307 checkHealth();
310 public Rectangle getHitBox() {
311 return new Rectangle(x - HIT_RANGE, y - HIT_RANGE, width + HIT_RANGE, height + HIT_RANGE);
314 public boolean isTakingDamage() {
315 return mTakingDamage;
318 public void setTakingDamage(boolean takingDamage) {
319 mTakingDamage = takingDamage;
321 if (takingDamage) {
322 if (mResetTakeDamageTask != null && mResetTakeDamageTask.isScheduled()) {
323 mResetTakeDamageTask.cancel();
324 } else if (mResetTakeDamageTask == null) {
325 mResetTakeDamageTask = new ResetTakeDamageTask();
328 Timer.schedule(mResetTakeDamageTask, DAMAGE_TINT_TIMEOUT_S);
332 protected Color getTintColor() {
333 return isTakingDamage() ? DAMAGE_TINT_COLOR : Color.WHITE;
336 public List<InventoryItem> getDrop(GameItemsHolder gameItemsHolder) {
337 return Collections.emptyList();
340 public abstract void draw(SpriteBatch spriteBatch, float x, float y, float delta);
342 public abstract void ai(GameWorld gameWorld, GameItemsHolder gameItemsHolder, MobsController mobsController, float delta);
344 public abstract void changeDir();
346 public abstract float getSpeed();
348 public abstract void jump();
350 @Override
351 public abstract SaveDataDto.MobSaveDataDto getSaveData();
353 public static Mob fromSaveData(SaveDataDto.MobSaveDataDto saveData) {
354 return MobSaveDataMapperKt.fromSaveData(saveData);