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;
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 (!player.inventory.canPickItem(drop.getItem())) {
117 return null;
120 if (drop.canMagnetTo(player)) {
121 return getShiftedPlayerRect(0);
124 final Rectangle shiftedLeft = getShiftedPlayerRect(-mGameWorld.getWidthPx());
125 if (drop.canMagnetTo(shiftedLeft)) {
126 return shiftedLeft;
129 final Rectangle shiftedRight = getShiftedPlayerRect(mGameWorld.getWidthPx());
130 if (drop.canMagnetTo(shiftedRight)) {
131 return shiftedRight;
134 return null;
137 private void pickUpDropIfPossible(Rectangle shiftedPlayerTarget, Drop drop) {
138 final Player player = mMobsController.getPlayer();
140 if (Intersector.overlaps(shiftedPlayerTarget, drop)) {
141 player.inventory.pickDrop(drop);
145 private void dropPhy(Drop drop, float delta) {
146 final Rectangle playerMagnetTarget = getShiftedMagnetingPlayerRect(drop);
147 final Vector2 dropVelocity = drop.getVelocity();
150 if (playerMagnetTarget != null) {
151 final Vector2 magnetVector = new Vector2(playerMagnetTarget.x - drop.x,
152 playerMagnetTarget.y - drop.y);
153 magnetVector.nor().scl(Drop.MAGNET_VELOCITY * delta);
154 dropVelocity.add(magnetVector);
155 } else {
156 dropVelocity.y += gravity.y * delta;
159 dropVelocity.x = MathUtils.clamp(dropVelocity.x, -Drop.MAGNET_VELOCITY, Drop.MAGNET_VELOCITY);
160 dropVelocity.y = MathUtils.clamp(dropVelocity.y, -Drop.MAGNET_VELOCITY, Drop.MAGNET_VELOCITY);
162 drop.x += dropVelocity.x * delta;
163 drop.y += dropVelocity.y * delta;
165 if (checkColl(drop)) {
166 dropVelocity.setZero();
167 do {
168 drop.y--;
169 } while (checkColl(drop));
172 if (playerMagnetTarget != null) {
173 pickUpDropIfPossible(playerMagnetTarget, drop);
177 private void mobXColl(Mob mob) {
178 if (checkColl(mob)) {
179 if (mob.canJump() && !mob.isFlyMode()) {
180 mob.y -= 8;
183 if (checkColl(mob)) {
184 if (mob.canJump() && !mob.isFlyMode()) {
185 mob.y += 8;
188 int d = 0;
190 if (mob.getVelocity().x < 0) {
191 d = 1;
192 } else if (mob.getVelocity().x > 0) {
193 d = -1;
196 mob.x = MathUtils.round(mob.getX());
198 while (checkColl(mob)) {
199 mob.x += d;
202 if (mob.canJump()) {
203 mob.changeDir();
208 mob.checkWorldBounds(mGameWorld);
211 private void mobYColl(Mob mob) {
212 if (checkColl(mob)) {
213 int d = -1;
215 if (mob.getVelocity().y < 0) {
216 d = 1;
219 if (d == -1) {
220 mob.setCanJump(true);
221 mob.setFlyMode(false);
223 int dmg = ((int)Math.max(0f, (((mob.getVelocity().y * mob.getVelocity().y) / (2 * gravity.y)) - 48f) / 16f));
224 if (dmg > 0) {
225 mob.damage(dmg);
229 mob.y = MathUtils.round(mob.getY());
231 while (checkColl(mob)) {
232 mob.y += d;
235 mob.getVelocity().y = 0;
237 } else {
238 mob.y += 1;
239 mob.setCanJump(checkColl(mob));
240 mob.y -= 1;
243 if (mob.getY() > mGameWorld.getHeightPx()) {
244 mob.kill();
248 private void playerPhy(Player player, float delta) {
249 if (player.isDead()) {
250 return;
253 if (getBlock(player).isFluid()) {
254 if (mMainConfig.isTouch() && player.getVelocity().x != 0 && !player.swim && !player.isFlyMode()) {
255 player.swim = true;
257 if (!player.swim) {
258 if (!player.isFlyMode() && player.getVelocity().y < 32f) {
259 player.getVelocity().y += gravity.y * delta;
261 if (!player.isFlyMode() && player.getVelocity().y > 32f) {
262 player.getVelocity().y -= player.getVelocity().y * 32f * delta;
264 } else {
265 player.getVelocity().y += PL_JUMP_VELOCITY * delta;
266 if (player.getVelocity().y < -player.getSpeed()) {
267 player.getVelocity().y = -player.getSpeed();
270 } else {
271 if (!player.isFlyMode() && player.getVelocity().y < PL_TERMINAL_VELOCITY) {
272 player.getVelocity().y += gravity.y * delta;
276 player.y += player.getVelocity().y * delta;
277 mobYColl(player);
279 player.x += player.getVelocity().x * (player.isFlyMode() ? 1.5f : 1) *
280 (getBlock(player).isFluid() && !player.isFlyMode() ? .8f : 1) * delta;
282 mobXColl(player);
284 if (mMainConfig.isTouch() && !player.isFlyMode() && player.canJump() && player.getVelocity().x != 0 && checkJump(player)) {
285 player.jump();
286 player.setCanJump(false);
290 private void mobPhy(Mob mob, float delta) {
291 if (mob.getType() == Mob.Type.MOB && getBlock(mob).isFluid()) {
292 if (mob.getVelocity().y > 32f) {
293 mob.getVelocity().y -= mob.getVelocity().y * 32f * delta;
296 mob.getVelocity().y += PL_JUMP_VELOCITY * delta;
298 if (mob.getVelocity().y < -mob.getSpeed()) {
299 mob.getVelocity().y = -mob.getSpeed();
301 } else if (!mob.isFlyMode() && mob.getVelocity().y < PL_TERMINAL_VELOCITY) {
302 mob.getVelocity().y += gravity.y * delta;
305 mob.y += mob.getVelocity().y * delta;
306 mobYColl(mob);
308 if (mob.isDead()) {
309 return;
312 mob.x += mob.getVelocity().x * delta;
313 mobXColl(mob);
315 if (mob.canJump() && mob.getVelocity().x != 0 && checkJump(mob)) {
316 mob.jump();
317 mob.setCanJump(false);
321 void update(float delta) {
322 Player player = mMobsController.getPlayer();
324 for (Iterator<Drop> it = mDropController.getIterator(); it.hasNext(); ) {
325 Drop drop = it.next();
326 dropPhy(drop, delta);
327 if (drop.getPickedUp()) {
328 it.remove();
332 for (Iterator<Mob> it = mMobsController.getMobs().iterator(); it.hasNext(); ) {
333 Mob mob = it.next();
334 mob.ai(mGameWorld, mGameItemsHolder, delta);
335 mobPhy(mob, delta);
336 if (mob.isDead()) {
337 it.remove();
341 playerPhy(player, delta);
342 player.ai(mGameWorld, mGameItemsHolder, delta);
343 if (player.isDead()) {
344 player.respawn(mGameWorld, mGameItemsHolder);