DEADSOFTWARE

Update version
[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 ru.deadsoftware.cavedroid.MainConfig;
8 import ru.deadsoftware.cavedroid.game.mobs.Mob;
9 import ru.deadsoftware.cavedroid.game.mobs.MobsController;
10 import ru.deadsoftware.cavedroid.game.mobs.player.Player;
11 import ru.deadsoftware.cavedroid.game.model.block.Block;
12 import ru.deadsoftware.cavedroid.game.objects.drop.Drop;
13 import ru.deadsoftware.cavedroid.game.objects.drop.DropController;
14 import ru.deadsoftware.cavedroid.game.world.GameWorld;
16 import javax.annotation.CheckForNull;
17 import javax.inject.Inject;
18 import java.util.Iterator;
21 @GameScope
22 public class GamePhysics {
24 public static final float PL_JUMP_VELOCITY = -133.332f;
25 public static final float PL_TERMINAL_VELOCITY = 1254.4f;
27 private final Vector2 gravity = new Vector2(0, 444.44f);
29 private final GameWorld mGameWorld;
30 private final MainConfig mMainConfig;
31 private final MobsController mMobsController;
32 private final DropController mDropController;
33 private final GameItemsHolder mGameItemsHolder;
35 @Inject
36 public GamePhysics(GameWorld gameWorld,
37 MainConfig mainConfig,
38 MobsController mobsController,
39 DropController dropController,
40 GameItemsHolder gameItemsHolder) {
41 mGameWorld = gameWorld;
42 mMainConfig = mainConfig;
43 mMobsController = mobsController;
44 mDropController = dropController;
45 mGameItemsHolder = gameItemsHolder;
46 }
48 /**
49 * Checks if mob should jump
50 *
51 * @return true if mob should jump
52 */
53 private boolean checkJump(Mob mob) {
54 int dir = mob.looksLeft() ? 0 : 1;
55 int blX = (int) (mob.getX() + mob.getWidth() * dir - 8 + 16 * dir);
56 int blY = (int) (mob.getY() + mob.getHeight() - 8);
57 Block block = mGameWorld.getForeMap(blX / 16, blY / 16);
59 if (checkColl(new Rectangle(blX, mob.getY() - 18, mob.getWidth(), mob.getHeight())) != null) {
60 return false;
61 }
63 return (block.toJump() &&
64 (mob.getY() + mob.getHeight()) - block.getRectangle(blX / 16, blY / 16).y > 8);
65 }
67 /**
68 * @return colliding rect or null if no collision
69 */
70 @CheckForNull
71 private Rectangle checkColl(Rectangle rect) {
72 int minX = (int) ((rect.x + rect.width / 2) / 16) - 4;
73 int minY = (int) ((rect.y + rect.height / 2) / 16) - 4;
74 int maxX = (int) ((rect.x + rect.width / 2) / 16) + 4;
75 int maxY = (int) ((rect.y + rect.height / 2) / 16) + 4;
77 if (minY < 0) {
78 minY = 0;
79 }
81 if (maxY > mGameWorld.getHeight()) {
82 maxY = mGameWorld.getHeight();
83 }
85 Block block;
86 for (int y = minY; y < maxY; y++) {
87 for (int x = minX; x < maxX; x++) {
88 if (!mGameWorld.hasForeAt(x, y)) {
89 continue;
90 }
91 block = mGameWorld.getForeMap(x, y);
92 if (block.hasCollision()) {
93 final Rectangle blockRect = block.getRectangle(x, y);
94 if (Intersector.overlaps(rect, blockRect)) {
95 return blockRect;
96 }
97 }
98 }
99 }
101 return null;
104 private Block getBlock(Rectangle rect) {
105 return mGameWorld.getForeMap((int) (rect.x + rect.width / 2) / 16,
106 (int) (rect.y + rect.height / 8 * 7) / 16);
109 private Rectangle getShiftedPlayerRect(float shift) {
110 final Player player = mMobsController.getPlayer();
111 return new Rectangle(player.x + shift, player.y, player.width, player.height);
114 /**
115 * @return Rectangle representing magneting target for this drop
116 */
117 @CheckForNull
118 private Rectangle getShiftedMagnetingPlayerRect(Drop drop) {
119 final Player player = mMobsController.getPlayer();
121 if (!player.inventory.canPickItem(drop)) {
122 return null;
125 if (drop.canMagnetTo(player)) {
126 return getShiftedPlayerRect(0);
129 final Rectangle shiftedLeft = getShiftedPlayerRect(-mGameWorld.getWidthPx());
130 if (drop.canMagnetTo(shiftedLeft)) {
131 return shiftedLeft;
134 final Rectangle shiftedRight = getShiftedPlayerRect(mGameWorld.getWidthPx());
135 if (drop.canMagnetTo(shiftedRight)) {
136 return shiftedRight;
139 return null;
142 private void pickUpDropIfPossible(Rectangle shiftedPlayerTarget, Drop drop) {
143 final Player player = mMobsController.getPlayer();
145 if (Intersector.overlaps(shiftedPlayerTarget, drop)) {
146 player.inventory.pickDrop(drop);
150 private void dropPhy(Drop drop, float delta) {
151 final Rectangle playerMagnetTarget = getShiftedMagnetingPlayerRect(drop);
152 final Vector2 dropVelocity = drop.getVelocity();
155 if (playerMagnetTarget != null) {
156 final Vector2 magnetVector = new Vector2(playerMagnetTarget.x - drop.x,
157 playerMagnetTarget.y - drop.y);
158 magnetVector.nor().scl(Drop.MAGNET_VELOCITY * delta);
159 dropVelocity.add(magnetVector);
160 } else {
161 dropVelocity.y += gravity.y * delta;
164 dropVelocity.x = MathUtils.clamp(dropVelocity.x, -Drop.MAGNET_VELOCITY, Drop.MAGNET_VELOCITY);
165 dropVelocity.y = MathUtils.clamp(dropVelocity.y, -Drop.MAGNET_VELOCITY, Drop.MAGNET_VELOCITY);
167 drop.x += dropVelocity.x * delta;
168 drop.y += dropVelocity.y * delta;
170 if (checkColl(drop) != null) {
171 dropVelocity.setZero();
172 do {
173 drop.y--;
174 } while (checkColl(drop) != null);
177 if (playerMagnetTarget != null) {
178 pickUpDropIfPossible(playerMagnetTarget, drop);
182 private void mobXColl(Mob mob) {
183 if (mob.getVelocity().x == 0f) {
184 return;
187 @CheckForNull Rectangle collidingRect = checkColl(mob);
189 if (collidingRect != null) {
190 if (mob.canJump() && !mob.isFlyMode() && collidingRect.y >= mob.y + mob.height - 8) {
191 mob.y = collidingRect.y - mob.height;
192 return;
195 collidingRect = checkColl(mob);
197 if (collidingRect != null) {
198 int d = 0;
200 if (mob.getVelocity().x < 0) {
201 d = 1;
202 } else if (mob.getVelocity().x > 0) {
203 d = -1;
206 if (d < 0) {
207 mob.x = collidingRect.x - mob.width;
208 } else {
209 mob.x = collidingRect.x + collidingRect.width;
212 // mob.x = MathUtils.round(mob.getX());
213 // while (checkColl(mob) != null) {
214 // mob.x += d;
215 // }
217 if (mob.canJump()) {
218 mob.changeDir();
223 mob.checkWorldBounds(mGameWorld);
226 private void mobYColl(Mob mob) {
227 @CheckForNull final Rectangle collidingRect = checkColl(mob);
228 if (collidingRect != null) {
229 int d = -1;
231 if (mob.getVelocity().y < 0) {
232 d = 1;
235 if (d == -1) {
236 mob.setCanJump(true);
237 mob.setFlyMode(false);
239 int dmg = ((int)Math.max(0f, (((mob.getVelocity().y * mob.getVelocity().y) / (2 * gravity.y)) - 48f) / 16f));
240 if (dmg > 0) {
241 mob.damage(dmg);
245 if (d < 0) {
246 mob.y = collidingRect.y - mob.height;
247 } else {
248 mob.y = collidingRect.y + collidingRect.height;
252 // mob.y = MathUtils.round(mob.getY());
253 //
254 // while (checkColl(mob)) {
255 // mob.y += d;
256 // }
258 mob.getVelocity().y = 0;
260 } else {
261 mob.y += 1;
262 mob.setCanJump(checkColl(mob) != null);
263 mob.y -= 1;
266 if (mob.getY() > mGameWorld.getHeightPx()) {
267 mob.kill();
271 private void playerPhy(Player player, float delta) {
272 if (player.isDead()) {
273 return;
276 if (getBlock(player).isFluid()) {
277 if (mMainConfig.isTouch() && player.getVelocity().x != 0 && !player.swim && !player.isFlyMode()) {
278 player.swim = true;
280 if (!player.swim) {
281 if (!player.isFlyMode() && player.getVelocity().y < 32f) {
282 player.getVelocity().y += gravity.y * delta;
284 if (!player.isFlyMode() && player.getVelocity().y > 32f) {
285 player.getVelocity().y -= player.getVelocity().y * 32f * delta;
287 } else {
288 player.getVelocity().y += PL_JUMP_VELOCITY * delta;
289 if (player.getVelocity().y < -player.getSpeed()) {
290 player.getVelocity().y = -player.getSpeed();
293 } else {
294 if (!player.isFlyMode() && player.getVelocity().y < PL_TERMINAL_VELOCITY) {
295 player.getVelocity().y += gravity.y * delta;
299 player.y += player.getVelocity().y * delta;
300 mobYColl(player);
302 player.x += player.getVelocity().x * (player.isFlyMode() ? 1.5f : 1) *
303 (getBlock(player).isFluid() && !player.isFlyMode() ? .8f : 1) * delta;
305 mobXColl(player);
307 if (mMainConfig.isTouch() && !player.isFlyMode() && player.canJump() && player.getVelocity().x != 0 && checkJump(player)) {
308 player.jump();
309 player.setCanJump(false);
313 private void mobPhy(Mob mob, float delta) {
314 if (mob.getType() == Mob.Type.MOB && getBlock(mob).isFluid()) {
315 if (mob.getVelocity().y > 32f) {
316 mob.getVelocity().y -= mob.getVelocity().y * 32f * delta;
319 mob.getVelocity().y += PL_JUMP_VELOCITY * delta;
321 if (mob.getVelocity().y < -mob.getSpeed()) {
322 mob.getVelocity().y = -mob.getSpeed();
324 } else if (!mob.isFlyMode() && mob.getVelocity().y < PL_TERMINAL_VELOCITY) {
325 mob.getVelocity().y += gravity.y * delta;
328 mob.y += mob.getVelocity().y * delta;
329 mobYColl(mob);
331 if (mob.isDead()) {
332 return;
335 mob.x += mob.getVelocity().x * delta;
336 mobXColl(mob);
338 if (mob.canJump() && mob.getVelocity().x != 0 && checkJump(mob)) {
339 mob.jump();
340 mob.setCanJump(false);
344 void update(float delta) {
345 Player player = mMobsController.getPlayer();
347 for (Iterator<Drop> it = mDropController.getIterator(); it.hasNext(); ) {
348 Drop drop = it.next();
349 dropPhy(drop, delta);
350 if (drop.getPickedUp()) {
351 it.remove();
355 for (Iterator<Mob> it = mMobsController.getMobs().iterator(); it.hasNext(); ) {
356 Mob mob = it.next();
357 mob.ai(mGameWorld, mGameItemsHolder, delta);
358 mobPhy(mob, delta);
359 if (mob.isDead()) {
360 it.remove();
364 playerPhy(player, delta);
365 player.ai(mGameWorld, mGameItemsHolder, delta);
366 if (player.isDead()) {
367 player.respawn(mGameWorld, mGameItemsHolder);