DEADSOFTWARE

Update version script
[cavedroid.git] / core / src / main / java / 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 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;
38 import java.util.Set;
40 @GameScope
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;
67 @Inject
68 GameRenderer(MainConfig mainConfig,
69 MobsController mobsController,
70 GameWorld gameWorld,
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>() {
86 @Override
87 public int compare(IGameRenderer o1, IGameRenderer o2) {
88 return o1.getRenderLayer() - o2.getRenderLayer();
89 }
90 });
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();
120 if (followPlayer) {
121 camTargetX = plTargetX + Math.min(player.getVelocity().x * 2, getWidth() / 2);
122 camTargetY = plTargetY + player.getVelocity().y;
123 } else {
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);
139 return;
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);
157 camX = getCamX();
158 camY = getCamY();
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);
193 } else {
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(
213 screenX,
214 screenY,
215 MouseInputActionKey.None.INSTANCE,
216 viewport);
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) {
228 return false;
231 boolean anyProcessed = false;
233 for (IMouseInputHandler handler : mMouseInputHandlers) {
234 final boolean conditions = handler.checkConditions(action);
235 if (conditions) {
236 anyProcessed = true;
237 handler.handle(action);
238 break;
240 // anyProcessed = anyProcessed || conditions;
242 return anyProcessed;
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);
251 @Override
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);
266 } else {
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) {
276 return nullButton;
278 for (ObjectMap.Entry<String, TouchButton> entry : Assets.guiMap) {
279 TouchButton button = entry.value;
280 if (button.getRect().contains(touchX, touchY)) {
281 return button;
285 if (mouseLeftTouchButton.getRect().contains(touchX, touchY)) {
286 return mouseLeftTouchButton;
289 if (mouseRightTouchButton.getRect().contains(touchX, touchY)) {
290 return mouseRightTouchButton;
293 return nullButton;
296 @Override
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);
308 } else {
309 return keyDown(touchedKey.getCode());
313 return onMouseActionEvent(screenX, screenY, button, false, pointer);
316 @Override
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) {
322 return false;
325 @Nullable MouseInputAction action =
326 mMouseInputActionMapper.mapDragged(screenX, screenY, getCameraViewport(), pointer);
327 return handleMouseAction(action);
330 @Override
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) {
342 return false;
345 boolean anyProcessed = false;
347 for (IKeyboardInputHandler handler : mKeyboardInputHandlers) {
348 final boolean conditions = handler.checkConditions(action);
349 if (conditions) {
350 anyProcessed = true;
351 handler.handle(action);
352 break;
356 return anyProcessed;
359 @Override
360 public boolean keyDown(int keycode) {
361 return handleKeyboardAction(keycode, true);
364 @Override
365 public boolean keyUp(int keycode) {
366 return handleKeyboardAction(keycode, false);
369 @Override
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()))
377 );
380 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
382 spriter.begin();
383 for (IGameRenderer iGameRenderer : mRenderers) {
384 iGameRenderer.draw(spriter, shaper, getCameraViewport(), delta);
386 handleMousePosition();
387 spriter.end();