diff --git a/core/src/main/assets/splashes/title/archs.png b/core/src/main/assets/splashes/title/archs.png new file mode 100644 index 000000000..cefda217e Binary files /dev/null and b/core/src/main/assets/splashes/title/archs.png differ diff --git a/core/src/main/assets/splashes/title/back_clusters.png b/core/src/main/assets/splashes/title/back_clusters.png new file mode 100644 index 000000000..73e1f7492 Binary files /dev/null and b/core/src/main/assets/splashes/title/back_clusters.png differ diff --git a/core/src/main/assets/splashes/title/front_small.png b/core/src/main/assets/splashes/title/front_small.png new file mode 100644 index 000000000..547078333 Binary files /dev/null and b/core/src/main/assets/splashes/title/front_small.png differ diff --git a/core/src/main/assets/splashes/title/mid_mixed.png b/core/src/main/assets/splashes/title/mid_mixed.png new file mode 100644 index 000000000..30c31b9dc Binary files /dev/null and b/core/src/main/assets/splashes/title/mid_mixed.png differ diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java index c20806af6..00a58af68 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java @@ -249,6 +249,13 @@ public class Assets { public static final String CAVES = "splashes/caves.jpg"; public static final String CITY = "splashes/city.jpg"; public static final String HALLS = "splashes/halls.jpg"; + + public static class Title { + public static final String ARCHS = "splashes/title/archs.png"; + public static final String BACK_CLUSTERS = "splashes/title/back_clusters.png"; + public static final String MID_MIXED = "splashes/title/mid_mixed.png"; + public static final String FRONT_SMALL = "splashes/title/front_small.png"; + } } public static class Sprites { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AboutScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AboutScene.java index a06c3f435..49470e0b8 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AboutScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AboutScene.java @@ -23,9 +23,9 @@ package com.shatteredpixel.shatteredpixeldungeon.scenes; import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon; import com.shatteredpixel.shatteredpixeldungeon.effects.Flare; -import com.shatteredpixel.shatteredpixeldungeon.ui.Archs; import com.shatteredpixel.shatteredpixeldungeon.ui.ExitButton; import com.shatteredpixel.shatteredpixeldungeon.ui.Icons; +import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground; import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; import com.shatteredpixel.shatteredpixeldungeon.ui.ScrollPane; import com.shatteredpixel.shatteredpixeldungeon.ui.Window; @@ -52,9 +52,8 @@ public class AboutScene extends PixelScene { RectF insets = getCommonInsets(); - Archs archs = new Archs(); - archs.setSize( w, h ); - add( archs ); + TitleBackground BG = new TitleBackground( w, h ); + add( BG ); //darkens the arches add(new ColorBlock(w, h, 0x88000000)); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/ChangesScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/ChangesScene.java index ab762c1b2..3361a6106 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/ChangesScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/ChangesScene.java @@ -27,9 +27,9 @@ import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon; import com.shatteredpixel.shatteredpixeldungeon.messages.Languages; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite; -import com.shatteredpixel.shatteredpixeldungeon.ui.Archs; import com.shatteredpixel.shatteredpixeldungeon.ui.ExitButton; import com.shatteredpixel.shatteredpixeldungeon.ui.Icons; +import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground; import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; import com.shatteredpixel.shatteredpixeldungeon.ui.ScrollPane; import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton; @@ -82,9 +82,8 @@ public class ChangesScene extends PixelScene { RectF insets = getCommonInsets(); - Archs archs = new Archs(); - archs.setSize(w, h); - //archs added later + TitleBackground BG = new TitleBackground(w, h); + //background added later w -= insets.left + insets.right; h -= insets.top + insets.bottom; @@ -350,7 +349,7 @@ public class ChangesScene extends PixelScene { btnOld.setRect(btn0_6.right()-2, btn0_8.top(), 22, changesSelected == 7 ? 19 : 15); addToBack(btnOld); - addToBack( archs ); + addToBack( BG ); fadeIn(); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java index 96a19ac09..1221b955a 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java @@ -44,6 +44,7 @@ import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.ui.GameLog; import com.shatteredpixel.shatteredpixeldungeon.ui.IconButton; import com.shatteredpixel.shatteredpixeldungeon.ui.Icons; +import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground; import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton; import com.shatteredpixel.shatteredpixeldungeon.windows.WndError; @@ -164,6 +165,7 @@ public class InterlevelScene extends PixelScene { int region = (int)Math.ceil(loadingDepth / 5f); if (region != lastRegion){ TextureCache.clear(); + TitleBackground.reset(); lastRegion = region; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/JournalScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/JournalScene.java index 361374e07..b73b8808a 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/JournalScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/JournalScene.java @@ -34,10 +34,10 @@ import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; import com.shatteredpixel.shatteredpixeldungeon.tiles.TerrainFeaturesTilemap; -import com.shatteredpixel.shatteredpixeldungeon.ui.Archs; import com.shatteredpixel.shatteredpixeldungeon.ui.ExitButton; import com.shatteredpixel.shatteredpixeldungeon.ui.IconButton; import com.shatteredpixel.shatteredpixeldungeon.ui.Icons; +import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground; import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton; import com.shatteredpixel.shatteredpixeldungeon.windows.IconTitle; import com.shatteredpixel.shatteredpixeldungeon.windows.WndJournal; @@ -82,9 +82,8 @@ public class JournalScene extends PixelScene { RectF insets = getCommonInsets(); - Archs archs = new Archs(); - archs.setSize( w, h ); - //archs added later + TitleBackground BG = new TitleBackground(w, h); + //BG added later w -= insets.left + insets.right; h -= insets.top + insets.bottom; @@ -228,7 +227,7 @@ public class JournalScene extends PixelScene { if (lastIDX != 3) btnAlchemy.icon().brightness(0.6f); addToBack(btnAlchemy); - addToBack(archs); + addToBack(BG); ExitButton btnExit = new ExitButton(); btnExit.setPos( insets.left + w - btnExit.width(), insets.top ); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/NewsScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/NewsScene.java index 5fabd82a0..14014647c 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/NewsScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/NewsScene.java @@ -29,9 +29,9 @@ import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.services.news.News; import com.shatteredpixel.shatteredpixeldungeon.services.news.NewsArticle; import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite; -import com.shatteredpixel.shatteredpixeldungeon.ui.Archs; import com.shatteredpixel.shatteredpixeldungeon.ui.ExitButton; import com.shatteredpixel.shatteredpixeldungeon.ui.Icons; +import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground; import com.shatteredpixel.shatteredpixeldungeon.ui.RedButton; import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton; @@ -64,9 +64,8 @@ public class NewsScene extends PixelScene { int h = Camera.main.height; RectF insets = getCommonInsets(); - Archs archs = new Archs(); - archs.setSize(w, h); - add(archs); + TitleBackground BG = new TitleBackground(w, h); + add(BG); w -= insets.left + insets.right; h -= insets.top + insets.bottom; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/PixelScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/PixelScene.java index f29552080..16187363c 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/PixelScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/PixelScene.java @@ -28,6 +28,7 @@ import com.shatteredpixel.shatteredpixeldungeon.SPDSettings; import com.shatteredpixel.shatteredpixeldungeon.effects.BadgeBanner; import com.shatteredpixel.shatteredpixeldungeon.messages.Languages; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; +import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground; import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; import com.shatteredpixel.shatteredpixeldungeon.ui.Tooltip; import com.shatteredpixel.shatteredpixeldungeon.ui.Window; @@ -102,6 +103,7 @@ public class PixelScene extends Scene { if (!inGameScene && InterlevelScene.lastRegion != -1){ InterlevelScene.lastRegion = -1; TextureCache.clear(); + TitleBackground.reset(); //good time to clear holiday cache as well Holiday.clearCachedHoliday(); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/RankingsScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/RankingsScene.java index e54c0e8ea..d6b730a1b 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/RankingsScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/RankingsScene.java @@ -32,12 +32,12 @@ import com.shatteredpixel.shatteredpixeldungeon.effects.Flare; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; -import com.shatteredpixel.shatteredpixeldungeon.ui.Archs; import com.shatteredpixel.shatteredpixeldungeon.ui.Button; import com.shatteredpixel.shatteredpixeldungeon.ui.ExitButton; import com.shatteredpixel.shatteredpixeldungeon.ui.IconButton; import com.shatteredpixel.shatteredpixeldungeon.ui.Icons; import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; +import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground; import com.shatteredpixel.shatteredpixeldungeon.ui.Window; import com.shatteredpixel.shatteredpixeldungeon.windows.IconTitle; import com.shatteredpixel.shatteredpixeldungeon.windows.WndDailies; @@ -58,8 +58,6 @@ public class RankingsScene extends PixelScene { private static final float MAX_ROW_WIDTH = 160; private static final float GAP = 4; - - private Archs archs; @Override public void create() { @@ -77,9 +75,8 @@ public class RankingsScene extends PixelScene { int h = Camera.main.height; RectF insets = getCommonInsets(); - archs = new Archs(); - archs.setSize( w, h ); - add( archs ); + TitleBackground BG = new TitleBackground(w, h); + add( BG ); w -= insets.left + insets.right; h -= insets.top + insets.bottom; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/StartScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/StartScene.java index 9086f0dd7..0c61dc106 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/StartScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/StartScene.java @@ -29,10 +29,10 @@ import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass; import com.shatteredpixel.shatteredpixeldungeon.journal.Journal; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; -import com.shatteredpixel.shatteredpixeldungeon.ui.Archs; import com.shatteredpixel.shatteredpixeldungeon.ui.Button; import com.shatteredpixel.shatteredpixeldungeon.ui.ExitButton; import com.shatteredpixel.shatteredpixeldungeon.ui.Icons; +import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground; import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton; import com.shatteredpixel.shatteredpixeldungeon.ui.Window; @@ -64,10 +64,9 @@ public class StartScene extends PixelScene { int w = Camera.main.width; int h = Camera.main.height; RectF insets = getCommonInsets(); - - Archs archs = new Archs(); - archs.setSize( w, h ); - add( archs ); + + TitleBackground BG = new TitleBackground(w, h); + add( BG ); w -= insets.left + insets.right; h -= insets.top + insets.bottom; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SupporterScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SupporterScene.java index f7f9213f6..0ed8f1db5 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SupporterScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SupporterScene.java @@ -25,9 +25,9 @@ import com.shatteredpixel.shatteredpixeldungeon.Chrome; import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon; import com.shatteredpixel.shatteredpixeldungeon.messages.Languages; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; -import com.shatteredpixel.shatteredpixeldungeon.ui.Archs; import com.shatteredpixel.shatteredpixeldungeon.ui.ExitButton; import com.shatteredpixel.shatteredpixeldungeon.ui.Icons; +import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground; import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton; import com.shatteredpixel.shatteredpixeldungeon.ui.Window; @@ -56,9 +56,8 @@ public class SupporterScene extends PixelScene { int elementWidth = PixelScene.landscape() ? 202 : 120; - Archs archs = new Archs(); - archs.setSize(w, h); - add(archs); + TitleBackground BG = new TitleBackground(w, h); + add(BG); w -= insets.right + insets.left; h -= insets.top + insets.bottom; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SurfaceScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SurfaceScene.java index 04097f055..cddd1244f 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SurfaceScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/SurfaceScene.java @@ -36,7 +36,7 @@ import com.shatteredpixel.shatteredpixeldungeon.sprites.EarthGuardianSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.GhostSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.RatSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.WardSprite; -import com.shatteredpixel.shatteredpixeldungeon.ui.Archs; +import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground; import com.shatteredpixel.shatteredpixeldungeon.ui.RedButton; import com.watabou.gltextures.SmartTexture; import com.watabou.gltextures.TextureCache; @@ -98,11 +98,9 @@ public class SurfaceScene extends PixelScene { int h = Camera.main.height; RectF insets = getCommonInsets(); - - Archs archs = new Archs(); - archs.reversed = true; - archs.setSize( w, h ); - add( archs ); + + TitleBackground BG = new TitleBackground(w, h); + add( BG ); w -= insets.left + insets.right; h -= insets.top + insets.bottom; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java index 9f2a52151..80eb580dd 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java @@ -36,10 +36,10 @@ import com.shatteredpixel.shatteredpixeldungeon.services.news.News; import com.shatteredpixel.shatteredpixeldungeon.services.updates.AvailableUpdateData; import com.shatteredpixel.shatteredpixeldungeon.services.updates.Updates; import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite; -import com.shatteredpixel.shatteredpixeldungeon.ui.Archs; import com.shatteredpixel.shatteredpixeldungeon.ui.ExitButton; import com.shatteredpixel.shatteredpixeldungeon.ui.Icons; import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton; +import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground; import com.shatteredpixel.shatteredpixeldungeon.ui.Window; import com.shatteredpixel.shatteredpixeldungeon.windows.WndOptions; import com.shatteredpixel.shatteredpixeldungeon.windows.WndSettings; @@ -75,9 +75,8 @@ public class TitleScene extends PixelScene { RectF insets = getCommonInsets(); - Archs archs = new Archs(); - archs.setSize( w, h ); - add( archs ); + TitleBackground BG = new TitleBackground( w, h ); + add( BG ); w -= insets.left + insets.right; h -= insets.top + insets.bottom; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java index 429af253b..569fd07c1 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java @@ -34,8 +34,8 @@ import com.shatteredpixel.shatteredpixeldungeon.effects.Fireball; import com.shatteredpixel.shatteredpixeldungeon.journal.Document; import com.shatteredpixel.shatteredpixeldungeon.journal.Journal; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; -import com.shatteredpixel.shatteredpixeldungeon.ui.Archs; import com.shatteredpixel.shatteredpixeldungeon.ui.Icons; +import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground; import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton; import com.shatteredpixel.shatteredpixeldungeon.windows.WndError; @@ -97,9 +97,8 @@ public class WelcomeScene extends PixelScene { int h = Camera.main.height; RectF insets = getCommonInsets(); - Archs archs = new Archs(); - archs.setSize( w, h ); - add( archs ); + TitleBackground BG = new TitleBackground(w, h); + add( BG ); //darkens the arches add(new ColorBlock(w, h, 0x88000000)); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TitleBackground.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TitleBackground.java new file mode 100644 index 000000000..7b6840df5 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TitleBackground.java @@ -0,0 +1,570 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2025 Evan Debenham + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package com.shatteredpixel.shatteredpixeldungeon.ui; + +import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.watabou.gltextures.TextureCache; +import com.watabou.noosa.Game; +import com.watabou.noosa.Group; +import com.watabou.noosa.Image; +import com.watabou.noosa.TextureFilm; +import com.watabou.noosa.ui.Component; +import com.watabou.utils.Random; +import com.watabou.utils.RectF; + +import java.util.ArrayList; + +public class TitleBackground extends Component { + + public static float SCROLL_SPEED = 15f; + + private float density = 1f; + + //Arch back layer + private static final TextureFilm ARCH_FILM = new TextureFilm(Assets.Splashes.Title.ARCHS, 333, 100); + private static Group archLayer; + private static ArrayList archs; + + //Cluster far layer + private static TextureFilm CLUSTER_FILM = new TextureFilm(Assets.Splashes.Title.BACK_CLUSTERS, 450, 250); + private static ArrayList clusters; + private static Group clusterLayer; + + //Mixed Item middle layer 1 + private static TextureFilm MID_FILM = new TextureFilm(Assets.Splashes.Title.MID_MIXED, 273, 242); + private static ArrayList mids1; + private static Group mids1Layer; + //Mixed Item middle layer 2 + private static ArrayList mids2; + private static Group mids2Layer; + + //Small Item front layer + private static TextureFilm SMALL_FILM = new TextureFilm(Assets.Splashes.Title.FRONT_SMALL, 112, 116); + private static ArrayList smalls; + private static Group smallLayer; + + private static boolean wasLandscape; + private static float oldBaseScale = 1; + private static float oldWidth = 0; + + public static void reset(){ + archs = null; + clusters = null; + mids1 = null; + mids2 = null; + smalls = null; + } + + public TitleBackground(int width, int height){ + super(); + x = y = 0; + this.width = width; + this.height = height; + setupObjects(); + } + + protected void setupObjects() { + + boolean landscape = width > height; + + float scale = height / 450f; + + //we reset in this case as scale changes + if (archs != null && (landscape != wasLandscape)){ + archs = null; + clusters = null; + mids1 = null; + mids2 = null; + smalls = null; + } + wasLandscape = landscape; + + archLayer = new Group(); + if (archs == null) { + archs = new ArrayList<>(); + } else { + convertArchLayer(archs, archLayer, scale); + } + add(archLayer); + + Image darkness = new Image(TextureCache.createGradient(0x00000000, 0x11000000, 0x22000000, 0x33000000, 0x44000000, 0x88000000)); + darkness.angle = 90; + darkness.x = width; + darkness.scale.x = height/6f; + darkness.scale.y = width; + add(darkness); + + if (!landscape){ + scale /= 1.5f; + oldBaseScale /= 1.5f; + } + + density = width / (800f * scale); + density = (density+0.5f)/1.5f; //pull density 33% of the way toward 1 if it is beyond it + + clusterLayer = new Group(); + if (clusters == null) { + clusters = new ArrayList<>(); + } else { + convertFloatingLayer(clusters, clusterLayer, scale, oldWidth); + } + add(clusterLayer); + + mids1Layer = new Group(); + if (mids1 == null){ + mids1 = new ArrayList<>(); + } else { + convertFloatingLayer(mids1, mids1Layer, scale, oldWidth); + } + add(mids1Layer); + + mids2Layer = new Group(); + if (mids2 == null){ + mids2 = new ArrayList<>(); + } else { + convertFloatingLayer(mids2, mids2Layer, scale, oldWidth); + } + add(mids2Layer); + + smallLayer = new Group(); + if (smalls == null){ + smalls = new ArrayList<>(); + } else { + convertFloatingLayer(smalls, smallLayer, scale, oldWidth); + } + add(smallLayer); + + oldWidth = width/scale; + if (!landscape){ + scale *= 1.5f; + } + oldBaseScale = scale; + + } + + //*** Logic for converting images between scene resets. *** + + //creates a new instance of a disposed of image, for recreation of this component after scene transition + protected Image convertImage(Image oldImg, float newBaseScale){ + Image newImg = new Image(oldImg.texture); + newImg.frame(oldImg.frame()); + float oldScale = oldImg.scale.x / oldBaseScale; + newImg.scale.set(newBaseScale*oldScale); + newImg.brightness(oldImg.rm); + float scaleDiff = newImg.scale.y / oldImg.scale.y; + newImg.x = oldImg.x * scaleDiff; + newImg.y = oldImg.y * scaleDiff; + newImg.angle = oldImg.angle; + return newImg; + } + + protected void convertArchLayer(ArrayList layerList, Group layerGroup, float newBaseScale){ + ArrayList oldImages = new ArrayList<>(layerList); + layerList.clear(); + float rightMost = 0; + for (int i = 0; i < oldImages.size(); i++){ + Image oldArch = oldImages.get(i); + Image newArch = convertImage(oldArch, newBaseScale); + layerList.add(newArch); + layerGroup.add(newArch); + rightMost = Math.max(rightMost, newArch.x + newArch.width()); + //if we're at the end of a row and haven't hit the end yet, add more archs! + while (newArch.x+newArch.width() < width + && (i == oldImages.size()-1 || oldImages.get(i+1).y > oldArch.y)){ + Image extraArch = new Image(Assets.Splashes.Title.ARCHS); + extraArch.frame(getArchFrame()); + extraArch.scale.set(newBaseScale); + extraArch.x = newArch.x + newArch.width(); + extraArch.x -= 9 * newArch.scale.x; //still want to inset here + extraArch.y = newArch.y; //y inset already done + layerList.add(extraArch); + layerGroup.add(extraArch); + newArch = extraArch; + } + } + } + + protected void convertFloatingLayer(ArrayList layerList, Group layerGroup, float newBaseScale, float oldWidth){ + ArrayList oldImages = new ArrayList<>(layerList); + layerList.clear(); + + float xShift = (width()/newBaseScale)/oldWidth; + for (int i = 0; i < oldImages.size(); i++){ + Image oldImage = oldImages.get(i); + Image newImage = convertImage(oldImage, newBaseScale); + if (newImage.x > 0) { + newImage.x *= xShift; + } + layerList.add(newImage); + layerGroup.add(newImage); + } + } + + ArrayList toMove = new ArrayList<>(); + + @Override + public synchronized void update() { + super.update(); + + float scale = height / 450f; + float shift = Game.elapsed * SCROLL_SPEED * scale; + + updateArchLayer(scale, shift); + if (width <= height){ + scale /= 1.5f; + } + shift *= 2f; + updateClusterLayer(scale, shift); + shift *= 1.5f; + updateMid1Layer(scale, shift); + shift *= 1.5f; + updateMid2Layer(scale, shift); + shift *= 1.5f; + updateFrontLayer(scale, shift); + + } + + //*** Arch layer logic *** + + private static final float[] INIT_ARCH_CHANCES = {5, 5, 2, 2, 2, 2}; + private static float[] arch_chances = INIT_ARCH_CHANCES.clone(); + + public RectF getArchFrame(){ + + int tile = Random.chances(arch_chances); + if (tile == -1){ + arch_chances = INIT_ARCH_CHANCES.clone(); + tile = Random.chances(arch_chances); + } + arch_chances[tile]--; + + return ARCH_FILM.get(tile); + } + + private void updateArchLayer(float scale, float shift){ + float bottom = 0; + + //pass over existing archs, raise them + for (Image arch : archs){ + arch.y -= shift; + if (arch.y + arch.height() < 0){ + toMove.add(arch); + } else if (arch.y + arch.height() > bottom){ + bottom = arch.y + arch.height(); + } + } + + //move any archs that scrolled off camera to the bottom + if (!toMove.isEmpty()){ + //we know it'll be one row + for (Image arch : toMove){ + arch.frame(getArchFrame()); + arch.y = bottom - 5*scale; + } + bottom += 100*scale; //arch height + toMove.clear(); + } + + //if we aren't low enough, add more arch layers + while (bottom < height){ + float left = archs.isEmpty() ? -Random.IntRange(5, 100) : archs.get(0).x; + while (left < width){ + Image arch = new Image(Assets.Splashes.Title.ARCHS); + arch.frame(getArchFrame()); + arch.scale.set(scale); + arch.x = left; + arch.y = bottom - 5*scale; + archLayer.add(arch); + archs.add(arch); + left += arch.width() - (9 * scale); + } + bottom += 100*scale; //arch height + } + + } + + //*** Cluster layer logic *** + + private static final float[] INIT_CLUSTER_CHANCES = {2, 2}; + private static float[] cluster_chances = INIT_CLUSTER_CHANCES.clone(); + + public RectF getClusterFrame(){ + + int tile = Random.chances(cluster_chances); + if (tile == -1){ + cluster_chances = INIT_CLUSTER_CHANCES.clone(); + tile = Random.chances(cluster_chances); + } + cluster_chances[tile]--; + + return CLUSTER_FILM.get(tile); + } + + private void updateClusterLayer(float scale, float shift){ + float bottom = 0; + float lastX = 0; + + for (Image cluster : clusters){ + cluster.y -= shift; + if (cluster.y + cluster.height() < -20){ + toMove.add(cluster); + } else if (cluster.y + cluster.height() > bottom){ + bottom = cluster.y + cluster.height(); + lastX = cluster.x; + } + } + + if (!toMove.isEmpty()){ + for (Image cluster : toMove){ + cluster.frame(getClusterFrame()); + float flex = 0; + do { + cluster.x = Random.Float(-cluster.width()/3f, width - 2*cluster.width()/3f); + flex += 1; + } while (Math.abs(cluster.x - lastX) < density*(cluster.width()/2f - flex)); + cluster.y = bottom - cluster.height() + Random.Float(cluster.height()/2f, cluster.height())/density; + cluster.angle = Random.Float(-20, 20); + bottom = cluster.y + cluster.height(); + lastX = cluster.x; + } + toMove.clear(); + } + + //clusters are 250 tall, add a bit for safety + float padding = 300 - (300/2f / density); + while (bottom < (height + padding)){ + Image cluster = new Image(Assets.Splashes.Title.BACK_CLUSTERS); + cluster.frame(getClusterFrame()); + cluster.scale.set(scale); + + float flex = 0; + do { + cluster.x = Random.Float(-cluster.width()/3f, width - 2*cluster.width()/3f); + flex += 1; + } while (Math.abs(cluster.x - lastX) < density*(cluster.width()/2f - flex)); + cluster.y = bottom - cluster.height() + Random.Float(cluster.height()/2f, cluster.height())/density; + cluster.angle = Random.Float(-20, 20); + + cluster.brightness(0.75f); + + clusters.add(cluster); + clusterLayer.add(cluster); + + bottom = cluster.y + cluster.height(); + lastX = cluster.x; + } + } + + //*** Mid layer (1 and 2) logic *** + + private static final float[] INIT_MID_CHANCES = {1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; + private static float[] mid_chances = INIT_MID_CHANCES.clone(); + + public RectF getMidFrame(){ + + int tile = Random.chances(mid_chances); + if (tile == -1){ + mid_chances = INIT_MID_CHANCES.clone(); + tile = Random.chances(mid_chances); + } + mid_chances[tile]--; + + return MID_FILM.get(tile); + } + + private void updateMid1Layer(float scale, float shift){ + float bottom = 0; + float lastX = 0; + + for (Image mid : mids1){ + mid.y -= shift; + if (mid.y + mid.height() < -20){ + toMove.add(mid); + } else if (mid.y + mid.height() > bottom){ + bottom = mid.y + mid.height(); + lastX = mid.x; + } + } + + if (!toMove.isEmpty()){ + for (Image mid : toMove){ + mid.frame(getMidFrame()); + float flex = 0; + do { + mid.x = Random.Float(-mid.width()/3f, width - 2*mid.width()/3f); + flex += 1; + } while (Math.abs(mid.x - lastX) < density*(mid.width()*0.75f - flex)); + mid.y = bottom - mid.height() + Random.Float(mid.height()*0.75f, mid.height())/density; + mid.angle = Random.Float(-20, 20); + bottom = mid.y + mid.height(); + lastX = mid.x; + } + toMove.clear(); + } + + //mids are ~250 tall, add a bit for safety + float padding = 300 - (300/2f / density); + while (bottom < (height + padding)){ + Image mid = new Image(Assets.Splashes.Title.MID_MIXED); + mid.frame(getMidFrame()); + mid.scale.set(scale * Random.Float(0.75f, 1.25f)); + + float flex = 0; + do { + mid.x = Random.Float(-mid.width()/3f, width - 2*mid.width()/3f); + flex += 1; + } while (Math.abs(mid.x - lastX) < density*(mid.width()*0.75f - flex)); + mid.y = bottom - mid.height() + Random.Float(mid.height()/2f, mid.height())/density; + mid.angle = Random.Float(-20, 20); + + mids1.add(mid); + mids1Layer.add(mid); + + bottom = mid.y + mid.height(); + lastX = mid.x; + } + } + + private void updateMid2Layer(float scale, float shift){ + float bottom = 0; + float lastX = 0; + + for (Image mid : mids2){ + mid.y -= shift; + if (mid.y + mid.height() < -20){ + toMove.add(mid); + } else if (mid.y + mid.height() > bottom){ + bottom = mid.y + mid.height(); + lastX = mid.x; + } + } + + if (!toMove.isEmpty()){ + for (Image mid : toMove){ + mid.frame(getMidFrame()); + float flex = 0; + do { + mid.x = Random.Float(-mid.width()/3f, width - 2*mid.width()/3f); + flex += 1; + } while (Math.abs(mid.x - lastX) < density*(mid.width()*0.75f - flex)); + mid.y = bottom - mid.height() + Random.Float(mid.height()/2f, mid.height())/density; + mid.angle = Random.Float(-20, 20); + bottom = mid.y + mid.height(); + lastX = mid.x; + } + toMove.clear(); + } + + //mids are ~250 tall, add a bit for safety + float padding = 300 - (300/2f / density); + while (bottom < (height + padding)){ + Image mid = new Image(Assets.Splashes.Title.MID_MIXED); + mid.frame(getMidFrame()); + mid.scale.set(scale * Random.Float(1.25f, 1.75f)); + + float flex = 0; + do { + mid.x = Random.Float(-mid.width()/3f, width - 2*mid.width()/3f); + flex += 1; + } while (Math.abs(mid.x - lastX) < density*(mid.width()*0.75f - flex)); + mid.y = bottom - mid.height() + Random.Float(mid.height()/2f, mid.height())/density; + mid.angle = Random.Float(-20, 20); + + mids2.add(mid); + mids2Layer.add(mid); + + bottom = mid.y + mid.height(); + lastX = mid.x; + } + } + + //*** Small front layer logic *** + + private static final float[] INIT_SMALL_CHANCES = {1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2}; + private static float[] small_chances = INIT_SMALL_CHANCES.clone(); + + public RectF getSmallFrame(){ + + int tile = Random.chances(small_chances); + if (tile == -1){ + small_chances = INIT_SMALL_CHANCES.clone(); + tile = Random.chances(small_chances); + } + small_chances[tile]--; + + return SMALL_FILM.get(tile); + } + + private void updateFrontLayer(float scale, float shift){ + float bottom = 0; + float lastX = 0; + + for (Image small : smalls){ + small.y -= shift; + if (small.y + small.height() < -20){ + toMove.add(small); + } else if (small.y + small.height() > bottom){ + bottom = small.y + small.height(); + lastX = small.x; + } + } + + if (!toMove.isEmpty()){ + for (Image small : toMove){ + small.frame(getSmallFrame()); + float flex = 0; + do { + small.x = Random.Float(-small.width()/3f, width - 2*small.width()/3f); + flex += 1; + } while (Math.abs(small.x - lastX) < density*(small.width() - flex)); + small.y = bottom - small.height() + Random.Float(small.height()/2f, small.height())/density; + small.angle = Random.Float(-20, 20); + bottom = small.y + small.height(); + lastX = small.x; + } + toMove.clear(); + } + + //smalls are ~115 tall, add a bit for safety + float padding = 150 - (150/2f / density); + while (bottom < (height + padding)){ + Image small = new Image(Assets.Splashes.Title.FRONT_SMALL); + small.frame(getSmallFrame()); + small.scale.set(scale * Random.Float(1.75f, 2.25f)); + + float flex = 0; + do { + small.x = Random.Float(-small.width()/3f, width - 2*small.width()/3f); + flex += 1; + } while (Math.abs(small.x - lastX) < density*(small.width() - flex)); + small.y = bottom - small.height() + Random.Float(small.height()/2f, small.height())/density; + small.angle = Random.Float(-20, 20); + + smalls.add(small); + smallLayer.add(small); + + bottom = small.y + small.height(); + lastX = small.x; + } + } + +}