DEADSOFTWARE

Change scale values
[cavedroid.git] / core / src / ru / deadsoftware / cavedroid / game / GameRenderer.java
1 package ru.deadsoftware.cavedroid.game;
2
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 ru.deadsoftware.cavedroid.MainConfig;
12 import ru.deadsoftware.cavedroid.game.input.IGameInputHandler;
13 import ru.deadsoftware.cavedroid.game.input.Joystick;
14 import ru.deadsoftware.cavedroid.game.input.action.KeyboardInputAction;
15 import ru.deadsoftware.cavedroid.game.input.action.MouseInputAction;
16 import ru.deadsoftware.cavedroid.game.input.action.keys.MouseInputActionKey;
17 import ru.deadsoftware.cavedroid.game.input.handler.mouse.CursorMouseInputHandler;
18 import ru.deadsoftware.cavedroid.game.input.mapper.KeyboardInputActionMapper;
19 import ru.deadsoftware.cavedroid.game.input.mapper.MouseInputActionMapper;
20 import ru.deadsoftware.cavedroid.game.mobs.MobsController;
21 import ru.deadsoftware.cavedroid.game.mobs.player.Player;
22 import ru.deadsoftware.cavedroid.game.objects.TouchButton;
23 import ru.deadsoftware.cavedroid.game.render.IGameRenderer;
24 import ru.deadsoftware.cavedroid.game.ui.TooltipManager;
25 import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager;
26 import ru.deadsoftware.cavedroid.game.world.GameWorld;
27 import ru.deadsoftware.cavedroid.misc.Assets;
28 import ru.deadsoftware.cavedroid.misc.Renderer;
29 import ru.deadsoftware.cavedroid.misc.utils.MeasureUnitsUtilsKt;
30 import ru.deadsoftware.cavedroid.misc.utils.RenderingUtilsKt;
31
32 import javax.annotation.CheckForNull;
33 import javax.inject.Inject;
34 import java.util.ArrayList;
35 import java.util.Comparator;
36 import java.util.List;
37 import java.util.Set;
38
39 @GameScope
40 public class GameRenderer extends Renderer {
41
42 private static final float CAMERA_SPEED = 72f;
43 private static final float MAX_CAM_DISTANCE_FROM_PLAYER = 64f;
44 private static final float DRAG_THRESHOLD = 1f;
45 private static final TouchButton nullButton = new TouchButton(null, -1, true);
46
47 private final MainConfig mMainConfig;
48 private final MobsController mMobsController;
49 private final GameWorld mGameWorld;
50 private final List<IGameRenderer> mRenderers;
51 private final CursorMouseInputHandler mCursorMouseInputHandler;
52 private final MouseInputActionMapper mMouseInputActionMapper;
53 private final KeyboardInputActionMapper mKeyboardInputActionMapper;
54 private final Set<IGameInputHandler<MouseInputAction>> mMouseInputHandlers;
55 private final Set<IGameInputHandler<KeyboardInputAction>> mKeyboardInputHandlers;
56 private final GameWindowsManager mGameWindowsManager;
57 private final TooltipManager mTooltipManager;
58
59 private final TouchButton mouseLeftTouchButton, mouseRightTouchButton;
60
61 private final Vector2 mCamCenterToPlayer = new Vector2();
62
63 private float mTouchDownX, mTouchDownY;
64 private long mCameraDelayMs = 0L;
65
66 @Inject
67 GameRenderer(MainConfig mainConfig,
68 MobsController mobsController,
69 GameWorld gameWorld,
70 Set<IGameRenderer> renderers,
71 CursorMouseInputHandler cursorMouseInputHandler,
72 MouseInputActionMapper mouseInputActionMapper,
73 KeyboardInputActionMapper keyboardInputActionMapper,
74 Set<IGameInputHandler<MouseInputAction>> mouseInputHandlers,
75 Set<IGameInputHandler<KeyboardInputAction>> keyboardInputHandlers,
76 GameWindowsManager gameWindowsManager,
77 TooltipManager tooltipManager) {
78 super(mainConfig.getWidth(), mainConfig.getHeight());
79
80 mMainConfig = mainConfig;
81 mMobsController = mobsController;
82 mGameWorld = gameWorld;
83 mRenderers = new ArrayList<>(renderers);
84 mRenderers.sort(Comparator.comparingInt(IGameRenderer::getRenderLayer));
85 mCursorMouseInputHandler = cursorMouseInputHandler;
86 mMouseInputActionMapper = mouseInputActionMapper;
87 mKeyboardInputActionMapper = keyboardInputActionMapper;
88 mMouseInputHandlers = mouseInputHandlers;
89 mKeyboardInputHandlers = keyboardInputHandlers;
90 mGameWindowsManager = gameWindowsManager;
91 mTooltipManager = tooltipManager;
92
93 mouseLeftTouchButton = new TouchButton(new Rectangle(getWidth() / 2, 0f, getWidth() / 2, getHeight() / 2), Input.Buttons.LEFT, true);
94 mouseRightTouchButton = new TouchButton(new Rectangle(getWidth() / 2, getHeight() / 2, getWidth() / 2, getHeight() / 2), Input.Buttons.RIGHT, true);
95
96 mMainConfig.setJoystick(new Joystick(mMobsController.getPlayer().getSpeed()));
97
98 Gdx.gl.glClearColor(0f, .6f, .6f, 1f);
99 }
100
101 private void updateDynamicCameraPosition(float delta) {
102 Player player = mMobsController.getPlayer();
103
104 float plTargetX = player.getX() + player.getWidth() / 2;
105 float plTargetY = player.getY() + player.getHeight() / 2;
106
107 float camCenterX = getCamX() + getWidth() / 2;
108 float camCenterY = getCamY() + getHeight() / 2;
109
110 float camTargetX, camTargetY;
111
112 if (player.controlMode == Player.ControlMode.WALK) {
113 camTargetX = plTargetX + Math.min(player.getVelocity().x * 2, getWidth() / 2);
114 camTargetY = plTargetY + player.getVelocity().y;
115 } else {
116 camTargetX = MeasureUnitsUtilsKt.getPx(player.cursorX) + MeasureUnitsUtilsKt.getPx(1) / 2;
117 camTargetY = MeasureUnitsUtilsKt.getPx(player.cursorY) + MeasureUnitsUtilsKt.getPx(1) / 2;
118 }
119
120 Vector2 moveVector = new Vector2(camTargetX - camCenterX, camTargetY - camCenterY);
121
122 if (player.controlMode == Player.ControlMode.WALK && player.getVelocity().isZero()) {
123 mCameraDelayMs = TimeUtils.millis();
124 mCamCenterToPlayer.x = plTargetX - camCenterX;
125 mCamCenterToPlayer.y = plTargetY - camCenterY;
126 }
127
128 if (TimeUtils.timeSinceMillis(mCameraDelayMs) < 500L && !player.getVelocity().isZero()) {
129 updateStaticCameraPosition(plTargetX - mCamCenterToPlayer.x,
130 camCenterY + moveVector.y * delta * 2);
131 return;
132 }
133
134 float camX = getCamX();
135 float camY = getCamY();
136 float worldWidth = MeasureUnitsUtilsKt.getPx(mGameWorld.getWidth()) - getWidth() / 2;
137
138 if (moveVector.x >= worldWidth) {
139 camX += mGameWorld.getWidthPx();
140 moveVector.x -= mGameWorld.getWidthPx();
141 } else if (moveVector.x <= -worldWidth) {
142 camX -= mGameWorld.getWidthPx();
143 moveVector.x += mGameWorld.getWidthPx();
144 }
145
146 setCamPos(camX + moveVector.x * delta * 2, camY + moveVector.y * delta * 2);
147
148
149 camX = getCamX();
150 camY = getCamY();
151
152 if (camX + getWidth() / 2 > plTargetX + MAX_CAM_DISTANCE_FROM_PLAYER) {
153 camX = plTargetX + MAX_CAM_DISTANCE_FROM_PLAYER - getWidth() / 2;
154 }
155
156 if (camY + getHeight() / 2 > plTargetY + MAX_CAM_DISTANCE_FROM_PLAYER) {
157 camY = plTargetY + MAX_CAM_DISTANCE_FROM_PLAYER - getHeight() / 2;
158 }
159
160 if (camX + getWidth() / 2 < plTargetX - MAX_CAM_DISTANCE_FROM_PLAYER) {
161 camX = plTargetX - MAX_CAM_DISTANCE_FROM_PLAYER - getWidth() / 2;
162 }
163
164 if (camY + getHeight() / 2 < plTargetY - MAX_CAM_DISTANCE_FROM_PLAYER) {
165 camY = plTargetY - MAX_CAM_DISTANCE_FROM_PLAYER - getHeight() / 2;
166 }
167
168 setCamPos(camX, camY);
169 }
170
171 private void updateStaticCameraPosition(float targetX, float targetY) {
172 setCamPos(targetX - getWidth() / 2, targetY - getHeight() / 2);
173 }
174
175 private void updateStaticCameraPosition() {
176 Player player = mMobsController.getPlayer();
177
178 updateStaticCameraPosition(player.getX() + player.getWidth() / 2,
179 player.getY() + player.getHeight() / 2);
180 }
181
182 private void updateCameraPosition(float delta) {
183 if (mMainConfig.isUseDynamicCamera()) {
184 updateDynamicCameraPosition(delta);
185 } else {
186 updateStaticCameraPosition();
187 }
188 }
189
190 private float transformScreenX(int screenX) {
191 return getWidth() / Gdx.graphics.getWidth() * screenX;
192 }
193
194 private float transformScreenY(int screenY) {
195 return getHeight() / Gdx.graphics.getHeight() * screenY;
196 }
197
198 private void handleMousePosition() {
199 final Rectangle viewport = getCameraViewport();
200
201 final float screenX = transformScreenX(Gdx.input.getX());
202 final float screenY = transformScreenY(Gdx.input.getY());
203
204 final MouseInputAction action = new MouseInputAction(
205 screenX,
206 screenY,
207 MouseInputActionKey.None.INSTANCE,
208 viewport);
209
210 mCursorMouseInputHandler.handle(action);
211
212 if (!mTooltipManager.getCurrentMouseTooltip().isEmpty()) {
213 RenderingUtilsKt.drawString(spriter, mTooltipManager.getCurrentMouseTooltip(), screenX + 1, screenY + 1, Color.BLACK);
214 RenderingUtilsKt.drawString(spriter, mTooltipManager.getCurrentMouseTooltip(), screenX, screenY, Color.WHITE);
215 }
216 }
217
218 private boolean handleMouseAction(@CheckForNull MouseInputAction action) {
219 if (action == null) {
220 return false;
221 }
222
223 boolean anyProcessed = false;
224
225 for (IGameInputHandler<MouseInputAction> handler : mMouseInputHandlers) {
226 final boolean conditions = handler.checkConditions(action);
227 if (conditions) {
228 anyProcessed = true;
229 handler.handle(action);
230 break;
231 }
232 // anyProcessed = anyProcessed || conditions;
233 }
234 return anyProcessed;
235 }
236
237 private boolean onMouseActionEvent(int mouseX, int mouseY, int button, boolean touchUp, int pointer) {
238 @CheckForNull MouseInputAction action = mMouseInputActionMapper
239 .map((float) mouseX, (float) mouseY, getCameraViewport(), button, touchUp, pointer);
240 return handleMouseAction(action);
241 }
242
243 @Override
244 public boolean touchUp(int screenX, int screenY, int pointer, int button) {
245 float touchX = transformScreenX(screenX);
246 float touchY = transformScreenY(screenY);
247
248 final Joystick joy = mMainConfig.getJoystick();
249
250 if (mMainConfig.isTouch()) {
251 if (joy != null && joy.getActive() && joy.getPointer() == pointer) {
252 return onMouseActionEvent(screenX, screenY, nullButton.getCode(), true, pointer);
253 }
254
255 TouchButton touchedKey = getTouchedKey(touchX, touchY);
256 if (touchedKey.isMouse()) {
257 return onMouseActionEvent(screenX, screenY, touchedKey.getCode(), true, pointer);
258 } else {
259 return keyUp(touchedKey.getCode());
260 }
261 }
262
263 return onMouseActionEvent(screenX, screenY, button, true, pointer);
264 }
265
266 private TouchButton getTouchedKey(float touchX, float touchY) {
267 if (mGameWindowsManager.getCurrentWindowType() != GameUiWindow.NONE) {
268 return nullButton;
269 }
270 for (ObjectMap.Entry<String, TouchButton> entry : Assets.guiMap) {
271 TouchButton button = entry.value;
272 if (button.getRect().contains(touchX, touchY)) {
273 return button;
274 }
275 }
276
277 if (mouseLeftTouchButton.getRect().contains(touchX, touchY)) {
278 return mouseLeftTouchButton;
279 }
280
281 if (mouseRightTouchButton.getRect().contains(touchX, touchY)) {
282 return mouseRightTouchButton;
283 }
284
285 return nullButton;
286 }
287
288 @Override
289 public boolean touchDown(int screenX, int screenY, int pointer, int button) {
290 float touchX = transformScreenX(screenX);
291 float touchY = transformScreenY(screenY);
292
293 mTouchDownX = touchX;
294 mTouchDownY = touchY;
295
296 if (mMainConfig.isTouch()) {
297 TouchButton touchedKey = getTouchedKey(touchX, touchY);
298 if (touchedKey.isMouse()) {
299 return onMouseActionEvent(screenX, screenY, touchedKey.getCode(), false, pointer);
300 } else {
301 return keyDown(touchedKey.getCode());
302 }
303 }
304
305 return onMouseActionEvent(screenX, screenY, button, false, pointer);
306 }
307
308 @Override
309 public boolean touchDragged(int screenX, int screenY, int pointer) {
310 float touchX = transformScreenX(screenX);
311 float touchY = transformScreenY(screenY);
312
313 if (Math.abs(touchX - mTouchDownX) < 16 && Math.abs(touchY - mTouchDownY) < DRAG_THRESHOLD) {
314 return false;
315 }
316
317 @CheckForNull MouseInputAction action =
318 mMouseInputActionMapper.mapDragged(screenX, screenY, getCameraViewport(), pointer);
319 return handleMouseAction(action);
320 }
321
322 @Override
323 public boolean scrolled(float amountX, float amountY) {
324 @CheckForNull MouseInputAction action = mMouseInputActionMapper
325 .mapScrolled(Gdx.input.getX(), Gdx.input.getY(), amountX, amountY, getCameraViewport());
326 return handleMouseAction(action);
327 }
328
329 private boolean handleKeyboardAction(int keycode, boolean isKeyDown) {
330 @CheckForNull final KeyboardInputAction action = mKeyboardInputActionMapper
331 .map(keycode, isKeyDown);
332
333 if (action == null) {
334 return false;
335 }
336
337 boolean anyProcessed = false;
338
339 for (IGameInputHandler<KeyboardInputAction> handler : mKeyboardInputHandlers) {
340 final boolean conditions = handler.checkConditions(action);
341 if (conditions) {
342 anyProcessed = true;
343 handler.handle(action);
344 break;
345 }
346 }
347
348 return anyProcessed;
349 }
350
351 @Override
352 public boolean keyDown(int keycode) {
353 return handleKeyboardAction(keycode, true);
354 }
355
356 @Override
357 public boolean keyUp(int keycode) {
358 return handleKeyboardAction(keycode, false);
359 }
360
361 @Override
362 public void render(float delta) {
363 updateCameraPosition(delta);
364
365 if (mMainConfig.getJoystick() != null && mMainConfig.getJoystick().getActive()) {
366 mMainConfig.getJoystick().updateState(
367 transformScreenX(Gdx.input.getX(mMainConfig.getJoystick().getPointer())),
368 transformScreenY(Gdx.input.getY(mMainConfig.getJoystick().getPointer()))
369 );
370 }
371
372 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
373
374 spriter.begin();
375 mRenderers.forEach(iGameRenderer -> iGameRenderer.draw(spriter, shaper, getCameraViewport(), delta));
376 handleMousePosition();
377 spriter.end();
378
379 }
380
381 }