DEADSOFTWARE

Add furnace, more craft and items
[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 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;
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;
39 @GameScope
40 public class GameRenderer extends Renderer {
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);
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;
59 private final TouchButton mouseLeftTouchButton, mouseRightTouchButton;
61 private final Vector2 mCamCenterToPlayer = new Vector2();
63 private float mTouchDownX, mTouchDownY;
64 private long mCameraDelayMs = 0L;
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());
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;
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);
96 mMainConfig.setJoystick(new Joystick(mMobsController.getPlayer().getSpeed()));
98 Gdx.gl.glClearColor(0f, .6f, .6f, 1f);
99 }
101 private void updateDynamicCameraPosition(float delta) {
102 Player player = mMobsController.getPlayer();
104 float plTargetX = player.getX() + player.getWidth() / 2;
105 float plTargetY = player.getY() + player.getHeight() / 2;
107 float camCenterX = getCamX() + getWidth() / 2;
108 float camCenterY = getCamY() + getHeight() / 2;
110 float camTargetX, camTargetY;
112 boolean followPlayer = player.controlMode == Player.ControlMode.WALK || !mMainConfig.isTouch();
114 if (followPlayer) {
115 camTargetX = plTargetX + Math.min(player.getVelocity().x * 2, getWidth() / 2);
116 camTargetY = plTargetY + player.getVelocity().y;
117 } else {
118 camTargetX = MeasureUnitsUtilsKt.getPx(player.cursorX) + MeasureUnitsUtilsKt.getPx(1) / 2;
119 camTargetY = MeasureUnitsUtilsKt.getPx(player.cursorY) + MeasureUnitsUtilsKt.getPx(1) / 2;
122 Vector2 moveVector = new Vector2(camTargetX - camCenterX, camTargetY - camCenterY);
124 if (followPlayer && player.getVelocity().isZero()) {
125 mCameraDelayMs = TimeUtils.millis();
126 mCamCenterToPlayer.x = plTargetX - camCenterX;
127 mCamCenterToPlayer.y = plTargetY - camCenterY;
130 if (TimeUtils.timeSinceMillis(mCameraDelayMs) < 500L && !player.getVelocity().isZero()) {
131 updateStaticCameraPosition(plTargetX - mCamCenterToPlayer.x,
132 camCenterY + moveVector.y * delta * 2);
133 return;
136 float camX = getCamX();
137 float camY = getCamY();
138 float worldWidth = MeasureUnitsUtilsKt.getPx(mGameWorld.getWidth()) - getWidth() / 2;
140 if (moveVector.x >= worldWidth) {
141 camX += mGameWorld.getWidthPx();
142 moveVector.x -= mGameWorld.getWidthPx();
143 } else if (moveVector.x <= -worldWidth) {
144 camX -= mGameWorld.getWidthPx();
145 moveVector.x += mGameWorld.getWidthPx();
148 setCamPos(camX + moveVector.x * delta * 2, camY + moveVector.y * delta * 2);
151 camX = getCamX();
152 camY = getCamY();
154 if (camX + getWidth() / 2 > plTargetX + MAX_CAM_DISTANCE_FROM_PLAYER) {
155 camX = plTargetX + MAX_CAM_DISTANCE_FROM_PLAYER - getWidth() / 2;
158 if (camY + getHeight() / 2 > plTargetY + MAX_CAM_DISTANCE_FROM_PLAYER) {
159 camY = plTargetY + MAX_CAM_DISTANCE_FROM_PLAYER - getHeight() / 2;
162 if (camX + getWidth() / 2 < plTargetX - MAX_CAM_DISTANCE_FROM_PLAYER) {
163 camX = plTargetX - MAX_CAM_DISTANCE_FROM_PLAYER - getWidth() / 2;
166 if (camY + getHeight() / 2 < plTargetY - MAX_CAM_DISTANCE_FROM_PLAYER) {
167 camY = plTargetY - MAX_CAM_DISTANCE_FROM_PLAYER - getHeight() / 2;
170 setCamPos(camX, camY);
173 private void updateStaticCameraPosition(float targetX, float targetY) {
174 setCamPos(targetX - getWidth() / 2, targetY - getHeight() / 2);
177 private void updateStaticCameraPosition() {
178 Player player = mMobsController.getPlayer();
180 updateStaticCameraPosition(player.getX() + player.getWidth() / 2,
181 player.getY() + player.getHeight() / 2);
184 private void updateCameraPosition(float delta) {
185 if (mMainConfig.isUseDynamicCamera()) {
186 updateDynamicCameraPosition(delta);
187 } else {
188 updateStaticCameraPosition();
192 private float transformScreenX(int screenX) {
193 return getWidth() / Gdx.graphics.getWidth() * screenX;
196 private float transformScreenY(int screenY) {
197 return getHeight() / Gdx.graphics.getHeight() * screenY;
200 private void handleMousePosition() {
201 final Rectangle viewport = getCameraViewport();
203 final float screenX = transformScreenX(Gdx.input.getX());
204 final float screenY = transformScreenY(Gdx.input.getY());
206 final MouseInputAction action = new MouseInputAction(
207 screenX,
208 screenY,
209 MouseInputActionKey.None.INSTANCE,
210 viewport);
212 mCursorMouseInputHandler.handle(action);
214 if (!mTooltipManager.getCurrentMouseTooltip().isEmpty()) {
215 RenderingUtilsKt.drawString(spriter, mTooltipManager.getCurrentMouseTooltip(), screenX + 1, screenY + 1, Color.BLACK);
216 RenderingUtilsKt.drawString(spriter, mTooltipManager.getCurrentMouseTooltip(), screenX, screenY, Color.WHITE);
220 private boolean handleMouseAction(@CheckForNull MouseInputAction action) {
221 if (action == null) {
222 return false;
225 boolean anyProcessed = false;
227 for (IGameInputHandler<MouseInputAction> handler : mMouseInputHandlers) {
228 final boolean conditions = handler.checkConditions(action);
229 if (conditions) {
230 anyProcessed = true;
231 handler.handle(action);
232 break;
234 // anyProcessed = anyProcessed || conditions;
236 return anyProcessed;
239 private boolean onMouseActionEvent(int mouseX, int mouseY, int button, boolean touchUp, int pointer) {
240 @CheckForNull MouseInputAction action = mMouseInputActionMapper
241 .map((float) mouseX, (float) mouseY, getCameraViewport(), button, touchUp, pointer);
242 return handleMouseAction(action);
245 @Override
246 public boolean touchUp(int screenX, int screenY, int pointer, int button) {
247 float touchX = transformScreenX(screenX);
248 float touchY = transformScreenY(screenY);
250 final Joystick joy = mMainConfig.getJoystick();
252 if (mMainConfig.isTouch()) {
253 if (joy != null && joy.getActive() && joy.getPointer() == pointer) {
254 return onMouseActionEvent(screenX, screenY, nullButton.getCode(), true, pointer);
257 TouchButton touchedKey = getTouchedKey(touchX, touchY);
258 if (touchedKey.isMouse()) {
259 return onMouseActionEvent(screenX, screenY, touchedKey.getCode(), true, pointer);
260 } else {
261 return keyUp(touchedKey.getCode());
265 return onMouseActionEvent(screenX, screenY, button, true, pointer);
268 private TouchButton getTouchedKey(float touchX, float touchY) {
269 if (mGameWindowsManager.getCurrentWindowType() != GameUiWindow.NONE) {
270 return nullButton;
272 for (ObjectMap.Entry<String, TouchButton> entry : Assets.guiMap) {
273 TouchButton button = entry.value;
274 if (button.getRect().contains(touchX, touchY)) {
275 return button;
279 if (mouseLeftTouchButton.getRect().contains(touchX, touchY)) {
280 return mouseLeftTouchButton;
283 if (mouseRightTouchButton.getRect().contains(touchX, touchY)) {
284 return mouseRightTouchButton;
287 return nullButton;
290 @Override
291 public boolean touchDown(int screenX, int screenY, int pointer, int button) {
292 float touchX = transformScreenX(screenX);
293 float touchY = transformScreenY(screenY);
295 mTouchDownX = touchX;
296 mTouchDownY = touchY;
298 if (mMainConfig.isTouch()) {
299 TouchButton touchedKey = getTouchedKey(touchX, touchY);
300 if (touchedKey.isMouse()) {
301 return onMouseActionEvent(screenX, screenY, touchedKey.getCode(), false, pointer);
302 } else {
303 return keyDown(touchedKey.getCode());
307 return onMouseActionEvent(screenX, screenY, button, false, pointer);
310 @Override
311 public boolean touchDragged(int screenX, int screenY, int pointer) {
312 float touchX = transformScreenX(screenX);
313 float touchY = transformScreenY(screenY);
315 if (Math.abs(touchX - mTouchDownX) < 16 && Math.abs(touchY - mTouchDownY) < DRAG_THRESHOLD) {
316 return false;
319 @CheckForNull MouseInputAction action =
320 mMouseInputActionMapper.mapDragged(screenX, screenY, getCameraViewport(), pointer);
321 return handleMouseAction(action);
324 @Override
325 public boolean scrolled(float amountX, float amountY) {
326 @CheckForNull MouseInputAction action = mMouseInputActionMapper
327 .mapScrolled(Gdx.input.getX(), Gdx.input.getY(), amountX, amountY, getCameraViewport());
328 return handleMouseAction(action);
331 private boolean handleKeyboardAction(int keycode, boolean isKeyDown) {
332 @CheckForNull final KeyboardInputAction action = mKeyboardInputActionMapper
333 .map(keycode, isKeyDown);
335 if (action == null) {
336 return false;
339 boolean anyProcessed = false;
341 for (IGameInputHandler<KeyboardInputAction> handler : mKeyboardInputHandlers) {
342 final boolean conditions = handler.checkConditions(action);
343 if (conditions) {
344 anyProcessed = true;
345 handler.handle(action);
346 break;
350 return anyProcessed;
353 @Override
354 public boolean keyDown(int keycode) {
355 return handleKeyboardAction(keycode, true);
358 @Override
359 public boolean keyUp(int keycode) {
360 return handleKeyboardAction(keycode, false);
363 @Override
364 public void render(float delta) {
365 updateCameraPosition(delta);
367 if (mMainConfig.getJoystick() != null && mMainConfig.getJoystick().getActive()) {
368 mMainConfig.getJoystick().updateState(
369 transformScreenX(Gdx.input.getX(mMainConfig.getJoystick().getPointer())),
370 transformScreenY(Gdx.input.getY(mMainConfig.getJoystick().getPointer()))
371 );
374 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
376 spriter.begin();
377 mRenderers.forEach(iGameRenderer -> iGameRenderer.draw(spriter, shaper, getCameraViewport(), delta));
378 handleMousePosition();
379 spriter.end();