From d4d4f21ba7f763bc28eb8f79977add26a670d50d Mon Sep 17 00:00:00 2001 From: fgnm Date: Wed, 26 Jun 2024 10:58:53 +0200 Subject: [PATCH] - Add Mini Map feature - Allow to extend `HyperLap2dRenderer` - Update copyright year --- CHANGES | 2 + hyperlap2d-common-api | 2 +- hyperlap2d-runtime-libgdx | 2 +- .../controller/BootstrapViewCommand.java | 1 + .../rednblack/editor/splash/SplashStage.java | 2 +- .../system/HyperLap2dRendererMiniMap.java | 71 +++++++++++++++++++ .../editor/utils/KeyBindingsLayout.java | 3 + .../editor/view/HyperLap2DScreen.java | 6 ++ .../rednblack/editor/view/stage/Sandbox.java | 6 +- .../editor/view/ui/dialog/AboutDialog.java | 2 +- .../editor/view/ui/dialog/MiniMapDialog.java | 64 +++++++++++++++++ .../view/ui/dialog/MiniMapDialogMediator.java | 43 +++++++++++ .../ui/widget/actors/basic/WhitePixel.java | 3 + 13 files changed, 202 insertions(+), 5 deletions(-) create mode 100644 src/main/java/games/rednblack/editor/system/HyperLap2dRendererMiniMap.java create mode 100644 src/main/java/games/rednblack/editor/view/ui/dialog/MiniMapDialog.java create mode 100644 src/main/java/games/rednblack/editor/view/ui/dialog/MiniMapDialogMediator.java diff --git a/CHANGES b/CHANGES index 93853c41..fb597343 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,7 @@ [0.1.5] - [BREAK CHANGE] Update Spine runtime support to `4.2.0` - Add Items Tree search filter +- Add Mini Map feature (press and hold keyboard `M` button) - Basic folder visualization for different atlas packages - Fix many editor memory leaks - Fix common crashes related to multi-thread issues @@ -8,6 +9,7 @@ **Runtime** - [BREAK CHANGE] Make `ZIndexComponent#layerName` field private - Optimize some built-in systems +- Allow to extend `HyperLap2dRenderer` and use custom rendering systems [0.1.4] - Update libGDX to 1.12.1 diff --git a/hyperlap2d-common-api b/hyperlap2d-common-api index 00ec5749..288141e3 160000 --- a/hyperlap2d-common-api +++ b/hyperlap2d-common-api @@ -1 +1 @@ -Subproject commit 00ec5749797633fea98216bdb0a07c62072ebb7a +Subproject commit 288141e3f9da3405fc8afb802b425c1e892c3b9f diff --git a/hyperlap2d-runtime-libgdx b/hyperlap2d-runtime-libgdx index b09d93de..db060b0d 160000 --- a/hyperlap2d-runtime-libgdx +++ b/hyperlap2d-runtime-libgdx @@ -1 +1 @@ -Subproject commit b09d93de8c8a3d12a3cc6798454a4512fcf675ed +Subproject commit db060b0d29c81d593b83c2fe563224ea41c93aff diff --git a/src/main/java/games/rednblack/editor/controller/BootstrapViewCommand.java b/src/main/java/games/rednblack/editor/controller/BootstrapViewCommand.java index f33eab26..257c27c6 100644 --- a/src/main/java/games/rednblack/editor/controller/BootstrapViewCommand.java +++ b/src/main/java/games/rednblack/editor/controller/BootstrapViewCommand.java @@ -94,6 +94,7 @@ public class BootstrapViewCommand extends SimpleCommand { facade.registerMediator(new ImagesPackDialogMediator()); facade.registerMediator(new AnimationsPackDialogMediator()); facade.registerMediator(new ShaderManagerDialogMediator()); + facade.registerMediator(new MiniMapDialogMediator()); facade.registerMediator(new SaveProjectDialogMediator()); } diff --git a/src/main/java/games/rednblack/editor/splash/SplashStage.java b/src/main/java/games/rednblack/editor/splash/SplashStage.java index 679bbbc9..514d339c 100644 --- a/src/main/java/games/rednblack/editor/splash/SplashStage.java +++ b/src/main/java/games/rednblack/editor/splash/SplashStage.java @@ -58,7 +58,7 @@ public class SplashStage extends Stage { companyName.setY(55 - companyName.getHeight() - 7); addActor(companyName); - Label copyright = new Label("Copyright (c) 2023, All rights reserved.", whiteLabelStyle); + Label copyright = new Label("Copyright (c) 2024, All rights reserved.", whiteLabelStyle); copyright.setX(13); copyright.setY(companyName.getY() - 20); addActor(copyright); diff --git a/src/main/java/games/rednblack/editor/system/HyperLap2dRendererMiniMap.java b/src/main/java/games/rednblack/editor/system/HyperLap2dRendererMiniMap.java new file mode 100644 index 00000000..67f39df6 --- /dev/null +++ b/src/main/java/games/rednblack/editor/system/HyperLap2dRendererMiniMap.java @@ -0,0 +1,71 @@ +package games.rednblack.editor.system; + +import com.artemis.annotations.All; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Camera; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.math.Rectangle; +import games.rednblack.editor.renderer.components.BoundingBoxComponent; +import games.rednblack.editor.renderer.components.NodeComponent; +import games.rednblack.editor.renderer.components.ViewPortComponent; +import games.rednblack.editor.renderer.systems.render.HyperLap2dRenderer; +import games.rednblack.editor.renderer.systems.render.logic.DrawableLogic; +import games.rednblack.editor.utils.runtime.SandboxComponentRetriever; + +@All(ViewPortComponent.class) +public class HyperLap2dRendererMiniMap extends HyperLap2dRenderer { + + private final Rectangle bounds = new Rectangle(); + + private final OrthographicCamera minimapCamera = new OrthographicCamera(); + + public HyperLap2dRendererMiniMap(Batch batch, boolean hasStencilBuffer) { + super(batch, hasStencilBuffer); + } + + public Texture getMiniMapTexture(int rootEntity) { + Camera oldCamera = camera; + camera = minimapCamera; + NodeComponent nodeComponent = nodeMapper.get(rootEntity); + bounds.set(0, 0, 0, 0); + Integer[] children = nodeComponent.children.begin(); + for (int i = 0, n = nodeComponent.children.size; i < n; i++) { + int child = children[i]; + BoundingBoxComponent boundingBoxComponent = SandboxComponentRetriever.get(child, BoundingBoxComponent.class); + if (boundingBoxComponent != null && boundingBoxComponent.rectangle != null) + bounds.merge(boundingBoxComponent.rectangle); + } + nodeComponent.children.end(); + + minimapCamera.setToOrtho(true, bounds.width, bounds.height); + minimapCamera.position.set(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2,0); + + Gdx.gl.glClearColor(0.318f, 0.318f, 0.318f, 1); + frameBufferManager.createIfNotExists("minimap", (int) (bounds.width * pixelsPerWU), (int) (bounds.height * pixelsPerWU), false, hasStencilBuffer); + frameBufferManager.begin("minimap"); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + minimapCamera.update(); + batch.setProjectionMatrix(minimapCamera.combined); + + drawableLogicMapper.beginPipeline(); + batch.begin(); + enableCull = false; + drawRecursively(rootEntity, 1f, DrawableLogic.RenderingType.TEXTURE); + enableCull = true; + batch.end(); + frameBufferManager.endCurrent(); + drawableLogicMapper.endPipeline(); + + camera = oldCamera; + + return frameBufferManager.getColorBufferTexture("minimap"); + } + + public Rectangle getMiniMapBounds() { + return bounds; + } +} diff --git a/src/main/java/games/rednblack/editor/utils/KeyBindingsLayout.java b/src/main/java/games/rednblack/editor/utils/KeyBindingsLayout.java index a721fa34..9dba5e51 100644 --- a/src/main/java/games/rednblack/editor/utils/KeyBindingsLayout.java +++ b/src/main/java/games/rednblack/editor/utils/KeyBindingsLayout.java @@ -61,6 +61,8 @@ public class KeyBindingsLayout { public static final int TOGGLE_FULL_SCREEN = 29; + public static final int SHOW_MINI_MAP = 30; + private static final ObjectMap defaultMapper = new ObjectMap<>(); static { defaultMapper.put(NEW_PROJECT, new KeyMapper(NEW_PROJECT, true, false, false, Input.Keys.N)); @@ -103,6 +105,7 @@ public class KeyBindingsLayout { defaultMapper.put(HIDE_GUI, new KeyMapper(HIDE_GUI, false, false, false, Input.Keys.F12)); defaultMapper.put(OPEN_CONSOLE, new KeyMapper(OPEN_CONSOLE, false, false, false, Input.Keys.F10)); defaultMapper.put(TOGGLE_FULL_SCREEN, new KeyMapper(TOGGLE_FULL_SCREEN, false, false, false, Input.Keys.F11)); + defaultMapper.put(SHOW_MINI_MAP, new KeyMapper(SHOW_MINI_MAP, false, false, false, Input.Keys.M)); } private static final Array mapping = new Array<>(); diff --git a/src/main/java/games/rednblack/editor/view/HyperLap2DScreen.java b/src/main/java/games/rednblack/editor/view/HyperLap2DScreen.java index 4592e6c9..76048075 100644 --- a/src/main/java/games/rednblack/editor/view/HyperLap2DScreen.java +++ b/src/main/java/games/rednblack/editor/view/HyperLap2DScreen.java @@ -241,6 +241,9 @@ public class HyperLap2DScreen implements Screen, InputProcessor { case KeyBindingsLayout.OPEN_CONSOLE: facade.sendNotification(MsgAPI.OPEN_CONSOLE); break; + case KeyBindingsLayout.SHOW_MINI_MAP: + facade.sendNotification(MsgAPI.SHOW_MINI_MAP); + break; } return false; } @@ -251,6 +254,9 @@ public class HyperLap2DScreen implements Screen, InputProcessor { case KeyBindingsLayout.HIDE_GUI: uiStage.addAction(Actions.parallel(Actions.touchable(Touchable.enabled), Actions.fadeIn(0.1f))); break; + case KeyBindingsLayout.SHOW_MINI_MAP: + facade.sendNotification(MsgAPI.HIDE_MINI_MAP); + break; } return false; } diff --git a/src/main/java/games/rednblack/editor/view/stage/Sandbox.java b/src/main/java/games/rednblack/editor/view/stage/Sandbox.java index 0bf510a4..ce27cafb 100644 --- a/src/main/java/games/rednblack/editor/view/stage/Sandbox.java +++ b/src/main/java/games/rednblack/editor/view/stage/Sandbox.java @@ -24,6 +24,7 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationGLESFix; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.math.Interpolation; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector2; @@ -48,6 +49,7 @@ import games.rednblack.editor.renderer.systems.ParticleSystem; import games.rednblack.editor.renderer.systems.PhysicsSystem; import games.rednblack.editor.renderer.utils.HyperJson; import games.rednblack.editor.renderer.utils.TextureArrayCpuPolygonSpriteBatch; +import games.rednblack.editor.system.HyperLap2dRendererMiniMap; import games.rednblack.editor.system.ParticleContinuousSystem; import games.rednblack.editor.system.PhysicsAdjustSystem; import games.rednblack.editor.system.TalosContinuousSystem; @@ -150,7 +152,8 @@ public class Sandbox { externalItemTypes.addExternalItemType(new TinyVGItemType()); externalItemTypes.addExternalItemType(new TypingLabelItemType()); - SceneConfiguration config = new SceneConfiguration(new TextureArrayCpuPolygonSpriteBatch(32_000), true); + Batch batch = new TextureArrayCpuPolygonSpriteBatch(32_767); + SceneConfiguration config = new SceneConfiguration(batch, true); config.setResourceRetriever(resourceManager); config.setExternalItemTypes(externalItemTypes); @@ -167,6 +170,7 @@ public class Sandbox { config.addSystem(new ParticleContinuousSystem()); config.removeSystem(TalosSystem.class); config.addSystem(new TalosContinuousSystem()); + config.setRendererSystem(new HyperLap2dRendererMiniMap(batch, true)); config.addSystem(manager); diff --git a/src/main/java/games/rednblack/editor/view/ui/dialog/AboutDialog.java b/src/main/java/games/rednblack/editor/view/ui/dialog/AboutDialog.java index e8d170ef..dae13f8e 100644 --- a/src/main/java/games/rednblack/editor/view/ui/dialog/AboutDialog.java +++ b/src/main/java/games/rednblack/editor/view/ui/dialog/AboutDialog.java @@ -54,7 +54,7 @@ public class AboutDialog extends H2DDialog { leftTable.add("Total Time").padTop(20).row(); leftTable.add(totalTimeSpent).row(); - contentTable.add("Copyright \u00A9 2023 Red & Black Games").left().row(); + contentTable.add("Copyright \u00A9 2024 Red & Black Games").left().row(); contentTable.add("").row(); contentTable.add("Dedicated to game lovers. Create something awesome!").left().row(); contentTable.add("").row(); diff --git a/src/main/java/games/rednblack/editor/view/ui/dialog/MiniMapDialog.java b/src/main/java/games/rednblack/editor/view/ui/dialog/MiniMapDialog.java new file mode 100644 index 00000000..4b816a64 --- /dev/null +++ b/src/main/java/games/rednblack/editor/view/ui/dialog/MiniMapDialog.java @@ -0,0 +1,64 @@ +package games.rednblack.editor.view.ui.dialog; + +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.ui.Image; +import com.badlogic.gdx.scenes.scene2d.ui.Table; +import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; +import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; +import com.badlogic.gdx.utils.Align; +import com.badlogic.gdx.utils.Scaling; +import com.kotcrab.vis.ui.VisUI; +import games.rednblack.editor.system.HyperLap2dRendererMiniMap; +import games.rednblack.editor.view.stage.Sandbox; + +public class MiniMapDialog extends Table { + private final TextureRegionDrawable drawable; + private final TextureRegion region; + private final Image miniMap; + + private Rectangle miniMapBounds; + + public MiniMapDialog() { + drawable = new TextureRegionDrawable(); + region = new TextureRegion(); + drawable.setRegion(region); + miniMap = new Image(drawable); + miniMap.addListener(new ClickListener() { + private final Vector2 touchPoint = new Vector2(); + + @Override + public void clicked(InputEvent event, float x, float y) { + touchPoint.set(x - miniMap.getImageX(), y - miniMap.getImageY()); + + float relativeX = (touchPoint.x) / miniMap.getImageWidth(); + float relativeY = (touchPoint.y) / miniMap.getImageHeight(); + + float transformedX = miniMapBounds.x + relativeX * miniMapBounds.width; + float transformedY = miniMapBounds.y + relativeY * miniMapBounds.height; + + Sandbox.getInstance().panSceneTo(transformedX, transformedY); + } + }); + miniMap.setAlign(Align.center); + add(miniMap); + + setBackground(VisUI.getSkin().getDrawable("panel")); + } + + public void update() { + Sandbox sandbox = Sandbox.getInstance(); + HyperLap2dRendererMiniMap rendererMiniMap = sandbox.getEngine().getSystem(HyperLap2dRendererMiniMap.class); + + Texture texture = rendererMiniMap.getMiniMapTexture(sandbox.getRootEntity()); + region.setRegion(texture); + drawable.setRegion(region); + miniMap.setScaling(Scaling.contain); + miniMap.setDrawable(drawable); + + miniMapBounds = rendererMiniMap.getMiniMapBounds(); + } +} diff --git a/src/main/java/games/rednblack/editor/view/ui/dialog/MiniMapDialogMediator.java b/src/main/java/games/rednblack/editor/view/ui/dialog/MiniMapDialogMediator.java new file mode 100644 index 00000000..0db3bdf6 --- /dev/null +++ b/src/main/java/games/rednblack/editor/view/ui/dialog/MiniMapDialogMediator.java @@ -0,0 +1,43 @@ +package games.rednblack.editor.view.ui.dialog; + +import com.badlogic.gdx.utils.Align; +import games.rednblack.editor.view.stage.Sandbox; +import games.rednblack.editor.view.stage.UIStage; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.puremvc.Mediator; +import games.rednblack.puremvc.interfaces.INotification; +import games.rednblack.puremvc.util.Interests; + +public class MiniMapDialogMediator extends Mediator { + private static final String TAG = MiniMapDialogMediator.class.getCanonicalName(); + private static final String NAME = TAG; + + public MiniMapDialogMediator() { + super(NAME, new MiniMapDialog()); + } + + @Override + public void listNotificationInterests(Interests interests) { + interests.add(MsgAPI.SHOW_MINI_MAP, MsgAPI.HIDE_MINI_MAP); + } + + @Override + public void handleNotification(INotification notification) { + super.handleNotification(notification); + Sandbox sandbox = Sandbox.getInstance(); + UIStage uiStage = sandbox.getUIStage(); + + switch (notification.getName()) { + case MsgAPI.SHOW_MINI_MAP: + viewComponent.setSize(uiStage.getWidth() * 0.6f, uiStage.getHeight() * 0.6f); + viewComponent.setOrigin(Align.center); + viewComponent.update(); + uiStage.addActor(viewComponent); + viewComponent.setPosition((uiStage.getWidth() - viewComponent.getWidth()) / 2, (uiStage.getHeight() - viewComponent.getHeight()) / 2); + break; + case MsgAPI.HIDE_MINI_MAP: + viewComponent.remove(); + break; + } + } +} diff --git a/src/main/java/games/rednblack/editor/view/ui/widget/actors/basic/WhitePixel.java b/src/main/java/games/rednblack/editor/view/ui/widget/actors/basic/WhitePixel.java index 80f04775..c760ddfa 100644 --- a/src/main/java/games/rednblack/editor/view/ui/widget/actors/basic/WhitePixel.java +++ b/src/main/java/games/rednblack/editor/view/ui/widget/actors/basic/WhitePixel.java @@ -4,6 +4,7 @@ import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; public class WhitePixel { public static WhitePixel sharedInstance; @@ -18,6 +19,7 @@ public class WhitePixel { public Texture texture; public TextureRegion textureRegion; + public TextureRegionDrawable drawable; public WhitePixel() { Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888); @@ -27,6 +29,7 @@ public class WhitePixel { texture = new Texture(pixmap, true); texture.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.MipMapLinearLinear); textureRegion = new TextureRegion(texture); + drawable = new TextureRegionDrawable(textureRegion); } public void dispose() {