DEADSOFTWARE

Add option for dynamic camera
[cavedroid.git] / core / src / ru / deadsoftware / cavedroid / game / GameRenderer.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.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 ru.deadsoftware.cavedroid.MainConfig;
11 import ru.deadsoftware.cavedroid.game.input.IGameInputHandler;
12 import ru.deadsoftware.cavedroid.game.input.Joystick;
13 import ru.deadsoftware.cavedroid.game.input.action.KeyboardInputAction;
14 import ru.deadsoftware.cavedroid.game.input.action.MouseInputAction;
15 import ru.deadsoftware.cavedroid.game.input.action.keys.MouseInputActionKey;
16 import ru.deadsoftware.cavedroid.game.input.handler.mouse.CursorMouseInputHandler;
17 import ru.deadsoftware.cavedroid.game.input.mapper.KeyboardInputActionMapper;
18 import ru.deadsoftware.cavedroid.game.input.mapper.MouseInputActionMapper;
19 import ru.deadsoftware.cavedroid.game.mobs.MobsController;
20 import ru.deadsoftware.cavedroid.game.mobs.player.Player;
21 import ru.deadsoftware.cavedroid.game.objects.TouchButton;
22 import ru.deadsoftware.cavedroid.game.render.IGameRenderer;
23 import ru.deadsoftware.cavedroid.game.ui.TooltipManager;
24 import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager;
25 import ru.deadsoftware.cavedroid.game.world.GameWorld;
26 import ru.deadsoftware.cavedroid.misc.Assets;
27 import ru.deadsoftware.cavedroid.misc.Renderer;
28 import ru.deadsoftware.cavedroid.misc.utils.MeasureUnitsUtilsKt;
29 import ru.deadsoftware.cavedroid.misc.utils.RenderingUtilsKt;
31 import javax.annotation.CheckForNull;
32 import javax.inject.Inject;
33 import java.util.ArrayList;
34 import java.util.Comparator;
35 import java.util.List;
36 import java.util.Set;
38 @GameScope
39 public class GameRenderer extends Renderer {
41 private static final float CAMERA_SPEED = 72f;
42 private static final float MAX_CAM_DISTANCE_FROM_PLAYER = 64f;
43 private static final float DRAG_THRESHOLD = 1f;
44 private static final TouchButton nullButton = new TouchButton(null, -1, true);
46 private final MainConfig mMainConfig;
47 private final MobsController mMobsController;
48 private final GameWorld mGameWorld;
49 private final List<IGameRenderer> mRenderers;
50 private final CursorMouseInputHandler mCursorMouseInputHandler;
51 private final MouseInputActionMapper mMouseInputActionMapper;
52 private final KeyboardInputActionMapper mKeyboardInputActionMapper;
53 private final Set<IGameInputHandler<MouseInputAction>> mMouseInputHandlers;
54 private final Set<IGameInputHandler<KeyboardInputAction>> mKeyboardInputHandlers;
55 private final GameWindowsManager mGameWindowsManager;
56 private final TooltipManager mTooltipManager;
58 private final TouchButton mouseLeftTouchButton, mouseRightTouchButton;
60 @Inject
61 GameRenderer(MainConfig mainConfig,
62 MobsController mobsController,
63 GameWorld gameWorld,
64 Set<IGameRenderer> renderers,
65 CursorMouseInputHandler cursorMouseInputHandler,
66 MouseInputActionMapper mouseInputActionMapper,
67 KeyboardInputActionMapper keyboardInputActionMapper,
68 Set<IGameInputHandler<MouseInputAction>> mouseInputHandlers,
69 Set<IGameInputHandler<KeyboardInputAction>> keyboardInputHandlers,
70 GameWindowsManager gameWindowsManager,
71 TooltipManager tooltipManager) {
72 super(mainConfig.getWidth(), mainConfig.getHeight());
74 mMainConfig = mainConfig;
75 mMobsController = mobsController;
76 mGameWorld = gameWorld;
77 mRenderers = new ArrayList<>(renderers);
78 mRenderers.sort(Comparator.comparingInt(IGameRenderer::getRenderLayer));
79 mCursorMouseInputHandler = cursorMouseInputHandler;
80 mMouseInputActionMapper = mouseInputActionMapper;
81 mKeyboardInputActionMapper = keyboardInputActionMapper;
82 mMouseInputHandlers = mouseInputHandlers;
83 mKeyboardInputHandlers = keyboardInputHandlers;
84 mGameWindowsManager = gameWindowsManager;
85 mTooltipManager = tooltipManager;
87 mouseLeftTouchButton = new TouchButton(new Rectangle(getWidth() / 2, 0f, getWidth() / 2, getHeight() / 2), Input.Buttons.LEFT, true);
88 mouseRightTouchButton = new TouchButton(new Rectangle(getWidth() / 2, getHeight() / 2, getWidth() / 2, getHeight() / 2), Input.Buttons.RIGHT, true);
90 mMainConfig.setJoystick(new Joystick(mMobsController.getPlayer().getSpeed()));
92 Gdx.gl.glClearColor(0f, .6f, .6f, 1f);
93 }
95 private float mTouchDownX, mTouchDownY;
97 private void updateDynamicCameraPosition(float delta) {
98 Player player = mMobsController.getPlayer();
100 float plTargetX = player.getX() + player.getWidth() / 2;
101 float plTargetY = player.getY() + player.getHeight() / 2;
103 float camTargetX, camTargetY;
105 if (player.controlMode == Player.ControlMode.WALK) {
106 camTargetX = plTargetX + Math.min(player.getVelocity().x * 2, getWidth() / 2);
107 camTargetY = plTargetY + player.getVelocity().y;
108 } else {
109 camTargetX = MeasureUnitsUtilsKt.getPx(player.cursorX) + MeasureUnitsUtilsKt.getPx(1) / 2;
110 camTargetY = MeasureUnitsUtilsKt.getPx(player.cursorY) + MeasureUnitsUtilsKt.getPx(1) / 2;
113 float camCenterX = getCamX() + getWidth() / 2;
114 float camCenterY = getCamY() + getHeight() / 2;
116 Vector2 moveVector = new Vector2(camTargetX - camCenterX, camTargetY - camCenterY);
118 float camX = getCamX();
119 float camY = getCamY();
120 float worldWidth = MeasureUnitsUtilsKt.getPx(mGameWorld.getWidth()) - getWidth() / 2;
122 if (moveVector.x >= worldWidth) {
123 camX += mGameWorld.getWidthPx();
124 moveVector.x -= mGameWorld.getWidthPx();
125 } else if (moveVector.x <= -worldWidth) {
126 camX -= mGameWorld.getWidthPx();
127 moveVector.x += mGameWorld.getWidthPx();
130 setCamPos(camX + moveVector.x * delta * 2, camY + moveVector.y * delta * 2);
133 camX = getCamX();
134 camY = getCamY();
136 if (camX + getWidth() / 2 > plTargetX + MAX_CAM_DISTANCE_FROM_PLAYER) {
137 camX = plTargetX + MAX_CAM_DISTANCE_FROM_PLAYER - getWidth() / 2;
140 if (camY + getHeight() / 2 > plTargetY + MAX_CAM_DISTANCE_FROM_PLAYER) {
141 camY = plTargetY + MAX_CAM_DISTANCE_FROM_PLAYER - getHeight() / 2;
144 if (camX + getWidth() / 2 < plTargetX - MAX_CAM_DISTANCE_FROM_PLAYER) {
145 camX = plTargetX - MAX_CAM_DISTANCE_FROM_PLAYER - getWidth() / 2;
148 if (camY + getHeight() / 2 < plTargetY - MAX_CAM_DISTANCE_FROM_PLAYER) {
149 camY = plTargetY - MAX_CAM_DISTANCE_FROM_PLAYER - getHeight() / 2;
152 setCamPos(camX, camY);
155 private void updateStaticCameraPosition() {
156 Player player = mMobsController.getPlayer();
158 setCamPos(player.getX() + player.getWidth() / 2 - getWidth() / 2,
159 player.getY() + player.getHeight() / 2 - getHeight() / 2);
162 private void updateCameraPosition(float delta) {
163 if (mMainConfig.isUseDynamicCamera()) {
164 updateDynamicCameraPosition(delta);
165 } else {
166 updateStaticCameraPosition();
170 private float transformScreenX(int screenX) {
171 return getWidth() / Gdx.graphics.getWidth() * screenX;
174 private float transformScreenY(int screenY) {
175 return getHeight() / Gdx.graphics.getHeight() * screenY;
178 private void handleMousePosition() {
179 final Rectangle viewport = getCameraViewport();
181 final float screenX = transformScreenX(Gdx.input.getX());
182 final float screenY = transformScreenY(Gdx.input.getY());
184 final MouseInputAction action = new MouseInputAction(
185 screenX,
186 screenY,
187 MouseInputActionKey.None.INSTANCE,
188 viewport);
190 mCursorMouseInputHandler.handle(action);
192 if (!mTooltipManager.getCurrentMouseTooltip().isEmpty()) {
193 RenderingUtilsKt.drawString(spriter, mTooltipManager.getCurrentMouseTooltip(), screenX + 1, screenY + 1, Color.BLACK);
194 RenderingUtilsKt.drawString(spriter, mTooltipManager.getCurrentMouseTooltip(), screenX, screenY, Color.WHITE);
198 private boolean handleMouseAction(@CheckForNull MouseInputAction action) {
199 if (action == null) {
200 return false;
203 boolean anyProcessed = false;
205 for (IGameInputHandler<MouseInputAction> handler : mMouseInputHandlers) {
206 final boolean conditions = handler.checkConditions(action);
207 if (conditions) {
208 anyProcessed = true;
209 handler.handle(action);
210 break;
212 // anyProcessed = anyProcessed || conditions;
214 return anyProcessed;
217 private boolean onMouseActionEvent(int mouseX, int mouseY, int button, boolean touchUp, int pointer) {
218 @CheckForNull MouseInputAction action = mMouseInputActionMapper
219 .map((float) mouseX, (float) mouseY, getCameraViewport(), button, touchUp, pointer);
220 return handleMouseAction(action);
223 @Override
224 public boolean touchUp(int screenX, int screenY, int pointer, int button) {
225 float touchX = transformScreenX(screenX);
226 float touchY = transformScreenY(screenY);
228 final Joystick joy = mMainConfig.getJoystick();
230 if (mMainConfig.isTouch()) {
231 if (joy != null && joy.getActive() && joy.getPointer() == pointer) {
232 return onMouseActionEvent(screenX, screenY, nullButton.getCode(), true, pointer);
235 TouchButton touchedKey = getTouchedKey(touchX, touchY);
236 if (touchedKey.isMouse()) {
237 return onMouseActionEvent(screenX, screenY, touchedKey.getCode(), true, pointer);
238 } else {
239 return keyUp(touchedKey.getCode());
243 return onMouseActionEvent(screenX, screenY, button, true, pointer);
246 private TouchButton getTouchedKey(float touchX, float touchY) {
247 if (mGameWindowsManager.getCurrentWindowType() != GameUiWindow.NONE) {
248 return nullButton;
250 for (ObjectMap.Entry<String, TouchButton> entry : Assets.guiMap) {
251 TouchButton button = entry.value;
252 if (button.getRect().contains(touchX, touchY)) {
253 return button;
257 if (mouseLeftTouchButton.getRect().contains(touchX, touchY)) {
258 return mouseLeftTouchButton;
261 if (mouseRightTouchButton.getRect().contains(touchX, touchY)) {
262 return mouseRightTouchButton;
265 return nullButton;
268 @Override
269 public boolean touchDown(int screenX, int screenY, int pointer, int button) {
270 float touchX = transformScreenX(screenX);
271 float touchY = transformScreenY(screenY);
273 mTouchDownX = touchX;
274 mTouchDownY = touchY;
276 if (mMainConfig.isTouch()) {
277 TouchButton touchedKey = getTouchedKey(touchX, touchY);
278 if (touchedKey.isMouse()) {
279 return onMouseActionEvent(screenX, screenY, touchedKey.getCode(), false, pointer);
280 } else {
281 return keyDown(touchedKey.getCode());
285 return onMouseActionEvent(screenX, screenY, button, false, pointer);
288 @Override
289 public boolean touchDragged(int screenX, int screenY, int pointer) {
290 float touchX = transformScreenX(screenX);
291 float touchY = transformScreenY(screenY);
293 if (Math.abs(touchX - mTouchDownX) < 16 && Math.abs(touchY - mTouchDownY) < DRAG_THRESHOLD) {
294 return false;
297 @CheckForNull MouseInputAction action =
298 mMouseInputActionMapper.mapDragged(screenX, screenY, getCameraViewport(), pointer);
299 return handleMouseAction(action);
302 @Override
303 public boolean scrolled(float amountX, float amountY) {
304 @CheckForNull MouseInputAction action = mMouseInputActionMapper
305 .mapScrolled(Gdx.input.getX(), Gdx.input.getY(), amountX, amountY, getCameraViewport());
306 return handleMouseAction(action);
309 private boolean handleKeyboardAction(int keycode, boolean isKeyDown) {
310 @CheckForNull final KeyboardInputAction action = mKeyboardInputActionMapper
311 .map(keycode, isKeyDown);
313 if (action == null) {
314 return false;
317 boolean anyProcessed = false;
319 for (IGameInputHandler<KeyboardInputAction> handler : mKeyboardInputHandlers) {
320 final boolean conditions = handler.checkConditions(action);
321 if (conditions) {
322 anyProcessed = true;
323 handler.handle(action);
324 break;
328 return anyProcessed;
331 @Override
332 public boolean keyDown(int keycode) {
333 return handleKeyboardAction(keycode, true);
336 @Override
337 public boolean keyUp(int keycode) {
338 return handleKeyboardAction(keycode, false);
341 @Override
342 public void render(float delta) {
343 updateCameraPosition(delta);
345 if (mMainConfig.getJoystick() != null && mMainConfig.getJoystick().getActive()) {
346 mMainConfig.getJoystick().updateState(
347 transformScreenX(Gdx.input.getX(mMainConfig.getJoystick().getPointer())),
348 transformScreenY(Gdx.input.getY(mMainConfig.getJoystick().getPointer()))
349 );
352 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
354 spriter.begin();
355 mRenderers.forEach(iGameRenderer -> iGameRenderer.draw(spriter, shaper, getCameraViewport(), delta));
356 handleMousePosition();
357 spriter.end();