DEADSOFTWARE

CaveGame in kotlin
[cavedroid.git] / core / src / ru / deadsoftware / cavedroid / game / GamePhysics.java
1 package ru.deadsoftware.cavedroid.game;
3 import com.badlogic.gdx.math.Intersector;
4 import com.badlogic.gdx.math.MathUtils;
5 import com.badlogic.gdx.math.Rectangle;
6 import com.badlogic.gdx.math.Vector2;
7 import org.jetbrains.annotations.Nullable;
8 import ru.deadsoftware.cavedroid.MainConfig;
9 import ru.deadsoftware.cavedroid.game.mobs.Mob;
10 import ru.deadsoftware.cavedroid.game.mobs.MobsController;
11 import ru.deadsoftware.cavedroid.game.mobs.player.Player;
12 import ru.deadsoftware.cavedroid.game.model.block.Block;
13 import ru.deadsoftware.cavedroid.game.model.item.InventoryItem;
14 import ru.deadsoftware.cavedroid.game.objects.drop.Drop;
15 import ru.deadsoftware.cavedroid.game.objects.drop.DropController;
16 import ru.deadsoftware.cavedroid.game.world.GameWorld;
18 import javax.inject.Inject;
19 import java.util.Iterator;
22 @GameScope
23 public class GamePhysics {
25 public static final float PL_JUMP_VELOCITY = -133.332f;
26 public static final float PL_TERMINAL_VELOCITY = 1254.4f;
28 private final Vector2 gravity = new Vector2(0, 444.44f);
30 private final GameWorld mGameWorld;
31 private final MainConfig mMainConfig;
32 private final MobsController mMobsController;
33 private final DropController mDropController;
34 private final GameItemsHolder mGameItemsHolder;
36 @Inject
37 public GamePhysics(GameWorld gameWorld,
38 MainConfig mainConfig,
39 MobsController mobsController,
40 DropController dropController,
41 GameItemsHolder gameItemsHolder) {
42 mGameWorld = gameWorld;
43 mMainConfig = mainConfig;
44 mMobsController = mobsController;
45 mDropController = dropController;
46 mGameItemsHolder = gameItemsHolder;
47 }
49 /**
50 * Checks if mob should jump
51 *
52 * @return true if mob should jump
53 */
54 private boolean checkJump(Mob mob) {
55 int dir = mob.looksLeft() ? 0 : 1;
56 int blX = (int) (mob.getX() + mob.getWidth() * dir - 8 + 16 * dir);
57 int blY = (int) (mob.getY() + mob.getHeight() - 8);
58 Block block = mGameWorld.getForeMap(blX / 16, blY / 16);
60 if (checkColl(new Rectangle(blX, mob.getY() - 18, mob.getWidth(), mob.getHeight())) != null) {
61 return false;
62 }
64 return (block.toJump() &&
65 (mob.getY() + mob.getHeight()) - block.getRectangle(blX / 16, blY / 16).y > 8);
66 }
68 /**
69 * @return colliding rect or null if no collision
70 */
71 @Nullable
72 private Rectangle checkColl(Rectangle rect) {
73 int minX = (int) ((rect.x + rect.width / 2) / 16) - 4;
74 int minY = (int) ((rect.y + rect.height / 2) / 16) - 4;
75 int maxX = (int) ((rect.x + rect.width / 2) / 16) + 4;
76 int maxY = (int) ((rect.y + rect.height / 2) / 16) + 4;
78 if (minY < 0) {
79 minY = 0;
80 }
82 if (maxY > mGameWorld.getHeight()) {
83 maxY = mGameWorld.getHeight();
84 }
86 Block block;
87 for (int y = minY; y < maxY; y++) {
88 for (int x = minX; x < maxX; x++) {
89 if (!mGameWorld.hasForeAt(x, y)) {
90 continue;
91 }
92 block = mGameWorld.getForeMap(x, y);
93 if (block.hasCollision()) {
94 final Rectangle blockRect = block.getRectangle(x, y);
95 if (Intersector.overlaps(rect, blockRect)) {
96 return blockRect;
97 }
98 }
99 }
102 return null;
105 private Block getBlock(Rectangle rect) {
106 return mGameWorld.getForeMap((int) (rect.x + rect.width / 2) / 16,
107 (int) (rect.y + rect.height / 8 * 7) / 16);
110 private Rectangle getShiftedPlayerRect(float shift) {
111 final Player player = mMobsController.getPlayer();
112 return new Rectangle(player.x + shift, player.y, player.width, player.height);
115 /**
116 * @return Rectangle representing magneting target for this drop
117 */
118 @Nullable
119 private Rectangle getShiftedMagnetingPlayerRect(Drop drop) {
120 final Player player = mMobsController.getPlayer();
122 if (!player.inventory.canPickItem(drop)) {
123 return null;
126 if (drop.canMagnetTo(player)) {
127 return getShiftedPlayerRect(0);
130 final Rectangle shiftedLeft = getShiftedPlayerRect(-mGameWorld.getWidthPx());
131 if (drop.canMagnetTo(shiftedLeft)) {
132 return shiftedLeft;
135 final Rectangle shiftedRight = getShiftedPlayerRect(mGameWorld.getWidthPx());
136 if (drop.canMagnetTo(shiftedRight)) {
137 return shiftedRight;
140 return null;
143 private void pickUpDropIfPossible(Rectangle shiftedPlayerTarget, Drop drop) {
144 final Player player = mMobsController.getPlayer();
146 if (Intersector.overlaps(shiftedPlayerTarget, drop)) {
147 player.inventory.pickDrop(drop);
151 private void dropPhy(Drop drop, float delta) {
152 final Rectangle playerMagnetTarget = getShiftedMagnetingPlayerRect(drop);
153 final Vector2 dropVelocity = drop.getVelocity();
156 if (playerMagnetTarget != null) {
157 final Vector2 magnetVector = new Vector2(playerMagnetTarget.x - drop.x,
158 playerMagnetTarget.y - drop.y);
159 magnetVector.nor().scl(Drop.MAGNET_VELOCITY * delta);
160 dropVelocity.add(magnetVector);
161 } else {
162 dropVelocity.y += gravity.y * delta;
165 dropVelocity.x = MathUtils.clamp(dropVelocity.x, -Drop.MAGNET_VELOCITY, Drop.MAGNET_VELOCITY);
166 dropVelocity.y = MathUtils.clamp(dropVelocity.y, -Drop.MAGNET_VELOCITY, Drop.MAGNET_VELOCITY);
168 drop.x += dropVelocity.x * delta;
169 drop.y += dropVelocity.y * delta;
171 if (checkColl(drop) != null) {
172 dropVelocity.setZero();
173 do {
174 drop.y--;
175 } while (checkColl(drop) != null);
178 if (playerMagnetTarget != null) {
179 pickUpDropIfPossible(playerMagnetTarget, drop);
183 private void mobXColl(Mob mob) {
184 if (mob.getVelocity().x == 0f) {
185 return;
188 @Nullable Rectangle collidingRect = checkColl(mob);
190 if (collidingRect != null) {
191 if (mob.canJump() && !mob.isFlyMode() && collidingRect.y >= mob.y + mob.height - 8) {
192 mob.y = collidingRect.y - mob.height;
193 return;
196 collidingRect = checkColl(mob);
198 if (collidingRect != null) {
199 int d = 0;
201 if (mob.getVelocity().x < 0) {
202 d = 1;
203 } else if (mob.getVelocity().x > 0) {
204 d = -1;
207 if (d < 0) {
208 mob.x = collidingRect.x - mob.width;
209 } else {
210 mob.x = collidingRect.x + collidingRect.width;
213 // mob.x = MathUtils.round(mob.getX());
214 // while (checkColl(mob) != null) {
215 // mob.x += d;
216 // }
218 if (mob.canJump()) {
219 mob.changeDir();
224 mob.checkWorldBounds(mGameWorld);
227 private void mobYColl(Mob mob) {
228 @Nullable final Rectangle collidingRect = checkColl(mob);
229 if (collidingRect != null) {
230 int d = -1;
232 if (mob.getVelocity().y < 0) {
233 d = 1;
236 if (d == -1) {
237 mob.setCanJump(true);
238 mob.setFlyMode(false);
240 int dmg = ((int)Math.max(0f, (((mob.getVelocity().y * mob.getVelocity().y) / (2 * gravity.y)) - 48f) / 16f));
241 if (dmg > 0) {
242 mob.damage(dmg);
246 if (d < 0) {
247 mob.y = collidingRect.y - mob.height;
248 } else {
249 mob.y = collidingRect.y + collidingRect.height;
253 // mob.y = MathUtils.round(mob.getY());
254 //
255 // while (checkColl(mob)) {
256 // mob.y += d;
257 // }
259 mob.getVelocity().y = 0;
261 } else {
262 mob.y += 1;
263 mob.setCanJump(checkColl(mob) != null);
264 mob.y -= 1;
267 if (mob.getY() > mGameWorld.getHeightPx()) {
268 mob.kill();
272 private void playerPhy(Player player, float delta) {
273 if (player.isDead()) {
274 return;
277 if (getBlock(player).isFluid()) {
278 if (mMainConfig.isTouch() && player.getVelocity().x != 0 && !player.swim && !player.isFlyMode()) {
279 player.swim = true;
281 if (!player.swim) {
282 if (!player.isFlyMode() && player.getVelocity().y < 32f) {
283 player.getVelocity().y += gravity.y * delta;
285 if (!player.isFlyMode() && player.getVelocity().y > 32f) {
286 player.getVelocity().y -= player.getVelocity().y * 32f * delta;
288 } else {
289 player.getVelocity().y += PL_JUMP_VELOCITY * delta;
290 if (player.getVelocity().y < -player.getSpeed()) {
291 player.getVelocity().y = -player.getSpeed();
294 } else {
295 if (!player.isFlyMode() && player.getVelocity().y < PL_TERMINAL_VELOCITY) {
296 player.getVelocity().y += gravity.y * delta;
300 player.y += player.getVelocity().y * delta;
301 mobYColl(player);
303 player.x += player.getVelocity().x * (player.isFlyMode() ? 1.5f : 1) *
304 (getBlock(player).isFluid() && !player.isFlyMode() ? .8f : 1) * delta;
306 mobXColl(player);
308 if (mMainConfig.isTouch() && !player.isFlyMode() && player.canJump() && player.getVelocity().x != 0 && checkJump(player)) {
309 player.jump();
310 player.setCanJump(false);
314 private void mobPhy(Mob mob, float delta) {
315 if (mob.getType() == Mob.Type.MOB && getBlock(mob).isFluid()) {
316 if (mob.getVelocity().y > 32f) {
317 mob.getVelocity().y -= mob.getVelocity().y * 32f * delta;
320 mob.getVelocity().y += PL_JUMP_VELOCITY * delta;
322 if (mob.getVelocity().y < -mob.getSpeed()) {
323 mob.getVelocity().y = -mob.getSpeed();
325 } else if (!mob.isFlyMode() && mob.getVelocity().y < PL_TERMINAL_VELOCITY) {
326 mob.getVelocity().y += gravity.y * delta;
329 mob.y += mob.getVelocity().y * delta;
330 mobYColl(mob);
332 if (mob.isDead()) {
333 return;
336 mob.x += mob.getVelocity().x * delta;
337 mobXColl(mob);
339 if (mob.canJump() && mob.getVelocity().x != 0 && checkJump(mob)) {
340 mob.jump();
341 mob.setCanJump(false);
345 void update(float delta) {
346 Player player = mMobsController.getPlayer();
348 for (Iterator<Drop> it = mDropController.getIterator(); it.hasNext(); ) {
349 Drop drop = it.next();
350 dropPhy(drop, delta);
351 if (drop.getPickedUp()) {
352 it.remove();
356 for (Iterator<Mob> it = mMobsController.getMobs().iterator(); it.hasNext(); ) {
357 Mob mob = it.next();
358 mob.ai(mGameWorld, mGameItemsHolder, mMobsController, delta);
359 mobPhy(mob, delta);
360 if (mob.isDead()) {
361 for (InventoryItem invItem : mob.getDrop(mGameItemsHolder)) {
362 mDropController.addDrop(mob.x, mob.y, invItem);
365 it.remove();
369 playerPhy(player, delta);
370 player.ai(mGameWorld, mGameItemsHolder, mMobsController, delta);
371 if (player.isDead()) {
372 for (InventoryItem invItem : player.inventory.getItems()) {
373 mDropController.addDrop(player.x, player.y, invItem);
375 player.inventory.clear();
376 player.respawn(mGameWorld, mGameItemsHolder);