1 package ru
.deadsoftware
.cavedroid
.game
;
3 import com
.badlogic
.gdx
.Gdx
;
4 import com
.badlogic
.gdx
.Input
;
5 import com
.badlogic
.gdx
.graphics
.Color
;
6 import com
.badlogic
.gdx
.graphics
.GL20
;
7 import com
.badlogic
.gdx
.math
.Rectangle
;
8 import com
.badlogic
.gdx
.math
.Vector2
;
9 import com
.badlogic
.gdx
.utils
.ObjectMap
;
10 import com
.badlogic
.gdx
.utils
.TimeUtils
;
11 import org
.jetbrains
.annotations
.Nullable
;
12 import ru
.deadsoftware
.cavedroid
.MainConfig
;
13 import ru
.deadsoftware
.cavedroid
.game
.input
.IKeyboardInputHandler
;
14 import ru
.deadsoftware
.cavedroid
.game
.input
.IMouseInputHandler
;
15 import ru
.deadsoftware
.cavedroid
.game
.input
.Joystick
;
16 import ru
.deadsoftware
.cavedroid
.game
.input
.action
.KeyboardInputAction
;
17 import ru
.deadsoftware
.cavedroid
.game
.input
.action
.MouseInputAction
;
18 import ru
.deadsoftware
.cavedroid
.game
.input
.action
.keys
.MouseInputActionKey
;
19 import ru
.deadsoftware
.cavedroid
.game
.input
.handler
.mouse
.CursorMouseInputHandler
;
20 import ru
.deadsoftware
.cavedroid
.game
.input
.mapper
.KeyboardInputActionMapper
;
21 import ru
.deadsoftware
.cavedroid
.game
.input
.mapper
.MouseInputActionMapper
;
22 import ru
.deadsoftware
.cavedroid
.game
.mobs
.MobsController
;
23 import ru
.deadsoftware
.cavedroid
.game
.mobs
.player
.Player
;
24 import ru
.deadsoftware
.cavedroid
.game
.objects
.TouchButton
;
25 import ru
.deadsoftware
.cavedroid
.game
.render
.IGameRenderer
;
26 import ru
.deadsoftware
.cavedroid
.game
.ui
.TooltipManager
;
27 import ru
.deadsoftware
.cavedroid
.game
.ui
.windows
.GameWindowsManager
;
28 import ru
.deadsoftware
.cavedroid
.game
.world
.GameWorld
;
29 import ru
.deadsoftware
.cavedroid
.misc
.Assets
;
30 import ru
.deadsoftware
.cavedroid
.misc
.Renderer
;
31 import ru
.deadsoftware
.cavedroid
.misc
.utils
.MeasureUnitsUtilsKt
;
32 import ru
.deadsoftware
.cavedroid
.misc
.utils
.RenderingUtilsKt
;
34 import javax
.inject
.Inject
;
35 import java
.util
.ArrayList
;
36 import java
.util
.Comparator
;
37 import java
.util
.List
;
41 public class GameRenderer
extends Renderer
{
43 private static final float CAMERA_SPEED
= 72f;
44 private static final float MAX_CAM_DISTANCE_FROM_PLAYER
= 64f;
45 private static final float DRAG_THRESHOLD
= 1f;
46 private static final TouchButton nullButton
= new TouchButton(null, -1, true);
48 private final MainConfig mMainConfig
;
49 private final MobsController mMobsController
;
50 private final GameWorld mGameWorld
;
51 private final List
<IGameRenderer
> mRenderers
;
52 private final CursorMouseInputHandler mCursorMouseInputHandler
;
53 private final MouseInputActionMapper mMouseInputActionMapper
;
54 private final KeyboardInputActionMapper mKeyboardInputActionMapper
;
55 private final Set
<IMouseInputHandler
> mMouseInputHandlers
;
56 private final Set
<IKeyboardInputHandler
> mKeyboardInputHandlers
;
57 private final GameWindowsManager mGameWindowsManager
;
58 private final TooltipManager mTooltipManager
;
60 private final TouchButton mouseLeftTouchButton
, mouseRightTouchButton
;
62 private final Vector2 mCamCenterToPlayer
= new Vector2();
64 private float mTouchDownX
, mTouchDownY
;
65 private long mCameraDelayMs
= 0L;
68 GameRenderer(MainConfig mainConfig
,
69 MobsController mobsController
,
71 Set
<IGameRenderer
> renderers
,
72 CursorMouseInputHandler cursorMouseInputHandler
,
73 MouseInputActionMapper mouseInputActionMapper
,
74 KeyboardInputActionMapper keyboardInputActionMapper
,
75 Set
<IMouseInputHandler
> mouseInputHandlers
,
76 Set
<IKeyboardInputHandler
> keyboardInputHandlers
,
77 GameWindowsManager gameWindowsManager
,
78 TooltipManager tooltipManager
) {
79 super(mainConfig
.getWidth(), mainConfig
.getHeight());
81 mMainConfig
= mainConfig
;
82 mMobsController
= mobsController
;
83 mGameWorld
= gameWorld
;
84 mRenderers
= new ArrayList
<>(renderers
);
85 kotlin
.collections
.CollectionsKt
.sortWith(mRenderers
, new Comparator
<IGameRenderer
>() {
87 public int compare(IGameRenderer o1
, IGameRenderer o2
) {
88 return o1
.getRenderLayer() - o2
.getRenderLayer();
91 mCursorMouseInputHandler
= cursorMouseInputHandler
;
92 mMouseInputActionMapper
= mouseInputActionMapper
;
93 mKeyboardInputActionMapper
= keyboardInputActionMapper
;
94 mMouseInputHandlers
= mouseInputHandlers
;
95 mKeyboardInputHandlers
= keyboardInputHandlers
;
96 mGameWindowsManager
= gameWindowsManager
;
97 mTooltipManager
= tooltipManager
;
99 mouseLeftTouchButton
= new TouchButton(new Rectangle(getWidth() / 2, 0f, getWidth() / 2, getHeight() / 2), Input
.Buttons
.LEFT
, true);
100 mouseRightTouchButton
= new TouchButton(new Rectangle(getWidth() / 2, getHeight() / 2, getWidth() / 2, getHeight() / 2), Input
.Buttons
.RIGHT
, true);
102 mMainConfig
.setJoystick(new Joystick(mMobsController
.getPlayer().getSpeed()));
104 Gdx
.gl
.glClearColor(0f, .6f, .6f, 1f);
107 private void updateDynamicCameraPosition(float delta
) {
108 Player player
= mMobsController
.getPlayer();
110 float plTargetX
= player
.getX() + player
.getWidth() / 2;
111 float plTargetY
= player
.getY() + player
.getHeight() / 2;
113 float camCenterX
= getCamX() + getWidth() / 2;
114 float camCenterY
= getCamY() + getHeight() / 2;
116 float camTargetX
, camTargetY
;
118 boolean followPlayer
= player
.controlMode
== Player
.ControlMode
.WALK
|| !mMainConfig
.isTouch();
121 camTargetX
= plTargetX
+ Math
.min(player
.getVelocity().x
* 2, getWidth() / 2);
122 camTargetY
= plTargetY
+ player
.getVelocity().y
;
124 camTargetX
= MeasureUnitsUtilsKt
.getPx(player
.cursorX
) + MeasureUnitsUtilsKt
.getPx(1) / 2;
125 camTargetY
= MeasureUnitsUtilsKt
.getPx(player
.cursorY
) + MeasureUnitsUtilsKt
.getPx(1) / 2;
128 Vector2 moveVector
= new Vector2(camTargetX
- camCenterX
, camTargetY
- camCenterY
);
130 if (followPlayer
&& player
.getVelocity().isZero()) {
131 mCameraDelayMs
= TimeUtils
.millis();
132 mCamCenterToPlayer
.x
= plTargetX
- camCenterX
;
133 mCamCenterToPlayer
.y
= plTargetY
- camCenterY
;
136 if (TimeUtils
.timeSinceMillis(mCameraDelayMs
) < 500L && !player
.getVelocity().isZero()) {
137 updateStaticCameraPosition(plTargetX
- mCamCenterToPlayer
.x
,
138 camCenterY
+ moveVector
.y
* delta
* 2);
142 float camX
= getCamX();
143 float camY
= getCamY();
144 float worldWidth
= MeasureUnitsUtilsKt
.getPx(mGameWorld
.getWidth()) - getWidth() / 2;
146 if (moveVector
.x
>= worldWidth
) {
147 camX
+= mGameWorld
.getWidthPx();
148 moveVector
.x
-= mGameWorld
.getWidthPx();
149 } else if (moveVector
.x
<= -worldWidth
) {
150 camX
-= mGameWorld
.getWidthPx();
151 moveVector
.x
+= mGameWorld
.getWidthPx();
154 setCamPos(camX
+ moveVector
.x
* delta
* 2, camY
+ moveVector
.y
* delta
* 2);
160 if (camX
+ getWidth() / 2 > plTargetX
+ MAX_CAM_DISTANCE_FROM_PLAYER
) {
161 camX
= plTargetX
+ MAX_CAM_DISTANCE_FROM_PLAYER
- getWidth() / 2;
164 if (camY
+ getHeight() / 2 > plTargetY
+ MAX_CAM_DISTANCE_FROM_PLAYER
) {
165 camY
= plTargetY
+ MAX_CAM_DISTANCE_FROM_PLAYER
- getHeight() / 2;
168 if (camX
+ getWidth() / 2 < plTargetX
- MAX_CAM_DISTANCE_FROM_PLAYER
) {
169 camX
= plTargetX
- MAX_CAM_DISTANCE_FROM_PLAYER
- getWidth() / 2;
172 if (camY
+ getHeight() / 2 < plTargetY
- MAX_CAM_DISTANCE_FROM_PLAYER
) {
173 camY
= plTargetY
- MAX_CAM_DISTANCE_FROM_PLAYER
- getHeight() / 2;
176 setCamPos(camX
, camY
);
179 private void updateStaticCameraPosition(float targetX
, float targetY
) {
180 setCamPos(targetX
- getWidth() / 2, targetY
- getHeight() / 2);
183 private void updateStaticCameraPosition() {
184 Player player
= mMobsController
.getPlayer();
186 updateStaticCameraPosition(player
.getX() + player
.getWidth() / 2,
187 player
.getY() + player
.getHeight() / 2);
190 private void updateCameraPosition(float delta
) {
191 if (mMainConfig
.isUseDynamicCamera()) {
192 updateDynamicCameraPosition(delta
);
194 updateStaticCameraPosition();
198 private float transformScreenX(int screenX
) {
199 return getWidth() / Gdx
.graphics
.getWidth() * screenX
;
202 private float transformScreenY(int screenY
) {
203 return getHeight() / Gdx
.graphics
.getHeight() * screenY
;
206 private void handleMousePosition() {
207 final Rectangle viewport
= getCameraViewport();
209 final float screenX
= transformScreenX(Gdx
.input
.getX());
210 final float screenY
= transformScreenY(Gdx
.input
.getY());
212 final MouseInputAction action
= new MouseInputAction(
215 MouseInputActionKey
.None
.INSTANCE
,
218 mCursorMouseInputHandler
.handle(action
);
220 if (!mTooltipManager
.getCurrentMouseTooltip().isEmpty()) {
221 RenderingUtilsKt
.drawString(spriter
, mTooltipManager
.getCurrentMouseTooltip(), screenX
+ 1, screenY
+ 1, Color
.BLACK
);
222 RenderingUtilsKt
.drawString(spriter
, mTooltipManager
.getCurrentMouseTooltip(), screenX
, screenY
, Color
.WHITE
);
226 private boolean handleMouseAction(@Nullable MouseInputAction action
) {
227 if (action
== null) {
231 boolean anyProcessed
= false;
233 for (IMouseInputHandler handler
: mMouseInputHandlers
) {
234 final boolean conditions
= handler
.checkConditions(action
);
237 handler
.handle(action
);
240 // anyProcessed = anyProcessed || conditions;
245 private boolean onMouseActionEvent(int mouseX
, int mouseY
, int button
, boolean touchUp
, int pointer
) {
246 @Nullable MouseInputAction action
= mMouseInputActionMapper
247 .map((float) mouseX
, (float) mouseY
, getCameraViewport(), button
, touchUp
, pointer
);
248 return handleMouseAction(action
);
252 public boolean touchUp(int screenX
, int screenY
, int pointer
, int button
) {
253 float touchX
= transformScreenX(screenX
);
254 float touchY
= transformScreenY(screenY
);
256 final Joystick joy
= mMainConfig
.getJoystick();
258 if (mMainConfig
.isTouch()) {
259 if (joy
!= null && joy
.getActive() && joy
.getPointer() == pointer
) {
260 return onMouseActionEvent(screenX
, screenY
, nullButton
.getCode(), true, pointer
);
263 TouchButton touchedKey
= getTouchedKey(touchX
, touchY
);
264 if (touchedKey
.isMouse()) {
265 return onMouseActionEvent(screenX
, screenY
, touchedKey
.getCode(), true, pointer
);
267 return keyUp(touchedKey
.getCode());
271 return onMouseActionEvent(screenX
, screenY
, button
, true, pointer
);
274 private TouchButton
getTouchedKey(float touchX
, float touchY
) {
275 if (mGameWindowsManager
.getCurrentWindowType() != GameUiWindow
.NONE
) {
278 for (ObjectMap
.Entry
<String
, TouchButton
> entry
: Assets
.guiMap
) {
279 TouchButton button
= entry
.value
;
280 if (button
.getRect().contains(touchX
, touchY
)) {
285 if (mouseLeftTouchButton
.getRect().contains(touchX
, touchY
)) {
286 return mouseLeftTouchButton
;
289 if (mouseRightTouchButton
.getRect().contains(touchX
, touchY
)) {
290 return mouseRightTouchButton
;
297 public boolean touchDown(int screenX
, int screenY
, int pointer
, int button
) {
298 float touchX
= transformScreenX(screenX
);
299 float touchY
= transformScreenY(screenY
);
301 mTouchDownX
= touchX
;
302 mTouchDownY
= touchY
;
304 if (mMainConfig
.isTouch()) {
305 TouchButton touchedKey
= getTouchedKey(touchX
, touchY
);
306 if (touchedKey
.isMouse()) {
307 return onMouseActionEvent(screenX
, screenY
, touchedKey
.getCode(), false, pointer
);
309 return keyDown(touchedKey
.getCode());
313 return onMouseActionEvent(screenX
, screenY
, button
, false, pointer
);
317 public boolean touchDragged(int screenX
, int screenY
, int pointer
) {
318 float touchX
= transformScreenX(screenX
);
319 float touchY
= transformScreenY(screenY
);
321 if (Math
.abs(touchX
- mTouchDownX
) < 16 && Math
.abs(touchY
- mTouchDownY
) < DRAG_THRESHOLD
) {
325 @Nullable MouseInputAction action
=
326 mMouseInputActionMapper
.mapDragged(screenX
, screenY
, getCameraViewport(), pointer
);
327 return handleMouseAction(action
);
331 public boolean scrolled(float amountX
, float amountY
) {
332 @Nullable MouseInputAction action
= mMouseInputActionMapper
333 .mapScrolled(Gdx
.input
.getX(), Gdx
.input
.getY(), amountX
, amountY
, getCameraViewport());
334 return handleMouseAction(action
);
337 private boolean handleKeyboardAction(int keycode
, boolean isKeyDown
) {
338 @Nullable final KeyboardInputAction action
= mKeyboardInputActionMapper
339 .map(keycode
, isKeyDown
);
341 if (action
== null) {
345 boolean anyProcessed
= false;
347 for (IKeyboardInputHandler handler
: mKeyboardInputHandlers
) {
348 final boolean conditions
= handler
.checkConditions(action
);
351 handler
.handle(action
);
360 public boolean keyDown(int keycode
) {
361 return handleKeyboardAction(keycode
, true);
365 public boolean keyUp(int keycode
) {
366 return handleKeyboardAction(keycode
, false);
370 public void render(float delta
) {
371 updateCameraPosition(delta
);
373 if (mMainConfig
.getJoystick() != null && mMainConfig
.getJoystick().getActive()) {
374 mMainConfig
.getJoystick().updateState(
375 transformScreenX(Gdx
.input
.getX(mMainConfig
.getJoystick().getPointer())),
376 transformScreenY(Gdx
.input
.getY(mMainConfig
.getJoystick().getPointer()))
380 Gdx
.gl
.glClear(GL20
.GL_COLOR_BUFFER_BIT
);
383 for (IGameRenderer iGameRenderer
: mRenderers
) {
384 iGameRenderer
.draw(spriter
, shaper
, getCameraViewport(), delta
);
386 handleMousePosition();