DEADSOFTWARE

cd900d873dc1398e6b41ea492be77a87feaca25a
[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.objects.Drop;
12 import ru.deadsoftware.cavedroid.game.objects.DropController;
13 import ru.deadsoftware.cavedroid.game.world.GameWorld;
15 import javax.annotation.CheckForNull;
16 import javax.inject.Inject;
17 import java.util.Iterator;
20 @GameScope
21 public class GamePhysics {
23 public static final float PL_SPEED = 69.072f;
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;
34 @Inject
35 public GamePhysics(GameWorld gameWorld,
36 MainConfig mainConfig,
37 MobsController mobsController,
38 DropController dropController) {
39 mGameWorld = gameWorld;
40 mMainConfig = mainConfig;
41 mMobsController = mobsController;
42 mDropController = dropController;
43 }
45 /**
46 * Checks if mob should jump
47 *
48 * @return true if mob should jump
49 */
50 private boolean checkJump(Mob mob) {
51 int dir = mob.looksLeft() ? 0 : 1;
52 int blX = (int) (mob.getX() + mob.getWidth() * dir - 8 + 16 * dir);
53 int blY = (int) (mob.getY() + mob.getHeight() - 8);
54 int block = mGameWorld.getForeMap(blX / 16, blY / 16);
56 if (checkColl(new Rectangle(blX, mob.getY() - 18, mob.getWidth(), mob.getHeight()))) {
57 block = 0;
58 }
60 return (block > 0 && GameItems.getBlock(block).toJump() &&
61 (mob.getY() + mob.getHeight()) - GameItems.getBlock(block).getRectangle(blX / 16, blY / 16).y > 8);
62 }
64 private boolean checkColl(Rectangle rect) {
65 int minX = (int) ((rect.x + rect.width / 2) / 16) - 4;
66 int minY = (int) ((rect.y + rect.height / 2) / 16) - 4;
67 int maxX = (int) ((rect.x + rect.width / 2) / 16) + 4;
68 int maxY = (int) ((rect.y + rect.height / 2) / 16) + 4;
70 if (minY < 0) {
71 minY = 0;
72 }
74 if (maxY > mGameWorld.getHeight()) {
75 maxY = mGameWorld.getHeight();
76 }
78 int block;
79 for (int y = minY; y < maxY; y++) {
80 for (int x = minX; x < maxX; x++) {
81 block = mGameWorld.getForeMap(x, y);
82 if (block > 0 && GameItems.getBlock(block).hasCollision()) {
83 if (Intersector.overlaps(rect, GameItems.getBlock(block).getRectangle(x, y))) {
84 return true;
85 }
86 }
87 }
88 }
90 return false;
91 }
93 private int getBlock(Rectangle rect) {
94 return mGameWorld.getForeMap((int) (rect.x + rect.width / 2) / 16,
95 (int) (rect.y + rect.height / 8 * 7) / 16);
96 }
98 private Rectangle getShiftedPlayerRect(float shift) {
99 final Player player = mMobsController.getPlayer();
100 return new Rectangle(player.x + shift, player.y, player.width, player.height);
103 /**
104 * @return Rectangle representing magneting target for this drop
105 */
106 @CheckForNull
107 private Rectangle getShiftedMagnetingPlayerRect(Drop drop) {
108 final Player player = mMobsController.getPlayer();
110 if (drop.canMagnetTo(player)) {
111 return getShiftedPlayerRect(0);
114 final Rectangle shiftedLeft = getShiftedPlayerRect(-mGameWorld.getWidthPx());
115 if (drop.canMagnetTo(shiftedLeft)) {
116 return shiftedLeft;
119 final Rectangle shiftedRight = getShiftedPlayerRect(mGameWorld.getWidthPx());
120 if (drop.canMagnetTo(shiftedRight)) {
121 return shiftedRight;
124 return null;
127 private void pickUpDropIfPossible(Rectangle shiftedPlayerTarget, Drop drop) {
128 final Player player = mMobsController.getPlayer();
130 if (Intersector.overlaps(shiftedPlayerTarget, drop)) {
131 player.pickUpDrop(drop);
135 private void dropPhy(Drop drop, float delta) {
136 final Rectangle playerMagnetTarget = getShiftedMagnetingPlayerRect(drop);
137 final Vector2 dropVelocity = drop.getVelocity();
140 if (playerMagnetTarget != null) {
141 final Vector2 magnetVector = new Vector2(playerMagnetTarget.x - drop.x,
142 playerMagnetTarget.y - drop.y);
143 magnetVector.nor().scl(Drop.MAGNET_VELOCITY * delta);
144 dropVelocity.add(magnetVector);
145 } else {
146 dropVelocity.y += gravity.y * delta;
149 dropVelocity.x = MathUtils.clamp(dropVelocity.x, -Drop.MAGNET_VELOCITY, Drop.MAGNET_VELOCITY);
150 dropVelocity.y = MathUtils.clamp(dropVelocity.y, -Drop.MAGNET_VELOCITY, Drop.MAGNET_VELOCITY);
152 drop.x += dropVelocity.x * delta;
153 drop.y += dropVelocity.y * delta;
155 if (checkColl(drop)) {
156 dropVelocity.setZero();
157 do {
158 drop.y--;
159 } while (checkColl(drop));
162 if (playerMagnetTarget != null) {
163 pickUpDropIfPossible(playerMagnetTarget, drop);
167 private void mobXColl(Mob mob) {
168 if (checkColl(mob)) {
169 if (mob.canJump() && !mob.isFlyMode()) {
170 mob.y -= 8;
173 if (checkColl(mob)) {
174 if (mob.canJump() && !mob.isFlyMode()) {
175 mob.y += 8;
178 int d = 0;
180 if (mob.getVelocity().x < 0) {
181 d = 1;
182 } else if (mob.getVelocity().x > 0) {
183 d = -1;
186 mob.x = MathUtils.round(mob.getX());
188 while (checkColl(mob)) {
189 mob.x += d;
192 if (mob.canJump()) {
193 mob.changeDir();
198 mob.checkWorldBounds(mGameWorld);
201 private void mobYColl(Mob mob) {
202 if (checkColl(mob)) {
203 int d = -1;
205 if (mob.getVelocity().y < 0) {
206 d = 1;
209 if (d == -1) {
210 mob.setCanJump(true);
211 mob.setFlyMode(false);
214 mob.y = MathUtils.round(mob.getY());
216 while (checkColl(mob)) {
217 mob.y += d;
220 mob.getVelocity().y = 0;
224 //todo fall damage
225 // h = (v^2) / 2g
226 // dmg = max(0, (h - 48) / 32) - half of blocks fallen starting from 3 blocks height
227 // int dmg = ((int)Math.max(0f, (((mob.getVelocity().y * mob.getVelocity().y) / (2 * gravity.y)) - 48f) / 16f));
228 // if (dmg > 0) System.out.println("Damage: " + dmg);
230 } else {
231 mob.y += 1;
232 mob.setCanJump(checkColl(mob));
233 mob.y -= 1;
236 if (mob.getY() > mGameWorld.getHeightPx()) {
237 mob.kill();
241 private void playerPhy(Player player, float delta) {
242 if (player.isDead()) {
243 return;
246 if (GameItems.isFluid(getBlock(player))) {
247 if (mMainConfig.isTouch() && player.getVelocity().x != 0 && !player.swim && !player.isFlyMode()) {
248 player.swim = true;
250 if (!player.swim) {
251 if (!player.isFlyMode() && player.getVelocity().y < 32f) {
252 player.getVelocity().y += gravity.y * delta;
254 if (!player.isFlyMode() && player.getVelocity().y > 32f) {
255 player.getVelocity().y -= player.getVelocity().y * 32f * delta;
257 } else {
258 player.getVelocity().y += PL_JUMP_VELOCITY * delta;
259 if (player.getVelocity().y < -PL_SPEED) {
260 player.getVelocity().y = -PL_SPEED;
263 } else {
264 if (!player.isFlyMode() && player.getVelocity().y < PL_TERMINAL_VELOCITY) {
265 player.getVelocity().y += gravity.y * delta;
269 player.y += player.getVelocity().y * delta;
270 mobYColl(player);
272 player.x += player.getVelocity().x * (player.isFlyMode() ? 1.5f : 1) *
273 (GameItems.isFluid(getBlock(player)) && !player.isFlyMode() ? .8f : 1) * delta;
275 mobXColl(player);
277 if (mMainConfig.isTouch() && !player.isFlyMode() && player.canJump() && player.getVelocity().x != 0 && checkJump(player)) {
278 player.getVelocity().y = PL_JUMP_VELOCITY;
279 player.setCanJump(false);
283 private void mobPhy(Mob mob, float delta) {
284 if (mob.getType() == Mob.Type.MOB && GameItems.isFluid(getBlock(mob))) {
285 if (mob.getVelocity().y > 32f) {
286 mob.getVelocity().y -= mob.getVelocity().y * 32f * delta;
289 mob.getVelocity().y += PL_JUMP_VELOCITY * delta;
291 if (mob.getVelocity().y < -PL_SPEED) {
292 mob.getVelocity().y = -PL_SPEED;
294 } else if (!mob.isFlyMode() && mob.getVelocity().y < PL_TERMINAL_VELOCITY) {
295 mob.getVelocity().y += gravity.y * delta;
298 mob.y += mob.getVelocity().y * delta;
299 mobYColl(mob);
301 if (mob.isDead()) {
302 return;
305 mob.x += mob.getVelocity().x * delta;
306 mobXColl(mob);
308 if (mob.canJump() && mob.getVelocity().x != 0 && checkJump(mob)) {
309 mob.getVelocity().y = PL_JUMP_VELOCITY;
310 mob.setCanJump(false);
314 void update(float delta) {
315 Player player = mMobsController.getPlayer();
317 for (Iterator<Drop> it = mDropController.getIterator(); it.hasNext(); ) {
318 Drop drop = it.next();
319 dropPhy(drop, delta);
320 if (drop.getPickedUp()) {
321 it.remove();
325 for (Iterator<Mob> it = mMobsController.getIterator(); it.hasNext(); ) {
326 Mob mob = it.next();
327 mob.ai(mGameWorld, delta);
328 mobPhy(mob, delta);
329 if (mob.isDead()) {
330 it.remove();
334 playerPhy(player, delta);
335 if (player.isDead()) {
336 player.respawn(mGameWorld);