Skip to content

Commit baaaaba

Browse files
committed
Working on the UI component, and bashing my head against the wall with input
1 parent 8874def commit baaaaba

File tree

6 files changed

+107
-43
lines changed

6 files changed

+107
-43
lines changed

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ repositories {
1616
}
1717

1818
dependencies {
19-
api("com.googlecode.lanterna:lanterna:3.1.2")
19+
implementation("com.googlecode.lanterna:lanterna:3.1.2")
2020
}
2121

2222
// Apply a specific Java toolchain to ease working on different environments.

readme.md

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,47 +7,77 @@ Uses Lanterna to emulate a terminal, also comes with a Pair class that is a basi
77

88
Requires Java 17+
99

10+
## What does it provide?
11+
12+
If you decide to use Console Java Engine to make your game with, first off thank you for using my project to make yours, secondly you might want to know what it provides.
13+
14+
As of version 0.1.20-Jyggalag the following is provided:
15+
16+
A Scene system
17+
A Pair class that emulates the C++ Standard Library's. (I thought it'd be nice to have when I first wrote this, this might be removed later)
18+
A Colors class that holds RGB colors. These colors were sourced from the [website](html-color.codes)
19+
A very basic Camera class. It's really basic camera.
20+
An Immediate Mode UI - I emulated how DearImGui works and currently adding features to the it as I go.
21+
An Input class - It handles keyboard input. I've been trying to implement a `justPressed` feature, but Lanterna only let's you know a key was pressed and not when it was released, held or pressed. So I might have to dig deeper and develop a separate input system from Lanterna.
22+
1023
## How to use
1124

12-
To use CJE, include it in your project, then create a class and extend the `ConsoleJavaEngine`. It provides a Skeleton for your project. After that all you need to do is create different `Scene` classes for you game. The `ConsoleRenderer` class holds methods to write to the screen.
25+
Under the hood, Console Java Engine uses Lanterna to create a Swing based Terminal for drawing to.
26+
27+
To utilize the Console Java Engine in your project, create a class that extends the `ConsoleJavaEngine` class. The Console Java Engine uses scenes so you will also need to create a class that extends `AbstractScene` class. The `AbstractScene` class provides methods for you to override so you can update, render to the screen, render ui, and process input. You can draw to the screen using the provided `ConsoleRenderer` object, and draw UI using the `UIContext` object pass through. `UIContext` uses an Immediate Mode gui system so you're able to create UI kinda like DearIMGui does.
28+
29+
A Skeleton is provided below for both a class that extends the `ConsoleJavaEngine` and a class that extends `AbstractScene`
30+
31+
The default font included is ascii-sector-16x16-tileset. This means that each cell will also be 16x16 "pixels", if you will, so when you specify you're width and height for creating your game, it'll be multiplied by the font's character width and height. 80, 48 is used here which would translate to a window size of 1280 by 768. This font was chosen because of it's ability to use Code Page 437. By utilizing '\u' then a number, you can use symbols from the code page.
1332

