diff --git a/build.gradle b/build.gradle index 8ffaf74..988bb05 100644 --- a/build.gradle +++ b/build.gradle @@ -30,6 +30,14 @@ application { mainClassName = "de.siphalor.was.Start" } +sourceSets { + main { + resources { + exclude '**/*.svg' + } + } +} + jar { manifest { attributes( diff --git a/src/main/java/de/siphalor/was/WhatAStorage.java b/src/main/java/de/siphalor/was/WhatAStorage.java index edb3235..1ed8935 100644 --- a/src/main/java/de/siphalor/was/WhatAStorage.java +++ b/src/main/java/de/siphalor/was/WhatAStorage.java @@ -6,20 +6,22 @@ import de.siphalor.was.content.pack.FileContentPack; import de.siphalor.was.content.pack.JarContentPack; import de.siphalor.was.content.product.ProductManager; import de.siphalor.was.content.quest.QuestManager; -import de.siphalor.was.state.MainMenuState; +import de.siphalor.was.state.GameState; +import de.siphalor.was.state.NoopState; import de.siphalor.was.state.State; +import de.siphalor.was.visual.layout.FixedAspectLayout; +import de.siphalor.was.visual.layout.FulfillingLayout; import java.awt.*; -import java.awt.event.ComponentAdapter; -import java.awt.event.ComponentEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; +import java.awt.event.*; +import java.awt.image.BufferStrategy; import java.io.File; import java.nio.file.Path; public class WhatAStorage { public static final String TITLE = "What a Storage"; private static final WhatAStorage INSTANCE = new WhatAStorage(); + private static final double ASPECT_RATIO = 16.0 / 9.0; public static WhatAStorage getInstance() { return INSTANCE; @@ -31,11 +33,13 @@ public class WhatAStorage { private final QuestManager questManager; private Frame frame; - private State state; - - private long lastTick; - private long minTickTime = 1000 / 60; private Canvas canvas; + private boolean fullScreen = false; + private BufferStrategy bufferStrategy; + private State state = new NoopState(); + + private boolean scheduleStop; + private long minTickTime = 1000 / 60; private WhatAStorage() { contentManager = new ContentManager(); @@ -79,43 +83,109 @@ public class WhatAStorage { public void start() { frame = new Frame(TITLE); - frame.setVisible(true); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { super.windowClosing(e); - frame.dispose(); + scheduleStop = true; } }); frame.addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { super.componentResized(e); - canvas.setSize(frame.getSize()); - state.onResize(frame.getWidth(), frame.getHeight()); + state.onResize(canvas.getWidth(), canvas.getHeight()); } }); - canvas = new Canvas(); - canvas.setSize(frame.getSize()); - frame.add(canvas); + frame.addKeyListener(new KeyListener() { + @Override + public void keyTyped(KeyEvent e) { - changeState(new MainMenuState(canvas.getWidth(), canvas.getHeight())); + } + + @Override + public void keyPressed(KeyEvent e) { + if (e.getExtendedKeyCode() == KeyEvent.VK_F11) { + GraphicsDevice device = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()[0]; + frame.dispose(); + if (fullScreen) { + System.out.println("End fullscreen"); + frame.setUndecorated(false); + frame.setVisible(true); + device.setFullScreenWindow(null); + fullScreen = false; + } else { + System.out.println("Start fullscreen"); + frame.setUndecorated(true); + frame.setVisible(true); + device.setFullScreenWindow(frame); + fullScreen = true; + } + } + } + + @Override + public void keyReleased(KeyEvent e) { + + } + }); + + Panel panel = new Panel(); + panel.setBackground(Color.BLACK); + frame.add(panel); + frame.setLayout(new FulfillingLayout(panel)); + + canvas = new Canvas(); + panel.add(canvas); + panel.setLayout(new FixedAspectLayout(ASPECT_RATIO, canvas)); + + frame.setVisible(true); + frame.pack(); + frame.setLocationRelativeTo(null); + + canvas.createBufferStrategy(2); + bufferStrategy = canvas.getBufferStrategy(); + + changeState(new GameState(frame.getWidth(), frame.getHeight())); } public void run() { - long time, timeDelta = minTickTime; - lastTick = System.currentTimeMillis(); + long time, timeDelta, tickBegin = System.nanoTime(); - while (frame.isVisible()) { - time = System.currentTimeMillis(); - timeDelta = time - lastTick - minTickTime; + while (!scheduleStop) { + time = System.nanoTime(); + timeDelta = time - tickBegin; + tickBegin = System.nanoTime(); - if (timeDelta >= 0) { - state.tick(); - state.render(canvas.getGraphics()); - lastTick = time; + state.tick((int) (timeDelta / 1_000_000L)); + + do { + do { + Graphics graphics = bufferStrategy.getDrawGraphics(); + + state.render(graphics); + + graphics.dispose(); + + } while(bufferStrategy.contentsRestored()); + + bufferStrategy.show(); + } while(bufferStrategy.contentsLost()); + + time = System.nanoTime(); + timeDelta = time - tickBegin; + + if (timeDelta < minTickTime) { + try { + Thread.sleep((minTickTime - timeDelta) / 1_000_000); + } catch (InterruptedException e) { + e.printStackTrace(); + } } } + + frame.setVisible(false); + frame.dispose(); } public void changeState(State newState) { @@ -124,6 +194,6 @@ public class WhatAStorage { } state = newState; state.enter(); - state.onResize(canvas.getWidth(), canvas.getHeight()); + state.onResize(frame.getWidth(), frame.getHeight()); } } diff --git a/src/main/java/de/siphalor/was/assets/AssetsManager.java b/src/main/java/de/siphalor/was/assets/AssetsManager.java index 5ebcb3a..9e53bd4 100644 --- a/src/main/java/de/siphalor/was/assets/AssetsManager.java +++ b/src/main/java/de/siphalor/was/assets/AssetsManager.java @@ -13,11 +13,11 @@ import java.util.Map; public class AssetsManager { private static final Map imageCache = new HashMap<>(); - public static final Image MISSINGNO = getImage("assets/missingno.png"); + public static final Image MISSINGNO = getImage("textures/missingno.png"); @Nullable public static InputStream getResource(@NotNull String path) { - return Thread.currentThread().getContextClassLoader().getResourceAsStream(path); + return Thread.currentThread().getContextClassLoader().getResourceAsStream("assets/" + path); } public static Image getImage(@NotNull String path) { diff --git a/src/main/java/de/siphalor/was/state/GameState.java b/src/main/java/de/siphalor/was/state/GameState.java index 17f027f..2f9146d 100644 --- a/src/main/java/de/siphalor/was/state/GameState.java +++ b/src/main/java/de/siphalor/was/state/GameState.java @@ -1,35 +1,54 @@ package de.siphalor.was.state; import de.siphalor.was.assets.AssetsManager; +import de.siphalor.was.util.Util; +import de.siphalor.was.visual.render.AnimatedTextureObject; +import de.siphalor.was.visual.render.Renderable; +import de.siphalor.was.visual.render.TextureObject; import java.awt.*; -import java.awt.image.BufferedImage; +import java.util.Collection; +import java.util.LinkedList; public class GameState extends State { - private BufferedImage main; + private static final Image BG = AssetsManager.getImage("textures/bg.png"); + private static final Image BIN_OPEN = AssetsManager.getImage("textures/bin_open.png"); + private static final Image BIN_CLOSED = AssetsManager.getImage("textures/bin_closed.png"); + + Collection renderables = new LinkedList<>(); + + private boolean binOpen = false; public GameState(int width, int height) { super(width, height); + + renderables.add(new TextureObject(600, 700, 400, 300) { + @Override + public Image getTexture() { + return binOpen ? BIN_OPEN : BIN_CLOSED; + } + }); + renderables.add(new AnimatedTextureObject(0, 500, 550, 400, 1000, + AssetsManager.getImage("textures/conveyor_in_0.png"), + AssetsManager.getImage("textures/conveyor_in_1.png"), + AssetsManager.getImage("textures/conveyor_in_2.png") + )); } @Override - public void tick() { - + public void tick(int delta) { + renderables.forEach(renderable -> renderable.tick(delta)); } @Override public void render(Graphics graphics) { - graphics.drawImage(main, 0, 0, getWidth(), getHeight(), (img, infoflags, x, y, width, height) -> false); + graphics.drawImage(BG, 0, 0, getWidth(), getHeight(), Util.dummyImageObserver()); + + renderables.forEach(renderable -> renderable.render(graphics, getWidth(), getHeight())); } @Override public void onResize(int width, int height) { super.onResize(width, height); - main = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); - redrawBg(main.getGraphics()); - } - - public void redrawBg(Graphics graphics) { - graphics.drawImage(AssetsManager.getImage("assets/menu/bg.png"), 0, 0, getWidth(), getHeight(), (img, infoflags, x, y, width, height) -> false); } } diff --git a/src/main/java/de/siphalor/was/state/MainMenuState.java b/src/main/java/de/siphalor/was/state/MainMenuState.java index 812c132..f63dfb3 100644 --- a/src/main/java/de/siphalor/was/state/MainMenuState.java +++ b/src/main/java/de/siphalor/was/state/MainMenuState.java @@ -1,6 +1,7 @@ package de.siphalor.was.state; import de.siphalor.was.assets.AssetsManager; +import de.siphalor.was.util.Util; import java.awt.*; @@ -12,15 +13,14 @@ public class MainMenuState extends State { } @Override - public void tick() { + public void tick(int delta) { } @Override public void render(Graphics graphics) { - if (bgDirty) { - graphics.drawImage(AssetsManager.getImage("assets/bg.png"), 0, 0, getWidth() - 1, getHeight() - 1, (img, infoflags, x, y, width, height) -> false); - } + Image image = AssetsManager.getImage("assets/textures/bg.png"); + graphics.drawImage(image, 0, 0, getWidth(), getHeight(), Util.dummyImageObserver()); } @Override diff --git a/src/main/java/de/siphalor/was/state/NoopState.java b/src/main/java/de/siphalor/was/state/NoopState.java new file mode 100644 index 0000000..60d868d --- /dev/null +++ b/src/main/java/de/siphalor/was/state/NoopState.java @@ -0,0 +1,19 @@ +package de.siphalor.was.state; + +import java.awt.*; + +public class NoopState extends State { + public NoopState() { + super(0,0); + } + + @Override + public void tick(int delta) { + + } + + @Override + public void render(Graphics graphics) { + + } +} diff --git a/src/main/java/de/siphalor/was/state/State.java b/src/main/java/de/siphalor/was/state/State.java index 757dd94..6edb8da 100644 --- a/src/main/java/de/siphalor/was/state/State.java +++ b/src/main/java/de/siphalor/was/state/State.java @@ -27,7 +27,7 @@ public abstract class State { } - public abstract void tick(); + public abstract void tick(int delta); public abstract void render(Graphics graphics); public void onResize(int width, int height) { diff --git a/src/main/java/de/siphalor/was/util/Util.java b/src/main/java/de/siphalor/was/util/Util.java index ae97899..009a91a 100644 --- a/src/main/java/de/siphalor/was/util/Util.java +++ b/src/main/java/de/siphalor/was/util/Util.java @@ -1,5 +1,6 @@ package de.siphalor.was.util; +import java.awt.image.ImageObserver; import java.util.function.IntPredicate; import java.util.function.Predicate; @@ -34,4 +35,8 @@ public class Util { } return packId + "." + path; } + + public static ImageObserver dummyImageObserver() { + return (img, infoflags, x, y, width, height) -> false; + } } diff --git a/src/main/java/de/siphalor/was/visual/layout/FixedAspectLayout.java b/src/main/java/de/siphalor/was/visual/layout/FixedAspectLayout.java new file mode 100644 index 0000000..50b3ebe --- /dev/null +++ b/src/main/java/de/siphalor/was/visual/layout/FixedAspectLayout.java @@ -0,0 +1,61 @@ +package de.siphalor.was.visual.layout; + +import org.jetbrains.annotations.Nullable; + +import java.awt.*; + +public class FixedAspectLayout implements LayoutManager { + /** + * Width through height + */ + private final double aspectRatio; + @Nullable + private Component component; + + public FixedAspectLayout(double aspectRatio) { + this(aspectRatio, null); + } + + public FixedAspectLayout(double aspectRatio, @Nullable Component component) { + this.aspectRatio = aspectRatio; + this.component = component; + } + + @Override + public void addLayoutComponent(String name, Component comp) { + component = comp; + } + + @Override + public void removeLayoutComponent(Component comp) { + if (component == comp) + component = null; + } + + @Override + public Dimension preferredLayoutSize(Container parent) { + return parent.getSize(); + } + + @Override + public Dimension minimumLayoutSize(Container parent) { + return parent.getSize(); + } + + @Override + public void layoutContainer(Container parent) { + if (component != null) { + Insets insets = parent.getInsets(); + int width = parent.getWidth() - (insets.left + insets.right); + int height = parent.getHeight() - (insets.top + insets.bottom); + + int calc = (int) (height * aspectRatio); + if (calc <= width) { + component.setBounds(insets.left + (width - calc) / 2, insets.top, calc, height); + } else { + calc = (int) (width / aspectRatio); + component.setBounds(insets.left, insets.top + (height - calc) / 2, width, calc); + } + } + } +} diff --git a/src/main/java/de/siphalor/was/visual/layout/FulfillingLayout.java b/src/main/java/de/siphalor/was/visual/layout/FulfillingLayout.java new file mode 100644 index 0000000..51b9939 --- /dev/null +++ b/src/main/java/de/siphalor/was/visual/layout/FulfillingLayout.java @@ -0,0 +1,49 @@ +package de.siphalor.was.visual.layout; + +import java.awt.*; + +public class FulfillingLayout implements LayoutManager { + private Component component; + + public FulfillingLayout() { + this(null); + } + + public FulfillingLayout(Component component) { + this.component = component; + } + + @Override + public void addLayoutComponent(String name, Component comp) { + component = comp; + } + + @Override + public void removeLayoutComponent(Component comp) { + component = null; + } + + @Override + public Dimension preferredLayoutSize(Container parent) { + Insets insets = parent.getInsets(); + return new Dimension(parent.getWidth() - (insets.left + insets.right), parent.getHeight() - (insets.top + insets.bottom)); + } + + @Override + public Dimension minimumLayoutSize(Container parent) { + Insets insets = parent.getInsets(); + return new Dimension(parent.getWidth() - (insets.left + insets.right), parent.getHeight() - (insets.top + insets.bottom)); + } + + @Override + public void layoutContainer(Container parent) { + if (component != null) { + Insets insets = parent.getInsets(); + + component.setBounds(insets.left, insets.top, + parent.getWidth() - (insets.left + insets.right), + parent.getHeight() - (insets.top + insets.bottom) + ); + } + } +} diff --git a/src/main/java/de/siphalor/was/visual/render/AnimatedTextureObject.java b/src/main/java/de/siphalor/was/visual/render/AnimatedTextureObject.java new file mode 100644 index 0000000..7b17e85 --- /dev/null +++ b/src/main/java/de/siphalor/was/visual/render/AnimatedTextureObject.java @@ -0,0 +1,31 @@ +package de.siphalor.was.visual.render; + +import java.awt.*; + +public class AnimatedTextureObject extends TextureObject { + private final int frameTime; + private final Image[] frames; + + private int time = 0; + + public AnimatedTextureObject(int x, int y, int width, int height, int frameTime, Image... frames) { + super(x, y, width, height); + this.frameTime = frameTime; + this.frames = frames; + } + + @Override + public void tick(int delta) { + super.tick(delta); + + time += delta; + if (time >= frames.length * frameTime) { + time = 0; + } + } + + @Override + public Image getTexture() { + return frames[time / frameTime]; + } +} diff --git a/src/main/java/de/siphalor/was/visual/render/Renderable.java b/src/main/java/de/siphalor/was/visual/render/Renderable.java new file mode 100644 index 0000000..577c8e8 --- /dev/null +++ b/src/main/java/de/siphalor/was/visual/render/Renderable.java @@ -0,0 +1,8 @@ +package de.siphalor.was.visual.render; + +import java.awt.*; + +public interface Renderable { + void tick(int delta); + void render(Graphics graphics, int width, int height); +} diff --git a/src/main/java/de/siphalor/was/visual/render/TextureObject.java b/src/main/java/de/siphalor/was/visual/render/TextureObject.java new file mode 100644 index 0000000..b47976c --- /dev/null +++ b/src/main/java/de/siphalor/was/visual/render/TextureObject.java @@ -0,0 +1,41 @@ +package de.siphalor.was.visual.render; + +import de.siphalor.was.util.Util; + +import java.awt.*; + +public abstract class TextureObject implements Renderable, Cloneable { + private int x; + private int y; + private int width; + private int height; + + protected TextureObject(int x, int y, int width, int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + public void mirrorX() { + x += width; + width = -width; + } + + public void mirrorY() { + y += height; + height = -height; + } + + public abstract Image getTexture(); + + @Override + public void tick(int delta) { + + } + + @Override + public void render(Graphics graphics, int width, int height) { + graphics.drawImage(getTexture(), x * width / 1600, y * height / 900, this.width * width / 1600, this.height * height / 900, Util.dummyImageObserver()); + } +} diff --git a/src/main/resources/assets/textures/bg.png b/src/main/resources/assets/textures/bg.png new file mode 100644 index 0000000..ddf2eb1 Binary files /dev/null and b/src/main/resources/assets/textures/bg.png differ diff --git a/src/main/resources/assets/textures/bg.svg b/src/main/resources/assets/textures/bg.svg new file mode 100644 index 0000000..a3aa39d --- /dev/null +++ b/src/main/resources/assets/textures/bg.svg @@ -0,0 +1,348 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/assets/textures/bin.svg b/src/main/resources/assets/textures/bin.svg new file mode 100644 index 0000000..791421d --- /dev/null +++ b/src/main/resources/assets/textures/bin.svg @@ -0,0 +1,635 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/assets/textures/bin_bordered.svg b/src/main/resources/assets/textures/bin_bordered.svg new file mode 100644 index 0000000..cdb8c58 --- /dev/null +++ b/src/main/resources/assets/textures/bin_bordered.svg @@ -0,0 +1,635 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/assets/textures/bin_closed.png b/src/main/resources/assets/textures/bin_closed.png new file mode 100644 index 0000000..55ab9e9 Binary files /dev/null and b/src/main/resources/assets/textures/bin_closed.png differ diff --git a/src/main/resources/assets/textures/bin_open.png b/src/main/resources/assets/textures/bin_open.png new file mode 100644 index 0000000..c299ee0 Binary files /dev/null and b/src/main/resources/assets/textures/bin_open.png differ diff --git a/src/main/resources/assets/textures/conveyor_in.svg b/src/main/resources/assets/textures/conveyor_in.svg new file mode 100644 index 0000000..6e195f6 --- /dev/null +++ b/src/main/resources/assets/textures/conveyor_in.svg @@ -0,0 +1,541 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/assets/textures/conveyor_in_0.png b/src/main/resources/assets/textures/conveyor_in_0.png new file mode 100644 index 0000000..6dfa973 Binary files /dev/null and b/src/main/resources/assets/textures/conveyor_in_0.png differ diff --git a/src/main/resources/assets/textures/conveyor_in_1.png b/src/main/resources/assets/textures/conveyor_in_1.png new file mode 100644 index 0000000..fb79052 Binary files /dev/null and b/src/main/resources/assets/textures/conveyor_in_1.png differ diff --git a/src/main/resources/assets/textures/conveyor_in_2.png b/src/main/resources/assets/textures/conveyor_in_2.png new file mode 100644 index 0000000..e0b7028 Binary files /dev/null and b/src/main/resources/assets/textures/conveyor_in_2.png differ diff --git a/src/main/resources/assets/textures/conveyor_in_bordered.svg b/src/main/resources/assets/textures/conveyor_in_bordered.svg new file mode 100644 index 0000000..ecb40cc --- /dev/null +++ b/src/main/resources/assets/textures/conveyor_in_bordered.svg @@ -0,0 +1,541 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/assets/textures/conveyor_in_overlay.png b/src/main/resources/assets/textures/conveyor_in_overlay.png new file mode 100644 index 0000000..6c910b5 Binary files /dev/null and b/src/main/resources/assets/textures/conveyor_in_overlay.png differ diff --git a/src/main/resources/assets/missingno.png b/src/main/resources/assets/textures/missingno.png similarity index 100% rename from src/main/resources/assets/missingno.png rename to src/main/resources/assets/textures/missingno.png