DEADSOFTWARE

Add player head rotation
[cavedroid.git] / core / src / ru / deadsoftware / cavedroid / game / GameInput.java
1 package ru.deadsoftware.cavedroid.game;
3 import com.badlogic.gdx.Gdx;
4 import com.badlogic.gdx.Input;
5 import com.badlogic.gdx.graphics.g2d.TextureRegion;
6 import com.badlogic.gdx.math.MathUtils;
7 import com.badlogic.gdx.utils.TimeUtils;
8 import com.google.common.collect.Range;
9 import ru.deadsoftware.cavedroid.MainConfig;
10 import ru.deadsoftware.cavedroid.game.mobs.Mob;
11 import ru.deadsoftware.cavedroid.game.mobs.MobsController;
12 import ru.deadsoftware.cavedroid.game.mobs.Pig;
13 import ru.deadsoftware.cavedroid.game.mobs.Player;
14 import ru.deadsoftware.cavedroid.game.objects.DropController;
15 import ru.deadsoftware.cavedroid.game.world.GameWorld;
16 import ru.deadsoftware.cavedroid.misc.Assets;
17 import ru.deadsoftware.cavedroid.misc.ControlMode;
19 import javax.inject.Inject;
21 import static ru.deadsoftware.cavedroid.game.GameItems.*;
23 @GameScope
24 public class GameInput {
26 private final MainConfig mMainConfig;
27 private final GameWorld mGameWorld;
28 private final DropController mDropController;
29 private final MobsController mMobsController;
30 private final Player mPlayer;
32 private ControlMode mControlMode;
34 private boolean mKeyDown;
35 private boolean mTouchedDown;
36 private boolean mDragging;
38 private int mKeyDownCode;
39 private int mTouchDownBtn;
40 private float mTouchDownX;
41 private float mTouchDownY;
42 private long mTouchDownTime;
44 private int mCurX;
45 private int mCurY;
46 private int mCreativeScroll;
47 private int mBlockDamage;
49 @Inject
50 public GameInput(MainConfig mainConfig,
51 GameWorld gameWorld,
52 DropController dropController,
53 MobsController mobsController) {
54 mMainConfig = mainConfig;
55 mGameWorld = gameWorld;
56 mDropController = dropController;
57 mMobsController = mobsController;
59 mPlayer = mMobsController.getPlayer();
61 mControlMode = mMainConfig.isTouch() ? ControlMode.WALK : ControlMode.CURSOR;
62 }
64 private boolean checkSwim() {
65 return GameItems.isFluid(mGameWorld.getForeMap(mPlayer.getMapX(), mPlayer.getLowerMapY()));
66 }
68 private void goUpwards() {
69 if (checkSwim()) {
70 mPlayer.swim = true;
71 } else if (mPlayer.canJump()) {
72 mPlayer.getVelocity().add(0, GamePhysics.PL_JUMP_VELOCITY);
73 } else if (!mPlayer.isFlyMode() && mPlayer.gameMode == 1) {
74 mPlayer.setFlyMode(true);
75 mPlayer.getVelocity().y = 0;
76 } else if (mPlayer.isFlyMode()) {
77 mPlayer.getVelocity().y = -GamePhysics.PL_SPEED;
78 }
79 }
81 @SuppressWarnings("IntegerDivisionInFloatingPointContext")
82 private boolean insideCreativeInv(float screenX, float screenY) {
83 TextureRegion creative = Assets.textureRegions.get("creative");
84 return (screenX > mMainConfig.getWidth() / 2 - creative.getRegionWidth() / 2 &&
85 screenX < mMainConfig.getWidth() / 2 + creative.getRegionWidth() / 2 &&
86 screenY > mMainConfig.getHeight() / 2 - creative.getRegionHeight() / 2 &&
87 screenY < mMainConfig.getHeight() / 2 + creative.getRegionHeight() / 2);
88 }
90 private void wasdPressed(int keycode) {
91 if (mControlMode == ControlMode.WALK || !mMainConfig.isTouch()) {
92 switch (keycode) {
93 case Input.Keys.A:
94 mPlayer.getVelocity().x = -GamePhysics.PL_SPEED;
95 mPlayer.setDir(Mob.Direction.LEFT);
96 if (mMainConfig.isTouch() && checkSwim()) {
97 mPlayer.swim = true;
98 }
99 break;
100 case Input.Keys.D:
101 mPlayer.getVelocity().x = GamePhysics.PL_SPEED;
102 mPlayer.setDir(Mob.Direction.RIGHT);
103 if (mMainConfig.isTouch() && checkSwim()) {
104 mPlayer.swim = true;
106 break;
107 case Input.Keys.W:
108 case Input.Keys.SPACE:
109 goUpwards();
110 break;
111 case Input.Keys.S:
112 case Input.Keys.CONTROL_LEFT:
113 mPlayer.getVelocity().y = GamePhysics.PL_SPEED;
114 break;
116 } else {
117 switch (keycode) {
118 case Input.Keys.A:
119 mCurX--;
120 break;
121 case Input.Keys.D:
122 mCurX++;
123 break;
124 case Input.Keys.W:
125 mCurY--;
126 break;
127 case Input.Keys.S:
128 mCurY++;
129 break;
131 mBlockDamage = 0;
135 private boolean isNotAutoselectable(int x, int y) {
136 return (!mGameWorld.hasForeAt(x, y) || !mGameWorld.getForeMapBlock(x, y).hasCollision());
139 private void checkCursorBounds() {
140 if (mCurY < 0) {
141 mCurY = 0;
142 } else if (mCurY >= mGameWorld.getHeight()) {
143 mCurY = mGameWorld.getHeight() - 1;
146 if (mControlMode == ControlMode.CURSOR) {
147 if (mCurX * 16 + 8 < mPlayer.getX() + mPlayer.getWidth() / 2) {
148 mPlayer.setDir(Mob.Direction.LEFT);
149 } else {
150 mPlayer.setDir(Mob.Direction.RIGHT);
155 public void moveCursor(GameRenderer gameRenderer) {
156 int pastX = mCurX;
157 int pastY = mCurY;
159 if (mControlMode == ControlMode.WALK && mMainConfig.isTouch()) {
160 mCurX = mPlayer.getMapX() + (mPlayer.looksLeft() ? -1 : 1);
161 mCurY = mPlayer.getUpperMapY();
162 for (int i = 0; i < 2 && isNotAutoselectable(mCurX, mCurY); i++) {
163 mCurY++;
165 if (isNotAutoselectable(mCurX, mCurY)) {
166 mCurX += mPlayer.looksLeft() ? 1 : -1;
168 } else if (!mMainConfig.isTouch()) {
169 final int tmpX = (int) (Gdx.input.getX() * (mMainConfig.getWidth() /
170 Gdx.graphics.getWidth()) + gameRenderer.getCamX());
171 mCurX = tmpX / 16;
173 final int tmpY = (int) (Gdx.input.getY() * (mMainConfig.getHeight() /
174 Gdx.graphics.getHeight()) + gameRenderer.getCamY());
175 mCurY = tmpY / 16;
177 if (tmpX < 0) {
178 mCurX--;
181 final double a = tmpX - mPlayer.x;
182 final double b = tmpY - mPlayer.y;
184 mPlayer.headRotation = (float) Math.atan(b / a) * MathUtils.radDeg;
187 if (pastX != mCurX || pastY != mCurY) {
188 mBlockDamage = 0;
191 checkCursorBounds();
194 private void useItem(int x, int y, int id, boolean bg) {
195 String key = getItem(id).isBlock() ? getBlockKey(id) : getItemKey(id);
196 if (id > 0) {
197 if (getItem(id).isBlock()) {
198 if (!bg) {
199 mGameWorld.placeToForeground(x, y, getBlockIdByItemId(id));
200 } else {
201 mGameWorld.placeToBackground(x, y, getBlockIdByItemId(id));
203 } else {
204 switch (key) {
205 case "bucket_water":
206 mGameWorld.placeToForeground(x, y, getBlockId("water"));
207 mPlayer.inventory[mPlayer.slot] = getItemId("bucket_empty");
208 break;
209 case "bucket_lava":
210 mGameWorld.placeToForeground(x, y, getBlockId("lava"));
211 mPlayer.inventory[mPlayer.slot] = getItemId("bucket_empty");
212 break;
218 private void pressLMB() {
219 if (mMainConfig.checkGameUiWindow(GameUiWindow.NONE) &&
220 ((mGameWorld.hasForeAt(mCurX, mCurY) && mGameWorld.getForeMapBlock(mCurX, mCurY).getHp() >= 0) ||
221 (!mGameWorld.hasForeAt(mCurX, mCurY) && mGameWorld.hasBackAt(mCurX, mCurY) &&
222 mGameWorld.getBackMapBlock(mCurX, mCurY).getHp() >= 0))) {
223 if (mPlayer.gameMode == 0) {
224 mBlockDamage++;
225 if (mGameWorld.hasForeAt(mCurX, mCurY)) {
226 if (mBlockDamage >= mGameWorld.getForeMapBlock(mCurX, mCurY).getHp()) {
227 mGameWorld.destroyForeMap(mCurX, mCurY);
228 mBlockDamage = 0;
230 } else if (mGameWorld.hasBackAt(mCurX, mCurY)) {
231 if (mBlockDamage >= mGameWorld.getBackMapBlock(mCurX, mCurY).getHp()) {
232 mGameWorld.destroyBackMap(mCurX, mCurY);
233 mBlockDamage = 0;
236 } else {
237 if (mGameWorld.hasForeAt(mCurX, mCurY)) {
238 mGameWorld.placeToForeground(mCurX, mCurY, 0);
239 } else if (mGameWorld.hasBackAt(mCurX, mCurY)) {
240 mGameWorld.placeToBackground(mCurX, mCurY, 0);
242 mTouchedDown = false;
247 private boolean insideHotbar(float x, float y) {
248 TextureRegion hotbar = Assets.textureRegions.get("hotbar");
249 return y < hotbar.getRegionHeight() &&
250 Range.open(mMainConfig.getWidth() / 2 - (float) hotbar.getRegionWidth() / 2,
251 mMainConfig.getWidth() / 2 + (float) hotbar.getRegionWidth() / 2).contains(x);
254 private void holdMB() {
255 if (mTouchDownBtn == Input.Buttons.RIGHT) {
256 useItem(mCurX, mCurY, mPlayer.inventory[mPlayer.slot], true);
257 mTouchedDown = false;
258 } else {
259 if (insideHotbar(mTouchDownX, mTouchDownY)) {
260 mMainConfig.setGameUiWindow(GameUiWindow.CREATIVE_INVENTORY);
261 mTouchedDown = false;
266 public void keyDown(int keycode) {
267 mKeyDown = true;
268 mKeyDownCode = keycode;
269 switch (keycode) {
270 case Input.Keys.A:
271 case Input.Keys.D:
272 case Input.Keys.W:
273 case Input.Keys.S:
274 case Input.Keys.SPACE:
275 case Input.Keys.CONTROL_LEFT:
276 wasdPressed(keycode);
277 break;
279 case Input.Keys.ALT_LEFT:
280 if (mMainConfig.isTouch()) {
281 mControlMode = mControlMode == ControlMode.WALK ? ControlMode.CURSOR : ControlMode.WALK;
283 break;
285 case Input.Keys.E:
286 if (mMainConfig.checkGameUiWindow(GameUiWindow.NONE)) {
287 switch (mPlayer.gameMode) {
288 case 0:
289 //TODO survival inv
290 break;
291 case 1:
292 mMainConfig.setGameUiWindow(GameUiWindow.CREATIVE_INVENTORY);
293 break;
295 } else {
296 mMainConfig.setGameUiWindow(GameUiWindow.NONE);
298 break;
300 case Input.Keys.G:
301 mMobsController.addMob(Pig.class, mCurX * 16, mCurY * 16);
302 break;
304 case Input.Keys.Q:
305 mGameWorld.placeToForeground(mCurX, mCurY, 8);
306 break;
308 case Input.Keys.ESCAPE:
309 case Input.Keys.BACK:
310 GameSaver.save(mMainConfig, mDropController, mMobsController, mGameWorld);
311 mMainConfig.getCaveGame().quitGame();
312 break;
314 case Input.Keys.F1:
315 mMainConfig.setShowInfo(!mMainConfig.isShowInfo());
316 break;
318 case Input.Keys.M:
319 mMainConfig.setShowMap(!mMainConfig.isShowMap());
320 break;
324 public void keyUp(int keycode) {
325 switch (keycode) {
326 case Input.Keys.A:
327 case Input.Keys.D:
328 mPlayer.getVelocity().x = 0;
329 if (mMainConfig.isTouch() && mPlayer.swim) {
330 mPlayer.swim = false;
332 break;
334 case Input.Keys.W:
335 case Input.Keys.S:
336 case Input.Keys.SPACE:
337 case Input.Keys.CONTROL_LEFT:
338 if (mPlayer.isFlyMode()) {
339 mPlayer.getVelocity().y = 0;
341 if (mPlayer.swim) {
342 mPlayer.swim = false;
344 break;
348 public void touchDown(float touchX, float touchY, int button) {
349 mTouchDownTime = TimeUtils.millis();
350 mTouchedDown = true;
351 mTouchDownBtn = button;
352 mTouchDownX = touchX;
353 mTouchDownY = touchY;
356 public void touchUp(float screenX, float screenY, int button) {
357 if (mDragging) {
358 mDragging = false;
359 return;
362 if (mMainConfig.isTouch() && mKeyDown) {
363 keyUp(mKeyDownCode);
364 mKeyDown = false;
366 TextureRegion hotbar = Assets.textureRegions.get("hotbar");
367 TextureRegion creative = Assets.textureRegions.get("creative");
368 if (mTouchedDown) {
369 if (mMainConfig.checkGameUiWindow(GameUiWindow.CREATIVE_INVENTORY) && insideCreativeInv(screenX, screenY)) {
370 int ix = (int) (screenX - (mMainConfig.getWidth() / 2 - creative.getRegionWidth() / 2 + 8)) / 18;
371 int iy = (int) (screenY - (mMainConfig.getHeight() / 2 - creative.getRegionHeight() / 2 + 18)) / 18;
372 int item = mCreativeScroll * 8 + (ix + iy * 8);
373 if (ix >= 8 || ix < 0 || iy < 0 || iy >= 5) {
374 item = -1;
376 if (item >= 0 && item < GameItems.getItemsSize()) {
377 System.arraycopy(mPlayer.inventory, 0, mPlayer.inventory, 1, 8);
378 mPlayer.inventory[0] = item;
380 } else if (mMainConfig.checkGameUiWindow(GameUiWindow.CREATIVE_INVENTORY)) {
381 mMainConfig.setGameUiWindow(GameUiWindow.NONE);
382 } else if (screenY < hotbar.getRegionHeight() &&
383 screenX > mMainConfig.getWidth() / 2 - (float) hotbar.getRegionWidth() / 2 &&
384 screenX < mMainConfig.getWidth() / 2 + (float) hotbar.getRegionWidth() / 2) {
385 mPlayer.slot = (int) ((screenX - (mMainConfig.getWidth() / 2 - hotbar.getRegionWidth() / 2)) / 20);
386 } else if (button == Input.Buttons.RIGHT) {
387 useItem(mCurX, mCurY,
388 mPlayer.inventory[mPlayer.slot], false);
389 } else if (button == Input.Buttons.LEFT) {
390 mBlockDamage = 0;
393 mTouchedDown = false;
396 public void touchDragged(float screenX, float screenY) {
397 if (Math.abs(screenX - mTouchDownX) < 16 && Math.abs(screenY - mTouchDownY) < 16) {
398 return;
401 mDragging = true;
402 if (mMainConfig.checkGameUiWindow(GameUiWindow.CREATIVE_INVENTORY) && Math.abs(screenY - mTouchDownY) > 16) {
403 if (insideCreativeInv(screenX, screenY)) {
404 mCreativeScroll -= (screenY - mTouchDownY) / 16;
405 mTouchDownX = screenX;
406 mTouchDownY = screenY;
407 if (mCreativeScroll < 0) {
408 mCreativeScroll = 0;
410 if (mCreativeScroll > GameProc.MAX_CREATIVE_SCROLL) {
411 mCreativeScroll = GameProc.MAX_CREATIVE_SCROLL;
417 public void scrolled(float amountX, float amountY) {
418 switch (mMainConfig.getGameUiWindow()) {
419 case NONE:
420 mPlayer.slot += (int) amountY;
421 if (mPlayer.slot < 0) {
422 mPlayer.slot = 8;
424 if (mPlayer.slot > 8) {
425 mPlayer.slot = 0;
427 break;
428 case CREATIVE_INVENTORY:
429 mCreativeScroll += (int) amountY;
430 if (mCreativeScroll < 0) {
431 mCreativeScroll = 0;
433 if (mCreativeScroll > GameProc.MAX_CREATIVE_SCROLL) {
434 mCreativeScroll = GameProc.MAX_CREATIVE_SCROLL;
436 break;
440 public int getKeyDownCode() {
441 return mKeyDownCode;
444 public boolean isKeyDown() {
445 return mKeyDown;
448 int getBlockDamage() {
449 return mBlockDamage;
452 int getCurX() {
453 return mCurX;
456 int getCurY() {
457 return mCurY;
460 int getCreativeScroll() {
461 return mCreativeScroll;
464 public ControlMode getControlMode() {
465 return mControlMode;
468 public void setControlMode(ControlMode controlMode) {
469 mControlMode = controlMode;
472 void update() {
473 if (mTouchedDown && mTouchDownBtn == Input.Buttons.LEFT) {
474 pressLMB();
476 if (mTouchedDown && TimeUtils.timeSinceMillis(mTouchDownTime) > 500) {
477 holdMB();