DEADSOFTWARE

Update README
[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;
11 import ru.deadsoftware.cavedroid.game.model.block.Block;
12 import ru.deadsoftware.cavedroid.game.objects.Drop;
13 import ru.deadsoftware.cavedroid.game.objects.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()))) {
60 return false;
61 }
63 return (block.toJump() &&
64 (mob.getY() + mob.getHeight()) - block.getRectangle(blX / 16, blY / 16).y > 8);
65 }
67 private boolean checkColl(Rectangle rect) {
68 int minX = (int) ((rect.x + rect.width / 2) / 16) - 4;
69 int minY = (int) ((rect.y + rect.height / 2) / 16) - 4;
70 int maxX = (int) ((rect.x + rect.width / 2) / 16) + 4;
71 int maxY = (int) ((rect.y + rect.height / 2) / 16) + 4;
73 if (minY < 0) {
74 minY = 0;
75 }
77 if (maxY > mGameWorld.getHeight()) {
78 maxY = mGameWorld.getHeight();
79 }
81 Block block;
82 for (int y = minY; y < maxY; y++) {
83 for (int x = minX; x < maxX; x++) {
84 if (!mGameWorld.hasForeAt(x, y)) {
85 continue;
86 }
87 block = mGameWorld.getForeMap(x, y);
88 if (block.hasCollision()) {
89 if (Intersector.overlaps(rect, block.getRectangle(x, y))) {
90 return true;
91 }
92 }
93 }
94 }
96 return false;
97 }
99 private Block getBlock(Rectangle rect) {
100 return mGameWorld.getForeMap((int) (rect.x + rect.width / 2) / 16,
101 (int) (rect.y + rect.height / 8 * 7) / 16);
104 private Rectangle getShiftedPlayerRect(float shift) {
105 final Player player = mMobsController.getPlayer();
106 return new Rectangle(player.x + shift, player.y, player.width, player.height);
109 /**
110 * @return Rectangle representing magneting target for this drop
111 */
112 @CheckForNull
113 private Rectangle getShiftedMagnetingPlayerRect(Drop drop) {
114 final Player player = mMobsController.getPlayer();
116 if (drop.canMagnetTo(player)) {
117 return getShiftedPlayerRect(0);
120 final Rectangle shiftedLeft = getShiftedPlayerRect(-mGameWorld.getWidthPx());
121 if (drop.canMagnetTo(shiftedLeft)) {
122 return shiftedLeft;
125 final Rectangle shiftedRight = getShiftedPlayerRect(mGameWorld.getWidthPx());
126 if (drop.canMagnetTo(shiftedRight)) {
127 return shiftedRight;
130 return null;
133 private void pickUpDropIfPossible(Rectangle shiftedPlayerTarget, Drop drop) {
134 final Player player = mMobsController.getPlayer();
136 if (Intersector.overlaps(shiftedPlayerTarget, drop)) {
137 player.pickUpDrop(drop);
141 private void dropPhy(Drop drop, float delta) {
142 final Rectangle playerMagnetTarget = getShiftedMagnetingPlayerRect(drop);
143 final Vector2 dropVelocity = drop.getVelocity();
146 if (playerMagnetTarget != null) {
147 final Vector2 magnetVector = new Vector2(playerMagnetTarget.x - drop.x,
148 playerMagnetTarget.y - drop.y);
149 magnetVector.nor().scl(Drop.MAGNET_VELOCITY * delta);
150 dropVelocity.add(magnetVector);
151 } else {
152 dropVelocity.y += gravity.y * delta;
155 dropVelocity.x = MathUtils.clamp(dropVelocity.x, -Drop.MAGNET_VELOCITY, Drop.MAGNET_VELOCITY);
156 dropVelocity.y = MathUtils.clamp(dropVelocity.y, -Drop.MAGNET_VELOCITY, Drop.MAGNET_VELOCITY);
158 drop.x += dropVelocity.x * delta;
159 drop.y += dropVelocity.y * delta;
161 if (checkColl(drop)) {
162 dropVelocity.setZero();
163 do {
164 drop.y--;
165 } while (checkColl(drop));
168 if (playerMagnetTarget != null) {
169 pickUpDropIfPossible(playerMagnetTarget, drop);
173 private void mobXColl(Mob mob) {
174 if (checkColl(mob)) {
175 if (mob.canJump() && !mob.isFlyMode()) {
176 mob.y -= 8;
179 if (checkColl(mob)) {
180 if (mob.canJump() && !mob.isFlyMode()) {
181 mob.y += 8;
184 int d = 0;
186 if (mob.getVelocity().x < 0) {
187 d = 1;
188 } else if (mob.getVelocity().x > 0) {
189 d = -1;
192 mob.x = MathUtils.round(mob.getX());
194 while (checkColl(mob)) {
195 mob.x += d;
198 if (mob.canJump()) {
199 mob.changeDir();
204 mob.checkWorldBounds(mGameWorld);
207 private void mobYColl(Mob mob) {
208 if (checkColl(mob)) {
209 int d = -1;
211 if (mob.getVelocity().y < 0) {
212 d = 1;
215 if (d == -1) {
216 mob.setCanJump(true);
217 mob.setFlyMode(false);
219 int dmg = ((int)Math.max(0f, (((mob.getVelocity().y * mob.getVelocity().y) / (2 * gravity.y)) - 48f) / 16f));
220 if (dmg > 0) {
221 mob.damage(dmg);
225 mob.y = MathUtils.round(mob.getY());
227 while (checkColl(mob)) {
228 mob.y += d;
231 mob.getVelocity().y = 0;
233 } else {
234 mob.y += 1;
235 mob.setCanJump(checkColl(mob));
236 mob.y -= 1;
239 if (mob.getY() > mGameWorld.getHeightPx()) {
240 mob.kill();
244 private void playerPhy(Player player, float delta) {
245 if (player.isDead()) {
246 return;
249 if (getBlock(player).isFluid()) {
250 if (mMainConfig.isTouch() && player.getVelocity().x != 0 && !player.swim && !player.isFlyMode()) {
251 player.swim = true;
253 if (!player.swim) {
254 if (!player.isFlyMode() && player.getVelocity().y < 32f) {
255 player.getVelocity().y += gravity.y * delta;
257 if (!player.isFlyMode() && player.getVelocity().y > 32f) {
258 player.getVelocity().y -= player.getVelocity().y * 32f * delta;
260 } else {
261 player.getVelocity().y += PL_JUMP_VELOCITY * delta;
262 if (player.getVelocity().y < -player.getSpeed()) {
263 player.getVelocity().y = -player.getSpeed();
266 } else {
267 if (!player.isFlyMode() && player.getVelocity().y < PL_TERMINAL_VELOCITY) {
268 player.getVelocity().y += gravity.y * delta;
272 player.y += player.getVelocity().y * delta;
273 mobYColl(player);
275 player.x += player.getVelocity().x * (player.isFlyMode() ? 1.5f : 1) *
276 (getBlock(player).isFluid() && !player.isFlyMode() ? .8f : 1) * delta;
278 mobXColl(player);
280 if (mMainConfig.isTouch() && !player.isFlyMode() && player.canJump() && player.getVelocity().x != 0 && checkJump(player)) {
281 player.jump();
282 player.setCanJump(false);
286 private void mobPhy(Mob mob, float delta) {
287 if (mob.getType() == Mob.Type.MOB && getBlock(mob).isFluid()) {
288 if (mob.getVelocity().y > 32f) {
289 mob.getVelocity().y -= mob.getVelocity().y * 32f * delta;
292 mob.getVelocity().y += PL_JUMP_VELOCITY * delta;
294 if (mob.getVelocity().y < -mob.getSpeed()) {
295 mob.getVelocity().y = -mob.getSpeed();
297 } else if (!mob.isFlyMode() && mob.getVelocity().y < PL_TERMINAL_VELOCITY) {
298 mob.getVelocity().y += gravity.y * delta;
301 mob.y += mob.getVelocity().y * delta;
302 mobYColl(mob);
304 if (mob.isDead()) {
305 return;
308 mob.x += mob.getVelocity().x * delta;
309 mobXColl(mob);
311 if (mob.canJump() && mob.getVelocity().x != 0 && checkJump(mob)) {
312 mob.jump();
313 mob.setCanJump(false);
317 void update(float delta) {
318 Player player = mMobsController.getPlayer();
320 for (Iterator<Drop> it = mDropController.getIterator(); it.hasNext(); ) {
321 Drop drop = it.next();
322 dropPhy(drop, delta);
323 if (drop.getPickedUp()) {
324 it.remove();
328 for (Iterator<Mob> it = mMobsController.getMobs().iterator(); it.hasNext(); ) {
329 Mob mob = it.next();
330 mob.ai(mGameWorld, mGameItemsHolder, delta);
331 mobPhy(mob, delta);
332 if (mob.isDead()) {
333 it.remove();
337 playerPhy(player, delta);
338 player.ai(mGameWorld, mGameItemsHolder, delta);
339 if (player.isDead()) {
340 player.respawn(mGameWorld, mGameItemsHolder);