1433
```Java
1534

16-
import com.googlecode.lanterna.input.KeyStroke;
1735
import com.spireprod.cje.ConsoleJavaEngine;
1836

1937
public class Adventure extends ConsoleJavaEngine {
2038

2139
public Adventure() {
22-
super("Adventure", 80, 24);
40+
super("Adventure", 80, 48);
2341
}
2442

2543
@Override
2644
protected void onGameCreate() {
27-
setScene(new GameScreen());
45+
setScene(new GameScene(this));
46+
}
47+
48+
public static void main(String[] args) {
49+
Adventure venture = new Adventure();
50+
venture.run();
2851
}
2952

3053
}
3154

32-
import com.googlecode.lanterna.input.KeyStroke;
55+
import com.spireprod.cje.ConsoleJavaEngine;
3356
import com.spireprod.cje.core.ConsoleRenderer;
34-
import com.spireprod.cje.core.scenes.Scene;
57+
import com.spireprod.cje.core.input.Input;
58+
import com.spireprod.cje.core.scenes.AbstractScene;
59+
import com.spireprod.cje.core.ui.UIContext;
3560

36-
public class GameScene implements Scene {
61+
public class GameScene extends AbstractScene {
62+
63+
public GameScene(ConsoleJavaEngine cje) {
64+
super(cje);
65+
}
3766

3867
@Override
3968
public void onSceneUpdate(float delta) {
40-
4169
}
4270

4371
@Override
4472
public void onSceneRender(ConsoleRenderer renderer) {
45-
4673
}
4774

4875
@Override
49-
public void onSceneInput(float delta, KeyStroke key) {
76+
public void onSceneUIRender(UIContext ctx, ConsoleRenderer renderer, Input input) {
77+
}
5078

79+
@Override
80+
public void onSceneInput(float delta, Input input) {
5181
}
5282

5383
}

src/main/java/com/spireprod/cje/ConsoleJavaEngine.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public abstract class ConsoleJavaEngine {
3333
public static final String PIXEL_SHADE_FULL = "\u2593";
3434
public static final String PIXEL_SHADE_HALF = "\u2592";
3535
public static int termWidth, termHeight;
36+
public static int screenWidth, screenHeight;
3637

3738
protected Terminal terminal;
3839
protected SceneManager sceneManager;
@@ -66,7 +67,8 @@ public ConsoleJavaEngine(String title, int width, int height) {
6667

6768
DefaultTerminalFactory defaultTermFactory = new DefaultTerminalFactory();
6869

69-
// Setup Default Font 'Ubuntu Mono'
70+
// Setup Default Font 'Ascii Sector 16x16 Tileset'
71+
// License is in resources folder/base jar.
7072
Font font = null;
7173
try {
7274
InputStream is = ConsoleJavaEngine.class.getResourceAsStream("/ascii-sector-16x16-tileset.ttf");
@@ -81,7 +83,7 @@ public ConsoleJavaEngine(String title, int width, int height) {
8183

8284
GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(font);
8385

84-
defaultTermFactory.setTerminalEmulatorTitle(title + " -" + CJE_VERSION)
86+
defaultTermFactory.setTerminalEmulatorTitle(title + " - " + CJE_VERSION)
8587
.setTerminalEmulatorFontConfiguration(
8688
SwingTerminalFontConfiguration.newInstance(font.deriveFont(Font.PLAIN, 16)))
8789
.setInitialTerminalSize(new TerminalSize(width, height)).setForceAWTOverSwing(false)
@@ -96,6 +98,9 @@ public ConsoleJavaEngine(String title, int width, int height) {
9698
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
9799
frame.setVisible(true);
98100

101+
screenWidth = frame.getWidth();
102+
screenHeight = frame.getHeight();
103+
99104
ctx = new UIContext();
100105
screen = new TerminalScreen(terminal);
101106
termWidth = frame.getTerminalSize().getColumns();

src/main/java/com/spireprod/cje/core/Camera.java

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.spireprod.cje.core;
22

3-
import java.util.Random;
4-
53
public class Camera {
64
private float x, y; // top-left world coordinate of the view
75
private final int viewWidth, viewHeight;
@@ -11,11 +9,6 @@ public class Camera {
119
private float panSpeed = 0;
1210
private boolean isPanning = false;
1311

14-
// Shake
15-
private float shakeTimer = 0;
16-
private float shakeMagnitude = 0;
17-
private final Random rng = new Random();
18-
1912
public Camera(int viewWidth, int viewHeight) {
2013
this.viewWidth = viewWidth;
2114
this.viewHeight = viewHeight;
@@ -36,12 +29,6 @@ public void panTo(float worldX, float worldY, float speed) {
3629
isPanning = true;
3730
}
3831

39-
// Shake the camera for a short time
40-
public void shake(float duration, float magnitude) {
41-
shakeTimer = duration;
42-
shakeMagnitude = magnitude;
43-
}
44-
4532
public void update(float deltaSeconds) {
4633
if (Float.isNaN(x) || Float.isNaN(y)) {
4734
System.err.println("Warning: NaN in camera coordinates. Resetting.");
@@ -61,19 +48,14 @@ public void update(float deltaSeconds) {
6148
isPanning = false;
6249
}
6350
}
64-
65-
// Shake logic
66-
if (shakeTimer > 0) {
67-
shakeTimer -= deltaSeconds;
68-
}
6951
}
7052

7153
public int getViewX() {
72-
return (int) x + getShakeOffset();
54+
return (int) x;
7355
}
7456

7557
public int getViewY() {
76-
return (int) y + getShakeOffset();
58+
return (int) y;
7759
}
7860

7961
public int worldToScreenX(int worldX) {
@@ -84,10 +66,6 @@ public int worldToScreenY(int worldY) {
8466
return worldY - getViewY();
8567
}
8668

87-
private int getShakeOffset() {
88-
return (shakeTimer > 0) ? rng.nextInt((int) (shakeMagnitude * 2 + 1)) - (int) shakeMagnitude : 0;
89-
}
90-
9169
private float lerp(float a, float b, float t) {
9270
return a + (b - a) * clamp(t, 0f, 1f);
9371
}

src/main/java/com/spireprod/cje/core/Colors.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ public class Colors {
1414
// Browns
1515

1616
public static RGB PULLMAN_BROWN = new RGB(100, 65, 23);
17+
public static RGB BISQUE = new RGB(255, 228, 196);
18+
public static RGB MOCCASIN = new RGB(255, 228, 181);
19+
public static RGB NAVAJO_WHITE = new RGB(255, 222, 173);
1720

1821
// Tans
1922

@@ -22,6 +25,8 @@ public class Colors {
2225
// Peaches
2326

2427
// Golds
28+
public static RGB GOLD = new RGB(255, 215, 0);
29+
public static RGB BEIGE = new RGB(245, 245, 220);
2530

2631
// Yellows
2732

@@ -30,10 +35,10 @@ public class Colors {
3035
// Olives
3136

3237
// Greens
33-
3438
public static RGB GREEN = new RGB(0, 255, 0);
3539
public static RGB LAWN_GREEN = new RGB(124, 252, 0);
3640
public static RGB PHTHALO_GREEN = new RGB(18, 53, 36);
41+
public static RGB MEDIUM_SPRING_GREEN = new RGB(0, 250, 154);
3742

3843
// Teals
3944

@@ -42,6 +47,7 @@ public class Colors {
4247
// Blues
4348
public static RGB BLUE = new RGB(0, 0, 255);
4449
public static RGB DODGER_BLUE = new RGB(30, 144, 255);
50+
public static RGB MUNSELL_BLUE = new RGB(0, 147, 175);
4551

4652
// Navys
4753

src/main/java/com/spireprod/cje/core/ui/UIContext.java

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22

33
import java.util.ArrayDeque;
44
import java.util.Deque;
5+
import java.util.function.Function;
56

67
import com.googlecode.lanterna.TextColor;
78
import com.googlecode.lanterna.input.KeyType;
89
import com.spireprod.cje.ConsoleJavaEngine;
10+
import com.spireprod.cje.core.Colors;
911
import com.spireprod.cje.core.ConsoleRenderer;
1012
import com.spireprod.cje.core.input.Input;
1113

@@ -16,7 +18,7 @@ public class UIContext {
1618
// Panel Offset Stack
1719
private int offsetX = 0;
1820
private int offsetY = 0;
19-
private final Deque<int[]> offsetStack = new ArrayDeque<>();
21+
private final Deque<int[]> offsetStack = new ArrayDeque<>(); // Panel OffsetStack
2022

2123
private ConsoleRenderer renderer;
2224
private Input input;
@@ -110,6 +112,34 @@ public boolean textInput(String label, int x, int y, StringBuilder buffer, TextC
110112
return false;
111113
}
112114

115+
public <T> boolean choiceBox(int x, int y, T[] boxObjs, int[] choiceIdx, Function<T, String> labelFunc,
116+
TextColor backgroundColor, TextColor textColor) {
117+
boolean fired = false;
118+
119+
for (int i = 0; i < boxObjs.length; i++) {
120+
boolean isSelected = (selectedIndex == totalItems);
121+
boolean choiceSelected = i == choiceIdx[0];
122+
123+
TextColor color = isSelected ? TextColor.ANSI.GREEN : textColor;
124+
String prefix = isSelected ? "> " : " ";
125+
126+
if (choiceSelected)
127+
color = Colors.BLUE;
128+
129+
renderer.writeString(prefix + labelFunc.apply(boxObjs[i]), offsetX + x, offsetY + y + i, backgroundColor,
130+
color);
131+
132+
if (isSelected && input.isKeyDown(KeyType.Enter)) {
133+
fired = true;
134+
choiceIdx[0] = i;
135+
}
136+
137+
totalItems++;
138+
}
139+
140+
return fired;
141+
}
142+
113143
// region: Panel
114144

115145
public void beginPanel(int x, int y, int width, int height, TextColor backgroundColor) {
@@ -124,15 +154,18 @@ public void beginPanel(int x, int y, int width, int height, TextColor background
124154
}
125155

126156
// Top/Bottom border
127-
renderer.writeString("+" + "-".repeat(width - 2) + "+", offsetX, offsetY, backgroundColor,
157+
renderer.writeString("+" + buildChainLine(width - 2) + "+", offsetX, offsetY, backgroundColor,
128158
TextColor.ANSI.WHITE);
129-
renderer.writeString("+" + "-".repeat(width - 2) + "+", offsetX, offsetY + height - 1, backgroundColor,
159+
renderer.writeString("+" + buildChainLine(width - 2) + "+", offsetX, offsetY + height - 1, backgroundColor,
130160
TextColor.ANSI.WHITE);
131161

132162
// Left/Right border
163+
char[] sideChain = new char[] { '|', ':' };
164+
133165
for (int iy = 1; iy < height - 1; iy++) {
134-
renderer.putChar('|', offsetX, offsetY + iy, TextColor.ANSI.WHITE, backgroundColor);
135-
renderer.putChar('|', offsetX + width - 1, offsetY + iy, TextColor.ANSI.WHITE, backgroundColor);
166+
char sideGlyph = sideChain[iy % sideChain.length];
167+
renderer.putChar(sideGlyph, offsetX, offsetY + iy, TextColor.ANSI.WHITE, backgroundColor);
168+
renderer.putChar(sideGlyph, offsetX + width - 1, offsetY + iy, TextColor.ANSI.WHITE, backgroundColor);
136169
}
137170

138171
}
@@ -161,4 +194,16 @@ public void handleInput(Input input) {
161194
selectedIndex = Math.floorMod(selectedIndex, totalItems);
162195
}
163196

197+
private String buildChainLine(int length) {
198+
String pattern = "-=";
199+
StringBuilder sb = new StringBuilder();
200+
while (sb.length() < length) {
201+
sb.append(pattern);
202+
}
203+
return sb.substring(0, length);
204+
}
205+
206+
public record Choice(Object choice, boolean fired) {
207+
}
208+
164209
}

0 commit comments

Comments
 (0)