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
.Intersector
;
7 import com
.badlogic
.gdx
.math
.MathUtils
;
8 import com
.badlogic
.gdx
.utils
.TimeUtils
;
9 import com
.google
.common
.collect
.Range
;
10 import ru
.deadsoftware
.cavedroid
.MainConfig
;
11 import ru
.deadsoftware
.cavedroid
.game
.actions
.CommonBlockActionUtilsKt
;
12 import ru
.deadsoftware
.cavedroid
.game
.actions
.placeblock
.IPlaceBlockAction
;
13 import ru
.deadsoftware
.cavedroid
.game
.actions
.useitem
.IUseItemAction
;
14 import ru
.deadsoftware
.cavedroid
.game
.mobs
.Mob
;
15 import ru
.deadsoftware
.cavedroid
.game
.mobs
.MobsController
;
16 import ru
.deadsoftware
.cavedroid
.game
.mobs
.Pig
;
17 import ru
.deadsoftware
.cavedroid
.game
.mobs
.Player
;
18 import ru
.deadsoftware
.cavedroid
.game
.model
.item
.Item
;
19 import ru
.deadsoftware
.cavedroid
.game
.objects
.DropController
;
20 import ru
.deadsoftware
.cavedroid
.game
.world
.GameWorld
;
21 import ru
.deadsoftware
.cavedroid
.misc
.Assets
;
22 import ru
.deadsoftware
.cavedroid
.misc
.ControlMode
;
24 import javax
.annotation
.CheckForNull
;
25 import javax
.inject
.Inject
;
29 import static ru
.deadsoftware
.cavedroid
.game
.GameItems
.*;
32 public class GameInput
{
34 private static final String TAG
= "GameInput";
36 private final MainConfig mMainConfig
;
37 private final GameWorld mGameWorld
;
38 private final DropController mDropController
;
39 private final MobsController mMobsController
;
40 private final Map
<String
, IUseItemAction
> mUseItemActionMap
;
41 private final Map
<String
, IPlaceBlockAction
> mPlaceBlockActionMap
;
43 private final Player mPlayer
;
45 private ControlMode mControlMode
;
47 private boolean mKeyDown
;
48 private boolean mTouchedDown
;
49 private boolean mDragging
;
51 private int mKeyDownCode
;
52 private int mTouchDownBtn
;
53 private float mTouchDownX
;
54 private float mTouchDownY
;
55 private long mTouchDownTime
;
59 private int mCreativeScroll
;
60 private int mBlockDamage
;
63 public GameInput(MainConfig mainConfig
,
65 DropController dropController
,
66 MobsController mobsController
,
67 Map
<String
, IUseItemAction
> useItemActionMap
,
68 Map
<String
, IPlaceBlockAction
> placeBlockActionMap
) {
69 mMainConfig
= mainConfig
;
70 mGameWorld
= gameWorld
;
71 mDropController
= dropController
;
72 mMobsController
= mobsController
;
73 mUseItemActionMap
= useItemActionMap
;
74 mPlaceBlockActionMap
= placeBlockActionMap
;
76 mPlayer
= mMobsController
.getPlayer();
78 mControlMode
= mMainConfig
.isTouch() ? ControlMode
.WALK
: ControlMode
.CURSOR
;
81 private boolean checkSwim() {
82 return GameItems
.isFluid(mGameWorld
.getForeMap(mPlayer
.getMapX(), mPlayer
.getLowerMapY()));
85 private void goUpwards() {
88 } else if (mPlayer
.canJump()) {
90 } else if (!mPlayer
.isFlyMode() && mPlayer
.gameMode
== 1) {
91 mPlayer
.setFlyMode(true);
92 mPlayer
.getVelocity().y
= 0;
93 } else if (mPlayer
.isFlyMode()) {
94 mPlayer
.getVelocity().y
= -mPlayer
.getSpeed();
98 @SuppressWarnings("IntegerDivisionInFloatingPointContext")
99 private boolean insideCreativeInv(float screenX
, float screenY
) {
100 TextureRegion creative
= Assets
.textureRegions
.get("creative");
101 return (screenX
> mMainConfig
.getWidth() / 2 - creative
.getRegionWidth() / 2 &&
102 screenX
< mMainConfig
.getWidth() / 2 + creative
.getRegionWidth() / 2 &&
103 screenY
> mMainConfig
.getHeight() / 2 - creative
.getRegionHeight() / 2 &&
104 screenY
< mMainConfig
.getHeight() / 2 + creative
.getRegionHeight() / 2);
107 private void wasdPressed(int keycode
) {
108 if (mControlMode
== ControlMode
.WALK
|| !mMainConfig
.isTouch()) {
111 mPlayer
.getVelocity().x
= -mPlayer
.getSpeed();
112 mPlayer
.setDir(Mob
.Direction
.LEFT
);
113 if (mMainConfig
.isTouch() && checkSwim()) {
118 mPlayer
.getVelocity().x
= mPlayer
.getSpeed();
119 mPlayer
.setDir(Mob
.Direction
.RIGHT
);
120 if (mMainConfig
.isTouch() && checkSwim()) {
125 case Input
.Keys
.SPACE
:
129 case Input
.Keys
.CONTROL_LEFT
:
130 mPlayer
.getVelocity().y
= mPlayer
.getSpeed();
152 private boolean isNotAutoselectable(int x
, int y
) {
153 return (!mGameWorld
.hasForeAt(x
, y
) || !mGameWorld
.getForeMapBlock(x
, y
).hasCollision());
156 private void checkCursorBounds() {
159 } else if (mCurY
>= mGameWorld
.getHeight()) {
160 mCurY
= mGameWorld
.getHeight() - 1;
163 if (mControlMode
== ControlMode
.CURSOR
) {
164 if (mCurX
* 16 + 8 < mPlayer
.getX() + mPlayer
.getWidth() / 2) {
165 mPlayer
.setDir(Mob
.Direction
.LEFT
);
167 mPlayer
.setDir(Mob
.Direction
.RIGHT
);
172 public void moveCursor(GameRenderer gameRenderer
) {
176 if (mControlMode
== ControlMode
.WALK
&& mMainConfig
.isTouch()) {
177 mCurX
= mPlayer
.getMapX() + (mPlayer
.looksLeft() ?
-1 : 1);
178 mCurY
= mPlayer
.getUpperMapY();
179 for (int i
= 0; i
< 2 && isNotAutoselectable(mCurX
, mCurY
); i
++) {
182 if (isNotAutoselectable(mCurX
, mCurY
)) {
183 mCurX
+= mPlayer
.looksLeft() ?
1 : -1;
185 } else if (!mMainConfig
.isTouch()) {
186 final int tmpX
= (int) (Gdx
.input
.getX() * (mMainConfig
.getWidth() /
187 Gdx
.graphics
.getWidth()) + gameRenderer
.getCamX());
190 final int tmpY
= (int) (Gdx
.input
.getY() * (mMainConfig
.getHeight() /
191 Gdx
.graphics
.getHeight()) + gameRenderer
.getCamY());
198 final double a
= tmpX
- mPlayer
.x
;
199 final double b
= tmpY
- mPlayer
.y
;
201 mPlayer
.headRotation
= (float) Math
.atan(b
/ a
) * MathUtils
.radDeg
;
204 if (pastX
!= mCurX
|| pastY
!= mCurY
) {
211 private void useItem(int x
, int y
, int id
, boolean bg
) {
212 mPlayer
.startHitting();
215 final Item item
= getItem(id
);
217 if (item
instanceof Item
.Placeable
) {
219 CommonBlockActionUtilsKt
.placeToForegroundAction(mPlaceBlockActionMap
, (Item
.Placeable
) item
, x
, y
);
221 CommonBlockActionUtilsKt
.placeToBackgroundAction(mPlaceBlockActionMap
, (Item
.Placeable
) item
, x
, y
);
223 } else if (item
instanceof Item
.Usable
) {
224 final String actionKey
= ((Item
.Usable
)item
).getUseActionKey();
225 final IUseItemAction useItemAction
= mUseItemActionMap
.get(actionKey
);
227 if (useItemAction
!= null) {
228 useItemAction
.perform((Item
.Usable
) item
, x
, y
);
230 Gdx
.app
.error(TAG
, "use item action " + actionKey
+ " not found");
236 private void hitMobs() {
237 final Player player
= mMobsController
.getPlayer();
238 mMobsController
.getMobs().forEach((mob
) -> {
239 if (Intersector
.overlaps(mob
, player
)) {
246 private void pressLMB() {
247 if (mMainConfig
.checkGameUiWindow(GameUiWindow
.NONE
)) {
248 mPlayer
.startHitting();
250 if ((mGameWorld
.hasForeAt(mCurX
, mCurY
) && mGameWorld
.getForeMapBlock(mCurX
, mCurY
).getHp() >= 0) ||
251 (!mGameWorld
.hasForeAt(mCurX
, mCurY
) && mGameWorld
.hasBackAt(mCurX
, mCurY
) &&
252 mGameWorld
.getBackMapBlock(mCurX
, mCurY
).getHp() >= 0)) {
253 if (mPlayer
.gameMode
== 0) {
255 if (mGameWorld
.hasForeAt(mCurX
, mCurY
)) {
256 if (mBlockDamage
>= mGameWorld
.getForeMapBlock(mCurX
, mCurY
).getHp()) {
257 mGameWorld
.destroyForeMap(mCurX
, mCurY
);
260 } else if (mGameWorld
.hasBackAt(mCurX
, mCurY
)) {
261 if (mBlockDamage
>= mGameWorld
.getBackMapBlock(mCurX
, mCurY
).getHp()) {
262 mGameWorld
.destroyBackMap(mCurX
, mCurY
);
267 if (mGameWorld
.hasForeAt(mCurX
, mCurY
)) {
268 mGameWorld
.placeToForeground(mCurX
, mCurY
, 0);
269 } else if (mGameWorld
.hasBackAt(mCurX
, mCurY
)) {
270 mGameWorld
.placeToBackground(mCurX
, mCurY
, 0);
272 mTouchedDown
= false;
276 mTouchedDown
= false;
281 private boolean insideHotbar(float x
, float y
) {
282 TextureRegion hotbar
= Assets
.textureRegions
.get("hotbar");
283 return y
< hotbar
.getRegionHeight() &&
284 Range
.open(mMainConfig
.getWidth() / 2 - (float) hotbar
.getRegionWidth() / 2,
285 mMainConfig
.getWidth() / 2 + (float) hotbar
.getRegionWidth() / 2).contains(x
);
288 private void holdMB() {
289 if (mTouchDownBtn
== Input
.Buttons
.RIGHT
) {
290 useItem(mCurX
, mCurY
, mPlayer
.inventory
[mPlayer
.slot
], true);
291 mTouchedDown
= false;
293 if (insideHotbar(mTouchDownX
, mTouchDownY
)) {
294 mMainConfig
.setGameUiWindow(GameUiWindow
.CREATIVE_INVENTORY
);
295 mTouchedDown
= false;
300 public void keyDown(int keycode
) {
302 mKeyDownCode
= keycode
;
308 case Input
.Keys
.SPACE
:
309 case Input
.Keys
.CONTROL_LEFT
:
310 wasdPressed(keycode
);
313 case Input
.Keys
.ALT_LEFT
:
314 if (mMainConfig
.isTouch()) {
315 mControlMode
= mControlMode
== ControlMode
.WALK ? ControlMode
.CURSOR
: ControlMode
.WALK
;
320 if (mMainConfig
.checkGameUiWindow(GameUiWindow
.NONE
)) {
321 switch (mPlayer
.gameMode
) {
326 mMainConfig
.setGameUiWindow(GameUiWindow
.CREATIVE_INVENTORY
);
330 mMainConfig
.setGameUiWindow(GameUiWindow
.NONE
);
335 final Mob pig
= new Pig(mCurX
* 16, mCurY
* 16);
336 pig
.attachToController(mMobsController
);
340 mGameWorld
.placeToForeground(mCurX
, mCurY
, 8);
343 case Input
.Keys
.GRAVE
:
344 mMobsController
.getPlayer().gameMode
= (mMobsController
.getPlayer().gameMode
+ 1) % 2;
347 case Input
.Keys
.ESCAPE
:
348 case Input
.Keys
.BACK
:
349 GameSaver
.save(mMainConfig
, mDropController
, mMobsController
, mGameWorld
);
350 mMainConfig
.getCaveGame().quitGame();
354 mMainConfig
.setShowInfo(!mMainConfig
.isShowInfo());
358 mMainConfig
.setShowMap(!mMainConfig
.isShowMap());
363 public void keyUp(int keycode
) {
367 mPlayer
.getVelocity().x
= 0;
368 if (mMainConfig
.isTouch() && mPlayer
.swim
) {
369 mPlayer
.swim
= false;
375 case Input
.Keys
.SPACE
:
376 case Input
.Keys
.CONTROL_LEFT
:
377 if (mPlayer
.isFlyMode()) {
378 mPlayer
.getVelocity().y
= 0;
381 mPlayer
.swim
= false;
387 public void touchDown(float touchX
, float touchY
, int button
) {
388 mTouchDownTime
= TimeUtils
.millis();
390 mTouchDownBtn
= button
;
391 mTouchDownX
= touchX
;
392 mTouchDownY
= touchY
;
395 public void touchUp(float screenX
, float screenY
, int button
) {
401 if (mMainConfig
.isTouch() && mKeyDown
) {
405 TextureRegion hotbar
= Assets
.textureRegions
.get("hotbar");
406 TextureRegion creative
= Assets
.textureRegions
.get("creative");
408 if (mMainConfig
.checkGameUiWindow(GameUiWindow
.CREATIVE_INVENTORY
) && insideCreativeInv(screenX
, screenY
)) {
409 int ix
= (int) (screenX
- (mMainConfig
.getWidth() / 2 - creative
.getRegionWidth() / 2 + 8)) / 18;
410 int iy
= (int) (screenY
- (mMainConfig
.getHeight() / 2 - creative
.getRegionHeight() / 2 + 18)) / 18;
411 int item
= mCreativeScroll
* 8 + (ix
+ iy
* 8);
412 if (ix
>= 8 || ix
< 0 || iy
< 0 || iy
>= 5) {
415 if (item
>= 0 && item
< GameItems
.getItemsSize()) {
416 System
.arraycopy(mPlayer
.inventory
, 0, mPlayer
.inventory
, 1, 8);
417 mPlayer
.inventory
[0] = item
;
419 } else if (mMainConfig
.checkGameUiWindow(GameUiWindow
.CREATIVE_INVENTORY
)) {
420 mMainConfig
.setGameUiWindow(GameUiWindow
.NONE
);
421 } else if (screenY
< hotbar
.getRegionHeight() &&
422 screenX
> mMainConfig
.getWidth() / 2 - (float) hotbar
.getRegionWidth() / 2 &&
423 screenX
< mMainConfig
.getWidth() / 2 + (float) hotbar
.getRegionWidth() / 2) {
424 mPlayer
.slot
= (int) ((screenX
- (mMainConfig
.getWidth() / 2 - hotbar
.getRegionWidth() / 2)) / 20);
425 } else if (button
== Input
.Buttons
.RIGHT
) {
426 useItem(mCurX
, mCurY
,
427 mPlayer
.inventory
[mPlayer
.slot
], false);
428 } else if (button
== Input
.Buttons
.LEFT
) {
432 mTouchedDown
= false;
435 public void touchDragged(float screenX
, float screenY
) {
436 if (Math
.abs(screenX
- mTouchDownX
) < 16 && Math
.abs(screenY
- mTouchDownY
) < 16) {
441 if (mMainConfig
.checkGameUiWindow(GameUiWindow
.CREATIVE_INVENTORY
) && Math
.abs(screenY
- mTouchDownY
) > 16) {
442 if (insideCreativeInv(screenX
, screenY
)) {
443 mCreativeScroll
-= (screenY
- mTouchDownY
) / 16;
444 mTouchDownX
= screenX
;
445 mTouchDownY
= screenY
;
446 if (mCreativeScroll
< 0) {
449 if (mCreativeScroll
> GameProc
.MAX_CREATIVE_SCROLL
) {
450 mCreativeScroll
= GameProc
.MAX_CREATIVE_SCROLL
;
456 public void scrolled(float amountX
, float amountY
) {
457 switch (mMainConfig
.getGameUiWindow()) {
459 mPlayer
.slot
+= (int) amountY
;
460 if (mPlayer
.slot
< 0) {
463 if (mPlayer
.slot
> 8) {
467 case CREATIVE_INVENTORY
:
468 mCreativeScroll
+= (int) amountY
;
469 if (mCreativeScroll
< 0) {
472 if (mCreativeScroll
> GameProc
.MAX_CREATIVE_SCROLL
) {
473 mCreativeScroll
= GameProc
.MAX_CREATIVE_SCROLL
;
479 public int getKeyDownCode() {
483 public boolean isKeyDown() {
487 int getBlockDamage() {
499 int getCreativeScroll() {
500 return mCreativeScroll
;
503 public ControlMode
getControlMode() {
507 public void setControlMode(ControlMode controlMode
) {
508 mControlMode
= controlMode
;
513 mPlayer
.stopHitting();
517 if (mTouchDownBtn
== Input
.Buttons
.LEFT
) {
521 if (mTouchedDown
&& TimeUtils
.timeSinceMillis(mTouchDownTime
) > 500) {