Compare commits

...

48 Commits

Author SHA1 Message Date
minjaesong
af619cda79 instead of frequently accessing Java from C-side, feed everything beforehand on Java-side 2019-02-08 11:46:30 +09:00
minjaesong
78bbd9c051 wip 2019-02-04 06:26:12 +09:00
minjaesong
3f108a6ea9 quicker camera on buildingmaker 2019-02-04 01:37:31 +09:00
minjaesong
a831a4d798 fixing mouseUp on NSMenu; making pen on buildingmaker work 2019-02-03 23:53:46 +09:00
minjaesong
e3ed712a42 F3 moved to PostProcessor; palette UI for buildingmaker 2019-02-03 17:01:27 +09:00
minjaesong
daf5c02605 #12 event for world block change -- mainly meant for fixture updating itself 2019-02-02 01:58:49 +09:00
minjaesong
e8b39fc668 blocksdrawer use offsetted time_t 2019-02-02 01:08:14 +09:00
minjaesong
c20d7edb34 closing #22 2019-02-01 22:45:34 +09:00
minjaesong
28f305e76f application icons 2019-02-01 20:15:19 +09:00
minjaesong
4c3fc2352c #21, also making seasonal grasses easier on PSD 2019-02-01 18:47:02 +09:00
minjaesong
01094d49eb wall block item to use its own texture (for real) 2019-02-01 17:28:08 +09:00
minjaesong
7d3bf0eece terrain texture change by all seasons 2019-02-01 15:59:54 +09:00
minjaesong
75f128a8f7 fixed notificator UI 2019-01-31 20:54:25 +09:00
minjaesong
514f1e9012 nsmenu to invoke class with defined args; working settime on buildingmaker 2019-01-31 18:01:33 +09:00
minjaesong
60db83eddb making sure unused screen be disposed, and not breaking the app 2019-01-31 13:29:40 +09:00
minjaesong
90a7fcd4d0 fix memory leak from my ididcy; relationship w #19 needs investigation 2019-01-31 05:02:44 +09:00
minjaesong
d93c6de851 language is moved inside of options 2019-01-31 03:27:03 +09:00
minjaesong
f603b58307 adjusting disposing behavs so that we can go back and forth the ingame and titlescr 2019-01-31 00:12:38 +09:00
minjaesong
074fe2438d inventory gamemenu visual only 2019-01-29 23:37:38 +09:00
minjaesong
69e9fa4b0f 3 screens impl of inventory UI wip 2019-01-29 20:24:11 +09:00
minjaesong
9373feff34 nice try, but it crashes the gpu AND I get <1 fps :( 2019-01-29 17:35:56 +09:00
minjaesong
10c188bea7 wrong colour fixed -- Gdx.Color.toIntBits() returns ABGR, GLSL expects RGBA 2019-01-29 03:04:01 +09:00
minjaesong
cd1ad9277a gpu rendered light wip 2019-01-29 02:21:22 +09:00
minjaesong
465ed0d7a4 inventory ui won't always draw item count 2019-01-28 19:22:47 +09:00
minjaesong
bd1c1bff8a amount of fluid affects the light absorption 2019-01-27 16:58:29 +09:00
minjaesong
8ac5f1dc9e nuked fluidcodex 2019-01-27 05:09:52 +09:00
minjaesong
268907ee9d so not making new objs frequently does make it bit faster... 2019-01-27 02:09:20 +09:00
minjaesong
9937c34d25 light calc takes fluid into account 2019-01-27 00:30:56 +09:00
minjaesong
bdbb30bc58 new watch design consistent with existing UI 2019-01-24 23:46:24 +09:00
minjaesong
bdbf6cd458 new TV-safe watch UI 2019-01-24 02:32:28 +09:00
minjaesong
e4f456ffa7 gapbox toggle with F11 2019-01-23 12:45:40 +09:00
minjaesong
73a6c844c8 less intrusive gapbox colours 2019-01-23 03:52:28 +09:00
minjaesong
84ca954a26 F12 for screenshot; it's high time to care about TVs
(besides, the EBU gap is also a good guideline for placing UIs on edge)
2019-01-23 03:46:46 +09:00
minjaesong
66b18bf8c5 equipped items are drawn into their respective slot 2019-01-23 00:50:20 +09:00
minjaesong
6d0bff2879 greater number of inventory cells 2019-01-23 00:09:31 +09:00
minjaesong
14b485dc32 small number font moved to apploader 2019-01-22 23:05:29 +09:00
minjaesong
a192abd657 glsl works differently on my macbook? 2019-01-22 22:23:30 +09:00
minjaesong
0d534fd60c adding demoworld.gz 2019-01-22 21:34:00 +09:00
minjaesong
a4dabbbf37 adding gradle-wrapper.jar 2019-01-22 21:27:56 +09:00
minjaesong
450874540c initial screen size is read from the config 2019-01-22 20:56:16 +09:00
minjaesong
53c45d6829 smoothDelta is now come from Gdx's LwjglGraphics instead of AppLoader 2019-01-22 13:16:21 +09:00
minjaesong
1c839f7135 test impl kalman delta on gdx 2019-01-22 06:30:11 +09:00
minjaesong
f133406df3 copyright update 2019-01-22 05:57:38 +09:00
minjaesong
ae14026191 implementing the iconic 'lag behind' camera the right way 2019-01-22 05:46:26 +09:00
minjaesong
b9a4e0f64b game actually reads fps setting from config 2019-01-22 05:29:03 +09:00
minjaesong
aef601e9b8 some classes in sprite assembler is now internal 2019-01-22 03:51:18 +09:00
minjaesong
88db71f780 ingame will only render visible actor 2019-01-22 03:50:35 +09:00
minjaesong
ded9cb1a10 instead of dealing with delta, we'll just update multiple times, THIS TIME IN CORRECT WAY
(because it really works :p)
2019-01-22 02:59:22 +09:00
130 changed files with 3554 additions and 1177 deletions

2
.gitignore vendored
View File

@@ -14,7 +14,7 @@ Thumbs.db
# Resources that should not be tracked
*.jar
assets/mods/basegame/demoworld
assets/mods/basegame/demoworld.gz
#assets/mods/basegame/demoworld.gz
external_resource_packs.zip
# IntelliJ

BIN
assets/appicon128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

BIN
assets/appicon16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 B

BIN
assets/appicon256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 559 B

BIN
assets/appicon32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B

BIN
assets/appicon64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 B

View File

@@ -71,7 +71,7 @@ The control is omnidirectional. In other words, \emph{not} cell-based.
\subsubsection{ISO\slash ANSI\slash JIS pedalboards}
Your default moving around uses ESDF (qwerty)\slash FRST (colemak)\slash .OEW (dvorak) pedals for default `WASD', in order for you to provide more modifier pedals---QAZ (qwerty\slash colemak), /A; (dvorak)---that are pressed with your little finger and more comfort to some pedalboards with Topre actuators.\footnote{Writers of this book would recommend you to use pedalboard with Cherry MX Red actuators, though any decent pedalboard should be sufficient.}
\subsubsection{Joypads}
\subsubsection{gamepads}
Your moving around uses left stick, and direction of the movement is \emph{not} limited to 8 directions, hence the term, “omni\-direc\-tion\-al”.
\section{World}

View File

@@ -0,0 +1,15 @@
SET basefilename=%~d1%~p1%~n1
SET inputextension=%~x1
rem inputextension should be dot-psd
rem color space must be Lab16
IF "%inputextension%" NEQ ".psd" goto fail
convert %1 -colorspace sRGB -write mpr:temp -background black -alpha Remove mpr:temp -compose Copy_Opacity -composite "%basefilename%.tga"
exit
:fail
echo "File not PSD"
pause
exit /b 1

Binary file not shown.

View File

@@ -2053,7 +2053,7 @@
},
{
"n": "MENU_LABEL_MAINMENU",
"s": "메뉴"
"s": "메인 메뉴"
},
{
"n": "MENU_LABEL_MORE",

View File

@@ -46,8 +46,8 @@
"145"; "0";"BLOCK_ICE_FRAGILE" ;"0.0508";"0.0508";"0.0508";"0.0508"; "5"; "930";"ICEI"; "1"; "0"; "1"; "0"; "0"; "0"; "N/A"; "0"; "4";"0.0000";"0.0000";"0.0000";"0.0000"
"146"; "146";"BLOCK_ICE_NATURAL" ;"0.1016";"0.1016";"0.1016";"0.1016"; "35"; "930";"ICEI"; "1"; "0"; "1"; "1"; "0"; "0"; "N/A"; "0"; "4";"0.0000";"0.0000";"0.0000";"0.0000"
"147"; "147";"BLOCK_ICE_CLEAR_MAGICAL" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"3720";"ICEX"; "1"; "0"; "1"; "1"; "0"; "0"; "N/A"; "0"; "4";"0.0744";"0.1252";"0.2268";"0.0000"
"148"; "148";"BLOCK_GLASS_CRUDE" ;"0.0120";"0.0040";"0.0120";"0.0080"; "5";"2500";"GLAS"; "1"; "0"; "1"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
"149"; "149";"BLOCK_GLASS_CLEAN" ;"0.0040";"0.0040";"0.0040";"0.0020"; "5";"2203";"GLAS"; "1"; "0"; "1"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
"148"; "148";"BLOCK_GLASS_CRUDE" ;"0.0876";"0.0424";"0.0876";"0.1252"; "5";"2500";"GLAS"; "1"; "0"; "1"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
"149"; "149";"BLOCK_GLASS_CLEAN" ;"0.0424";"0.0424";"0.0424";"0.0636"; "5";"2203";"GLAS"; "1"; "0"; "1"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
"160"; "160";"BLOCK_PLATFORM_STONE" ;"0.0312";"0.0312";"0.0312";"0.0312"; "5"; "N/A";"ROCK"; "0"; "1"; "1"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
"161"; "161";"BLOCK_PLATFORM_WOODEN" ;"0.0312";"0.0312";"0.0312";"0.0312"; "5"; "N/A";"WOOD"; "0"; "1"; "1"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
"162"; "162";"BLOCK_PLATFORM_EBONY" ;"0.0312";"0.0312";"0.0312";"0.0312"; "5"; "N/A";"WOOD"; "0"; "1"; "1"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
@@ -98,15 +98,15 @@
"256"; "256";"BLOCK_LANTERN_IRON_REGULAR" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"FXTR"; "0"; "0"; "1"; "0"; "0"; "0"; "N/A"; "0";"16";"1.0000";"0.6372";"0.0000";"0.0000"
"257"; "257";"BLOCK_SUNSTONE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"ROCK"; "1"; "0"; "0"; "0"; "0"; "2"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
"258"; "258";"BLOCK_DAYLIGHT_CAPACITOR" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "0"; "0"; "3"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
"4094"; "0";"BLOCK_LAVA" ;"0.9696";"0.9696";"0.9696";"0.9696";"100";"2600";"ROCK"; "0"; "0"; "1"; "0"; "0"; "0"; "32"; "0";"16";"0.7664";"0.2032";"0.0000";"0.0000"
"4095"; "0";"BLOCK_WATER" ;"0.1016";"0.0744";"0.0508";"0.0508";"100";"1000";"WATR"; "0"; "0"; "1"; "0"; "0"; "0"; "16"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
"4096"; "0";"BLOCK_WATER" ;"0.1016";"0.0744";"0.0508";"0.0826";"100";"1000";"WATR"; "0"; "0"; "1"; "0"; "0"; "0"; "16"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
"4097"; "0";"BLOCK_LAVA" ;"0.9696";"0.9696";"0.9696";"0.9696";"100";"2600";"ROCK"; "0"; "0"; "1"; "0"; "0"; "0"; "32"; "0";"16";"0.7664";"0.2032";"0.0000";"0.0000"
"-1"; "0";"BLOCK_NULL" ;"4.0000";"4.0000";"4.0000";"4.0000"; "-1";"2600";"NULL"; "0"; "0"; "1"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
## Notes ##
#
# Lava/Water props are left for future references, do not delete them until FluidCodex is built #
#
# id: Block ID
# id: Block ID. ID equal to or greater than 4096 is for fluids, mainly for lighting calculation.
# drop: Drop ID
#
# shdr/g/b, lumr/g/b: Shade RGB/ Lum RGB.
Can't render this file because it contains an unexpected character in line 1 and column 20.

Binary file not shown.

View File

@@ -8,22 +8,22 @@
"multithread": true,
"joypadkeyn": 4,
"joypadkeyw": 1,
"joypadkeys": 2,
"joypadkeye": 3,
"gamepadkeyn": 4,
"gamepadkeyw": 1,
"gamepadkeys": 2,
"gamepadkeye": 3,
"joypadlup": 4,
"joypadrup": 5,
"joypadldown": 6,
"joypadrdown": 7,
"gamepadlup": 4,
"gamepadrup": 5,
"gamepadldown": 6,
"gamepadrdown": 7,
"joypadlstickx": 0,
"joypadlsticky": 1,
"joypadrstickx": 2,
"joypadrsticky": 3,
"gamepadlstickx": 0,
"gamepadlsticky": 1,
"gamepadrstickx": 2,
"gamepadrsticky": 3,
"joypadlabelstyle": "msxb360",
"gamepadlabelstyle": "msxb360",
"keyup": 33,

BIN
assets/mods/basegame/demoworld.gz LFS Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -10,5 +10,5 @@ uniform sampler2D u_texture;
void main(void) {
gl_FragColor = texture2D(u_texture, v_texCoords);
gl_FragColor = vec4(texture2D(u_texture, v_texCoords).rgb, 1.0);
}

108
assets/raytracelight.frag Normal file
View File

@@ -0,0 +1,108 @@
#version 120
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_color;
varying vec2 v_texCoords;
// all 3 must have the same dimension!
// the divisor of 2 input and an output must be the same. I.e. either divide all by 4, or not.
uniform sampler2D shades;
uniform sampler2D lights;
// WARNING -- Gdx.Color.toIntBits returns ABGR, but GLSL expects RGBA. Use the function Color.toRGBA() in LightmapRenderNew
uniform sampler2D u_texture;
uniform vec2 outSize;
uniform float multiplier = 4.0; // if divided by four, put 4.0 in there
#define TRAVERSE_SIZE 128 // should be good for screen size up to 1920 for tile size of 16
vec4 sampleFrom(sampler2D from, vec2 which) {
return texture2D(from, which / outSize);
}
int traceRayCount(vec2 delta) {
vec2 absDelta = abs(delta);
int arraySize = int(max(absDelta.x, absDelta.y));
return arraySize + 1;
}
vec2[TRAVERSE_SIZE] traceRay(int arraySize, vec2 from, vec2 to) {
vec2 delta = to - from;
vec2[TRAVERSE_SIZE] returnArray;
int arri = 0;
// if the line is not vertical...
if (delta.x != 0) {
float deltaError = abs(delta.y / delta.x);
float error = 0.0;
float traceY = from.y;
for (float traceX = from.x; traceX <= to.x; traceX++) {
// plot(traceX, traceY)
returnArray[arri] = vec2(traceX, traceY);
arri = arri + 1;
error = error + deltaError;
if (error >= 0.5) {
traceY = traceY + sign(delta.y);
error = error - 1.0;
}
}
}
else {
for (float traceY = from.y; traceY <= to.y; traceY++) {
returnArray[arri] = vec2(from.x, traceY);
}
}
return returnArray;
}
void main() {
// this code will produce y-flipped image. It's your job to flip it again (e.g. using y-flipped fullscreen quad)
// Nice try, but it kills GPU :(
// reason: looks like traceRayCount() returns value greater than TRAVERSE_SIZE.
// even if I make traceRayCount() to return constant 3, I get less than 1 fps on GTX 970.
vec4 outColor = vec4(0.0,0.0,0.0,0.0);
// 1. pick a light source
for (int y = 0; y < int(outSize.y); y++) {
for (int x = 0; x < int(outSize.x); x++) {
vec2 from = vec2(x + 0.5, y + 0.5); // +0.5 is used because gl_FragCoord does
vec2 to = gl_FragCoord.xy;
vec2 delta = to - from;
int traceCount = traceRayCount(delta);
vec4 light = sampleFrom(lights, from);
// 2. get a trace path
vec2[TRAVERSE_SIZE] returnArray = traceRay(traceCount, from, to);
// 2.1 get angular darkening coefficient
vec2 unitVec = delta / max(delta.x, delta.y);
float angularDimming = sqrt(unitVec.x * unitVec.x + unitVec.y * unitVec.y);
//float angularDimming = 1.0; // TODO depends on the angle of (lightPos, gl_FragCoord.x)
// 3. traverse the light path to dim the "light"
// var "light" will be attenuated after this loop
for (int i = 0; i < traceCount; i++) {
vec4 shade = sampleFrom(shades, returnArray[i]) * angularDimming;
light = light - shade;
}
// 4. mix the incoming light into the light buffer.
outColor = max(outColor, light);
}
}
gl_FragColor = outColor * multiplier;
//gl_FragColor = vec4(0,1,0,1);
//gl_FragColor = sampleFrom(lights, gl_FragCoord.xy) * multiplier;
}

View File

@@ -87,18 +87,18 @@ void main() {
ivec2 breakageXY = getTileXY(breakage + 5); // +5 is hard-coded constant that depends on the atlas
mediump vec2 coordInTile = mod(pxCoord, tileSizeInPx) / tileSizeInPx; // 0..1 regardless of tile position in atlas
vec2 coordInTile = mod(pxCoord, tileSizeInPx) / tileSizeInPx; // 0..1 regardless of tile position in atlas
// don't really need highp here; read the GLES spec
mediump vec2 singleTileSizeInUV = vec2(1) / tilesInAtlas; // constant 0.00390625 for unmodified default uniforms
vec2 singleTileSizeInUV = vec2(1) / tilesInAtlas; // constant 0.00390625 for unmodified default uniforms
mediump vec2 uvCoordForTile = coordInTile * singleTileSizeInUV; // 0..0.00390625 regardless of tile position in atlas
vec2 uvCoordForTile = coordInTile * singleTileSizeInUV; // 0..0.00390625 regardless of tile position in atlas
mediump vec2 uvCoordOffsetTile = tileXY * singleTileSizeInUV; // where the tile starts in the atlas, using uv coord (0..1)
mediump vec2 uvCoordOffsetBreakage = breakageXY * singleTileSizeInUV;
vec2 uvCoordOffsetTile = tileXY * singleTileSizeInUV; // where the tile starts in the atlas, using uv coord (0..1)
vec2 uvCoordOffsetBreakage = breakageXY * singleTileSizeInUV;
mediump vec2 finalUVCoordForTile = uvCoordForTile + uvCoordOffsetTile;// where we should be actually looking for in atlas, using UV coord (0..1)
mediump vec2 finalUVCoordForBreakage = uvCoordForTile + uvCoordOffsetBreakage;
vec2 finalUVCoordForTile = uvCoordForTile + uvCoordOffsetTile;// where we should be actually looking for in atlas, using UV coord (0..1)
vec2 finalUVCoordForBreakage = uvCoordForTile + uvCoordOffsetBreakage;
// blending a breakage tex with main tex
@@ -110,7 +110,7 @@ void main() {
vec4 finalBreakage = texture2D(tilesAtlas, finalUVCoordForBreakage);
vec4 finalColor = mix(finalTile, finalBreakage, finalBreakage.a);
vec4 finalColor = vec4(mix(finalTile.rgb, finalBreakage.rgb, finalBreakage.a), finalTile.a);
gl_FragColor = colourFilter * finalColor;

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,743 @@
/*******************************************************************************
* Copyright 2011 See AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.badlogic.gdx.backends.lwjgl;
import com.badlogic.gdx.Application;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Graphics;
import com.badlogic.gdx.graphics.Cursor.SystemCursor;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.GL30;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.glutils.GLVersion;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.GdxRuntimeException;
import com.badlogic.gdx.utils.SharedLibraryLoader;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.ContextAttribs;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.PixelFormat;
import java.awt.*;
import java.nio.ByteBuffer;
/** An implementation of the {@link Graphics} interface based on Lwjgl.
* @author mzechner */
public class LwjglGraphics implements Graphics {
/** The suppored OpenGL extensions */
static Array<String> extensions;
static GLVersion glVersion;
GL20 gl20;
GL30 gl30;
long frameId = -1;
float deltaTime = 0;
long frameStart = 0;
int frames = 0;
int fps;
long lastTime = System.nanoTime();
Canvas canvas;
boolean vsync = false;
boolean resize = false;
LwjglApplicationConfiguration config;
BufferFormat bufferFormat = new BufferFormat(8, 8, 8, 8, 16, 8, 0, false);
volatile boolean isContinuous = true;
volatile boolean requestRendering = false;
boolean softwareMode;
boolean usingGL30;
// deltaTime kalman filter related variables
private float kalmanEstimate = 1.0f/60.0f;
private float kalmanErrorCovariance = 1.0f;
private final float kalmanErrorRate = 0.2f; // 0.2: empirical value
private final float kalmanUpdateThreshold = 0.1f;
private final float getMagnitudeDifferenceEpsilon = 0.00001f;
LwjglGraphics (LwjglApplicationConfiguration config) {
this.config = config;
}
LwjglGraphics (Canvas canvas) {
this.config = new LwjglApplicationConfiguration();
config.width = canvas.getWidth();
config.height = canvas.getHeight();
this.canvas = canvas;
}
LwjglGraphics (Canvas canvas, LwjglApplicationConfiguration config) {
this.config = config;
this.canvas = canvas;
}
public int getHeight () {
if (canvas != null)
return Math.max(1, canvas.getHeight());
else
return (int)(Display.getHeight() * Display.getPixelScaleFactor());
}
public int getWidth () {
if (canvas != null)
return Math.max(1, canvas.getWidth());
else
return (int)(Display.getWidth() * Display.getPixelScaleFactor());
}
@Override
public int getBackBufferWidth () {
return getWidth();
}
@Override
public int getBackBufferHeight () {
return getHeight();
}
public long getFrameId () {
return frameId;
}
public float getDeltaTime () {
return kalmanEstimate;
}
private void resetDeltaSmoothingHistory() {
kalmanEstimate = 1.0f/60.0f;
kalmanErrorCovariance = 1.0f;
}
// only for a > 0 && b > 0
private float getMagnitudeDifference(float a, float b) {
if (a < getMagnitudeDifferenceEpsilon || b < getMagnitudeDifferenceEpsilon) {
return (a + b) / getMagnitudeDifferenceEpsilon;
}
if (a > b) {
return a / b;
}
else {
return b / a;
}
}
private void updateKalmanRenderDelta() {
// The problem with this kalman filter is that it assumes most simplistic situation:
// 1. the actual delta (measured delta - noise) is constant (that is, not constantly increasing or something)
// 2. everything is linear
// We may need to implement Extended Kalman Filter but what is Jacobian, I suck at maths.
//
// Instead, this implementation will reset itself when difference in magnitude between
// old and new is greater than set value.
//
// It's not perfect but it works, much better than averaging.
if (getMagnitudeDifference(deltaTime, kalmanEstimate) >= 2.0) {
resetDeltaSmoothingHistory();
}
// measurement value
float observation = deltaTime;
if (observation <= kalmanUpdateThreshold) {
// time update
float priorEstimate = kalmanEstimate;
float priorError = kalmanErrorCovariance;
// measurement update
float gain = priorError / (priorError + kalmanErrorRate);
float newEstimate = priorEstimate + gain * (observation - priorEstimate);
float newError = (1.0f - gain) * priorError;
kalmanEstimate = newEstimate;
kalmanErrorCovariance = newError;
}
}
public float getRawDeltaTime () {
return deltaTime;
}
public GraphicsType getType () {
return GraphicsType.LWJGL;
}
public GLVersion getGLVersion () {
return glVersion;
}
public boolean isGL20Available () {
return gl20 != null;
}
public GL20 getGL20 () {
return gl20;
}
@Override
public void setGL20 (GL20 gl20) {
this.gl20 = gl20;
if (gl30 == null) {
Gdx.gl = gl20;
Gdx.gl20 = gl20;
}
}
@Override
public boolean isGL30Available () {
return gl30 != null;
}
@Override
public GL30 getGL30 () {
return gl30;
}
@Override
public void setGL30 (GL30 gl30) {
this.gl30 = gl30;
if (gl30 != null) {
this.gl20 = gl30;
Gdx.gl = gl20;
Gdx.gl20 = gl20;
Gdx.gl30 = gl30;
}
}
public int getFramesPerSecond () {
return fps;
}
void updateTime () {
long time = System.nanoTime();
deltaTime = (time - lastTime) / 1000000000.0f;
lastTime = time;
if (time - frameStart >= 1000000000) {
fps = frames;
frames = 0;
frameStart = time;
}
frames++;
updateKalmanRenderDelta();
}
void setupDisplay () throws LWJGLException {
if (config.useHDPI) {
System.setProperty("org.lwjgl.opengl.Display.enableHighDPI", "true");
}
if (canvas != null) {
Display.setParent(canvas);
} else {
boolean displayCreated = false;
if(!config.fullscreen) {
displayCreated = setWindowedMode(config.width, config.height);
} else {
DisplayMode bestMode = null;
for(DisplayMode mode: getDisplayModes()) {
if(mode.width == config.width && mode.height == config.height) {
if(bestMode == null || bestMode.refreshRate < this.getDisplayMode().refreshRate) {
bestMode = mode;
}
}
}
if(bestMode == null) {
bestMode = this.getDisplayMode();
}
displayCreated = setFullscreenMode(bestMode);
}
if (!displayCreated) {
if (config.setDisplayModeCallback != null) {
config = config.setDisplayModeCallback.onFailure(config);
if (config != null) {
displayCreated = setWindowedMode(config.width, config.height);
}
}
if (!displayCreated) {
throw new GdxRuntimeException("Couldn't set display mode " + config.width + "x" + config.height + ", fullscreen: "
+ config.fullscreen);
}
}
if (config.iconPaths.size > 0) {
ByteBuffer[] icons = new ByteBuffer[config.iconPaths.size];
for (int i = 0, n = config.iconPaths.size; i < n; i++) {
Pixmap pixmap = new Pixmap(Gdx.files.getFileHandle(config.iconPaths.get(i), config.iconFileTypes.get(i)));
if (pixmap.getFormat() != Format.RGBA8888) {
Pixmap rgba = new Pixmap(pixmap.getWidth(), pixmap.getHeight(), Format.RGBA8888);
rgba.drawPixmap(pixmap, 0, 0);
pixmap.dispose();
pixmap = rgba;
}
icons[i] = ByteBuffer.allocateDirect(pixmap.getPixels().limit());
icons[i].put(pixmap.getPixels()).flip();
pixmap.dispose();
}
Display.setIcon(icons);
}
}
Display.setTitle(config.title);
Display.setResizable(config.resizable);
Display.setInitialBackground(config.initialBackgroundColor.r, config.initialBackgroundColor.g,
config.initialBackgroundColor.b);
Display.setLocation(config.x, config.y);
createDisplayPixelFormat(config.useGL30, config.gles30ContextMajorVersion, config.gles30ContextMinorVersion);
initiateGL();
}
/**
* Only needed when setupDisplay() is not called.
*/
void initiateGL() {
extractVersion();
extractExtensions();
initiateGLInstances();
}
private static void extractVersion () {
String versionString = org.lwjgl.opengl.GL11.glGetString(GL11.GL_VERSION);
String vendorString = org.lwjgl.opengl.GL11.glGetString(GL11.GL_VENDOR);
String rendererString = org.lwjgl.opengl.GL11.glGetString(GL11.GL_RENDERER);
glVersion = new GLVersion(Application.ApplicationType.Desktop, versionString, vendorString, rendererString);
}
private static void extractExtensions () {
extensions = new Array<String>();
if (glVersion.isVersionEqualToOrHigher(3, 2)) {
int numExtensions = GL11.glGetInteger(GL30.GL_NUM_EXTENSIONS);
for (int i = 0; i < numExtensions; ++i)
extensions.add(org.lwjgl.opengl.GL30.glGetStringi(GL20.GL_EXTENSIONS, i));
} else {
extensions.addAll(org.lwjgl.opengl.GL11.glGetString(GL20.GL_EXTENSIONS).split(" "));
}
}
/** @return whether the supported OpenGL (not ES) version is compatible with OpenGL ES 3.x. */
private static boolean fullCompatibleWithGLES3 () {
// OpenGL ES 3.0 is compatible with OpenGL 4.3 core, see http://en.wikipedia.org/wiki/OpenGL_ES#OpenGL_ES_3.0
return glVersion.isVersionEqualToOrHigher(4, 3);
}
/** @return whether the supported OpenGL (not ES) version is compatible with OpenGL ES 2.x. */
private static boolean fullCompatibleWithGLES2 () {
// OpenGL ES 2.0 is compatible with OpenGL 4.1 core
// see https://www.opengl.org/registry/specs/ARB/ES2_compatibility.txt
return glVersion.isVersionEqualToOrHigher(4, 1) || extensions.contains("GL_ARB_ES2_compatibility", false);
}
private static boolean supportsFBO () {
// FBO is in core since OpenGL 3.0, see https://www.opengl.org/wiki/Framebuffer_Object
return glVersion.isVersionEqualToOrHigher(3, 0) || extensions.contains("GL_EXT_framebuffer_object", false)
|| extensions.contains("GL_ARB_framebuffer_object", false);
}
private void createDisplayPixelFormat (boolean useGL30, int gles30ContextMajor, int gles30ContextMinor) {
try {
if (useGL30) {
ContextAttribs context = new ContextAttribs(gles30ContextMajor, gles30ContextMinor).withForwardCompatible(false)
.withProfileCore(true);
try {
Display.create(new PixelFormat(config.r + config.g + config.b, config.a, config.depth, config.stencil,
config.samples), context);
} catch (Exception e) {
System.out.println("LwjglGraphics: OpenGL " + gles30ContextMajor + "." + gles30ContextMinor
+ "+ core profile (GLES 3.0) not supported.");
createDisplayPixelFormat(false, gles30ContextMajor, gles30ContextMinor);
return;
}
System.out.println("LwjglGraphics: created OpenGL " + gles30ContextMajor + "." + gles30ContextMinor
+ "+ core profile (GLES 3.0) context. This is experimental!");
usingGL30 = true;
} else {
Display
.create(new PixelFormat(config.r + config.g + config.b, config.a, config.depth, config.stencil, config.samples));
usingGL30 = false;
}
bufferFormat = new BufferFormat(config.r, config.g, config.b, config.a, config.depth, config.stencil, config.samples,
false);
} catch (Exception ex) {
Display.destroy();
try {
Thread.sleep(200);
} catch (InterruptedException ignored) {
}
try {
Display.create(new PixelFormat(0, 16, 8));
if (getDisplayMode().bitsPerPixel == 16) {
bufferFormat = new BufferFormat(5, 6, 5, 0, 16, 8, 0, false);
}
if (getDisplayMode().bitsPerPixel == 24) {
bufferFormat = new BufferFormat(8, 8, 8, 0, 16, 8, 0, false);
}
if (getDisplayMode().bitsPerPixel == 32) {
bufferFormat = new BufferFormat(8, 8, 8, 8, 16, 8, 0, false);
}
} catch (Exception ex2) {
Display.destroy();
try {
Thread.sleep(200);
} catch (InterruptedException ignored) {
}
try {
Display.create(new PixelFormat());
} catch (Exception ex3) {
if (!softwareMode && config.allowSoftwareMode) {
softwareMode = true;
System.setProperty("org.lwjgl.opengl.Display.allowSoftwareOpenGL", "true");
createDisplayPixelFormat(useGL30, gles30ContextMajor, gles30ContextMinor);
return;
}
throw new GdxRuntimeException("OpenGL is not supported by the video driver.", ex3);
}
if (getDisplayMode().bitsPerPixel == 16) {
bufferFormat = new BufferFormat(5, 6, 5, 0, 8, 0, 0, false);
}
if (getDisplayMode().bitsPerPixel == 24) {
bufferFormat = new BufferFormat(8, 8, 8, 0, 8, 0, 0, false);
}
if (getDisplayMode().bitsPerPixel == 32) {
bufferFormat = new BufferFormat(8, 8, 8, 8, 8, 0, 0, false);
}
}
}
}
public void initiateGLInstances () {
if (usingGL30) {
gl30 = new LwjglGL30();
gl20 = gl30;
} else {
gl20 = new LwjglGL20();
}
if (!glVersion.isVersionEqualToOrHigher(2, 0))
throw new GdxRuntimeException("OpenGL 2.0 or higher with the FBO extension is required. OpenGL version: "
+ GL11.glGetString(GL11.GL_VERSION) + "\n" + glVersion.getDebugVersionString());
if (!supportsFBO()) {
throw new GdxRuntimeException("OpenGL 2.0 or higher with the FBO extension is required. OpenGL version: "
+ GL11.glGetString(GL11.GL_VERSION) + ", FBO extension: false\n" + glVersion.getDebugVersionString());
}
Gdx.gl = gl20;
Gdx.gl20 = gl20;
Gdx.gl30 = gl30;
}
@Override
public float getPpiX () {
return Toolkit.getDefaultToolkit().getScreenResolution();
}
@Override
public float getPpiY () {
return Toolkit.getDefaultToolkit().getScreenResolution();
}
@Override
public float getPpcX () {
return (Toolkit.getDefaultToolkit().getScreenResolution() / 2.54f);
}
@Override
public float getPpcY () {
return (Toolkit.getDefaultToolkit().getScreenResolution() / 2.54f);
}
@Override
public float getDensity () {
if (config.overrideDensity != -1) return config.overrideDensity / 160f;
return (Toolkit.getDefaultToolkit().getScreenResolution() / 160f);
}
@Override
public boolean supportsDisplayModeChange () {
return true;
}
@Override
public Monitor getPrimaryMonitor () {
return new LwjglMonitor(0, 0, "Primary Monitor");
}
@Override
public Monitor getMonitor () {
return getPrimaryMonitor();
}
@Override
public Monitor[] getMonitors () {
return new Monitor[] { getPrimaryMonitor() };
}
@Override
public DisplayMode[] getDisplayModes (Monitor monitor) {
return getDisplayModes();
}
@Override
public DisplayMode getDisplayMode (Monitor monitor) {
return getDisplayMode();
}
@Override
public boolean setFullscreenMode (DisplayMode displayMode) {
org.lwjgl.opengl.DisplayMode mode = ((LwjglDisplayMode)displayMode).mode;
try {
if (!mode.isFullscreenCapable()) {
Display.setDisplayMode(mode);
} else {
Display.setDisplayModeAndFullscreen(mode);
}
float scaleFactor = Display.getPixelScaleFactor();
config.width = (int)(mode.getWidth() * scaleFactor);
config.height = (int)(mode.getHeight() * scaleFactor);
if (Gdx.gl != null) Gdx.gl.glViewport(0, 0, config.width, config.height);
resize = true;
return true;
} catch (LWJGLException e) {
return false;
}
}
/** Kindly stolen from http://lwjgl.org/wiki/index.php?title=LWJGL_Basics_5_(Fullscreen), not perfect but will do. */
@Override
public boolean setWindowedMode (int width, int height) {
if (getWidth() == width && getHeight() == height && !Display.isFullscreen()) {
return true;
}
try {
org.lwjgl.opengl.DisplayMode targetDisplayMode = null;
boolean fullscreen = false;
if (fullscreen) {
org.lwjgl.opengl.DisplayMode[] modes = Display.getAvailableDisplayModes();
int freq = 0;
for (int i = 0; i < modes.length; i++) {
org.lwjgl.opengl.DisplayMode current = modes[i];
if ((current.getWidth() == width) && (current.getHeight() == height)) {
if ((targetDisplayMode == null) || (current.getFrequency() >= freq)) {
if ((targetDisplayMode == null) || (current.getBitsPerPixel() > targetDisplayMode.getBitsPerPixel())) {
targetDisplayMode = current;
freq = targetDisplayMode.getFrequency();
}
}
// if we've found a match for bpp and frequence against the
// original display mode then it's probably best to go for this one
// since it's most likely compatible with the monitor
if ((current.getBitsPerPixel() == Display.getDesktopDisplayMode().getBitsPerPixel())
&& (current.getFrequency() == Display.getDesktopDisplayMode().getFrequency())) {
targetDisplayMode = current;
break;
}
}
}
} else {
targetDisplayMode = new org.lwjgl.opengl.DisplayMode(width, height);
}
if (targetDisplayMode == null) {
return false;
}
boolean resizable = !fullscreen && config.resizable;
Display.setDisplayMode(targetDisplayMode);
Display.setFullscreen(fullscreen);
// Workaround for bug in LWJGL whereby resizable state is lost on DisplayMode change
if (resizable == Display.isResizable()) {
Display.setResizable(!resizable);
}
Display.setResizable(resizable);
float scaleFactor = Display.getPixelScaleFactor();
config.width = (int)(targetDisplayMode.getWidth() * scaleFactor);
config.height = (int)(targetDisplayMode.getHeight() * scaleFactor);
if (Gdx.gl != null) Gdx.gl.glViewport(0, 0, config.width, config.height);
resize = true;
return true;
} catch (LWJGLException e) {
return false;
}
}
@Override
public DisplayMode[] getDisplayModes () {
try {
org.lwjgl.opengl.DisplayMode[] availableDisplayModes = Display.getAvailableDisplayModes();
DisplayMode[] modes = new DisplayMode[availableDisplayModes.length];
int idx = 0;
for (org.lwjgl.opengl.DisplayMode mode : availableDisplayModes) {
if (mode.isFullscreenCapable()) {
modes[idx++] = new LwjglDisplayMode(mode.getWidth(), mode.getHeight(), mode.getFrequency(),
mode.getBitsPerPixel(), mode);
}
}
return modes;
} catch (LWJGLException e) {
throw new GdxRuntimeException("Couldn't fetch available display modes", e);
}
}
@Override
public DisplayMode getDisplayMode () {
org.lwjgl.opengl.DisplayMode mode = Display.getDesktopDisplayMode();
return new LwjglDisplayMode(mode.getWidth(), mode.getHeight(), mode.getFrequency(), mode.getBitsPerPixel(), mode);
}
@Override
public void setTitle (String title) {
Display.setTitle(title);
}
/**
* Display must be reconfigured via {@link #setWindowedMode(int, int)} for the changes to take
* effect.
*/
@Override
public void setUndecorated (boolean undecorated) {
System.setProperty("org.lwjgl.opengl.Window.undecorated", undecorated ? "true" : "false");
}
/**
* Display must be reconfigured via {@link #setWindowedMode(int, int)} for the changes to take
* effect.
*/
@Override
public void setResizable (boolean resizable) {
this.config.resizable = resizable;
Display.setResizable(resizable);
}
@Override
public BufferFormat getBufferFormat () {
return bufferFormat;
}
@Override
public void setVSync (boolean vsync) {
this.vsync = vsync;
Display.setVSyncEnabled(vsync);
}
@Override
public boolean supportsExtension (String extension) {
return extensions.contains(extension, false);
}
@Override
public void setContinuousRendering (boolean isContinuous) {
this.isContinuous = isContinuous;
}
@Override
public boolean isContinuousRendering () {
return isContinuous;
}
@Override
public void requestRendering () {
synchronized (this) {
requestRendering = true;
}
}
public boolean shouldRender () {
synchronized (this) {
boolean rq = requestRendering;
requestRendering = false;
return rq || isContinuous || Display.isDirty();
}
}
@Override
public boolean isFullscreen () {
return Display.isFullscreen();
}
public boolean isSoftwareMode () {
return softwareMode;
}
/** A callback used by LwjglApplication when trying to create the display */
public interface SetDisplayModeCallback {
/** If the display creation fails, this method will be called. Suggested usage is to modify the passed configuration to use a
* common width and height, and set fullscreen to false.
* @return the configuration to be used for a second attempt at creating a display. A null value results in NOT attempting
* to create the display a second time */
public LwjglApplicationConfiguration onFailure (LwjglApplicationConfiguration initialConfig);
}
@Override
public com.badlogic.gdx.graphics.Cursor newCursor (Pixmap pixmap, int xHotspot, int yHotspot) {
return new LwjglCursor(pixmap, xHotspot, yHotspot);
}
@Override
public void setCursor (com.badlogic.gdx.graphics.Cursor cursor) {
if (canvas != null && SharedLibraryLoader.isMac) {
return;
}
try {
Mouse.setNativeCursor(((LwjglCursor)cursor).lwjglCursor);
} catch (LWJGLException e) {
throw new GdxRuntimeException("Could not set cursor image.", e);
}
}
@Override
public void setSystemCursor (SystemCursor systemCursor) {
if (canvas != null && SharedLibraryLoader.isMac) {
return;
}
try {
Mouse.setNativeCursor(null);
} catch (LWJGLException e) {
throw new GdxRuntimeException("Couldn't set system cursor");
}
}
private class LwjglDisplayMode extends DisplayMode {
org.lwjgl.opengl.DisplayMode mode;
public LwjglDisplayMode (int width, int height, int refreshRate, int bitsPerPixel, org.lwjgl.opengl.DisplayMode mode) {
super(width, height, refreshRate, bitsPerPixel);
this.mode = mode;
}
}
private class LwjglMonitor extends Monitor {
protected LwjglMonitor (int virtualX, int virtualY, String name) {
super(virtualX, virtualY, name);
}
}
}

View File

@@ -13,7 +13,7 @@ import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
class SpriteAnimation(val parentActor: ActorWBMovable) {
private lateinit var textureRegion: TextureRegionPack
lateinit var textureRegion: TextureRegionPack; private set
var currentFrame = 0
var currentRow = 0

View File

@@ -7,11 +7,11 @@ import java.util.*
import kotlin.collections.HashMap
import kotlin.collections.HashSet
data class Joint(val name: String, val position: ADPropertyObject.Vector2i) {
internal data class Joint(val name: String, val position: ADPropertyObject.Vector2i) {
override fun toString() = "$name $position"
}
data class Skeleton(val name: String, val joints: List<Joint>) {
internal data class Skeleton(val name: String, val joints: List<Joint>) {
override fun toString() = "$name=$joints"
}
@@ -22,12 +22,12 @@ data class Skeleton(val name: String, val joints: List<Joint>) {
* @param frames number of frames this animation has
* @param skeleton list of joints to be transformed
*/
data class Animation(val name: String, val delay: Float, val row: Int, val frames: Int, val skeleton: Skeleton) {
internal data class Animation(val name: String, val delay: Float, val row: Int, val frames: Int, val skeleton: Skeleton) {
override fun toString() = "$name delay: $delay, row: $row, frames: $frames, skeleton: ${skeleton.name}"
}
/** Later the 'translate' can be changed so that it represents affine transformation (Matrix2d) */
data class Transform(val joint: Joint, val translate: ADPropertyObject.Vector2i) {
internal data class Transform(val joint: Joint, val translate: ADPropertyObject.Vector2i) {
override fun toString() = "$joint transform: $translate"
}
@@ -41,11 +41,11 @@ class ADProperties {
lateinit var bodyparts: List<String>; private set
lateinit var bodypartFiles: List<String>; private set
/** properties that are being used as skeletons (SKELETON_STAND) */
lateinit var skeletons: HashMap<String, Skeleton>; private set
internal lateinit var skeletons: HashMap<String, Skeleton>; private set
/** properties that are recognised as animations (ANIM_RUN, ANIM)IDLE) */
lateinit var animations: HashMap<String, Animation>; private set
internal lateinit var animations: HashMap<String, Animation>; private set
/** an "animation frame" property (ANIM_RUN_1, ANIM_RUN_2) */
lateinit var transforms: HashMap<String, List<Transform>>; private set
internal lateinit var transforms: HashMap<String, List<Transform>>; private set
private val reservedProps = listOf("SPRITESHEET", "EXTENSION")
private val animMustContain = listOf("DELAY", "ROW", "SKELETON")
@@ -56,7 +56,7 @@ class ADProperties {
var frameHeight: Int = -1; private set
var originX: Int = -1; private set
var originY: Int = -1; private set
val origin: ADPropertyObject.Vector2i
internal val origin: ADPropertyObject.Vector2i
get() = ADPropertyObject.Vector2i(originX, originY)
private val animFrameSuffixRegex = Regex("""_[0-9]+""")
@@ -209,11 +209,11 @@ class ADProperties {
fun toFilename(partName: String) =
"${this.baseFilename}${partName.toLowerCase()}${this.extension}"
fun getAnimByFrameName(frameName: String) = animations[getAnimNameFromFrame(frameName)]!!
fun getFrameNumberFromName(frameName: String) = frameName.substring(frameName.lastIndexOf('_') + 1 until frameName.length).toInt()
internal fun getAnimByFrameName(frameName: String) = animations[getAnimNameFromFrame(frameName)]!!
internal fun getFrameNumberFromName(frameName: String) = frameName.substring(frameName.lastIndexOf('_') + 1 until frameName.length).toInt()
fun getSkeleton(name: String) = skeletons[name]!!
fun getTransform(name: String) = transforms[name]!!
internal fun getSkeleton(name: String) = skeletons[name]!!
internal fun getTransform(name: String) = transforms[name]!!
private fun getAnimNameFromFrame(s: String) = s.substring(0 until s.lastIndexOf('_'))
@@ -271,7 +271,7 @@ class ADPropertyObject(propertyRaw: String) {
}
}
companion object {
internal companion object {
private val floatRegex = Regex("""-?[0-9]+(\.[0-9]*)?""")
private val ivec2Regex = Regex("""-?[0-9]+,-?[0-9]+""")
private val variableInputSepRegex = Regex(""" +""")
@@ -292,7 +292,7 @@ class ADPropertyObject(propertyRaw: String) {
fun isADstring(property: String) = !isADvariable(property)
}
data class Vector2i(var x: Int, var y: Int) {
internal data class Vector2i(var x: Int, var y: Int) {
override fun toString() = "($x, $y)"
operator fun plus(other: Vector2i) = Vector2i(this.x + other.x, this.y + other.y)

View File

@@ -89,7 +89,7 @@ object AssembleSheetPixmap {
}
object AssembleFrameBase {
internal object AssembleFrameBase {
/**
* Returns joints list with tranform applied.
* @param skeleton list of joints

View File

@@ -1,8 +1,7 @@
package net.torvald.terrarum;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.*;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.audio.AudioDevice;
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
@@ -16,11 +15,19 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import net.torvald.dataclass.ArrayListMap;
import net.torvald.getcpuname.GetCpuName;
import net.torvald.terrarum.gamecontroller.KeyToggler;
import net.torvald.terrarum.imagefont.TinyAlphNum;
import net.torvald.terrarum.modulebasegame.Ingame;
import net.torvald.terrarum.modulebasegame.IngameRenderer;
import net.torvald.terrarum.utils.JsonFetcher;
import net.torvald.terrarum.utils.JsonWriter;
import net.torvald.terrarum.worlddrawer.BlocksDrawer;
import net.torvald.terrarum.worlddrawer.LightmapRenderer;
import net.torvald.terrarumsansbitmap.gdx.GameFontBase;
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack;
import org.lwjgl.input.Controller;
import org.lwjgl.input.Controllers;
import java.io.File;
import java.io.IOException;
@@ -106,9 +113,26 @@ public class AppLoader implements ApplicationListener {
}
public static final String GAME_NAME = "Terrarum";
public static final String COPYRIGHT_DATE_NAME = "Copyright 2013-2018 Torvald (minjaesong)";
public static final String COPYRIGHT_DATE_NAME = "Copyright 2013-2019 Torvald (minjaesong)";
public static String GAME_LOCALE = System.getProperty("user.language") + System.getProperty("user.country");
public static final String systemArch = System.getProperty("os.arch");
public static String processor;
public static String processorVendor;
public static String renderer;
public static String rendererVendor;
public static final boolean is32BitJVM = !System.getProperty("sun.arch.data.model").contains("64");
public static final float TV_SAFE_GRAPHICS = 0.05f; // as per EBU recommendation (https://tech.ebu.ch/docs/r/r095.pdf)
public static final float TV_SAFE_ACTION = 0.035f; // as per EBU recommendation (https://tech.ebu.ch/docs/r/r095.pdf)
public static int getTvSafeGraphicsWidth() { return Math.round(screenW * TV_SAFE_GRAPHICS); }
public static int getTvSafeGraphicsHeight() { return Math.round(screenH * TV_SAFE_GRAPHICS); }
public static int getTvSafeActionWidth() { return Math.round(screenW * TV_SAFE_ACTION); }
public static int getTvSafeActionHeight() { return Math.round(screenH * TV_SAFE_ACTION); }
/**
* These languages won't distinguish regional differences (e.g. enUS and enUK, frFR and frCA)
*/
@@ -142,9 +166,16 @@ public class AppLoader implements ApplicationListener {
private static boolean splashDisplayed = false;
private static boolean postInitFired = false;
private static boolean screenshotRequested = false;
private static boolean resizeRequested = false;
private static Point2i resizeReqSize;
public static LwjglApplicationConfiguration appConfig;
public static GameFontBase fontGame;
public static TinyAlphNum fontSmallNumbers;
/** A gamepad. Multiple gamepads may controll this single virtualised gamepad. */
public static org.lwjgl.input.Controller gamepad = null;
public static float gamepadDeadzone = 0.1f;
/**
* For the events depends on rendering frame (e.g. flicker on post-hit invincibility)
@@ -154,23 +185,52 @@ public class AppLoader implements ApplicationListener {
public static ArrayListMap debugTimers = new ArrayListMap<String, Long>();
public static final int defaultW = 1110;
public static final int defaultH = 740;
public static final int minimumW = 1080;
public static final int minimumH = 720;
public static void main(String[] args) {
// load configs
getDefaultDirectory();
createDirs();
readConfigJson();
try { processor = GetCpuName.getModelName(); }
catch (IOException e1) { processor = "Unknown"; }
try { processorVendor = GetCpuName.getCPUID(); }
catch (IOException e2) { processorVendor = "Unknown"; }
ShaderProgram.pedantic = false;
LwjglApplicationConfiguration appConfig = new LwjglApplicationConfiguration();
//appConfig.useGL30 = true; // used: loads GL 3.2, unused: loads GL 4.6; what the fuck?
appConfig.vSyncEnabled = false;
appConfig.vSyncEnabled = getConfigBoolean("usevsync");
appConfig.resizable = false;//true;
appConfig.width = 1110; // photographic ratio (1.5:1)
appConfig.height = 740; // photographic ratio (1.5:1)
appConfig.backgroundFPS = 9999;
appConfig.foregroundFPS = 9999;
//appConfig.width = 1110; // photographic ratio (1.5:1)
//appConfig.height = 740; // photographic ratio (1.5:1)
appConfig.width = getConfigInt("screenwidth");
appConfig.height = getConfigInt("screenheight");
appConfig.backgroundFPS = getConfigInt("displayfps");
appConfig.foregroundFPS = getConfigInt("displayfps");
appConfig.title = GAME_NAME;
appConfig.forceExit = false;
// load app icon
int[] appIconSizes = new int[]{256,128,64,32,16};
for (int size : appIconSizes) {
String name = "assets/appicon" + size + ".png";
if (new File("./" + name).exists()) {
appConfig.addIcon(name, Files.FileType.Internal);
}
}
if (args.length == 1 && args[0].equals("isdev=true")) {
IS_DEVELOPMENT_BUILD = true;
// safe area box
//KeyToggler.INSTANCE.forceSet(Input.Keys.F11, true);
}
new LwjglApplication(new AppLoader(appConfig), appConfig);
@@ -179,6 +239,7 @@ public class AppLoader implements ApplicationListener {
private static ShaderProgram shaderBayerSkyboxFill;
public static ShaderProgram shaderHicolour;
public static ShaderProgram shaderPassthru;
public static ShaderProgram shaderColLUT;
public static Mesh fullscreenQuad;
@@ -207,23 +268,33 @@ public class AppLoader implements ApplicationListener {
Gdx.gl20.glViewport(0, 0, width, height);
}
public static final double UPDATE_RATE = 1.0 / 60.0; // TODO set it like 1/100, because apparent framerate is limited by update rate
private float loadTimer = 0f;
private final float showupTime = 100f / 1000f;
private FrameBuffer renderFBO;
public static AssetManager assetManager;
@Override
public void create() {
assetManager = new AssetManager();
// set basis of draw
logoBatch = new SpriteBatch();
camera = new OrthographicCamera(((float) appConfig.width), ((float) appConfig.height));
initViewPort(appConfig.width, appConfig.height);
// logo here :p
logo = new TextureRegion(new Texture(Gdx.files.internal("assets/graphics/logo_placeholder.tga")));
logo.flip(false, true);
// set GL graphics constants
shaderBayerSkyboxFill = loadShader("assets/4096.vert", "assets/4096_bayer_skyboxfill.frag");
shaderHicolour = loadShader("assets/4096.vert", "assets/hicolour.frag");
shaderPassthru = loadShader("assets/4096.vert", "assets/passthru.frag");
shaderColLUT = loadShader("assets/4096.vert", "assets/passthru.frag");
fullscreenQuad = new Mesh(
@@ -233,99 +304,50 @@ public class AppLoader implements ApplicationListener {
VertexAttribute.TexCoords(0)
);
updateFullscreenQuad(appConfig.width, appConfig.height);
}
private static double _kalman_xhat_k = 1.0 / 60.0;
private static double _kalman_return_value = _kalman_xhat_k;
private static double _kalman_p_k = 1.0;
private static final double _kalman_R = 0.2; // 0.2: empirical value
private final double _KALMAN_UPDATE_THRE = 0.1;
// enlist suitable gamepads
try {
Controllers.create();
/**
* Because fuck you GDX. (No, really; take a look at LwjglGraphics.java, getDeltaTime() and rawDeltaTime() are exactly the same)
* @return Render delta that is smoothed out.
*/
public static double getSmoothDelta() {
// kalman filter is calculated but not actually being used.
printdbg(this, "Available gamepads: " + Controllers.getControllerCount());
for (int x = 0; x < Controllers.getControllerCount(); x++) {
Controller gamepad = Controllers.getController(x);
printdbg(this, String.format("Gamepad #%d: %s", x + 1, gamepad.getName()));
}
}
catch (Throwable e) {
printdbg(this, "Exception occured while creating controllers -- there will be no gamepads available.");
printdbg(this, e);
}
// below is the kalman part
return _kalman_return_value;
}
// set up renderer info variables
renderer = Gdx.graphics.getGLVersion().getRendererString();
rendererVendor = Gdx.graphics.getGLVersion().getVendorString();
// make loading list
public static void resetDeltaSmoothingHistory() {
_kalman_xhat_k = 1.0 / 60.0;
_kalman_p_k = 1.0;
}
/**
* @link http://bilgin.esme.org/BitsAndBytes/KalmanFilterforDummies
*/
private void updateKalmanRenderDelta() {
// TODO implement nonlinear kalman filter
// kalman filter is calculated but not actually being used.
// the problem with this kalman filter is that it assumes most simplistic situation:
// 1. the actual delta (measured delta - noise) is constant
// 2. everything is linear
// we may need to implement Extended Kalman Filter but wtf is Jacobian, I suck at maths.
// Instead, the kalman filter will reset when new delta is given-value-times greater/lesser
// it's not perfect but it works.
double observation = ((double) Gdx.graphics.getRawDeltaTime());
if (getMul(observation, _kalman_return_value) >= 2.5) {
resetDeltaSmoothingHistory();
}
// measurement value
double _kalman_zed_k = observation;
if (_kalman_zed_k <= _KALMAN_UPDATE_THRE) {
// time update
double _kalman_xhatminus_k = _kalman_xhat_k;
double _kalman_pminus_k = _kalman_p_k;
// measurement update
double _kalman_gain = _kalman_pminus_k / (_kalman_pminus_k + _kalman_R);
double _kalman_xhat_kNew = _kalman_xhatminus_k + _kalman_gain * (_kalman_zed_k - _kalman_xhatminus_k);
double _kalman_p_kNew = (1.0 - _kalman_gain) * _kalman_pminus_k;
_kalman_xhat_k = _kalman_xhat_kNew;
_kalman_p_k = _kalman_p_kNew;
_kalman_return_value = _kalman_xhat_kNew;
}
}
private final double getMul_epsilon = 0.00001;
// only for a > 0 && b > 0
private double getMul(double a, double b) {
if (a < getMul_epsilon || b < getMul_epsilon) {
return a + b;
}
if (a > b) {
return a / b;
}
else {
return b / a;
}
// moved to LwjglGraphics
}
@Override
public void render() {
Gdx.gl.glDisable(GL20.GL_DITHER);
if (splashDisplayed && !postInitFired) {
postInitFired = true;
postInit();
}
// update smooth delta AFTER postInit
updateKalmanRenderDelta();
FrameBufferManager.begin(renderFBO);
gdxClearAndSetBlend(.094f, .094f, .094f, 0f);
setCameraPosition(0, 0);
@@ -365,15 +387,24 @@ public class AppLoader implements ApplicationListener {
}
// draw the screen
else {
screen.render(((float) getSmoothDelta()));
screen.render((float) UPDATE_RATE);
}
KeyToggler.INSTANCE.update(screen instanceof Ingame);
// nested FBOs are just not a thing in GL!
net.torvald.terrarum.FrameBufferManager.end();
PostProcessor.INSTANCE.draw(camera.combined, renderFBO);
// process resize request
if (resizeRequested) {
resizeRequested = false;
resize(resizeReqSize.getX(), resizeReqSize.getY());
}
// process screenshot request
if (screenshotRequested) {
screenshotRequested = false;
@@ -394,6 +425,11 @@ public class AppLoader implements ApplicationListener {
@Override
public void resize(int width, int height) {
printdbg(this, "Resize called");
for (StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) {
printdbg(this, stackTraceElement);
}
//initViewPort(width, height);
screenW = width;
@@ -422,9 +458,12 @@ public class AppLoader implements ApplicationListener {
updateFullscreenQuad(screenW, screenH);
printdbg(this, "Resize event");
printdbg(this, "Resize end");
}
resetDeltaSmoothingHistory();
public static void resizeScreen(int width, int height) {
resizeRequested = true;
resizeReqSize = new Point2i(Math.max(width, minimumW), Math.max(height, minimumH));
}
@Override
@@ -438,7 +477,19 @@ public class AppLoader implements ApplicationListener {
}
IngameRenderer.INSTANCE.dispose();
if (Controllers.isCreated()) Controllers.destroy();
Terrarum.INSTANCE.dispose();
shaderBayerSkyboxFill.dispose();
shaderHicolour.dispose();
shaderColLUT.dispose();
assetManager.dispose();
fullscreenQuad.dispose();
fontGame.dispose();
fontSmallNumbers.dispose();
// delete temp files
new File("./tmp_wenquanyi.tga").delete(); // FIXME this is pretty much ad-hoc
@@ -461,6 +512,7 @@ public class AppLoader implements ApplicationListener {
if (this.screen != null) {
this.screen.hide();
this.screen.dispose();
}
this.screen = screen;
if (this.screen != null) {
@@ -468,17 +520,15 @@ public class AppLoader implements ApplicationListener {
this.screen.resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
}
printdbg(this, "Screen transisiton complete: " + this.screen.getClass().getCanonicalName());
System.gc();
resetDeltaSmoothingHistory();
printdbg(this, "Screen transisiton complete: " + this.screen.getClass().getCanonicalName());
}
/**
* Init stuffs which needs GL context
*/
private void postInit() {
// load configs
getDefaultDirectory();
createDirs();
readConfigJson();
textureWhiteSquare = new Texture(Gdx.files.internal("assets/graphics/ortho_line_tex_2px.tga"));
textureWhiteSquare.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest);
@@ -486,6 +536,7 @@ public class AppLoader implements ApplicationListener {
fontGame = new GameFontBase("assets/graphics/fonts/terrarum-sans-bitmap", false, true,
Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest, false, 256, false
);
fontSmallNumbers = TinyAlphNum.INSTANCE;
audioDevice = Gdx.audio.newAudioDevice(48000, false);
@@ -495,6 +546,10 @@ public class AppLoader implements ApplicationListener {
}
BlocksDrawer.INSTANCE.getWorld(); // will initialize the BlocksDrawer by calling dummy method
LightmapRenderer.INSTANCE.hdr(0f);
printdbg(this, "PostInit done");
}
@@ -505,7 +560,7 @@ public class AppLoader implements ApplicationListener {
logoBatch.setProjectionMatrix(camera.combined);
}
private void updateFullscreenQuad(int WIDTH, int HEIGHT) {
private void updateFullscreenQuad(int WIDTH, int HEIGHT) { // NOT y-flipped quads!
fullscreenQuad.setVertices(new float[]{
0f, 0f, 0f, 1f, 1f, 1f, 1f, 0f, 1f,
WIDTH, 0f, 0f, 1f, 1f, 1f, 1f, 1f, 1f,
@@ -532,7 +587,7 @@ public class AppLoader implements ApplicationListener {
public static String configDir;
public static RunningEnvironment environment;
private void getDefaultDirectory() {
private static void getDefaultDirectory() {
String OS = OSName.toUpperCase();
if (OS.contains("WIN")) {
operationSystem = "WINDOWS";
@@ -550,11 +605,11 @@ public class AppLoader implements ApplicationListener {
operationSystem = "SOLARIS";
defaultDir = System.getProperty("user.home") + "/.Terrarum";
}
else if (System.getProperty("java.runtime.name").toUpperCase().contains("ANDROID")) {
/*else if (System.getProperty("java.runtime.name").toUpperCase().contains("ANDROID")) {
operationSystem = "ANDROID";
defaultDir = System.getProperty("user.home") + "/.Terrarum";
environment = RunningEnvironment.MOBILE;
}
}*/
else {
operationSystem = "UNKNOWN";
defaultDir = System.getProperty("user.home") + "/.Terrarum";
@@ -568,7 +623,7 @@ public class AppLoader implements ApplicationListener {
System.out.println(String.format("default directory: %s", defaultDir));
}
private void createDirs() {
private static void createDirs() {
File[] dirs = {new File(defaultSaveDir)};
for (File it : dirs) {
@@ -659,16 +714,19 @@ public class AppLoader implements ApplicationListener {
* Return config from config set. If the config does not exist, default value will be returned.
* @param key
* *
* @return Config from config set or default config if it does not exist.
* *
* @throws NullPointerException if the specified config simply does not exist.
* @return Config from config set or default config if it does not exist. If the default value is undefined, will return false.
*/
public static boolean getConfigBoolean(String key) {
Object cfg = getConfigMaster(key);
if (cfg instanceof JsonPrimitive)
return ((JsonPrimitive) cfg).getAsBoolean();
else
return ((boolean) cfg);
try {
Object cfg = getConfigMaster(key);
if (cfg instanceof JsonPrimitive)
return ((JsonPrimitive) cfg).getAsBoolean();
else
return ((boolean) cfg);
}
catch (NullPointerException keyNotFound) {
return false;
}
}
public static int[] getConfigIntArray(String key) {
@@ -714,7 +772,7 @@ public class AppLoader implements ApplicationListener {
if (config == null) {
if (defaults == null) {
throw new NullPointerException("key not found: '$key'");
throw new NullPointerException("key not found: '" + key + "'");
}
else {
return defaults;
@@ -734,13 +792,13 @@ public class AppLoader implements ApplicationListener {
// //
public static void printdbg(Object obj, Object message) {
if (IS_DEVELOPMENT_BUILD || getConfigBoolean("forcedevbuild")) {
if (IS_DEVELOPMENT_BUILD) {
System.out.println("[" + obj.getClass().getSimpleName() + "] " + message.toString());
}
}
public static void printdbgerr(Object obj, Object message) {
if (IS_DEVELOPMENT_BUILD || getConfigBoolean("forcedevbuild")) {
if (IS_DEVELOPMENT_BUILD) {
System.err.println("[" + obj.getClass().getSimpleName() + "] " + message.toString());
}
}
@@ -748,10 +806,36 @@ public class AppLoader implements ApplicationListener {
public static ShaderProgram loadShader(String vert, String frag) {
ShaderProgram s = new ShaderProgram(Gdx.files.internal(vert), Gdx.files.internal(frag));
if (s.getLog().contains("error C")) {
if (s.getLog().toLowerCase().contains("error")) {
throw new Error(String.format("Shader program loaded with %s, %s failed:\n%s", vert, frag, s.getLog()));
}
return s;
}
public static void measureDebugTime(String name, kotlin.jvm.functions.Function0<kotlin.Unit> block) {
if (IS_DEVELOPMENT_BUILD) {
//debugTimers.put(name, kotlin.system.TimingKt.measureNanoTime(block));
long start = System.nanoTime();
block.invoke();
debugTimers.put(name, System.nanoTime() - start);
}
}
public static void setDebugTime(String name, long value) {
if (IS_DEVELOPMENT_BUILD) {
debugTimers.put(name, value);
}
}
public static void addDebugTime(String target, String... targets) {
if (IS_DEVELOPMENT_BUILD) {
long l = 0L;
for (String s : targets) {
l += ((long) debugTimers.get(s));
}
debugTimers.put(target, l);
}
}
}

View File

@@ -14,35 +14,36 @@ object DefaultConfig {
val jsonObject = JsonObject()
jsonObject.addProperty("displayfps", 0) // 0: no limit, non-zero: limit
jsonObject.addProperty("usevsync", true)
jsonObject.addProperty("forcedevbuild", false)
jsonObject.addProperty("usevsync", false)
jsonObject.addProperty("screenwidth", AppLoader.defaultW)
jsonObject.addProperty("screenheight", AppLoader.defaultH)
jsonObject.addProperty("imtooyoungtodie", false) // no perma-death
jsonObject.addProperty("language", AppLoader.getSysLang())
jsonObject.addProperty("notificationshowuptime", 6500)
jsonObject.addProperty("notificationshowuptime", 4000)
jsonObject.addProperty("multithread", true) // experimental!
jsonObject.addProperty("multithreadedlight", false) // experimental!
// control-gamepad
jsonObject.addProperty("joypadkeyn", 4)
jsonObject.addProperty("joypadkeyw", 1)
jsonObject.addProperty("joypadkeys", 2)
jsonObject.addProperty("joypadkeye", 3) // logitech indices
jsonObject.addProperty("gamepadkeyn", 4)
jsonObject.addProperty("gamepadkeyw", 1)
jsonObject.addProperty("gamepadkeys", 2)
jsonObject.addProperty("gamepadkeye", 3) // logitech indices
jsonObject.addProperty("joypadlup", 4)
jsonObject.addProperty("joypadrup", 5)
jsonObject.addProperty("joypadldown", 6)
jsonObject.addProperty("joypadrdown", 7) // logitech indices
jsonObject.addProperty("gamepadlup", 4)
jsonObject.addProperty("gamepadrup", 5)
jsonObject.addProperty("gamepadldown", 6)
jsonObject.addProperty("gamepadrdown", 7) // logitech indices
jsonObject.addProperty("joypadlstickx", 0)
jsonObject.addProperty("joypadlsticky", 1)
jsonObject.addProperty("joypadrstickx", 2)
jsonObject.addProperty("joypadrsticky", 3) // 0-1-2-3 but sometimes 3-2-1-0 ?! what the actual fuck?
jsonObject.addProperty("gamepadlstickx", 0)
jsonObject.addProperty("gamepadlsticky", 1)
jsonObject.addProperty("gamepadrstickx", 2)
jsonObject.addProperty("gamepadrsticky", 3) // 0-1-2-3 but sometimes 3-2-1-0 ?! what the actual fuck?
jsonObject.addProperty("joypadlabelstyle", "msxb360") // "nwii", "logitech", "sonyps", "msxb360", "generic"
jsonObject.addProperty("gamepadlabelstyle", "msxb360") // "nwii", "logitech", "sonyps", "msxb360", "generic"

View File

@@ -464,7 +464,7 @@ class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
override fun run() {
var updateTries = 0
while (ingame.updateDeltaCounter >= ingame.updateRate) {
ingame.updateGame(AppLoader.getSmoothDelta().toFloat())
ingame.updateGame(AppLoader.UPDATE_RATE.toFloat())
ingame.updateDeltaCounter -= ingame.updateRate
updateTries++
@@ -529,7 +529,7 @@ class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
while (updateDeltaCounter >= updateRate) {
//updateGame(delta)
AppLoader.debugTimers["Ingame.update"] = measureNanoTime { updateGame(delta) }
AppLoader.measureDebugTime("Ingame.update") { updateGame(delta) }
updateDeltaCounter -= updateRate
updateTries++
@@ -544,7 +544,7 @@ class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
/** RENDER CODE GOES HERE */
//renderGame(batch)
AppLoader.debugTimers["Ingame.render"] = measureNanoTime { renderGame(batch) }
AppLoader.measureDebugTime("Ingame.render") { renderGame(batch) }
}
protected fun updateGame(delta: Float) {
@@ -1090,7 +1090,7 @@ class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
}
playableActorDelegate = newActor
WorldSimulator(player, AppLoader.getSmoothDelta().toFloat())
WorldSimulator(player, AppLoader.UPDATE_RATE.toFloat())
}
private fun changePossession(refid: Int) {
@@ -1107,7 +1107,7 @@ class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
// accept new delegate
playableActorDelegate = PlayableActorDelegate(getActorByID(refid) as ActorHumanoid)
playableActorDelegate!!.actor.collisionType = ActorWithPhysics.COLLISION_KINEMATIC
WorldSimulator(player, AppLoader.getSmoothDelta().toFloat())
WorldSimulator(player, AppLoader.UPDATE_RATE.toFloat())
}
/** Send message to notifier UI and toggle the UI as opened. */

View File

@@ -17,9 +17,9 @@ class GdxColorMap {
height = pixmap.height
is2D = pixmap.height > 1
data = kotlin.IntArray(pixmap.width * pixmap.height, {
data = kotlin.IntArray(pixmap.width * pixmap.height) {
pixmap.getPixel(it % pixmap.width, it / pixmap.width)
})
}
AppLoader.printdbg(this, "Loading colormap from ${imageFile.name()}; PixmapFormat: ${pixmap.format}; Dimension: $width x $height")

View File

@@ -2,9 +2,11 @@ package net.torvald.terrarum
import com.badlogic.gdx.Screen
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.utils.Queue
import net.torvald.terrarum.gameactors.Actor
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
import net.torvald.terrarum.realestate.LandUtil
import net.torvald.terrarum.ui.ConsoleWindow
import java.util.*
import java.util.concurrent.locks.Lock
@@ -45,6 +47,10 @@ open class IngameInstance(val batch: SpriteBatch) : Screen {
val actorContainer = ArrayList<Actor>(ACTORCONTAINER_INITIAL_SIZE)
val actorContainerInactive = ArrayList<Actor>(ACTORCONTAINER_INITIAL_SIZE)
protected val terrainChangeQueue = Queue<BlockChangeQueueItem>()
protected val wallChangeQueue = Queue<BlockChangeQueueItem>()
protected val wireChangeQueue = Queue<BlockChangeQueueItem>()
override fun hide() {
}
@@ -96,6 +102,33 @@ open class IngameInstance(val batch: SpriteBatch) : Screen {
open fun worldSecondaryClickEnd(delta: Float) {
}
/**
* Event for triggering fixture update when something is placed/removed on the world.
* Normally only called by GameWorld.setTileTerrain
*
* Queueing schema is used to make sure things are synchronised.
*/
open fun queueTerrainChangedEvent(old: Int, new: Int, position: Long) {
val (x, y) = LandUtil.resolveBlockAddr(world, position)
terrainChangeQueue.addFirst(BlockChangeQueueItem(old, new, x, y))
}
/**
* Wall version of terrainChanged() event
*/
open fun queueWallChangedEvent(old: Int, new: Int, position: Long) {
val (x, y) = LandUtil.resolveBlockAddr(world, position)
wallChangeQueue.addFirst(BlockChangeQueueItem(old, new, x, y))
}
/**
* Wire version of terrainChanged() event
*/
open fun queueWireChangedEvent(old: Int, new: Int, position: Long) {
val (x, y) = LandUtil.resolveBlockAddr(world, position)
wireChangeQueue.addFirst(BlockChangeQueueItem(old, new, x, y))
}
///////////////////////
@@ -215,6 +248,8 @@ open class IngameInstance(val batch: SpriteBatch) : Screen {
}
}
data class BlockChangeQueueItem(val old: Int, val new: Int, val posX: Int, val posY: Int)
}
inline fun Lock.lock(body: () -> Unit) {

View File

@@ -239,7 +239,7 @@ object LoadScreen : ScreenAdapter() {
for (i in 0 until messages.elemCount) {
Terrarum.fontGame.draw(it,
messages[i] ?: "",
40f,
AppLoader.getTvSafeGraphicsWidth() + 16f,
80f + (messages.size - i - 1) * Terrarum.fontGame.lineHeight
)
}
@@ -264,7 +264,7 @@ object LoadScreen : ScreenAdapter() {
for (i in 0 until messages.elemCount) {
Terrarum.fontGame.draw(it,
messages[i] ?: "",
40f,
AppLoader.getTvSafeGraphicsWidth() + 16f,
80f + (messages.size - i - 1) * Terrarum.fontGame.lineHeight
)
}
@@ -313,7 +313,6 @@ object LoadScreen : ScreenAdapter() {
}
override fun hide() {
dispose()
}
override fun resize(width: Int, height: Int) {

View File

@@ -1,14 +1,18 @@
package net.torvald.terrarum
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Input
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.OrthographicCamera
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.g2d.TextureRegion
import com.badlogic.gdx.graphics.glutils.FrameBuffer
import com.badlogic.gdx.graphics.glutils.ShaderProgram
import com.badlogic.gdx.graphics.glutils.ShapeRenderer
import com.badlogic.gdx.math.Matrix4
import kotlin.system.measureNanoTime
import net.torvald.terrarum.gamecontroller.KeyToggler
import net.torvald.terrarum.ui.BasicDebugInfoWindow
/**
* Must be called by the App Loader
@@ -16,52 +20,139 @@ import kotlin.system.measureNanoTime
object PostProcessor {
private lateinit var batch: SpriteBatch // not nulling to save some lines of code
//private lateinit var camera: OrthographicCamera
private var textureRegion: TextureRegion? = null
private lateinit var shapeRenderer: ShapeRenderer
private lateinit var camera: OrthographicCamera
private lateinit var lutTex: Texture
private var init = false
fun reloadLUT(filename: String) {
lutTex = Texture(Gdx.files.internal("assets/clut/$filename"))
}
private val defaultResCol = Color(0x66ffff66)
private val safeAreaCol = Color(0xffffff66.toInt())
private val safeAreaCol2 = Color(0xffffff44.toInt())
private val debugUI = BasicDebugInfoWindow()
fun draw(projMat: Matrix4, fbo: FrameBuffer) {
if (textureRegion == null) {
textureRegion = TextureRegion(fbo.colorBufferTexture)
// init
if (!init) {
init = true
debugUI.setPosition(0, 0)
batch = SpriteBatch()
camera = OrthographicCamera(AppLoader.screenW.toFloat(), AppLoader.screenH.toFloat())
camera.setToOrtho(true)
batch.projectionMatrix = camera.combined
shapeRenderer = ShapeRenderer()
Gdx.gl20.glViewport(0, 0, AppLoader.appConfig.width, AppLoader.appConfig.height)
}
debugUI.update(Gdx.graphics.deltaTime)
AppLoader.debugTimers["Renderer.PostProcessor"] = measureNanoTime {
AppLoader.measureDebugTime("Renderer.PostProcessor") {
gdxClearAndSetBlend(.094f, .094f, .094f, 0f)
val shader: ShaderProgram? =
if (AppLoader.getConfigBoolean("fxdither"))
AppLoader.shaderHicolour
else
null
fbo.colorBufferTexture.bind(0)
shader?.begin()
shader?.setUniformMatrix("u_projTrans", projMat)
shader?.setUniformi("u_texture", 0)
AppLoader.fullscreenQuad.render(shader, GL20.GL_TRIANGLES)
shader?.end()
Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0) // so that batch that comes next will bind any tex to it
postShader(projMat, fbo)
if (AppLoader.IS_DEVELOPMENT_BUILD && KeyToggler.isOn(Input.Keys.F11)) {
drawSafeArea()
}
if (KeyToggler.isOn(Input.Keys.F3)) {
if (!debugUI.isOpened && !debugUI.isOpening) debugUI.setAsOpen()
batch.inUse { debugUI.renderUI(batch, camera) }
}
else {
if (!debugUI.isClosed && !debugUI.isClosing) debugUI.setAsClose()
}
}
}
private fun postShader(projMat: Matrix4, fbo: FrameBuffer) {
val shader: ShaderProgram? =
if (AppLoader.getConfigBoolean("fxdither"))
AppLoader.shaderHicolour
else
AppLoader.shaderPassthru
fbo.colorBufferTexture.bind(0)
shader?.begin()
shader?.setUniformMatrix("u_projTrans", projMat)
shader?.setUniformi("u_texture", 0)
AppLoader.fullscreenQuad.render(shader, GL20.GL_TRIANGLES)
shader?.end()
Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0) // so that batch that comes next will bind any tex to it
}
private fun drawSafeArea() {
val tvSafeAreaW = AppLoader.getTvSafeGraphicsWidth().toFloat()
val tvSafeAreaH = AppLoader.getTvSafeGraphicsHeight().toFloat()
val tvSafeArea2W = AppLoader.getTvSafeActionWidth().toFloat()
val tvSafeArea2H = AppLoader.getTvSafeActionHeight().toFloat()
shapeRenderer.inUse(ShapeRenderer.ShapeType.Line) {
shapeRenderer.color = safeAreaCol2
shapeRenderer.rect(
tvSafeArea2W, tvSafeArea2H, AppLoader.screenW - 2 * tvSafeArea2W, AppLoader.screenH - 2 * tvSafeArea2H
)
shapeRenderer.color = safeAreaCol
shapeRenderer.rect(
tvSafeAreaW, tvSafeAreaH, AppLoader.screenW - 2 * tvSafeAreaW, AppLoader.screenH - 2 * tvSafeAreaH
)
shapeRenderer.color = defaultResCol
shapeRenderer.rect(
(AppLoader.screenW - AppLoader.minimumW).div(2).toFloat(),
(AppLoader.screenH - AppLoader.minimumH).div(2).toFloat(),
AppLoader.minimumW.toFloat(),
AppLoader.minimumH.toFloat()
)
}
try {
batch.inUse {
batch.color = safeAreaCol
AppLoader.fontSmallNumbers.draw(
batch, safeAreaStr,
tvSafeAreaW, tvSafeAreaH - 10
)
batch.color = defaultResCol
AppLoader.fontSmallNumbers.draw(
batch, defaultResStr,
(AppLoader.screenW - AppLoader.minimumW).div(2).toFloat(),
(AppLoader.screenH - AppLoader.minimumH).div(2).minus(10).toFloat()
)
}
}
catch (doNothing: NullPointerException) { }
finally {
// one-time call, caused by catching NPE before batch ends
if (batch.isDrawing) {
batch.end()
}
}
}
private val defaultResStr = "${AppLoader.minimumW}x${AppLoader.minimumH}"
private val safeAreaStr = "TV Safe Area"
/**
* Camera will be moved so that (newX, newY) would be sit on the top-left edge.
*/

View File

@@ -14,7 +14,6 @@ import com.badlogic.gdx.graphics.glutils.ShapeRenderer
import com.badlogic.gdx.utils.GdxRuntimeException
import com.jme3.math.FastMath
import net.torvald.dataclass.CircularArray
import net.torvald.getcpuname.GetCpuName
import net.torvald.random.HQRNG
import net.torvald.terrarum.AppLoader.*
import net.torvald.terrarum.gameactors.Actor
@@ -74,22 +73,12 @@ object Terrarum : Screen {
get() = HEIGHT.ushr(1)
/**
* To be used with physics simulator
* To be used with physics simulator. This is a magic number.
*/
val PHYS_TIME_FRAME: Double = 26.0 + (2.0 / 3.0)
val PHYS_CONST_MULT: Double = 60.0 / (26.0 + (2.0 / 3.0))
val PHYS_REF_FPS: Double = 60.0
// 26.0 + (2.0 / 3.0) // lower value == faster gravity response (IT WON'T HOTSWAP!!)
// protip: using METER, game unit and SI unit will have same number
/**
* To be used with render, to achieve smooth frame drawing
* TARGET_INTERNAL_FPS > PHYS_TIME_FRAME for smooth frame drawing
*/
val TARGET_INTERNAL_FPS: Double = 60.0
var previousScreen: Screen? = null // to be used with temporary states like StateMonitorCheck
@@ -132,22 +121,22 @@ object Terrarum : Screen {
val fontGame: GameFontBase = AppLoader.fontGame
lateinit var fontSmallNumbers: TinyAlphNum
val fontSmallNumbers: TinyAlphNum = AppLoader.fontSmallNumbers
var joypadLabelStart: Char = 0xE000.toChar() // lateinit
var joypadLableSelect: Char = 0xE000.toChar() // lateinit
var joypadLabelNinA: Char = 0xE000.toChar() // lateinit TODO
var joypadLabelNinB: Char = 0xE000.toChar() // lateinit TODO
var joypadLabelNinX: Char = 0xE000.toChar() // lateinit TODO
var joypadLabelNinY: Char = 0xE000.toChar() // lateinit TODO
var joypadLabelNinL: Char = 0xE000.toChar() // lateinit TODO
var joypadLabelNinR: Char = 0xE000.toChar() // lateinit TODO
var joypadLabelNinZL: Char = 0xE000.toChar() // lateinit TODO
var joypadLabelNinZR: Char = 0xE000.toChar() // lateinit TODO
val joypadLabelLEFT = 0xE068.toChar()
val joypadLabelDOWN = 0xE069.toChar()
val joypadLabelUP = 0xE06A.toChar()
val joypadLabelRIGHT = 0xE06B.toChar()
var gamepadLabelStart: Char = 0xE000.toChar() // lateinit
var gamepadLableSelect: Char = 0xE000.toChar() // lateinit
var gamepadLabelNinA: Char = 0xE000.toChar() // lateinit TODO
var gamepadLabelNinB: Char = 0xE000.toChar() // lateinit TODO
var gamepadLabelNinX: Char = 0xE000.toChar() // lateinit TODO
var gamepadLabelNinY: Char = 0xE000.toChar() // lateinit TODO
var gamepadLabelNinL: Char = 0xE000.toChar() // lateinit TODO
var gamepadLabelNinR: Char = 0xE000.toChar() // lateinit TODO
var gamepadLabelNinZL: Char = 0xE000.toChar() // lateinit TODO
var gamepadLabelNinZR: Char = 0xE000.toChar() // lateinit TODO
val gamepadLabelLEFT = 0xE068.toChar()
val gamepadLabelDOWN = 0xE069.toChar()
val gamepadLabelUP = 0xE06A.toChar()
val gamepadLabelRIGHT = 0xE06B.toChar()
// 0x0 - 0xF: Game-related
// 0x10 - 0x1F: Config
@@ -170,10 +159,6 @@ object Terrarum : Screen {
val STATE_ID_TOOL_NOISEGEN = 0x200
val STATE_ID_TOOL_RUMBLE_DIAGNOSIS = 0x201
var controller: org.lwjgl.input.Controller? = null
private set
val CONTROLLER_DEADZONE = 0.1f
/** Available CPU threads */
val THREADS = Runtime.getRuntime().availableProcessors() + 1
@@ -189,15 +174,6 @@ object Terrarum : Screen {
const val NAME = AppLoader.GAME_NAME
val systemArch = System.getProperty("os.arch")
val processor = GetCpuName.getModelName()
val processorVendor = GetCpuName.getCPUID()
lateinit var renderer: String
lateinit var rendererVendor: String
val is32BitJVM = !System.getProperty("sun.arch.data.model").contains("64")
lateinit var shaderBlur: ShaderProgram
lateinit var shaderBayer: ShaderProgram
lateinit var shaderSkyboxFill: ShaderProgram
@@ -233,12 +209,12 @@ object Terrarum : Screen {
println("vendor = $processorVendor")
joypadLabelStart = when (getConfigString("joypadlabelstyle")) {
gamepadLabelStart = when (getConfigString("gamepadlabelstyle")) {
"nwii" -> 0xE04B.toChar() // + mark
"logitech" -> 0xE05A.toChar() // number 10
else -> 0xE042.toChar() // |> mark (sonyps, msxb360, generic)
}
joypadLableSelect = when (getConfigString("joypadlabelstyle")) {
gamepadLableSelect = when (getConfigString("gamepadlabelstyle")) {
"nwii" -> 0xE04D.toChar() // - mark
"logitech" -> 0xE059.toChar() // number 9
"sonyps" -> 0xE043.toChar() // solid rectangle
@@ -248,7 +224,7 @@ object Terrarum : Screen {
// setting environment as MOBILE precedes this code
if (environment != RunningEnvironment.MOBILE) {
//if (environment != RunningEnvironment.MOBILE) {
environment = try {
Controllers.getController(0) // test if controller exists
if (getConfigString("pcgamepadenv") == "console")
@@ -259,7 +235,8 @@ object Terrarum : Screen {
catch (e: IndexOutOfBoundsException) {
RunningEnvironment.PC
}
}
//}
}
@@ -284,11 +261,6 @@ object Terrarum : Screen {
val MINIMAL_GL_MAX_TEXTURE_SIZE = 4096
override fun show() {
if (environment != RunningEnvironment.MOBILE) {
Gdx.gl.glDisable(GL20.GL_DITHER)
}
assetManager = AssetManager()
@@ -301,10 +273,6 @@ object Terrarum : Screen {
println("GL_MAX_TEXTURE_SIZE = $GL_MAX_TEXTURE_SIZE")
println("GL info:\n$glInfo") // debug info
// set up renderer info variables
renderer = Gdx.graphics.glVersion.rendererString
rendererVendor = Gdx.graphics.glVersion.vendorString
if (GL_VERSION < MINIMAL_GL_VERSION || GL_MAX_TEXTURE_SIZE < MINIMAL_GL_MAX_TEXTURE_SIZE) {
// TODO notify properly
@@ -321,10 +289,7 @@ object Terrarum : Screen {
shapeRender = ShapeRenderer()
fontSmallNumbers = TinyAlphNum
ShaderProgram.pedantic = false
shaderBlur = AppLoader.loadShader("assets/blur.vert", "assets/blur.frag")
@@ -409,8 +374,8 @@ object Terrarum : Screen {
}
override fun render(delta: Float) {
AppLoader.debugTimers["GDX.rawDelta"] = Gdx.graphics.rawDeltaTime.times(1000_000_000f).toLong()
AppLoader.debugTimers["GDX.smtDelta"] = AppLoader.getSmoothDelta().times(1000_000_000f).toLong()
AppLoader.setDebugTime("GDX.rawDelta", Gdx.graphics.rawDeltaTime.times(1000_000_000f).toLong())
AppLoader.setDebugTime("GDX.smtDelta", Gdx.graphics.deltaTime.times(1000_000_000f).toLong())
AppLoader.getINSTANCE().screen.render(delta)
}
@@ -422,35 +387,24 @@ object Terrarum : Screen {
AppLoader.getINSTANCE().screen.resume()
}
/** Don't call this! Call AppLoader.dispose() */
override fun dispose() {
AppLoader.getINSTANCE().screen.dispose()
fontGame.dispose()
fontSmallNumbers.dispose()
//dispose any other resources used in this level
shaderBayer.dispose()
shaderSkyboxFill.dispose()
shaderBlur.dispose()
shaderBlendGlow.dispose()
shapeRender.dispose()
batch.dispose()
ingame?.dispose()
}
override fun hide() {
AppLoader.getINSTANCE().screen.hide()
}
/** For the actual resize, call AppLoader.resize() */
override fun resize(width: Int, height: Int) {
/*try {
AppLoader.getINSTANCE().screen.resize(width, height)
}
catch (e: NullPointerException) { }*/ // I sense circular recursion...
ingame?.resize(width, height)
printdbg(this, "newsize: ${Gdx.graphics.width}x${Gdx.graphics.height} | internal: ${width}x$height")
}
@@ -468,28 +422,36 @@ object Terrarum : Screen {
}
/** Position of the cursor in the world */
inline val mouseX: Double
val mouseX: Double
get() = WorldCamera.x + Gdx.input.x / (ingame?.screenZoom ?: 1f).toDouble()
/** Position of the cursor in the world */
inline val mouseY: Double
val mouseY: Double
get() = WorldCamera.y + Gdx.input.y / (ingame?.screenZoom ?: 1f).toDouble()
/** Position of the cursor in the world */
@JvmStatic inline val mouseTileX: Int
val oldMouseX: Double
get() = WorldCamera.x + (Gdx.input.x - Gdx.input.deltaX) / (ingame?.screenZoom ?: 1f).toDouble()
/** Position of the cursor in the world */
val oldMouseY: Double
get() = WorldCamera.y + (Gdx.input.y - Gdx.input.deltaY) / (ingame?.screenZoom ?: 1f).toDouble()
/** Position of the cursor in the world */
@JvmStatic val mouseTileX: Int
get() = (mouseX / FeaturesDrawer.TILE_SIZE).floorInt()
/** Position of the cursor in the world */
@JvmStatic inline val mouseTileY: Int
@JvmStatic val mouseTileY: Int
get() = (mouseY / FeaturesDrawer.TILE_SIZE).floorInt()
/** Position of the cursor in the world */
@JvmStatic val oldMouseTileX: Int
get() = (oldMouseX / FeaturesDrawer.TILE_SIZE).floorInt()
/** Position of the cursor in the world */
@JvmStatic val oldMouseTileY: Int
get() = (oldMouseY / FeaturesDrawer.TILE_SIZE).floorInt()
inline val mouseScreenX: Int
get() = Gdx.input.x
inline val mouseScreenY: Int
get() = Gdx.input.y
/** Bigger than 1.0 */
/** Delta converted as it it was a FPS */
inline val updateRate: Double
get() = 1.0 / AppLoader.getSmoothDelta()
/** Smaller than 1.0 */
val renderRate = 1.0 / TARGET_INTERNAL_FPS
val renderRateStr = TARGET_INTERNAL_FPS.toString()
get() = 1.0 / Gdx.graphics.deltaTime
/**
* Usage:
*
@@ -571,6 +533,14 @@ fun SpriteBatch.drawStraightLine(x: Float, y: Float, otherEnd: Float, thickness:
infix fun Color.mul(other: Color): Color = this.cpy().mul(other)
infix fun Color.mulAndAssign(other: Color): Color {
this.r *= other.r
this.g *= other.g
this.b *= other.b
this.a *= other.a
return this
}
fun blendMul(batch: SpriteBatch) {
@@ -657,7 +627,7 @@ object BlendMode {
}
enum class RunningEnvironment {
PC, CONSOLE, MOBILE
PC, CONSOLE//, MOBILE
}
infix fun Color.screen(other: Color) = Color(
@@ -717,6 +687,7 @@ fun Double.roundInt(): Int = Math.round(this).toInt()
fun Float.roundInt(): Int = Math.round(this)
fun Double.abs() = Math.abs(this)
fun Double.sqr() = this * this
fun Float.sqr() = this * this
fun Double.sqrt() = Math.sqrt(this)
fun Float.sqrt() = FastMath.sqrt(this)
fun Int.abs() = this.absoluteValue

View File

@@ -23,6 +23,7 @@ import net.torvald.terrarum.modulebasegame.Ingame
import net.torvald.terrarum.modulebasegame.IngameRenderer
import net.torvald.terrarum.modulebasegame.gameactors.HumanoidNPC
import net.torvald.terrarum.modulebasegame.gameworld.GameWorldExtension
import net.torvald.terrarum.modulebasegame.gameworld.WorldTime
import net.torvald.terrarum.modulebasegame.ui.UIRemoCon
import net.torvald.terrarum.modulebasegame.ui.UITitleRemoConYaml
import net.torvald.terrarum.modulebasegame.weather.WeatherMixer
@@ -129,7 +130,8 @@ class TitleScreen(val batch: SpriteBatch) : Screen {
demoWorld = ReadLayerData(FileInputStream(ModMgr.getFile("basegame", "demoworld")))
// set time to summer
demoWorld.time.addTime(WorldTime.DAY_LENGTH * 32)
// construct camera nodes
val nodeCount = 100
@@ -198,26 +200,28 @@ class TitleScreen(val batch: SpriteBatch) : Screen {
private val introUncoverTime: Second = 0.3f
private var introUncoverDeltaCounter = 0f
private var updateDeltaCounter = 0.0
protected val renderRate = Terrarum.renderRate
private var updateAkku = 0.0
override fun render(delta: Float) {
// async update
updateDeltaCounter += delta
if (delta < 1f / 10f) { // discard async if measured FPS <= 10
var updateTries = 0
while (updateDeltaCounter >= renderRate && updateTries < 6) {
updateScreen(delta)
updateDeltaCounter -= renderRate
updateTries++
}
}
else {
updateScreen(delta)
// async update and render
val dt = Gdx.graphics.deltaTime
updateAkku += dt
var i = 0L
while (updateAkku >= delta) {
AppLoader.measureDebugTime("Ingame.update") { updateScreen(delta) }
updateAkku -= delta
i += 1
}
AppLoader.setDebugTime("Ingame.updateCounter", i)
// render? just do it anyway
renderScreen()
AppLoader.measureDebugTime("Ingame.render") { renderScreen() }
AppLoader.setDebugTime("Ingame.render-Light",
(AppLoader.debugTimers["Ingame.render"] as Long) - ((AppLoader.debugTimers["Renderer.LightTotal"] as? Long) ?: 0)
)
}
fun updateScreen(delta: Float) {

View File

@@ -6,7 +6,9 @@ import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull
import net.torvald.terrarum.ui.*
import net.torvald.terrarum.ui.UIItem
import net.torvald.terrarum.ui.UIItemImageButton
import net.torvald.terrarum.ui.UIUtils
/**
* Created by minjaesong on 2017-10-20.
@@ -18,6 +20,12 @@ class UIItemInventoryCatBar(
override val width: Int
) : UIItem(parentUI) {
// deal with the moving position
override var oldPosX = posX
override var oldPosY = posY
private val parentInventory = parentUI
private val catIcons = parentUI.catIcons
private val catArrangement = parentUI.catArrangement
@@ -91,15 +99,23 @@ class UIItemInventoryCatBar(
private val underlineColour = Color(0xeaeaea_40.toInt())
private val underlineHighlightColour = mainButtons[0].highlightCol
private var highlighterXPos = mainButtons[selectedIndex].posX.toDouble()
private var highlighterXPos = mainButtons[selectedIndex].posX.toFloat()
private var highlighterXStart = highlighterXPos
private var highlighterXEnd = highlighterXPos
private val highlighterYPos = catIcons.tileH + 4f
private var highlighterMoving = false
private val highlighterMoveDuration: Second = 0.1f
private val highlighterMoveDuration: Second = 0.15f
private var highlighterMoveTimer: Second = 0f
private var transitionFired = false
/**
* 0: map, 1: inventory caticons, 2: menu
*/
var selectedPanel = 1
private set
// set up underlined indicator
init {
// procedurally generate texture
@@ -134,8 +150,8 @@ class UIItemInventoryCatBar(
highlighterXPos = UIUtils.moveQuick(
highlighterXStart,
highlighterXEnd,
highlighterMoveTimer.toDouble(),
highlighterMoveDuration.toDouble()
highlighterMoveTimer,
highlighterMoveDuration
)
if (highlighterMoveTimer > highlighterMoveDuration) {
@@ -150,23 +166,61 @@ class UIItemInventoryCatBar(
mainButtons.forEachIndexed { index, btn ->
btn.update(delta)
if (btn.mousePushed && selectedPanel != 1) {
transitionFired = true
selectedPanel = 1
}
if (btn.mousePushed && index != selectedIndex) {
// normal stuffs
val oldIndex = selectedIndex
highlighterXStart = mainButtons[selectedIndex].posX.toDouble() // using old selectedIndex
highlighterXStart = mainButtons[selectedIndex].posX.toFloat() // using old selectedIndex
selectedIndex = index
highlighterMoving = true
highlighterXEnd = mainButtons[selectedIndex].posX.toDouble() // using new selectedIndex
highlighterXEnd = mainButtons[selectedIndex].posX.toFloat() // using new selectedIndex
selectionChangeListener?.invoke(oldIndex, index)
}
btn.highlighted = (index == selectedIndex) // forcibly highlight if this.highlighted != null
if (selectedPanel == 1) {
btn.highlighted = (index == selectedIndex) // forcibly highlight if this.highlighted != null
sideButtons[0].highlighted = false
sideButtons[3].highlighted = false
}
}
sideButtons[0].update(delta)
sideButtons[3].update(delta)
// more transition stuffs
if (sideButtons[0].mousePushed) {
if (selectedPanel != 0) transitionFired = true
mainButtons.forEach { it.highlighted = false }
selectedPanel = 0
parentInventory.requestTransition(0)
sideButtons[0].highlighted = true
sideButtons[3].highlighted = false
}
else if (sideButtons[3].mousePushed) {
if (selectedPanel != 2) transitionFired = true
mainButtons.forEach { it.highlighted = false }
selectedPanel = 2
parentInventory.requestTransition(2)
transitionFired = true
sideButtons[0].highlighted = false
sideButtons[3].highlighted = true
}
if (transitionFired) {
transitionFired = false
parentInventory.requestTransition(2 - selectedPanel)
}
}
override fun render(batch: SpriteBatch, camera: Camera) {
@@ -186,8 +240,12 @@ class UIItemInventoryCatBar(
batch.drawStraightLine(posX.toFloat(), posY + height - 1f, posX + width.toFloat(), 1f, false)
// indicator
batch.color = underlineHighlightColour
batch.draw(underlineIndTex, (highlighterXPos - buttonGapSize / 2).toFloat().round(), posY + highlighterYPos)
if (selectedPanel == 1) {
batch.color = underlineHighlightColour
batch.draw(underlineIndTex, (highlighterXPos - buttonGapSize / 2).toFloat().round(), posY + highlighterYPos)
}
}

View File

@@ -36,6 +36,10 @@ class UIItemInventoryElem(
val drawBackOnNull: Boolean = true
) : UIItemInventoryCellBase(parentUI, posX, posY, item, amount, itemImage, quickslot, equippedSlot) {
// deal with the moving position
override var oldPosX = posX
override var oldPosY = posY
companion object {
val height = 48
val UNIQUE_ITEM_HAS_NO_AMOUNT = -1
@@ -194,7 +198,6 @@ class UIItemInventoryElem(
override fun dispose() {
itemImage?.texture?.dispose()
}
override fun keyUp(keycode: Int): Boolean {

View File

@@ -33,6 +33,10 @@ class UIItemInventoryElemSimple(
val drawBackOnNull: Boolean = true
) : UIItemInventoryCellBase(parentUI, posX, posY, item, amount, itemImage, quickslot, equippedSlot) {
// deal with the moving position
override var oldPosX = posX
override var oldPosY = posY
companion object {
val height = UIItemInventoryElem.height
}
@@ -96,8 +100,8 @@ class UIItemInventoryElemSimple(
batch.drawStraightLine(barOffset, posY + height - thickness, barOffset + barFullLen * (item!!.durability / item!!.maxDurability), thickness, false)
}
}
else {
// draw item count
// draw item count when applicable
else if (item!!.stackable) {
val amountString = amount.toString()
// highlight item count (blocks/walls) if the item is equipped
@@ -176,7 +180,6 @@ class UIItemInventoryElemSimple(
override fun dispose() {
itemImage?.texture?.dispose()
}
override fun keyUp(keycode: Int): Boolean {

View File

@@ -123,7 +123,10 @@ inline class Yaml(val text: String) {
val nodeString = it.drop(2)
val nodeNameAndInvocation = nodeString.split(SEPARATOR)
val nodeName = nodeNameAndInvocation[0]
val nodeInvocation = loadClass(nodeNameAndInvocation[1])
val nodeInvocation = if (nodeNameAndInvocation.size == 2)
loadClass(nodeNameAndInvocation[1])
else
null
val nameInvokePair = nodeName to nodeInvocation
@@ -193,5 +196,5 @@ inline class Yaml(val text: String) {
*
*/
interface YamlInvokable {
operator fun invoke()
operator fun invoke(args: Array<Any>)
}

View File

@@ -1,6 +1,9 @@
package net.torvald.terrarum.blockproperties
import com.badlogic.gdx.graphics.Color
import net.torvald.terrarum.AppLoader
import net.torvald.terrarum.gameworld.FluidType
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.MapLayer
import net.torvald.terrarum.gameworld.PairedMapLayer
import net.torvald.terrarum.utils.CSVFetcher
@@ -72,6 +75,19 @@ object BlockCodex {
}
}
operator fun get(fluidType: FluidType?): BlockProp {
if (fluidType == null || fluidType.value == 0) {
return blockProps[Block.AIR]
}
try {
return blockProps[fluidType.abs() + GameWorld.TILES_SUPPORTED - 1]
}
catch (e: NullPointerException) {
throw NullPointerException("Blockprop with raw id $fluidType does not exist.")
}
}
fun getOrNull(rawIndex: Int?): BlockProp? {
if (rawIndex == null || rawIndex == Block.NULL) {
return null
@@ -95,6 +111,7 @@ object BlockCodex {
prop.shadeColG = floatVal(record, "shdg") / LightmapRenderer.MUL_FLOAT
prop.shadeColB = floatVal(record, "shdb") / LightmapRenderer.MUL_FLOAT
prop.shadeColA = floatVal(record, "shduv") / LightmapRenderer.MUL_FLOAT
prop.shadeColor = Color(prop.shadeColR, prop.shadeColG, prop.shadeColB, prop.shadeColA)
prop.strength = intVal(record, "str")
prop.density = intVal(record, "dsty")
@@ -103,6 +120,7 @@ object BlockCodex {
prop.lumColG = floatVal(record, "lumg") / LightmapRenderer.MUL_FLOAT
prop.lumColB = floatVal(record, "lumb") / LightmapRenderer.MUL_FLOAT
prop.lumColA = floatVal(record, "lumuv") / LightmapRenderer.MUL_FLOAT
prop.internalLumCol = Color(prop.lumColR, prop.lumColG, prop.lumColB, prop.lumColA)
prop.friction = intVal(record, "fr")
prop.viscosity = intVal(record, "vscs")

View File

@@ -16,6 +16,7 @@ class BlockProp {
var shadeColG = 0f
var shadeColB = 0f
var shadeColA = 0f
lateinit var shadeColor: Color
/**
* @param opacity Raw RGB value, without alpha
@@ -39,12 +40,13 @@ class BlockProp {
var lumColG = 0f
var lumColB = 0f
var lumColA = 0f
lateinit var internalLumCol: Color
/**
* @param luminosity
*/
inline val luminosity: Color
get() = BlockPropUtil.getDynamicLumFunc(Color(lumColR, lumColG, lumColB, lumColA), dynamicLuminosityFunction)
get() = BlockPropUtil.getDynamicLumFunc(internalLumCol, dynamicLuminosityFunction)
var drop: Int = 0

View File

@@ -4,7 +4,6 @@ import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.Color
import com.jme3.math.FastMath
import net.torvald.random.HQRNG
import net.torvald.terrarum.AppLoader
import net.torvald.terrarum.Second
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.modulebasegame.gameworld.WorldTime
@@ -64,9 +63,9 @@ object BlockPropUtil {
internal fun dynamicLumFuncTickClock() {
// FPS-time compensation
if (Gdx.graphics.framesPerSecond > 0) {
flickerFuncX += AppLoader.getSmoothDelta().toFloat() * 1000f
breathFuncX += AppLoader.getSmoothDelta().toFloat() * 1000f
pulsateFuncX += AppLoader.getSmoothDelta().toFloat() * 1000f
flickerFuncX += Gdx.graphics.deltaTime * 1000f
breathFuncX += Gdx.graphics.deltaTime * 1000f
pulsateFuncX += Gdx.graphics.deltaTime * 1000f
}
// flicker-related vars

View File

@@ -44,6 +44,7 @@ object CommandDict {
"kill" to KillActor,
"money" to MoneyDisp,
"screenshot" to TakeScreenshot,
//"resize" to ResizeScreen,
// Test codes
"bulletintest" to SetBulletin,

View File

@@ -22,7 +22,8 @@ internal object CommandInterpreter {
"help",
"version",
"tips",
"screenshot"
"screenshot",
"resize"
)
internal fun execute(command: String) {

View File

@@ -1,6 +1,6 @@
package net.torvald.terrarum.console
import net.torvald.terrarum.console.ConsoleCommand
import com.badlogic.gdx.Gdx
/**
* Created by minjaesong on 2016-01-15.
@@ -8,7 +8,7 @@ import net.torvald.terrarum.console.ConsoleCommand
internal object QuitApp : ConsoleCommand {
override fun execute(args: Array<String>) {
System.exit(1)
Gdx.app.exit()
}
override fun printUsage() {

View File

@@ -0,0 +1,30 @@
package net.torvald.terrarum.console
import net.torvald.terrarum.AppLoader
import net.torvald.terrarum.Terrarum
object ResizeScreen: ConsoleCommand {
override fun execute(args: Array<String>) {
if (args.size == 3) {
Terrarum.resize(args[1].toInt(), args[2].toInt())
}
else if (args.size == 2) {
when (args[1]) {
"720p" -> AppLoader.resizeScreen(1280,720)
"1080p" -> AppLoader.resizeScreen(1920,1080)
"default" -> AppLoader.resizeScreen(AppLoader.defaultW, AppLoader.defaultH)
else -> { printUsage(); return }
}
}
else {
printUsage(); return
}
Echo("Screen resized to ${AppLoader.screenW}x${AppLoader.screenH}")
}
override fun printUsage() {
Echo("Usage: resize [width] [height]. Minimum size is ${AppLoader.minimumW}x${AppLoader.minimumH}")
Echo("Reserved keywords: 720p, 1080p, default")
}
}

View File

@@ -29,6 +29,9 @@ object AVKey {
const val JUMPPOWER = "jumppower"
const val JUMPPOWERBUFF = "$JUMPPOWER$BUFF"
/** NOT meant for living creatures. Also, only effective when noclip=true. E.g. camera actor */
const val FRICTIONMULT = "frictionmult"
/** Int
* "Default" value of 1 000
*/

View File

@@ -1,7 +1,5 @@
package net.torvald.terrarum.gameactors
import com.badlogic.gdx.Input
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.spriteanimation.SpriteAnimation
import net.torvald.terrarum.*
@@ -9,7 +7,6 @@ import net.torvald.terrarum.AppLoader.printdbg
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.blockproperties.BlockCodex
import net.torvald.terrarum.blockproperties.BlockProp
import net.torvald.terrarum.gamecontroller.KeyToggler
import net.torvald.terrarum.gameworld.BlockAddress
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
@@ -95,7 +92,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
)
/**
* TODO Pixels per 1/60 seconds.
* Unit: Pixels per 1/60 (or AppLoader.UPDATE_RATE) seconds.
*
* When the engine resolves this value, the framerate must be accounted for. E.g.:
* 3.0 is resolved as 3.0 if FPS is 60, but the same value should be resolved as 6.0 if FPS is 30.
@@ -109,15 +106,21 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
* Acceleration: used in code like:
* veloY += 3.0
* +3.0 is acceleration. You __accumulate__ acceleration to the velocity.
*
* V for Velocity!
*/
internal val externalForce = Vector2(0.0, 0.0)
internal val externalV = Vector2(0.0, 0.0)
@Transient private val VELO_HARD_LIMIT = 100.0
/**
* Unit: Pixels per 1/60 (or AppLoader.UPDATE_RATE) seconds.
*
* for "Controllable" actors
*
* V for Velocity!
*/
var controllerMoveDelta: Vector2? = if (this is Controllable) Vector2() else null
var controllerV: Vector2? = if (this is Controllable) Vector2() else null
// not sure we need this...
//var jumpable = true // this is kind of like "semaphore"
@@ -338,7 +341,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
inline val feetPosTile: IntArray
get() = intArrayOf(hIntTilewiseHitbox.centeredX.floorInt(), hIntTilewiseHitbox.endY.floorInt())
override fun run() = update(AppLoader.getSmoothDelta().toFloat())
override fun run() = update(AppLoader.UPDATE_RATE.toFloat())
/**
* Add vector value to the velocity, in the time unit of single frame.
@@ -348,23 +351,17 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
* @param acc : Acceleration in Vector2
*/
fun applyForce(acc: Vector2) {
externalForce += acc * speedMultByTile
externalV += acc * speedMultByTile
}
private val bounceDampenVelThreshold = 0.5
override fun update(fdelta: Float) {
override fun update(delta: Float) {
if (isUpdate && !flagDespawn) {
//val delta = Gdx.graphics.rawDeltaTime.toDouble()
val delta = AppLoader.getSmoothDelta()
//println("${Gdx.graphics.rawDeltaTime.toDouble()}\t${AppLoader.getSmoothDelta()}")
if (!assertPrinted) assertInit()
if (sprite != null) sprite!!.update(fdelta)
if (spriteGlow != null) spriteGlow!!.update(fdelta)
if (sprite != null) sprite!!.update(delta)
if (spriteGlow != null) spriteGlow!!.update(delta)
// make NoClip work for player
if (true) {//this == Terrarum.ingame!!.actorNowPlaying) {
@@ -381,7 +378,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
////////////////////////////////////////////////////////////////
// Codes that modifies velocity (moveDelta and externalForce) //
// Codes that modifies velocity (moveDelta and externalV) //
////////////////////////////////////////////////////////////////
// --> Apply more forces <-- //
@@ -396,8 +393,8 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
}
// hard limit velocity
externalForce.x = externalForce.x.bipolarClamp(VELO_HARD_LIMIT) // displaceHitbox SHOULD use moveDelta
externalForce.y = externalForce.y.bipolarClamp(VELO_HARD_LIMIT)
externalV.x = externalV.x.bipolarClamp(VELO_HARD_LIMIT) // displaceHitbox SHOULD use moveDelta
externalV.y = externalV.y.bipolarClamp(VELO_HARD_LIMIT)
if (!isChronostasis) {
///////////////////////////////////////////////////
@@ -410,11 +407,11 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
* This body is NON-STATIC and the other body is STATIC
*/
if (!isNoCollideWorld) {
displaceHitbox(delta)
displaceHitbox(delta.toDouble())
}
else {
val vecSum = externalForce + (controllerMoveDelta ?: Vector2(0.0, 0.0))
hitbox.translate(vecSum * (Terrarum.PHYS_REF_FPS * delta))
val vecSum = externalV + (controllerV ?: Vector2(0.0, 0.0))
hitbox.translate(vecSum)
}
//////////////////////////////////////////////////////////////
@@ -428,7 +425,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
// TODO less friction for non-animating objects (make items glide far more on ice)
// FIXME asymmetry on friction
setHorizontalFriction(delta) // friction SHOULD use and alter externalForce
setHorizontalFriction(delta) // friction SHOULD use and alter externalV
//if (isNoClip) { // TODO also hanging on the rope, etc.
setVerticalFriction(delta)
//}
@@ -470,33 +467,33 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
if (!(isWalled(hitbox, COLLIDING_LEFT) && walkX < 0)
|| !(isWalled(hitbox, COLLIDING_RIGHT) && walkX > 0)
) {
moveDelta.x = externalForce.x + walkX
moveDelta.x = externalV.x + walkX
}
// decide whether to ignore walkY
if (!(isWalled(hitbox, COLLIDING_TOP) && walkY < 0)
|| !(isWalled(hitbox, COLLIDING_BOTTOM) && walkY > 0)
) {
moveDelta.y = externalForce.y + walkY
moveDelta.y = externalV.y + walkY
}
}
else {
if (!isWalled(hitbox, COLLIDING_LEFT)
|| !isWalled(hitbox, COLLIDING_RIGHT)
) {
moveDelta.x = externalForce.x
moveDelta.x = externalV.x
}
// decide whether to ignore walkY
if (!isWalled(hitbox, COLLIDING_TOP)
|| !isWalled(hitbox, COLLIDING_BOTTOM)
) {
moveDelta.y = externalForce.y
moveDelta.y = externalV.y
}
}
}*/
fun getDrag(delta: Double, externalForce: Vector2): Vector2 {
fun getDrag(delta: Float, externalForce: Vector2): Vector2 {
/**
* weight; gravitational force in action
* W = mass * G (9.8 [m/s^2])
@@ -514,7 +511,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
val V: Vector2 = (W - D) / Terrarum.PHYS_TIME_FRAME * SI_TO_GAME_ACC
return V * (Terrarum.PHYS_REF_FPS * delta).sqrt()
return V
// FIXME v * const, where const = 1.0 for FPS=60, sqrt(2.0) for FPS=30, etc.
// this is "close enough" solution and not perfect.
@@ -535,11 +532,11 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
*
* Apply only if not grounded; normal force is precessed separately.
*/
private fun applyGravitation(delta: Double) {
private fun applyGravitation(delta: Float) {
if (!isNoSubjectToGrav && !(gravitation.y > 0 && walledBottom || gravitation.y < 0 && walledTop)) {
//if (!isWalled(hitbox, COLLIDING_BOTTOM)) {
applyForce(getDrag(delta, externalForce))
applyForce(getDrag(delta, externalV))
//}
}
}
@@ -587,7 +584,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
// if not touching:
// do nothing
// [Friction]:
// deform vector "externalForce"
// deform vector "externalV"
// if isControllable:
// also alter walkX/Y
// translate ((nextHitbox)) hitbox by moveDelta (forces), this consumes force
@@ -637,7 +634,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
fun Double.modTileDelta() = this - this.modTile()
val vectorSum = (externalForce + controllerMoveDelta) * (Terrarum.PHYS_REF_FPS * delta)
val vectorSum = (externalV + controllerV)
val ccdSteps = minOf(16, (vectorSum.magnitudeSquared / TILE_SIZE.sqr()).floorInt() + 1) // adaptive
@@ -838,20 +835,20 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
// bounce X/Y
if (bounceX) {
externalForce.x *= elasticity
controllerMoveDelta?.let { controllerMoveDelta!!.x *= elasticity }
externalV.x *= elasticity
controllerV?.let { controllerV!!.x *= elasticity }
}
if (bounceY) {
externalForce.y *= elasticity
controllerMoveDelta?.let { controllerMoveDelta!!.y *= elasticity }
externalV.y *= elasticity
controllerV?.let { controllerV!!.y *= elasticity }
}
if (zeroX) {
externalForce.x = 0.0
controllerMoveDelta?.let { controllerMoveDelta!!.x = 0.0 }
externalV.x = 0.0
controllerV?.let { controllerV!!.x = 0.0 }
}
if (zeroY) {
externalForce.y = 0.0
controllerMoveDelta?.let { controllerMoveDelta!!.y = 0.0 }
externalV.y = 0.0
controllerV?.let { controllerV!!.y = 0.0 }
}
@@ -1012,11 +1009,11 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
(BlockCodex[tile].isSolid) ||
// platforms, moving downward AND not "going down"
(this is ActorHumanoid && BlockCodex[tile].isPlatform &&
externalForce.y + (controllerMoveDelta?.y ?: 0.0) >= 0.0 &&
externalV.y + (controllerV?.y ?: 0.0) >= 0.0 &&
!this.isDownDown && this.axisY <= 0f) ||
// platforms, moving downward
(this !is ActorHumanoid && BlockCodex[tile].isPlatform &&
externalForce.y + (controllerMoveDelta?.y ?: 0.0) >= 0.0)
externalV.y + (controllerV?.y ?: 0.0) >= 0.0)
// TODO: as for the platform, only apply it when it's a feet tile
@@ -1071,58 +1068,60 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
/** about stopping
* for about get moving, see updateMovementControl */
private fun setHorizontalFriction(delta: Double) {
private fun setHorizontalFriction(delta: Float) {
val friction = if (isNoClip)
BASE_FRICTION * BlockCodex[Block.STONE].friction.frictionToMult()
BASE_FRICTION * (actorValue.getAsDouble(AVKey.FRICTIONMULT) ?: 1.0) * BlockCodex[Block.STONE].friction.frictionToMult()
else {
// TODO status quo if !submerged else linearBlend(feetFriction, bodyFriction, submergedRatio)
BASE_FRICTION * if (grounded) feetFriction else bodyFriction
}
if (externalForce.x < 0) {
externalForce.x += friction
if (externalForce.x > 0) externalForce.x = 0.0 // compensate overshoot
if (externalV.x < 0) {
externalV.x += friction
if (externalV.x > 0) externalV.x = 0.0 // compensate overshoot
}
else if (externalForce.x > 0) {
externalForce.x -= friction
if (externalForce.x < 0) externalForce.x = 0.0 // compensate overshoot
else if (externalV.x > 0) {
externalV.x -= friction
if (externalV.x < 0) externalV.x = 0.0 // compensate overshoot
}
if (this is Controllable) {
if (controllerMoveDelta!!.x < 0) {
controllerMoveDelta!!.x += friction
if (controllerMoveDelta!!.x > 0) controllerMoveDelta!!.x = 0.0
if (controllerV!!.x < 0) {
controllerV!!.x += friction
if (controllerV!!.x > 0) controllerV!!.x = 0.0
}
else if (controllerMoveDelta!!.x > 0) {
controllerMoveDelta!!.x -= friction
if (controllerMoveDelta!!.x < 0) controllerMoveDelta!!.x = 0.0
else if (controllerV!!.x > 0) {
controllerV!!.x -= friction
if (controllerV!!.x < 0) controllerV!!.x = 0.0
}
}
}
private fun setVerticalFriction(delta: Double) {
private fun setVerticalFriction(delta: Float) {
val friction = if (isNoClip)
BASE_FRICTION * BlockCodex[Block.STONE].friction.frictionToMult()
BASE_FRICTION * (actorValue.getAsDouble(AVKey.FRICTIONMULT) ?: 1.0) * BlockCodex[Block.STONE].friction.frictionToMult()
else
BASE_FRICTION * bodyFriction
// TODO wall friction (wall skid) similar to setHorizintalFriction ?
if (externalForce.y < 0) {
externalForce.y += friction
if (externalForce.y > 0) externalForce.y = 0.0 // compensate overshoot
if (externalV.y < 0) {
externalV.y += friction
if (externalV.y > 0) externalV.y = 0.0 // compensate overshoot
}
else if (externalForce.y > 0) {
externalForce.y -= friction
if (externalForce.y < 0) externalForce.y = 0.0 // compensate overshoot
else if (externalV.y > 0) {
externalV.y -= friction
if (externalV.y < 0) externalV.y = 0.0 // compensate overshoot
}
if (this is Controllable) {
if (controllerMoveDelta!!.y < 0) {
controllerMoveDelta!!.y += friction
if (controllerMoveDelta!!.y > 0) controllerMoveDelta!!.y = 0.0
if (controllerV!!.y < 0) {
controllerV!!.y += friction
if (controllerV!!.y > 0) controllerV!!.y = 0.0
}
else if (controllerMoveDelta!!.y > 0) {
controllerMoveDelta!!.y -= friction
if (controllerMoveDelta!!.y < 0) controllerMoveDelta!!.y = 0.0
else if (controllerV!!.y > 0) {
controllerV!!.y -= friction
if (controllerV!!.y < 0) controllerV!!.y = 0.0
}
}
}
@@ -1343,10 +1342,11 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
override fun drawBody(batch: SpriteBatch) {
if (isVisible && sprite != null) {
if (!KeyToggler.isOn(Input.Keys.F12)) {
//if (!KeyToggler.isOn(Input.Keys.F12)) {
BlendMode.resolve(drawMode, batch)
drawSpriteInGoodPosition(sprite!!, batch)
}
/*}
// ye olde tilewiseposition debugger, we don't use it anymore.
else {
batch.color = Color.NAVY
val hb = intTilewiseHitbox
@@ -1360,7 +1360,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
batch.color = Color.VIOLET
batch.fillRect(hitbox.startX.toFloat(), hitbox.startY.toFloat(), hitbox.width.toFloat(), hitbox.height.toFloat())
}
}*/
}
}
@@ -1443,8 +1443,8 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
field = value
if (value) {
externalForce.zero()
controllerMoveDelta?.zero()
externalV.zero()
controllerV?.zero()
}
}

View File

@@ -46,7 +46,7 @@ import org.luaj.vm2.*
*/
fun composeActorObject(actor: ActorWBMovable): LuaTable {
val t: LuaTable = LuaTable()
val moveDelta = actor.externalForce + actor.controllerMoveDelta
val moveDelta = actor.externalV + actor.controllerV
t["name"] = actor.actorValue.getAsString(AVKey.NAME).toLua()
t["startX"] = actor.hitbox.centeredX.toLua()

View File

@@ -68,6 +68,8 @@ class IngameController(val ingame: Ingame) : InputAdapter() {
/////////////////////
}
private var f12Down = false
override fun keyDown(keycode: Int): Boolean {
if (ingame.canPlayerControl) {
@@ -90,14 +92,19 @@ class IngameController(val ingame: Ingame) : InputAdapter() {
ingame.uiContainer.forEach { it.keyDown(keycode) } // for KeyboardControlled UIcanvases
// Debug UIs
if (keycode == Input.Keys.F3) {
ingame.debugWindow.toggleOpening()
}
if (keycode == Input.Keys.GRAVE) {
ingame.consoleHandler.toggleOpening()
}
// screenshot key
if (keycode == Input.Keys.F12 && !f12Down) {
AppLoader.requestScreenshot()
ingame.sendNotification(arrayOf("Screenshot taken", ""))
f12Down = true
println("Screenshot taken.")
}
return true
}
@@ -111,6 +118,10 @@ class IngameController(val ingame: Ingame) : InputAdapter() {
ingame.uiContainer.forEach { it.keyUp(keycode) } // for KeyboardControlled UIcanvases
// screenshot key
if (keycode == Input.Keys.F12) f12Down = false
return true
}
@@ -131,10 +142,10 @@ class IngameController(val ingame: Ingame) : InputAdapter() {
if (ingame.uiContainer.map { if ((it.isOpening || it.isOpened) && it.mouseUp) 1 else 0 }.sum() == 0) { // no UI on the mouse, right?
if (button == AppLoader.getConfigInt("mouseprimary")) {
ingame.worldPrimaryClickEnd(AppLoader.getSmoothDelta().toFloat())
ingame.worldPrimaryClickEnd(AppLoader.UPDATE_RATE.toFloat())
}
if (button == AppLoader.getConfigInt("mousesecondary")) {
ingame.worldSecondaryClickEnd(AppLoader.getSmoothDelta().toFloat())
ingame.worldSecondaryClickEnd(AppLoader.UPDATE_RATE.toFloat())
}
}
}
@@ -172,10 +183,10 @@ class IngameController(val ingame: Ingame) : InputAdapter() {
if (ingame.uiContainer.map { if ((it.isOpening || it.isOpened) && it.mouseUp) 1 else 0 }.sum() == 0) { // no UI on the mouse, right?
if (button == AppLoader.getConfigInt("mouseprimary")) {
ingame.worldPrimaryClickStart(AppLoader.getSmoothDelta().toFloat())
ingame.worldPrimaryClickStart(AppLoader.UPDATE_RATE.toFloat())
}
if (button == AppLoader.getConfigInt("mousesecondary")) {
ingame.worldSecondaryClickStart(AppLoader.getSmoothDelta().toFloat())
ingame.worldSecondaryClickStart(AppLoader.UPDATE_RATE.toFloat())
}
}
}

View File

@@ -3,7 +3,7 @@ package net.torvald.terrarum.gamecontroller
/**
* Created by minjaesong on 2016-01-15.
*/
@Deprecated("Use Gdx.Input.Keys")
/*@Deprecated("Use Gdx.Input.Keys")
object DeprecatedAsFuckKey {
val RETURN = 28
@@ -90,4 +90,4 @@ object DeprecatedAsFuckKey {
val PGDN = 209
val HOME = 199
val END = 207
}
}*/

View File

@@ -1,29 +1,7 @@
package net.torvald.terrarum.gameworld
import net.torvald.terrarum.blockproperties.Fluid
/**
* Created by minjaesong on 2016-08-06.
*/
object FluidCodex {
operator fun get(type: FluidType): FluidProp {
return if (type sameAs Fluid.NULL)
nullProp
else
waterProp
}
// TODO temporary, should read from CSV
val nullProp = FluidProp.getNullProp()
val waterProp = FluidProp()
init {
waterProp.shadeColR = 0.1016f
waterProp.shadeColG = 0.0744f
waterProp.shadeColB = 0.0508f
waterProp.shadeColA = 0.0508f
waterProp.density = 1000
}
}
// Use BlockCodex. --Torvald, 2019-01-27

View File

@@ -1,14 +1,9 @@
package net.torvald.terrarum.gameworld
import com.badlogic.gdx.graphics.Color
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.blockproperties.BlockCodex
import net.torvald.terrarum.blockproperties.BlockPropUtil
/**
* Created by minjaesong on 2018-12-29.
*/
class FluidProp {
/*class FluidProp {
var density: Int = 0
@@ -45,4 +40,4 @@ class FluidProp {
return p
}
}
}
}*/

View File

@@ -2,6 +2,7 @@
package net.torvald.terrarum.gameworld
import com.badlogic.gdx.graphics.Color
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.blockproperties.BlockCodex
import net.torvald.terrarum.blockproperties.Fluid
@@ -220,9 +221,13 @@ open class GameWorld {
fun setTileWall(x: Int, y: Int, tile: Byte, damage: Int) {
val (x, y) = coerceXY(x, y)
val oldWall = getTileFromWall(x, y)
layerWall.setTile(x, y, tile)
layerWallLowBits.setData(x, y, damage)
wallDamages.remove(LandUtil.getBlockAddr(this, x, y))
if (oldWall != null)
Terrarum.ingame?.queueWallChangedEvent(oldWall, tile.toUint() * PairedMapLayer.RANGE + damage, LandUtil.getBlockAddr(this, x, y))
}
/**
@@ -230,6 +235,7 @@ open class GameWorld {
*/
fun setTileTerrain(x: Int, y: Int, tile: Byte, damage: Int) {
val (x, y) = coerceXY(x, y)
val oldTerrain = getTileFromTerrain(x, y)
layerTerrain.setTile(x, y, tile)
layerTerrainLowBits.setData(x, y, damage)
val blockAddr = LandUtil.getBlockAddr(this, x, y)
@@ -240,11 +246,18 @@ open class GameWorld {
fluidTypes.remove(blockAddr)
}
// fluid tiles-item should be modified so that they will also place fluid onto their respective map
if (oldTerrain != null)
Terrarum.ingame?.queueTerrainChangedEvent(oldTerrain, tile.toUint() * PairedMapLayer.RANGE + damage, LandUtil.getBlockAddr(this, x, y))
}
fun setTileWire(x: Int, y: Int, tile: Byte) {
val (x, y) = coerceXY(x, y)
val oldWire = getTileFromWire(x, y)
layerWire.setTile(x, y, tile)
if (oldWire != null)
Terrarum.ingame?.queueWireChangedEvent(oldWire, tile.toUint(), LandUtil.getBlockAddr(this, x, y))
}
fun getTileFrom(mode: Int, x: Int, y: Int): Int? {
@@ -412,7 +425,7 @@ open class GameWorld {
data class FluidInfo(val type: FluidType, val amount: Float) {
/** test if this fluid should be considered as one */
fun isFluid() = type != Fluid.NULL && amount >= WorldSimulator.FLUID_MIN_MASS
fun getProp() = FluidCodex[type]
fun getProp() = BlockCodex[type]
override fun toString() = "Fluid type: ${type.value}, amount: $amount"
}
@@ -443,6 +456,7 @@ open class GameWorld {
}
infix fun Int.fmod(other: Int) = Math.floorMod(this, other)
infix fun Long.fmod(other: Long) = Math.floorMod(this, other)
infix fun Float.fmod(other: Float) = if (this >= 0f) this % other else (this % other) + other
inline class FluidType(val value: Int) {

View File

@@ -3,10 +3,10 @@ package net.torvald.terrarum.itemproperties
import com.badlogic.gdx.graphics.Color
import net.torvald.random.HQRNG
import net.torvald.terrarum.ItemValue
import net.torvald.terrarum.modulebasegame.gameactors.ActorInventory
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
import net.torvald.terrarum.itemproperties.ItemCodex.ITEM_DYNAMIC
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.gameactors.ActorInventory
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
typealias ItemID = Int
@@ -207,28 +207,39 @@ abstract class GameItem : Comparable<GameItem>, Cloneable {
object EquipPosition {
@JvmStatic val NULL = -1
@JvmStatic val ARMOUR = 0
// you can add alias to address something like LEGGINGS, BREASTPLATE, RINGS, NECKLACES, etc.
@JvmStatic val BODY_BACK = 1 // wings, jetpacks, etc.
@JvmStatic val BODY_BUFF2 = 2
@JvmStatic val BODY_BUFF3 = 3
@JvmStatic val BODY_BUFF4 = 4
@JvmStatic val BODY_BUFF5 = 5
@JvmStatic val BODY_BUFF6 = 6
@JvmStatic val BODY_BUFF7 = 7
@JvmStatic val BODY_BUFF8 = 8
@JvmStatic val HAND_GRIP = 9
@JvmStatic val HAND_GAUNTLET = 10
@JvmStatic val HAND_BUFF2 = 11
@JvmStatic val HAND_BUFF3 = 12
@JvmStatic val HAND_BUFF4 = 13
@JvmStatic val BODY_ARMOUR = 0
@JvmStatic val BODY_FOOTWEAR = 1 // wings, jetpacks, etc.
@JvmStatic val FOOTWEAR = 14
@JvmStatic val HEADGEAR = 2
@JvmStatic val HAND_GAUNTLET = 3
@JvmStatic val HEADGEAR = 15
@JvmStatic val HAND_GRIP = 4
@JvmStatic val TOOL_HOOKSHOT = 5
@JvmStatic val INDEX_MAX = 15
@JvmStatic val BODY_BUFF1 = 6
@JvmStatic val BODY_BUFF2 = 8
@JvmStatic val BODY_BUFF3 = 10
@JvmStatic val HAND_BUFF1 = 7
@JvmStatic val HAND_BUFF2 = 9
@JvmStatic val HAND_BUFF3 = 11
// invisible from the inventory UI
// intended for semi-permanant (de)buff (e.g. lifetime achivement, curse)
// can be done with actorvalue and some more code, but it's easier to just make
// such (de)buffs as an item.
@JvmStatic val STIGMA_1 = 12
@JvmStatic val STIGMA_2 = 13
@JvmStatic val STIGMA_3 = 14
@JvmStatic val STIGMA_4 = 15
@JvmStatic val STIGMA_5 = 16
@JvmStatic val STIGMA_6 = 17
@JvmStatic val STIGMA_7 = 18
@JvmStatic val STIGMA_8 = 19
@JvmStatic val INDEX_MAX = 19
}
object Category {

View File

@@ -192,12 +192,38 @@ object ItemCodex {
override fun startSecondaryUse(delta: Float): Boolean {
val ingame = Terrarum.ingame!! as Ingame // must be in here
ingame.world.setFluid(Terrarum.mouseTileX, Terrarum.mouseTileY, Fluid.WATER, 1f)
ingame.world.setFluid(Terrarum.mouseTileX, Terrarum.mouseTileY, Fluid.WATER, 4f)
return true
}
}
// test lava bucket
itemCodex[9001] = object : GameItem() {
override var dynamicID: ItemID = 9001
override val originalID: ItemID = 9001
override val isUnique: Boolean = true
override val originalName: String = "Infinite Lava Bucket"
override var baseMass: Double = 1000.0
override var baseToolSize: Double? = null
override var inventoryCategory: String = "tool"
override var stackable: Boolean = false
override val isDynamic: Boolean = false
override val material: Material = Material(1,1,1,1,1,1,1,1,1,1.0)
override val equipPosition: Int = EquipPosition.HAND_GRIP
override fun startSecondaryUse(delta: Float): Boolean {
val ingame = Terrarum.ingame!! as Ingame // must be in here
ingame.world.setFluid(Terrarum.mouseTileX, Terrarum.mouseTileY, Fluid.LAVA, 4f)
return true
}
}
// read from save (if applicable) and fill dynamicItemDescription
@@ -233,23 +259,27 @@ object ItemCodex {
fun getItemImage(item: GameItem?): TextureRegion? {
if (item == null) return null
return getItemImage(item.originalID)
}
fun getItemImage(itemOriginalID: Int): TextureRegion {
// terrain
if (item.originalID in ITEM_TILES) {
if (itemOriginalID in ITEM_TILES) {
return BlocksDrawer.tilesTerrain.get(
(item.originalID % 16) * 16,
item.originalID / 16
(itemOriginalID % 16) * 16,
itemOriginalID / 16
)
}
// wall
else if (item.originalID in ITEM_WALLS) {
else if (itemOriginalID in ITEM_WALLS) {
return BlocksDrawer.tileItemWall.get(
(item.originalID.minus(ITEM_WALLS.first) % 16) * 16,
(item.originalID.minus(ITEM_WALLS.first) / 16)
(itemOriginalID.minus(ITEM_WALLS.first) % 16),
(itemOriginalID.minus(ITEM_WALLS.first) / 16)
)
}
// wire
else if (item.originalID in ITEM_WIRES) {
return BlocksDrawer.tilesWire.get((item.originalID % 16) * 16, item.originalID / 16)
else if (itemOriginalID in ITEM_WIRES) {
return BlocksDrawer.tilesWire.get((itemOriginalID % 16) * 16, itemOriginalID / 16)
}
// TODO get it real, using originalID...?
else

View File

@@ -118,7 +118,7 @@ object Lang {
// special treatment
if (key.startsWith("MENU_LABEL_PRESS_START_SYMBOL"))
return ret2.replace('>', Terrarum.joypadLabelStart).capitalize()
return ret2.replace('>', Terrarum.gamepadLabelStart).capitalize()
return if (key.getEndTag().contains("bg"))
"${AppLoader.fontGame.charsetOverrideBulgarian}${ret2.capitalize()}${AppLoader.fontGame.charsetOverrideDefault}"

View File

@@ -4,23 +4,20 @@ import com.badlogic.gdx.Gdx
import com.badlogic.gdx.InputAdapter
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.terrarum.AppLoader
import net.torvald.terrarum.IngameInstance
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.Yaml
import net.torvald.terrarum.*
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.gameactors.*
import net.torvald.terrarum.gamecontroller.KeyToggler
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
import net.torvald.terrarum.modulebasegame.gameworld.GameWorldExtension
import net.torvald.terrarum.modulebasegame.gameworld.WorldTime
import net.torvald.terrarum.modulebasegame.ui.Notification
import net.torvald.terrarum.modulebasegame.ui.UIEditorPalette
import net.torvald.terrarum.modulebasegame.weather.WeatherMixer
import net.torvald.terrarum.ui.UICanvas
import net.torvald.terrarum.ui.UINSMenu
import net.torvald.terrarum.worlddrawer.LightmapRenderer
import net.torvald.terrarum.worlddrawer.WorldCamera
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import kotlin.system.measureNanoTime
/**
* Created by minjaesong on 2018-07-06.
@@ -29,24 +26,26 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
private val menuYaml = Yaml("""
- File
- New
- New flat ter.
- New rand. ter.
- Export…
- Export sel…
- Import…
- Save world
- Load world
- Save terrain
- Load terrain
- Exit to Title : net.torvald.terrarum.modulebasegame.YamlCommandExit
- Tool
- Pencil
- Pencil : net.torvald.terrarum.modulebasegame.YamlCommandToolPencil
- Eyedropper
- Select mrq.
- Select mrq. : net.torvald.terrarum.modulebasegame.YamlCommandToolMarquee
- Move
- Undo
- Redo
- Time
- Morning
- Noon
- Dusk
- Night
- Morning : net.torvald.terrarum.modulebasegame.YamlCommandSetTimeMorning
- Noon : net.torvald.terrarum.modulebasegame.YamlCommandSetTimeNoon
- Dusk : net.torvald.terrarum.modulebasegame.YamlCommandSetTimeDusk
- Night : net.torvald.terrarum.modulebasegame.YamlCommandSetTimeNight
- Set…
- Weather
- Sunny
@@ -72,6 +71,8 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
}
}
// set time to summer
gameWorld.time.addTime(WorldTime.DAY_LENGTH * 32)
world = gameWorld
}
@@ -81,23 +82,29 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
val uiToolbox = UINSMenu("Menu", 100, menuYaml)
val notifier = Notification()
val uiPalette = UIEditorPalette()
val uiContainer = ArrayList<UICanvas>()
var currentPenMode = PENMODE_PENCIL
val blockPointingCursor = object : ActorWithBody(Actor.RenderOrder.OVERLAY) {
override var referenceID: ActorID? = Terrarum.generateUniqueReferenceID(renderOrder)
val body = TextureRegionPack(Gdx.files.internal("assets/graphics/blocks/block_markings_common.tga"), 16, 16)
override val hitbox = Hitbox(0.0, 0.0, 16.0, 16.0)
init {
this.actorValue[AVKey.LUMR] = 1.0
this.actorValue[AVKey.LUMG] = 1.0
}
override fun drawBody(batch: SpriteBatch) {
batch.color = Color.YELLOW
batch.draw(body.get(0, 0), hitbox.startX.toFloat(), hitbox.startY.toFloat())
batch.color = toolCursorColour[currentPenMode]
batch.draw(body.get(currentPenMode, 0), hitbox.startX.toFloat(), hitbox.startY.toFloat())
}
override fun drawGlow(batch: SpriteBatch) { }
@@ -120,8 +127,15 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
}
}
protected var updateDeltaCounter = 0.0
protected val updateRate = 1.0 / Terrarum.TARGET_INTERNAL_FPS
companion object {
const val PENMODE_PENCIL = 0
const val PENMODE_MARQUEE = 1
val toolCursorColour = arrayOf(
Color.YELLOW,
Color.MAGENTA
)
}
private val actorsRenderOverlay = ArrayList<ActorWithBody>()
@@ -132,12 +146,18 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
actorsRenderOverlay.add(blockPointingCursor)
uiContainer.add(uiToolbox)
uiContainer.add(uiPalette)
uiContainer.add(notifier)
uiToolbox.setPosition(0, 0)
uiToolbox.isVisible = true
uiToolbox.invocationArgument = arrayOf(this)
uiPalette.setPosition(Terrarum.WIDTH - uiPalette.width, 0)
uiPalette.isVisible = true
notifier.setPosition(
(Terrarum.WIDTH - notifier.width) / 2, Terrarum.HEIGHT - notifier.height)
@@ -154,43 +174,62 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
super.show()
}
private var updateAkku = 0.0
override fun render(delta: Float) {
Gdx.graphics.setTitle(Ingame.getCanonicalTitle())
// ASYNCHRONOUS UPDATE AND RENDER //
val dt = Gdx.graphics.deltaTime
updateAkku += dt
// async update
updateDeltaCounter += delta
if (delta < 1f / 10f) { // discard async if measured FPS <= 10
var updateTries = 0
while (updateDeltaCounter >= updateRate) {
updateGame(delta)
updateDeltaCounter -= updateRate
updateTries++
}
}
else {
updateGame(delta)
var i = 0L
while (updateAkku >= delta) {
AppLoader.measureDebugTime("Ingame.update") { updateGame(delta) }
updateAkku -= delta
i += 1
}
AppLoader.setDebugTime("Ingame.updateCounter", i)
// render? just do it anyway
renderGame()
AppLoader.measureDebugTime("Ingame.render") { renderGame() }
AppLoader.setDebugTime("Ingame.render-Light",
(AppLoader.debugTimers["Ingame.render"] as Long) - ((AppLoader.debugTimers["Renderer.LightTotal"] as? Long) ?: 0)
)
}
private fun updateGame(delta: Float) {
KeyToggler.update(false)
var mouseOnUI = false
WeatherMixer.update(delta, actorNowPlaying, gameWorld)
blockPointingCursor.update(delta)
actorNowPlaying?.update(delta)
uiContainer.forEach { it.update(delta) }
uiContainer.forEach {
it.update(delta)
if (it.isVisible && it.mouseUp) {
mouseOnUI = true
}
}
WorldCamera.update(world, actorNowPlaying)
// make pen work HERE
if (Gdx.input.isTouched && !mouseOnUI) {
makePenWork(Terrarum.mouseTileX, Terrarum.mouseTileY)
// TODO drag support using bresenham's algo
// for some reason it just doesn't work...
}
}
private fun renderGame() {
IngameRenderer(world as GameWorldExtension, actorsRenderOverlay = actorsRenderOverlay, uisToDraw = uiContainer)
IngameRenderer.invoke(world as GameWorldExtension, actorsRenderOverlay = actorsRenderOverlay, uisToDraw = uiContainer)
}
override fun resize(width: Int, height: Int) {
@@ -198,11 +237,24 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
uiToolbox.setPosition(0, 0)
notifier.setPosition(
(Terrarum.WIDTH - notifier.width) / 2, Terrarum.HEIGHT - notifier.height)
println("[BuildingMaker] Resize event")
}
override fun dispose() {
IngameRenderer.dispose()
blockPointingCursor.dispose()
}
private fun makePenWork(worldTileX: Int, worldTileY: Int) {
val world = gameWorld
val palSelection = uiPalette.fore
when (currentPenMode) {
// test paint terrain layer
PENMODE_PENCIL -> {
world.setTileTerrain(worldTileX, worldTileY, palSelection)
}
}
}
}
@@ -232,6 +284,7 @@ class BuildingMakerController(val screen: BuildingMaker) : InputAdapter() {
return true
}
// let left mouse button to paint, because that's how graphic tablets work
override fun touchDragged(screenX: Int, screenY: Int, pointer: Int): Boolean {
screen.uiContainer.forEach { it.touchDragged(screenX, screenY, pointer) }
return true
@@ -260,10 +313,12 @@ class MovableWorldCamera : ActorHumanoid(0, usePhysics = false) {
actorValue[AVKey.SPEED] = 8.0
actorValue[AVKey.SPEEDBUFF] = 1.0
actorValue[AVKey.ACCEL] = ActorHumanoid.WALK_ACCEL_BASE
actorValue[AVKey.ACCELBUFF] = 1.0
actorValue[AVKey.ACCELBUFF] = 4.0
actorValue[AVKey.JUMPPOWER] = 0.0
actorValue[AVKey.FRICTIONMULT] = 4.0
}
override fun drawBody(batch: SpriteBatch) {
}
@@ -274,3 +329,45 @@ class MovableWorldCamera : ActorHumanoid(0, usePhysics = false) {
}
}
class YamlCommandExit : YamlInvokable {
override fun invoke(args: Array<Any>) {
Terrarum.setScreen(TitleScreen(Terrarum.batch))
}
}
class YamlCommandSetTimeMorning : YamlInvokable {
override fun invoke(args: Array<Any>) {
(args[0] as BuildingMaker).gameWorld.time.setTimeOfToday(WorldTime.parseTime("7h00"))
}
}
class YamlCommandSetTimeNoon : YamlInvokable {
override fun invoke(args: Array<Any>) {
(args[0] as BuildingMaker).gameWorld.time.setTimeOfToday(WorldTime.parseTime("12h30"))
}
}
class YamlCommandSetTimeDusk : YamlInvokable {
override fun invoke(args: Array<Any>) {
(args[0] as BuildingMaker).gameWorld.time.setTimeOfToday(WorldTime.parseTime("18h40"))
}
}
class YamlCommandSetTimeNight : YamlInvokable {
override fun invoke(args: Array<Any>) {
(args[0] as BuildingMaker).gameWorld.time.setTimeOfToday(WorldTime.parseTime("0h30"))
}
}
class YamlCommandToolPencil : YamlInvokable {
override fun invoke(args: Array<Any>) {
(args[0] as BuildingMaker).currentPenMode = BuildingMaker.PENMODE_PENCIL
}
}
class YamlCommandToolMarquee : YamlInvokable {
override fun invoke(args: Array<Any>) {
(args[0] as BuildingMaker).currentPenMode = BuildingMaker.PENMODE_MARQUEE
}
}

View File

@@ -13,7 +13,6 @@ import net.torvald.terrarum.console.Authenticator
import net.torvald.terrarum.gameactors.Actor
import net.torvald.terrarum.gameactors.ActorWithBody
import net.torvald.terrarum.gamecontroller.IngameController
import net.torvald.terrarum.gamecontroller.KeyToggler
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.itemproperties.GameItem
import net.torvald.terrarum.modulebasegame.console.AVTracker
@@ -22,13 +21,10 @@ import net.torvald.terrarum.modulebasegame.gameactors.*
import net.torvald.terrarum.modulebasegame.gameactors.physicssolver.CollisionSolver
import net.torvald.terrarum.modulebasegame.gameworld.GameWorldExtension
import net.torvald.terrarum.modulebasegame.gameworld.WorldSimulator
import net.torvald.terrarum.modulebasegame.imagefont.Watch7SegMain
import net.torvald.terrarum.modulebasegame.imagefont.WatchDotAlph
import net.torvald.terrarum.modulebasegame.ui.*
import net.torvald.terrarum.modulebasegame.weather.WeatherMixer
import net.torvald.terrarum.modulebasegame.worldgenerator.RoguelikeRandomiser
import net.torvald.terrarum.modulebasegame.worldgenerator.WorldGenerator
import net.torvald.terrarum.ui.BasicDebugInfoWindow
import net.torvald.terrarum.ui.ConsoleWindow
import net.torvald.terrarum.ui.UICanvas
import net.torvald.terrarum.worlddrawer.FeaturesDrawer
@@ -36,7 +32,6 @@ import net.torvald.terrarum.worlddrawer.LightmapRenderer
import net.torvald.terrarum.worlddrawer.WorldCamera
import java.util.*
import java.util.concurrent.locks.ReentrantLock
import kotlin.system.measureNanoTime
/**
@@ -66,6 +61,11 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
private val actorsRenderFront = ArrayList<ActorWithBody>(ACTORCONTAINER_INITIAL_SIZE)
private val actorsRenderOverlay= ArrayList<ActorWithBody>(ACTORCONTAINER_INITIAL_SIZE)
private var visibleActorsRenderBehind: List<ActorWithBody> = ArrayList(1)
private var visibleActorsRenderMiddle: List<ActorWithBody> = ArrayList(1)
private var visibleActorsRenderMidTop: List<ActorWithBody> = ArrayList(1)
private var visibleActorsRenderFront: List<ActorWithBody> = ArrayList(1)
private var visibleActorsRenderOverlay: List<ActorWithBody> = ArrayList(1)
//var screenZoom = 1.0f // definition moved to IngameInstance
//val ZOOM_MAXIMUM = 4.0f // definition moved to IngameInstance
@@ -82,7 +82,7 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
fun getCanonicalTitle() = AppLoader.GAME_NAME +
" — F: ${Gdx.graphics.framesPerSecond}" +
if (AppLoader.IS_DEVELOPMENT_BUILD)
"t${Terrarum.updateRateStr} / RT${Terrarum.renderRateStr})" +
"F${Terrarum.updateRateStr})" +
" — M: J${Terrarum.memJavaHeap}M / N${Terrarum.memNativeHeap}M / X${Terrarum.memXmx}M"
else
""
@@ -95,7 +95,6 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
lateinit var debugWindow: UICanvas
lateinit var notifier: UICanvas
lateinit var uiPieMenu: UICanvas
@@ -276,31 +275,18 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
consoleHandler.setPosition(0, 0)
// init debug window
debugWindow = BasicDebugInfoWindow()
debugWindow.setPosition(0, 0)
// init notifier
notifier = Notification()
notifier.setPosition(
(Terrarum.WIDTH - notifier.width) / 2, Terrarum.HEIGHT - notifier.height)
(Terrarum.WIDTH - notifier.width) / 2,
Terrarum.HEIGHT - notifier.height - AppLoader.getTvSafeGraphicsHeight()
)
// >- queue up game UIs that should pause the world -<
// inventory
/*uiInventoryPlayer = UIInventory(player,
width = 900,
height = Terrarum.HEIGHT - 160,
categoryWidth = 210,
toggleKeyLiteral = AppLoader.getConfigInt("keyinventory")
)*/
/*uiInventoryPlayer.setPosition(
-uiInventoryPlayer.width,
70
)*/
uiInventoryPlayer = UIInventoryFull(actorNowPlaying,
uiInventoryPlayer = UIInventoryFull(actorNowPlaying!!,
toggleKeyLiteral = AppLoader.getConfigInt("keyinventory")
)
uiInventoryPlayer.setPosition(0, 0)
@@ -309,7 +295,7 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
// quick bar
uiQuickBar = UIQuickslotBar()
uiQuickBar.isVisible = true
uiQuickBar.setPosition((Terrarum.WIDTH - uiQuickBar.width) / 2, 8)
uiQuickBar.setPosition((Terrarum.WIDTH - uiQuickBar.width) / 2, AppLoader.getTvSafeGraphicsHeight())
// pie menu
uiPieMenu = uiQuickslotPie()
@@ -332,7 +318,10 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
uiWatchTierOne = UITierOneWatch(actorNowPlaying)
uiWatchTierOne.setAsAlwaysVisible()
uiWatchTierOne.setPosition(Terrarum.WIDTH - uiWatchTierOne.width, uiWatchBasic.height - 2)
uiWatchTierOne.setPosition(
((Terrarum.WIDTH - AppLoader.getTvSafeActionWidth()) - (uiQuickBar.posX + uiQuickBar.width) - uiWatchTierOne.width) / 2 + (uiQuickBar.posX + uiQuickBar.width),
AppLoader.getTvSafeGraphicsHeight() + 8
)
uiTooltip = UITooltip()
@@ -373,12 +362,12 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
// these need to appear on top of any others
uiContainer.add(notifier)
uiContainer.add(debugWindow)
LightmapRenderer.fireRecalculateEvent()
AppLoader.setDebugTime("Ingame.updateCounter", 0)
@@ -408,7 +397,7 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
itemOnGrip?.endSecondaryUse(delta)
}
protected val renderRate = Terrarum.renderRate
private var firstTimeRun = true
@@ -421,7 +410,7 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
}
}
private var countdownToDeltaReset = 15 // number of frames
private var updateAkku = 0.0
override fun render(delta: Float) {
// Q&D solution for LoadScreen and Ingame, where while LoadScreen is working, Ingame now no longer has GL Context
@@ -442,40 +431,28 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
gameFullyLoaded = true
}
if (countdownToDeltaReset >= 0) {3
if (countdownToDeltaReset == 0) {
AppLoader.resetDeltaSmoothingHistory()
}
countdownToDeltaReset -= 1
}
// ASYNCHRONOUS UPDATE AND RENDER //
/** UPDATE CODE GOES HERE */
val dt = Gdx.graphics.deltaTime
updateAkku += dt
if (false && AppLoader.getConfigBoolean("multithread")) { // NO MULTITHREADING: camera don't like concurrent modification (jittery actor movements)
if (firstTimeRun || updateThreadWrapper.state == Thread.State.TERMINATED) {
updateThreadWrapper = Thread(ingameUpdateThread, "Terrarum UpdateThread")
updateThreadWrapper.start()
if (firstTimeRun) firstTimeRun = false
}
// else, NOP;
}
else {
AppLoader.debugTimers["Ingame.update"] = measureNanoTime { updateGame(delta) }
var i = 0L
while (updateAkku >= delta) {
AppLoader.measureDebugTime("Ingame.update") { updateGame(delta) }
updateAkku -= delta
i += 1
}
AppLoader.setDebugTime("Ingame.updateCounter", i)
/** RENDER CODE GOES HERE */
AppLoader.debugTimers["Ingame.render"] = measureNanoTime { renderGame() }
AppLoader.debugTimers["Ingame.render-Light"] =
AppLoader.measureDebugTime("Ingame.render") { renderGame() }
AppLoader.setDebugTime("Ingame.render-Light",
(AppLoader.debugTimers["Ingame.render"] as Long) - ((AppLoader.debugTimers["Renderer.LightTotal"] as? Long) ?: 0)
)
}
protected fun updateGame(delta: Float) {
@@ -484,7 +461,6 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
particlesActive = 0
KeyToggler.update()
ingameController.update(delta)
@@ -505,8 +481,6 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
// camera-related updates //
////////////////////////////
FeaturesDrawer.update(delta)
WorldCamera.update(gameworld, actorNowPlaying)
///////////////////////////
@@ -522,6 +496,14 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
particlesContainer.forEach { if (!it.flagDespawn) particlesActive++; it.update(delta) }
// TODO thread pool(?)
CollisionSolver.process()
WorldCamera.update(gameworld, actorNowPlaying)
// completely consume block change queues because why not
terrainChangeQueue.clear()
wallChangeQueue.clear()
wireChangeQueue.clear()
}
@@ -543,13 +525,15 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
private fun renderGame() {
Gdx.graphics.setTitle(getCanonicalTitle())
filterVisibleActors()
IngameRenderer.invoke(
world as GameWorldExtension,
actorsRenderBehind,
actorsRenderMiddle,
actorsRenderMidTop,
actorsRenderFront,
actorsRenderOverlay,
visibleActorsRenderBehind,
visibleActorsRenderMiddle,
visibleActorsRenderMidTop,
visibleActorsRenderFront,
visibleActorsRenderOverlay,
particlesContainer,
actorNowPlaying,
uiContainer
@@ -557,6 +541,14 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
}
private fun filterVisibleActors() {
visibleActorsRenderBehind = actorsRenderBehind.filter { it.inScreen() }
visibleActorsRenderMiddle = actorsRenderMiddle.filter { it.inScreen() }
visibleActorsRenderMidTop = actorsRenderMidTop.filter { it.inScreen() }
visibleActorsRenderFront = actorsRenderFront.filter { it.inScreen() }
visibleActorsRenderOverlay=actorsRenderOverlay.filter { it.inScreen() }
}
private fun repossessActor() {
// check if currently pocessed actor is removed from game
if (!theGameHasActor(actorNowPlaying)) {
@@ -672,6 +664,12 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
}
}
}
if (it is CuedByTerrainChange) {
terrainChangeQueue.forEach { cue ->
it.updateForWorldChange(cue)
}
}
}
}
actorNowPlaying?.update(delta)
@@ -886,7 +884,7 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
}
override fun hide() {
dispose()
uiContainer.forEach { it.handler.dispose() }
}
@@ -914,6 +912,7 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
notifier.setPosition(
(Terrarum.WIDTH - notifier.width) / 2, Terrarum.HEIGHT - notifier.height)
uiQuickBar.setPosition((Terrarum.WIDTH - uiQuickBar.width) / 2, AppLoader.getTvSafeGraphicsHeight())
// inventory
/*uiInventoryPlayer =
@@ -926,7 +925,11 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
// basic watch-style notification bar (temperature, new mail)
uiWatchBasic.setPosition(Terrarum.WIDTH - uiWatchBasic.width, 0)
uiWatchTierOne.setPosition(Terrarum.WIDTH - uiWatchTierOne.width, uiWatchBasic.height - 2)
uiWatchTierOne.setPosition(
((Terrarum.WIDTH - AppLoader.getTvSafeGraphicsWidth()) - (uiQuickBar.posX + uiQuickBar.width) - uiWatchTierOne.width) / 2 + (uiQuickBar.posX + uiQuickBar.width),
AppLoader.getTvSafeGraphicsHeight() + 8
)
}
@@ -934,26 +937,16 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
}
override fun dispose() {
IngameRenderer.dispose()
actorsRenderBehind.forEach { it.dispose() }
actorsRenderMiddle.forEach { it.dispose() }
actorsRenderMidTop.forEach { it.dispose() }
actorsRenderFront.forEach { it.dispose() }
actorsRenderOverlay.forEach { it.dispose() }
uiAliases.forEach { it.dispose() }
uiAliasesPausing.forEach { it.dispose() }
WatchDotAlph.dispose()
Watch7SegMain.dispose()
WatchDotAlph.dispose()
ItemSlotImageFactory.dispose()
MessageWindow.SEGMENT_BLACK.dispose()
MessageWindow.SEGMENT_WHITE.dispose()
uiContainer.forEach {
it.handler.dispose()
it.dispose()
}
}
@@ -962,4 +955,5 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
printdbg(this, "-> $it")
}
}
}

View File

@@ -79,6 +79,9 @@ object IngameRenderer {
init()
batch.color = Color.WHITE
BlocksDrawer.world = world
LightmapRenderer.setWorld(world)
FeaturesDrawer.world = world
@@ -208,6 +211,7 @@ object IngameRenderer {
// works but some UI elements have wrong transparency -> should be fixed with Terrarum.gdxCleanAndSetBlend -- Torvald 2019-01-12
blendNormal(batch)
batch.color = Color.WHITE
}

View File

@@ -225,20 +225,20 @@ open class ActorHumanoid(
isRightDown = Gdx.input.isKeyPressed(AppLoader.getConfigInt("keyright"))
isJumpDown = Gdx.input.isKeyPressed(AppLoader.getConfigInt("keyjump"))
if (Terrarum.controller != null) {
axisX = Terrarum.controller!!.getAxisValue(AppLoader.getConfigInt("joypadlstickx"))
axisY = Terrarum.controller!!.getAxisValue(AppLoader.getConfigInt("joypadlsticky"))
axisRX = Terrarum.controller!!.getAxisValue(AppLoader.getConfigInt("joypadrstickx"))
axisRY = Terrarum.controller!!.getAxisValue(AppLoader.getConfigInt("joypadrsticky"))
if (AppLoader.gamepad != null) {
axisX = AppLoader.gamepad!!.getAxisValue(AppLoader.getConfigInt("gamepadlstickx"))
axisY = AppLoader.gamepad!!.getAxisValue(AppLoader.getConfigInt("gamepadlsticky"))
axisRX = AppLoader.gamepad!!.getAxisValue(AppLoader.getConfigInt("gamepadrstickx"))
axisRY = AppLoader.gamepad!!.getAxisValue(AppLoader.getConfigInt("gamepadrsticky"))
// deadzonning
if (Math.abs(axisX) < Terrarum.CONTROLLER_DEADZONE) axisX = 0f
if (Math.abs(axisY) < Terrarum.CONTROLLER_DEADZONE) axisY = 0f
if (Math.abs(axisRX) < Terrarum.CONTROLLER_DEADZONE) axisRX = 0f
if (Math.abs(axisRY) < Terrarum.CONTROLLER_DEADZONE) axisRY = 0f
if (Math.abs(axisX) < AppLoader.gamepadDeadzone) axisX = 0f
if (Math.abs(axisY) < AppLoader.gamepadDeadzone) axisY = 0f
if (Math.abs(axisRX) < AppLoader.gamepadDeadzone) axisRX = 0f
if (Math.abs(axisRY) < AppLoader.gamepadDeadzone) axisRY = 0f
isJumpDown = Gdx.input.isKeyPressed(AppLoader.getConfigInt("keyjump")) ||
Terrarum.controller!!.isButtonPressed(GAMEPAD_JUMP)
AppLoader.gamepad!!.isButtonPressed(GAMEPAD_JUMP)
}
}
else {
@@ -250,7 +250,7 @@ open class ActorHumanoid(
}
private inline val hasController: Boolean
get() = if (isGamer) Terrarum.controller != null
get() = if (isGamer) AppLoader.gamepad != null
else true
private fun processInput(delta: Float) {
@@ -384,7 +384,7 @@ open class ActorHumanoid(
*
* Be warned.
*
* @param left (even if the game is joypad controlled, you must give valid value)
* @param left (even if the game is gamepad controlled, you must give valid value)
* @param absAxisVal (set AXIS_KEYBOARD if keyboard controlled)
* @author minjaesong
*/
@@ -406,9 +406,9 @@ open class ActorHumanoid(
avAcceleration * applyVelo(walkCounterX) * (if (left) -1f else 1f) * absAxisVal
if (absAxisVal != AXIS_KEYBOARD)
controllerMoveDelta?.x?.let { controllerMoveDelta!!.x = controllerMoveDelta!!.x.plus(readonly_totalX).bipolarClamp(avSpeedCap * absAxisVal) }
controllerV?.x?.let { controllerV!!.x = controllerV!!.x.plus(readonly_totalX).bipolarClamp(avSpeedCap * absAxisVal) }
else
controllerMoveDelta?.x?.let { controllerMoveDelta!!.x = controllerMoveDelta!!.x.plus(readonly_totalX).bipolarClamp(avSpeedCap) }
controllerV?.x?.let { controllerV!!.x = controllerV!!.x.plus(readonly_totalX).bipolarClamp(avSpeedCap) }
if (walkCounterX < 1000000) {
walkCounterX += 1
@@ -424,7 +424,7 @@ open class ActorHumanoid(
/**
* @param up (even if the game is joypad controlled, you must give valid value)
* @param up (even if the game is gamepad controlled, you must give valid value)
* *
* @param absAxisVal (set AXIS_KEYBOARD if keyboard controlled)
*/
@@ -444,9 +444,9 @@ open class ActorHumanoid(
avAcceleration * applyVelo(walkCounterY) * (if (up) -1f else 1f) * absAxisVal
if (absAxisVal != AXIS_KEYBOARD)
controllerMoveDelta?.y?.let { controllerMoveDelta!!.y = controllerMoveDelta!!.y.plus(readonly_totalY).bipolarClamp(avSpeedCap * absAxisVal) }
controllerV?.y?.let { controllerV!!.y = controllerV!!.y.plus(readonly_totalY).bipolarClamp(avSpeedCap * absAxisVal) }
else
controllerMoveDelta?.y?.let { controllerMoveDelta!!.y = controllerMoveDelta!!.y.plus(readonly_totalY).bipolarClamp(avSpeedCap) }
controllerV?.y?.let { controllerV!!.y = controllerV!!.y.plus(readonly_totalY).bipolarClamp(avSpeedCap) }
if (walkCounterY < 1000000) {
walkCounterY += 1
@@ -489,6 +489,7 @@ open class ActorHumanoid(
private var oldJUMPPOWERBUFF = -1.0 // init
private var oldScale = -1.0
private var oldDragCoefficient = -1.0
// used by some AIs
var jumpAirTime: Double = -1.0
get() {
// compare all the affecting variables
@@ -519,7 +520,7 @@ open class ActorHumanoid(
val timedJumpCharge = jumpFunc(MAX_JUMP_LENGTH, jmpCtr)
forceVec.y -= getJumpAcc(jumpPower, timedJumpCharge)
forceVec.y += getDrag(1.0 / Terrarum.PHYS_REF_FPS, forceVec).y
forceVec.y += getDrag(AppLoader.UPDATE_RATE.toFloat(), forceVec).y
simYPos += forceVec.y // ignoring all the fluid drag OTHER THAN THE AIR
@@ -564,7 +565,7 @@ open class ActorHumanoid(
jumpAcc = getJumpAcc(jumpPower, timedJumpCharge)
controllerMoveDelta?.y?.let { controllerMoveDelta!!.y -= jumpAcc } // feed negative value to the vector
controllerV?.y?.let { controllerV!!.y -= jumpAcc } // feed negative value to the vector
// do not think of resetting this to zero when counter hit the ceiling; that's HOW NOT
// newtonian physics work, stupid myself :(
@@ -609,7 +610,7 @@ open class ActorHumanoid(
sprite?.update(delta)
spriteGlow?.update(delta)
if (walledBottom && controllerMoveDelta?.x != 0.0) {
if (walledBottom && controllerV?.x != 0.0) {
//switch row
sprite?.switchRow(SPRITE_ROW_WALK)
spriteGlow?.switchRow(SPRITE_ROW_WALK)
@@ -617,8 +618,8 @@ open class ActorHumanoid(
// set anim frame delay
// 4f of the divider is a magic number, empirically decided
if (this is HasAssembledSprite) {
sprite?.delays?.set(SPRITE_ROW_WALK, scale.sqrt().toFloat() / (4f * (controllerMoveDelta?.x ?: 0.0001).abs().toFloat())) // FIXME empirical value
spriteGlow?.delays?.set(SPRITE_ROW_WALK, scale.sqrt().toFloat() / (4f * (controllerMoveDelta?.x ?: 0.0001).abs().toFloat())) // FIXME empirical value
sprite?.delays?.set(SPRITE_ROW_WALK, scale.sqrt().toFloat() / (4f * (controllerV?.x ?: 0.0001).abs().toFloat())) // FIXME empirical value
spriteGlow?.delays?.set(SPRITE_ROW_WALK, scale.sqrt().toFloat() / (4f * (controllerV?.x ?: 0.0001).abs().toFloat())) // FIXME empirical value
}

View File

@@ -211,7 +211,7 @@ class ActorInventory(val actor: Pocketed, var maxCapacity: Int, var capacityMode
actor.avStrength / 1000.0
else
1.0 // TODO variable: scale, strength
val swingDmgToFrameDmg = AppLoader.getSmoothDelta().toFloat().toDouble() / actor.actorValue.getAsDouble(AVKey.ACTION_INTERVAL)!!
val swingDmgToFrameDmg = AppLoader.UPDATE_RATE.toFloat().toDouble() / actor.actorValue.getAsDouble(AVKey.ACTION_INTERVAL)!!
// damage the item
newItem.durability -= (baseDamagePerSwing * swingDmgToFrameDmg).toFloat()

View File

@@ -1,5 +1,6 @@
package net.torvald.terrarum.modulebasegame.gameactors
import net.torvald.terrarum.IngameInstance
import net.torvald.terrarum.Point2d
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.gameactors.ActorWBMovable
@@ -7,9 +8,9 @@ import net.torvald.terrarum.gameactors.ActorWBMovable
/**
* Created by minjaesong on 2016-06-17.
*/
open class FixtureBase(val blockBox: BlockBox) :
open class FixtureBase(val blockBox: BlockBox, val blockBoxProps: BlockBoxProps = BlockBoxProps(0)) :
// disabling physics (not allowing the fixture to move) WILL make things easier
ActorWBMovable(RenderOrder.BEHIND, immobileBody = true, usePhysics = false) {
ActorWBMovable(RenderOrder.BEHIND, immobileBody = true, usePhysics = false), CuedByTerrainChange {
/**
* Block-wise position of this fixture when it's placed on the world. Null if it's not on the world
@@ -32,6 +33,10 @@ open class FixtureBase(val blockBox: BlockBox) :
}
open fun updateSelf() {
}
/**
@@ -42,6 +47,33 @@ open class FixtureBase(val blockBox: BlockBox) :
}
}
interface CuedByTerrainChange {
/**
* Fired by world's BlockChanged event (fired when blocks are placed/removed).
* The flooding check must run on every frame. use updateSelf() for that.
*
* E.g. if a fixture block that is inside of BlockBox is missing, destroy and drop self.
*/
fun updateForWorldChange(cue: IngameInstance.BlockChangeQueueItem) {
}
}
/**
* Standard 32-bit binary flags.
*
* (LSB)
* - 0: fluid resist - when FALSE, the fixture will break itself to item/nothing. For example, crops has this flag FALSE.
* - 1: don't drop item when broken - when TRUE, the fixture will simply disappear instead of dropping itself. For example, crop has this flag TRUE.
*
* (MSB)
*
* In the savegame's JSON, this flag set should be stored as signed integer.
*/
inline class BlockBoxProps(val flags: Int) {
}
data class BlockBox(var collisionType: Int, var width: Int, var height: Int) {
fun redefine(collisionType: Int, width: Int, height: Int) {

View File

@@ -23,7 +23,7 @@ open class ParticleBase(renderOrder: Actor.RenderOrder, val despawnUponCollision
/** Will NOT actually delete from the CircularArray */
@Volatile var flagDespawn = false
override fun run() = update(AppLoader.getSmoothDelta().toFloat())
override fun run() = update(AppLoader.UPDATE_RATE.toFloat())
var isNoSubjectToGrav = false
var dragCoefficient = 3.0

View File

@@ -10,7 +10,6 @@ import net.torvald.terrarum.gameactors.AVKey
import net.torvald.terrarum.gameactors.ActorWBMovable
import net.torvald.terrarum.gameactors.Controllable
import net.torvald.terrarum.gameactors.Hitbox
import net.torvald.terrarum.gameworld.GameWorld
/**
* Created by minjaesong on 2018-01-17.
@@ -37,7 +36,7 @@ class PhysTestLuarLander : ActorWBMovable(RenderOrder.MIDTOP), Controllable {
super.update(delta)
if (Gdx.input.isKeyPressed(Input.Keys.UP)) {
controllerMoveDelta!!.y = avSpeedCap
controllerV!!.y = avSpeedCap
}
}

View File

@@ -99,5 +99,6 @@ object PlayerBuilderSigrid {
walls.forEach { inventory.add(it + 4096, 9995) }
inventory.add(ItemCodex.ITEM_STATIC.first)
inventory.add(9000)
inventory.add(9001)
}
}

View File

@@ -28,7 +28,7 @@ interface Pocketed {
}
inventory.itemEquipped[item.equipPosition] = null
item.effectOnUnequip(AppLoader.getSmoothDelta().toFloat())
item.effectOnUnequip(AppLoader.UPDATE_RATE.toFloat())
}
// no need for equipSlot(Int)
@@ -50,7 +50,7 @@ interface Pocketed {
if (item.equipPosition >= 0) {
inventory.itemEquipped[item.equipPosition] = item
item.effectWhenEquipped(AppLoader.getSmoothDelta().toFloat())
item.effectWhenEquipped(AppLoader.UPDATE_RATE.toFloat())
}
// else do nothing
}
@@ -69,13 +69,13 @@ interface Pocketed {
fun consumePrimary(item: GameItem) {
if (item.startPrimaryUse(AppLoader.getSmoothDelta().toFloat())) {
if (item.startPrimaryUse(AppLoader.UPDATE_RATE.toFloat())) {
inventory.consumeItem(this as Actor, item) // consume on successful
}
}
fun consumeSecondary(item: GameItem) {
if (item.startSecondaryUse(AppLoader.getSmoothDelta().toFloat()))
if (item.startSecondaryUse(AppLoader.UPDATE_RATE.toFloat()))
inventory.consumeItem(this as Actor, item) // consume on successful
}
}

View File

@@ -9,7 +9,6 @@ import net.torvald.terrarum.blockproperties.BlockCodex
import net.torvald.terrarum.gameactors.ActorWBMovable
import net.torvald.terrarum.gameactors.Hitbox
import net.torvald.terrarum.gameactors.Luminous
import net.torvald.terrarum.gameworld.GameWorld
import org.dyn4j.geometry.Vector2
import java.util.*
@@ -54,7 +53,7 @@ open class ProjectileSimple(
posPre = Point2d(fromPoint.x, fromPoint.y)
// lightbox sized 8x8 centered to the bullet
lightBoxList.add(Hitbox(-4.0, -4.0, 8.0, 8.0))
//this.externalForce.set(velocity)
//this.externalV.set(velocity)
damage = bulletDatabase[type][OFFSET_DAMAGE] as Int
displayColour = bulletDatabase[type][OFFSET_COL] as Color
@@ -64,7 +63,7 @@ open class ProjectileSimple(
setHitboxDimension(2, 2, 0, 0) // should be following sprite's properties if there IS one
externalForce.set((fromPoint to toPoint).setMagnitude(speed.toDouble()))
externalV.set((fromPoint to toPoint).setMagnitude(speed.toDouble()))

View File

@@ -10,13 +10,13 @@ class ThreadActorUpdate(val startIndex: Int, val endIndex: Int) : Runnable {
override fun run() {
for (i in startIndex..endIndex) {
val it = Terrarum.ingame!!.actorContainer[i]
it.update(AppLoader.getSmoothDelta().toFloat())
it.update(AppLoader.UPDATE_RATE.toFloat())
if (it is Pocketed) {
it.inventory.forEach { inventoryEntry ->
inventoryEntry.item.effectWhileInPocket(AppLoader.getSmoothDelta().toFloat())
inventoryEntry.item.effectWhileInPocket(AppLoader.UPDATE_RATE.toFloat())
if (it.equipped(inventoryEntry.item)) {
inventoryEntry.item.effectWhenEquipped(AppLoader.getSmoothDelta().toFloat())
inventoryEntry.item.effectWhenEquipped(AppLoader.UPDATE_RATE.toFloat())
}
}
}

View File

@@ -150,8 +150,8 @@ object CollisionSolver {
// if they actually makes collision (e.g. player vs ball), solve it
if (a makesCollisionWith b) {
val a_moveDelta = a.externalForce + a.controllerMoveDelta
val b_moveDelta = b.externalForce + b.controllerMoveDelta
val a_moveDelta = a.externalV + a.controllerV
val b_moveDelta = b.externalV + b.controllerV
val ux_1 = a_moveDelta.x
val ux_2 = b_moveDelta.x

View File

@@ -1,5 +1,7 @@
package net.torvald.terrarum.modulebasegame.gameworld
import net.torvald.terrarum.gameworld.fmod
typealias time_t = Long
@@ -96,11 +98,11 @@ class WorldTime(initTime: Long = 0L) {
// these functions won't need inlining for performance
val yearlyDays: Int // 0 - 119
get() = (TIME_T.toPositiveInt().div(DAY_LENGTH) % YEAR_DAYS)
get() = (TIME_T.div(DAY_LENGTH) fmod YEAR_DAYS.toLong()).toInt()
val days: Int // 1 - 30 fixed
get() = (yearlyDays % 30) + 1
get() = (yearlyDays % MONTH_LENGTH) + 1
val months: Int // 1 - 4
get() = (yearlyDays / 30) + 1
get() = (yearlyDays / MONTH_LENGTH) + 1
val years: Int
get() = TIME_T.div(YEAR_DAYS * DAY_LENGTH).abs().toInt() + EPOCH_YEAR
@@ -153,6 +155,9 @@ class WorldTime(initTime: Long = 0L) {
val EPOCH_YEAR = 125
/**
* Parse a time in the format of "8h30" (hour and minute) or "39882" (second) and return a time of day, in seconds
*/
fun parseTime(s: String): Int =
if (s.length >= 4 && s.contains('h')) {
s.toLowerCase().substringBefore('h').toInt() * HOUR_SEC +

View File

@@ -0,0 +1,38 @@
package net.torvald.terrarum.modulebasegame.imagefont
import com.badlogic.gdx.graphics.g2d.Batch
import com.badlogic.gdx.graphics.g2d.BitmapFont
import com.badlogic.gdx.graphics.g2d.GlyphLayout
import net.torvald.terrarum.ModMgr
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
/**
* Created by minjaesong on 2019-01-24.
*/
object WatchFont : BitmapFont() {
internal val W = 9
internal val H = 12
internal val fontSheet = TextureRegionPack(ModMgr.getGdxFile("basegame", "fonts/watch_new.tga"), W, H)
init {
setOwnsTexture(true)
}
override fun draw(batch: Batch, str: CharSequence, x: Float, y: Float): GlyphLayout? {
str.forEachIndexed { index, c ->
batch.draw(
fontSheet.get((c - '0') % 16, (c - '0') / 16),
x + W * index, y
)
}
return null
}
override fun getLineHeight() = H.toFloat()
override fun getCapHeight() = getLineHeight()
override fun getXHeight() = getLineHeight()
}

View File

@@ -23,7 +23,7 @@ class PickaxeGeneric(override val originalID: ItemID) : GameItem() {
override var stackable = true
override var maxDurability = 147
override var durability = maxDurability.toFloat()
override val equipPosition = 9
override val equipPosition = GameItem.EquipPosition.HAND_GRIP
override var inventoryCategory = Category.TOOL
override val isUnique = false
override val isDynamic = true
@@ -47,10 +47,10 @@ class PickaxeGeneric(override val originalID: ItemID) : GameItem() {
// linear search filter (check for intersection with tilewise mouse point and tilewise hitbox)
// return false if hitting actors
Terrarum.ingame!!.actorContainer.forEach({
Terrarum.ingame!!.actorContainer.forEach {
if (it is ActorWBMovable && it.hIntTilewiseHitbox.intersects(mousePoint))
return false
})
}
// return false if here's no tile
if (Block.AIR == (Terrarum.ingame!!.world).getTileFromTerrain(mouseTileX, mouseTileY))

View File

@@ -17,8 +17,11 @@ import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
*/
object ItemSlotImageFactory {
val colourBlack = Color(0x404040_FF)
val colourWhite = Color(0xC0C0C0_FF.toInt())
val CELLCOLOUR_BLACK_OPAQUE = Color(0x404040_FF)
val CELLCOLOUR_WHITE_OPAQUE = Color(0xC0C0C0_FF.toInt())
val CELLCOLOUR_BLACK = Color(0x404040_88)
val CELLCOLOUR_WHITE = Color(0xC0C0C0_88.toInt())
val slotImage = TextureRegionPack(Gdx.files.internal("./assets/graphics/gui/quickbar/item_slots_atlas.tga"), 38, 38) // must have same w/h as slotLarge

View File

@@ -1,19 +1,10 @@
package net.torvald.terrarum.modulebasegame.ui
import com.badlogic.gdx.graphics.Camera
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.terrarum.Second
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.blendNormal
import net.torvald.terrarum.ui.UICanvas
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
/**
* Created by minjaesong on 2016-01-27.
*/
class MessageWindow(override var width: Int, isBlackVariant: Boolean) : UICanvas() {
/*class MessageWindow(override var width: Int, isBlackVariant: Boolean) : UICanvas() {
private val segment = if (isBlackVariant) SEGMENT_BLACK else SEGMENT_WHITE
@@ -49,6 +40,9 @@ class MessageWindow(override var width: Int, isBlackVariant: Boolean) : UICanvas
messagesList.forEachIndexed { index, s ->
Terrarum.fontGame.draw(batch, s, segment.tileW + LRmargin, (segment.tileH - Terrarum.fontGame.lineHeight) / 2f)
}
AppLoader.printdbg(this, "render")
}
override fun doOpening(delta: Float) {
@@ -76,4 +70,4 @@ class MessageWindow(override var width: Int, isBlackVariant: Boolean) : UICanvas
val SEGMENT_BLACK = TextureRegionPack("assets/graphics/gui/message_black.tga", 8, 56)
val SEGMENT_WHITE = TextureRegionPack("assets/graphics/gui/message_white.tga", 8, 56)
}
}
}*/

View File

@@ -1,32 +1,45 @@
package net.torvald.terrarum.modulebasegame.ui
import com.badlogic.gdx.graphics.Camera
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.terrarum.AppLoader
import net.torvald.terrarum.Second
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.blendNormal
import net.torvald.terrarum.ui.UICanvas
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
/**
* Created by minjaesong on 2016-01-23.
*/
class Notification : UICanvas() {
private val SHOWUP_MAX = 15000
private val segment = SEGMENT_BLACK
private var fontCol: Color = Color.WHITE // assuming alpha of 1.0
override var openCloseTime: Second = OPEN_CLOSE_TIME
private val LRmargin = 0f // there's "base value" of 8 px for LR (width of segment tile)
private val SHOWUP_MAX = 6500
override var width: Int = 500
internal var msgUI = MessageWindow(width, true)
override var height: Int = msgUI.height
override var height: Int = segment.tileH
private val visibleTime = Math.min(
AppLoader.getConfigInt("notificationshowuptime"),
SHOWUP_MAX
)
) / 1000f
private var displayTimer = 0f
internal var message: Array<String> = Array(MessageWindow.MESSAGES_DISPLAY) { "" }
internal var message: Array<String> = Array(MESSAGES_DISPLAY) { "" }
override var openCloseTime: Second = MessageWindow.OPEN_CLOSE_TIME
init {
}
override fun updateUI(delta: Float) {
if (handler.isOpened)
@@ -38,8 +51,34 @@ class Notification : UICanvas() {
}
}
private val textAreaHeight = 48f
private val imageToTextAreaDelta = (segment.tileH - textAreaHeight) / 2
private val drawColor = Color(1f,1f,1f,1f)
override fun renderUI(batch: SpriteBatch, camera: Camera) {
msgUI.render(batch, camera)
blendNormal(batch)
drawColor.a = handler.opacity
fontCol.a = handler.opacity
val textWidth = width//maxOf(width, messagesList.map { Terrarum.fontGame.getWidth(it) }.sorted()[1])
batch.color = drawColor
batch.draw(segment.get(0, 0), -segment.tileW.toFloat(), 0f)
batch.draw(segment.get(1, 0), 0f, 0f, textWidth.toFloat(), segment.tileH.toFloat())
batch.draw(segment.get(2, 0), textWidth.toFloat(), 0f)
batch.color = fontCol
message.forEachIndexed { index, s ->
val y = imageToTextAreaDelta + index * (textAreaHeight / 2) + (textAreaHeight / 2 - Terrarum.fontGame.lineHeight) / 2
Terrarum.fontGame.draw(batch, s, LRmargin, y)
}
// dunno why, it doesn't work without this.
drawColor.a = 1f
fontCol.a = 1f
}
override fun doOpening(delta: Float) {
@@ -60,7 +99,6 @@ class Notification : UICanvas() {
fun sendNotification(message: Array<String>) {
this.message = message
msgUI.setMessage(this.message)
handler.openCloseCounter = 0f
handler.opacity = 0f
handler.setAsOpen()
@@ -68,4 +106,15 @@ class Notification : UICanvas() {
override fun dispose() {
}
companion object {
// private int messagesShowingIndex = 0;
val MESSAGES_DISPLAY = 2
val OPEN_CLOSE_TIME = 0.16f
// will be disposed by Terrarum (application main instance)
val SEGMENT_BLACK = TextureRegionPack("assets/graphics/gui/message_black.tga", 8, 56)
val SEGMENT_WHITE = TextureRegionPack("assets/graphics/gui/message_white.tga", 8, 56)
}
}

View File

@@ -0,0 +1,164 @@
package net.torvald.terrarum.modulebasegame.ui
import com.badlogic.gdx.graphics.Camera
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.blendNormal
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.fillRect
import net.torvald.terrarum.itemproperties.ItemCodex
import net.torvald.terrarum.modulebasegame.ui.ItemSlotImageFactory.CELLCOLOUR_BLACK
import net.torvald.terrarum.ui.UICanvas
import net.torvald.terrarum.ui.UINSMenu
/**
* Created by minjaesong on 2019-02-03.
*/
class UIEditorPalette : UICanvas() {
override var width = 36
override var height = 72
override var openCloseTime = 0f
val LINE_HEIGHT = 24
val TEXT_OFFSETX = 3f
val TEXT_OFFSETY = (LINE_HEIGHT - Terrarum.fontGame.lineHeight) / 2f
fun mouseOnTitleBar() =
relativeMouseX in 0 until width && relativeMouseY in 0 until LINE_HEIGHT
var fore = Block.STONE_BRICKS
var back = Block.GLASS_CRUDE
private val titleText = "Pal."
private val swapIcon: Texture
init {
// make swap icon, because I can't be bothered to make yet another tga
val clut = intArrayOf(0, 0xaaaaaaff.toInt(), -1, -1)
val swapIconPixmap = Pixmap(13, 13, Pixmap.Format.RGBA8888)
arrayOf(
0b00_00_11_01_00_00_00_00_00_00_00_00_00,
0b00_11_11_01_00_00_00_00_00_00_00_00_00,
0b11_11_11_11_11_11_11_11_11_11_01_00_00,
0b01_11_11_01_01_01_01_01_01_11_01_00_00,
0b00_01_11_01_00_00_00_00_00_11_01_00_00,
0b00_00_01_01_00_00_00_00_00_11_01_00_00,
0b00_00_00_00_00_00_00_00_00_11_01_00_00,
0b00_00_00_00_00_00_00_00_00_11_01_00_00,
0b00_00_00_00_00_00_00_00_00_11_01_00_00,
0b00_00_00_00_00_00_00_11_11_11_11_11_01,
0b00_00_00_00_00_00_00_01_11_11_11_01_01,
0b00_00_00_00_00_00_00_00_01_11_01_01_00,
0b00_00_00_00_00_00_00_00_00_01_01_00_00
).reversed().forEachIndexed { index, bits ->
for (shiftmask in 12 downTo 0) {
val bit = bits.ushr(shiftmask * 2).and(3)
swapIconPixmap.drawPixel(12 - shiftmask, index, clut[bit])
}
}
swapIcon = Texture(swapIconPixmap)
swapIconPixmap.dispose()
}
override fun renderUI(batch: SpriteBatch, camera: Camera) {
// draw title bar
batch.color = UINSMenu.DEFAULT_TITLEBACKCOL
blendNormal(batch)
batch.fillRect(0f, 0f, width.toFloat(), LINE_HEIGHT.toFloat())
// draw "Pal."
batch.color = UINSMenu.DEFAULT_TITLETEXTCOL
Terrarum.fontGame.draw(batch, titleText, TEXT_OFFSETX, TEXT_OFFSETY)
// draw background
batch.color = CELLCOLOUR_BLACK
batch.fillRect(0f, LINE_HEIGHT.toFloat(), 36f, 48f)
// draw back and fore selection
batch.color = Color.WHITE
// TODO carve the overlap
batch.draw(ItemCodex.getItemImage(back), 14f, 41f)
batch.draw(ItemCodex.getItemImage(fore), 6f, 33f)
Terrarum.fontSmallNumbers.draw(batch, fore.toString(), 3f, 61f)
// draw swap icon
batch.color = Color.WHITE
batch.draw(swapIcon, 22f, 26f)
}
override fun updateUI(delta: Float) {
}
fun swapForeAndBack() {
// xor used, because why not?
fore = fore xor back
back = back xor fore
fore = fore xor back
}
override fun doOpening(delta: Float) {
}
override fun doClosing(delta: Float) {
}
override fun endOpening(delta: Float) {
}
override fun endClosing(delta: Float) {
}
override fun dispose() {
}
private var dragOriginX = 0 // relative mousepos
private var dragOriginY = 0 // relative mousepos
private var dragForReal = false
private var swapDown = false
override fun touchDragged(screenX: Int, screenY: Int, pointer: Int): Boolean {
if (mouseInScreen(screenX, screenY)) {
if (dragForReal) {
handler.setPosition(screenX - dragOriginX, screenY - dragOriginY)
//println("drag $screenX, $screenY")
}
}
return true
}
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
if (mouseOnTitleBar()) {
dragOriginX = relativeMouseX
dragOriginY = relativeMouseY
dragForReal = true
}
else {
dragForReal = false
}
// make swap button work
if (!swapDown && (relativeMouseX in 14..35 && relativeMouseY in 24..32 || relativeMouseX in 22..35 && relativeMouseY in 33..40)) {
swapDown = true
swapForeAndBack()
}
return true
}
override fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
swapDown = false
return true
}
}

View File

@@ -142,9 +142,9 @@ package net.torvald.terrarum.modulebasegame.ui
"${0xe011.toChar()}..${0xe010.toChar()} ${Lang["GAME_INVENTORY_REGISTER"]}$SP" +
"${0xe034.toChar()} ${Lang["GAME_INVENTORY_DROP"]}"
else
"$joypadLabelNinY ${Lang["GAME_INVENTORY_USE"]}$SP" +
"$gamepadLabelNinY ${Lang["GAME_INVENTORY_USE"]}$SP" +
"${0xe011.toChar()}${0xe010.toChar()} ${Lang["GAME_INVENTORY_REGISTER"]}$SP" +
"$joypadLabelNinA ${Lang["GAME_INVENTORY_DROP"]}"
"$gamepadLabelNinA ${Lang["GAME_INVENTORY_DROP"]}"
val listControlClose: String
get() = if (Terrarum.environment == RunningEnvironment.PC)
"${0xe037.toChar()} ${Lang["GAME_ACTION_CLOSE"]}"

View File

@@ -13,13 +13,16 @@ import net.torvald.terrarum.modulebasegame.Ingame
import net.torvald.terrarum.modulebasegame.gameactors.ActorInventory.Companion.CAPACITY_MODE_NO_ENCUMBER
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
import net.torvald.terrarum.ui.UICanvas
import net.torvald.terrarum.ui.UIItem
import net.torvald.terrarum.ui.UIItemTextButtonList
import net.torvald.terrarum.ui.UIUtils
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
/**
* Created by minjaesong on 2017-10-21.
*/
class UIInventoryFull(
var actor: Pocketed?,
var actor: Pocketed,
toggleKeyLiteral: Int? = null, toggleButtonLiteral: Int? = null,
// UI positions itself? (you must g.flush() yourself after the g.translate(Int, Int))
@@ -27,11 +30,15 @@ class UIInventoryFull(
doNotWarnConstant: Boolean = false
) : UICanvas(toggleKeyLiteral, toggleButtonLiteral, customPositioning, doNotWarnConstant) {
private val debugvals = false
override var width: Int = Terrarum.WIDTH
override var height: Int = Terrarum.HEIGHT
val internalWidth: Int = 686
val internalHeight: Int = 558 // grad_begin..grad_end..contents..grad_begin..grad_end
private val itemListToEquipViewGap = 24
val internalWidth: Int = UIItemInventoryDynamicList.WIDTH + UIItemInventoryEquippedView.WIDTH + itemListToEquipViewGap
val internalHeight: Int = 166 + UIItemInventoryDynamicList.HEIGHT // grad_begin..grad_end..contents..grad_begin..grad_end
@@ -49,9 +56,19 @@ class UIInventoryFull(
"${0xe034.toChar()} ${Lang["GAME_INVENTORY_DROP"]}"
else
"${0xe069.toChar()} ${Lang["GAME_ACTION_CLOSE"]}$SP" +
"${Terrarum.joypadLabelNinY} ${Lang["GAME_INVENTORY_USE"]}$SP" +
"${Terrarum.gamepadLabelNinY} ${Lang["GAME_INVENTORY_USE"]}$SP" +
"${0xe011.toChar()}${0xe010.toChar()} ${Lang["GAME_INVENTORY_REGISTER"]}$SP" +
"${Terrarum.joypadLabelNinA} ${Lang["GAME_INVENTORY_DROP"]}"
"${Terrarum.gamepadLabelNinA} ${Lang["GAME_INVENTORY_DROP"]}"
val minimapControlHelp: String
get() = if (AppLoader.environment == RunningEnvironment.PC)
"${0xe031.toChar()} ${Lang["GAME_ACTION_CLOSE"]}"
else
"${0xe069.toChar()} ${Lang["GAME_ACTION_CLOSE"]}$SP${0xe06b.toChar()} ${Lang["GAME_INVENTORY"]}"
val gameMenuControlHelp: String
get() = if (AppLoader.environment == RunningEnvironment.PC)
"${0xe031.toChar()} ${Lang["GAME_ACTION_CLOSE"]}"
else
"${0xe069.toChar()} ${Lang["GAME_ACTION_CLOSE"]}$SP${0xe068.toChar()} ${Lang["GAME_INVENTORY"]}"
val controlHelpHeight = Terrarum.fontGame.lineHeight
private var encumbrancePerc = 0f
@@ -62,7 +79,7 @@ class UIInventoryFull(
val categoryBar = UIItemInventoryCatBar(
this,
(Terrarum.WIDTH - catBarWidth) / 2,
66 + (Terrarum.HEIGHT - internalHeight) / 2,
42 + (Terrarum.HEIGHT - internalHeight) / 2,
catBarWidth
)
val catSelection: Int
@@ -73,48 +90,100 @@ class UIInventoryFull(
override var openCloseTime: Second = 0.0f
private val itemList: UIItemInventoryDynamicList? =
if (actor != null) {
UIItemInventoryDynamicList(
this,
actor!!.inventory,
0 + (Terrarum.WIDTH - internalWidth) / 2,
109 + (Terrarum.HEIGHT - internalHeight) / 2
)
}
else null
private val itemList: UIItemInventoryDynamicList =
UIItemInventoryDynamicList(
this,
actor.inventory,
0 + (Terrarum.WIDTH - internalWidth) / 2,
109 + (Terrarum.HEIGHT - internalHeight) / 2
)
private val equipped: UIItemInventoryEquippedView? =
if (actor != null) {
UIItemInventoryEquippedView(
this,
actor!!.inventory,
actor as ActorWBMovable,
internalWidth - UIItemInventoryEquippedView.width + (Terrarum.WIDTH - internalWidth) / 2,
109 + (Terrarum.HEIGHT - internalHeight) / 2
)
}
else null
private val equipped: UIItemInventoryEquippedView =
UIItemInventoryEquippedView(
this,
actor.inventory,
actor as ActorWBMovable,
internalWidth - UIItemInventoryEquippedView.WIDTH + (Terrarum.WIDTH - internalWidth) / 2,
109 + (Terrarum.HEIGHT - internalHeight) / 2
)
private val gameMenuListWidth = 400
private val gameMenuListHeight = 40 * 5
private val gameMenuCharInfoHeight = 64 + 40 // no top margin, 40 bottom margin
private val gameMenuListTotalHeight = gameMenuListHeight + gameMenuCharInfoHeight
private val gameMenuButtons = UIItemTextButtonList(
this, arrayOf("MENU_LABEL_MAINMENU", "MENU_LABEL_DESKTOP", "MENU_OPTIONS_CONTROLS", "MENU_OPTIONS_SOUND", "MENU_LABEL_GRAPHICS"),
Terrarum.WIDTH + (Terrarum.WIDTH - gameMenuListWidth) / 2,
(itemList.height - gameMenuListTotalHeight) / 2 + itemList.posY + gameMenuCharInfoHeight,
gameMenuListWidth, gameMenuListHeight,
readFromLang = true,
textAreaWidth = gameMenuListWidth,
activeBackCol = Color(0),
highlightBackCol = Color(0),
backgroundCol = Color(0),
inactiveCol = Color.WHITE,
defaultSelection = null
)
private val SCREEN_MINIMAP = 2f
private val SCREEN_INVENTORY = 1f
private val SCREEN_MENU = 0f
private var currentScreen = SCREEN_INVENTORY
private var transitionRequested = false
private var transitionOngoing = false
private var transitionReqSource = SCREEN_INVENTORY
private var transitionReqTarget = SCREEN_INVENTORY
private var transitionTimer = 0f
private val transitionLength = 0.212f
private val transitionalUpdateUIs = ArrayList<UIItem>()
private val transitionalUpdateUIoriginalPosX = ArrayList<Int>()
private fun addToTransitionalGroup(item: UIItem) {
transitionalUpdateUIs.add(item)
transitionalUpdateUIoriginalPosX.add(item.posX)
}
private fun updateTransitionalItems() {
for (k in 0..transitionalUpdateUIs.lastIndex) {
val intOff = inventoryScrOffX.roundInt()
transitionalUpdateUIs[k].posX = transitionalUpdateUIoriginalPosX[k] + intOff
}
}
init {
addItem(categoryBar)
itemList?.let { addItem(it) }
equipped?.let { addItem(it) }
itemList.let { addItem(it) }
equipped.let { addItem(it) }
categoryBar.selectionChangeListener = { old, new ->
rebuildList()
itemList?.itemPage = 0 // set scroll to zero
itemList?.rebuild() // have to manually rebuild, too!
itemList.itemPage = 0 // set scroll to zero
itemList.rebuild() // have to manually rebuild, too!
}
rebuildList()
addToTransitionalGroup(itemList)
addToTransitionalGroup(equipped)
addToTransitionalGroup(gameMenuButtons)
// make gameMenuButtons work
gameMenuButtons.selectionChangeListener = { old, new ->
if (new == 0) {
Terrarum.setScreen(TitleScreen(Terrarum.batch))
}
else if (new == 1) {
Gdx.app.exit()
}
}
}
private var offsetX = ((Terrarum.WIDTH - internalWidth) / 2).toFloat()
@@ -129,8 +198,9 @@ class UIInventoryFull(
categoryBar.update(delta)
itemList?.update(delta)
equipped?.update(delta)
transitionalUpdateUIs.forEach { it.update(delta) }
}
private val gradStartCol = Color(0x404040_60)
@@ -140,9 +210,45 @@ class UIInventoryFull(
private val weightBarWidth = 60f
private var xEnd = (Terrarum.WIDTH + internalWidth).div(2).toFloat()
private var yEnd = (Terrarum.HEIGHT + internalHeight).div(2).toFloat()
fun requestTransition(target: Int) {
if (!transitionOngoing) {
transitionRequested = true
transitionReqSource = currentScreen.round()
transitionReqTarget = target.toFloat()
}
}
override fun renderUI(batch: SpriteBatch, camera: Camera) {
val xEnd = (Terrarum.WIDTH + internalWidth).div(2).toFloat()
val yEnd = (Terrarum.HEIGHT + internalHeight).div(2).toFloat()
if (transitionRequested && !transitionOngoing) {
transitionRequested = false
transitionOngoing = true
transitionTimer = 0f
}
if (transitionOngoing) {
transitionTimer += Gdx.graphics.deltaTime
currentScreen = UIUtils.moveQuick(transitionReqSource, transitionReqTarget, transitionTimer, transitionLength)
if (transitionTimer > transitionLength) {
transitionOngoing = false
currentScreen = transitionReqTarget
}
}
// update at render time
updateTransitionalItems()
if (debugvals) {
batch.color = Color.WHITE
AppLoader.fontSmallNumbers.draw(batch, "screen:$currentScreen", 500f, 20f)
}
// background fill
@@ -167,66 +273,141 @@ class UIInventoryFull(
// UI items
categoryBar.render(batch, camera)
itemList?.render(batch, camera)
equipped?.render(batch, camera)
if (currentScreen > 1f + epsilon) {
renderScreenMinimap(batch, camera)
if (debugvals) {
batch.color = Color.CORAL
AppLoader.fontSmallNumbers.draw(batch, "Map", 300f, 10f)
}
}
if (currentScreen in epsilon..2f - epsilon) {
renderScreenInventory(batch, camera)
if (debugvals) {
batch.color = Color.CHARTREUSE
AppLoader.fontSmallNumbers.draw(batch, "Inv", 350f, 10f)
}
}
if (currentScreen < 1f - epsilon) {
renderScreenGamemenu(batch, camera)
if (debugvals) {
batch.color = Color.SKY
AppLoader.fontSmallNumbers.draw(batch, "Men", 400f, 10f)
}
}
if (debugvals) {
batch.color = Color.WHITE
AppLoader.fontSmallNumbers.draw(batch, "inventoryScrOffX:$inventoryScrOffX", 500f, 10f)
}
}
private val epsilon = 0.001f
private val minimapScrOffX: Float
get() = (currentScreen - 2f) * Terrarum.WIDTH
/**
* - 0 on inventory screen
* - +WIDTH on minimap screen
* - -WIDTH on gamemenu screen
*/
private val inventoryScrOffX: Float
get() = (currentScreen - 1f) * Terrarum.WIDTH
private val menuScrOffX: Float
get() = (currentScreen) * Terrarum.WIDTH
private fun renderScreenMinimap(batch: SpriteBatch, camera: Camera) {
// control hints
blendNormal(batch)
batch.color = Color.WHITE
Terrarum.fontGame.draw(batch, minimapControlHelp, offsetX + minimapScrOffX, yEnd - 20)
}
private fun renderScreenGamemenu(batch: SpriteBatch, camera: Camera) {
// control hints
blendNormal(batch)
batch.color = Color.WHITE
Terrarum.fontGame.draw(batch, gameMenuControlHelp, offsetX + menuScrOffX, yEnd - 20)
// text buttons
gameMenuButtons.render(batch, camera)
// character info window
// !! DUMMY !!
batch.color = itemList.backColour
batch.fillRect(
((Terrarum.WIDTH - 400) / 2) + menuScrOffX,
(itemList.height - gameMenuListTotalHeight) / 2 + itemList.posY.toFloat(),
gameMenuListWidth.toFloat(),
64f
)
}
private fun renderScreenInventory(batch: SpriteBatch, camera: Camera) {
itemList.render(batch, camera)
equipped.render(batch, camera)
// control hints
blendNormal(batch)
batch.color = Color.WHITE
Terrarum.fontGame.draw(batch, listControlHelp, offsetX, offsetY + internalHeight)
Terrarum.fontGame.draw(batch, listControlHelp, offsetX + inventoryScrOffX, yEnd - 20)
// encumbrance meter
if (actor != null) {
val encumbranceText = Lang["GAME_INVENTORY_ENCUMBRANCE"]
val encumbranceText = Lang["GAME_INVENTORY_ENCUMBRANCE"]
Terrarum.fontGame.draw(batch,
encumbranceText,
xEnd - 9 - Terrarum.fontGame.getWidth(encumbranceText) - weightBarWidth,
yEnd
)
Terrarum.fontGame.draw(batch,
encumbranceText,
xEnd - 9 - Terrarum.fontGame.getWidth(encumbranceText) - weightBarWidth + inventoryScrOffX,
yEnd-20
)
// encumbrance bar background
blendMul(batch)
batch.color = Color(0xa0a0a0_ff.toInt())
batch.fillRect(
xEnd - 3 - weightBarWidth,
yEnd + 3f,
weightBarWidth,
controlHelpHeight - 6f
)
// encumbrance bar
blendNormal(batch)
batch.color = if (isEncumbered) Color(0xff0000_cc.toInt()) else Color(0x00ff00_cc.toInt())
batch.fillRect(
xEnd - 3 - weightBarWidth,
yEnd + 3f,
if (actor?.inventory?.capacityMode == CAPACITY_MODE_NO_ENCUMBER)
1f
else // make sure 1px is always be seen
minOf(weightBarWidth, maxOf(1f, weightBarWidth * encumbrancePerc)),
controlHelpHeight - 5f
)
}
// encumbrance bar background
blendMul(batch)
batch.color = Color(0xa0a0a0_ff.toInt())
batch.fillRect(
xEnd - 3 - weightBarWidth + inventoryScrOffX,
yEnd-20 + 3f,
weightBarWidth,
controlHelpHeight - 6f
)
// encumbrance bar
blendNormal(batch)
batch.color = if (isEncumbered) Color(0xff0000_cc.toInt()) else Color(0x00ff00_cc.toInt())
batch.fillRect(
xEnd - 3 - weightBarWidth + inventoryScrOffX,
yEnd-20 + 3f,
if (actor.inventory.capacityMode == CAPACITY_MODE_NO_ENCUMBER)
1f
else // make sure 1px is always be seen
minOf(weightBarWidth, maxOf(1f, weightBarWidth * encumbrancePerc)),
controlHelpHeight - 5f
)
}
fun rebuildList() {
itemList?.rebuild()
equipped?.rebuild()
itemList.rebuild()
equipped.rebuild()
actor?.let {
encumbrancePerc = actor!!.inventory.capacity.toFloat() / actor!!.inventory.maxCapacity
isEncumbered = actor!!.inventory.isEncumbered
}
encumbrancePerc = actor.inventory.capacity.toFloat() / actor.inventory.maxCapacity
isEncumbered = actor.inventory.isEncumbered
}
override fun dispose() {
categoryBar.dispose()
itemList?.dispose()
equipped?.dispose()
itemList.dispose()
equipped.dispose()
}
@@ -243,7 +424,7 @@ class UIInventoryFull(
}
override fun endClosing(delta: Float) {
(Terrarum.ingame as? Ingame)?.setTooltipMessage(null) // required!!
(Terrarum.ingame as? Ingame)?.setTooltipMessage(null) // required!
}
@@ -253,6 +434,9 @@ class UIInventoryFull(
offsetX = ((Terrarum.WIDTH - internalWidth) / 2).toFloat()
offsetY = ((Terrarum.HEIGHT - internalHeight) / 2).toFloat()
xEnd = (Terrarum.WIDTH + internalWidth).div(2).toFloat()
yEnd = (Terrarum.HEIGHT + internalHeight).div(2).toFloat()
}

View File

@@ -10,6 +10,7 @@ import net.torvald.terrarum.itemproperties.ItemCodex
import net.torvald.terrarum.modulebasegame.Ingame
import net.torvald.terrarum.modulebasegame.gameactors.ActorInventory
import net.torvald.terrarum.modulebasegame.gameactors.InventoryPair
import net.torvald.terrarum.modulebasegame.ui.ItemSlotImageFactory.CELLCOLOUR_BLACK
import net.torvald.terrarum.ui.UIItem
import net.torvald.terrarum.ui.UIItemImageButton
import java.util.*
@@ -32,8 +33,14 @@ class UIItemInventoryDynamicList(
override var posY: Int
) : UIItem(parentUI) {
override val width = 496
override val height = 384
// deal with the moving position
override var oldPosX = posX
override var oldPosY = posY
override val width = WIDTH
override val height = HEIGHT
val backColour = CELLCOLOUR_BLACK
private val catArrangement = parentUI.catArrangement
@@ -74,35 +81,44 @@ class UIItemInventoryDynamicList(
val defaultTextColour = Color(0xeaeaea_ff.toInt())
private val listGap = 8
private val itemList = Array<UIItemInventoryCellBase>(7 * 2) {
UIItemInventoryElem(
companion object {
const val listGap = 8
const val horizontalCells = 11
const val verticalCells = 8
val largeListWidth = (horizontalCells * UIItemInventoryElemSimple.height + (horizontalCells - 2) * listGap) / 2
val WIDTH = horizontalCells * UIItemInventoryElemSimple.height + (horizontalCells - 1) * listGap
val HEIGHT = verticalCells * UIItemInventoryElemSimple.height + (verticalCells - 1) * listGap
}
private val itemGrid = Array<UIItemInventoryCellBase>(horizontalCells * verticalCells) {
UIItemInventoryElemSimple(
parentUI = inventoryUI,
posX = this.posX + (272 + listGap) * (it % 2),
posY = this.posY + (UIItemInventoryElem.height + listGap) * (it / 2),
width = 272,
posX = this.posX + (UIItemInventoryElemSimple.height + listGap) * (it % horizontalCells),
posY = this.posY + (UIItemInventoryElemSimple.height + listGap) * (it / horizontalCells),
item = null,
amount = UIItemInventoryElem.UNIQUE_ITEM_HAS_NO_AMOUNT,
itemImage = null,
mouseoverBackCol = Color(0x282828_ff),
mouseoverBackBlendMode = BlendMode.SCREEN,
backCol = Color(0x404040_88),
backCol = backColour,
backBlendMode = BlendMode.NORMAL,
drawBackOnNull = true,
inactiveTextCol = defaultTextColour
)
}
private val itemGrid = Array<UIItemInventoryCellBase>(7 * 10) {
UIItemInventoryElemSimple(
private val itemList = Array<UIItemInventoryCellBase>(verticalCells * 2) {
UIItemInventoryElem(
parentUI = inventoryUI,
posX = this.posX + (UIItemInventoryElemSimple.height + listGap) * (it % 10),
posY = this.posY + (UIItemInventoryElemSimple.height + listGap) * (it / 10),
posX = this.posX + (largeListWidth + listGap) * (it % 2),
posY = this.posY + (UIItemInventoryElem.height + listGap) * (it / 2),
width = largeListWidth,
item = null,
amount = UIItemInventoryElem.UNIQUE_ITEM_HAS_NO_AMOUNT,
itemImage = null,
mouseoverBackCol = Color(0x282828_ff),
mouseoverBackBlendMode = BlendMode.SCREEN,
backCol = Color(0x404040_88),
backCol = backColour,
backBlendMode = BlendMode.NORMAL,
drawBackOnNull = true,
inactiveTextCol = defaultTextColour
@@ -196,6 +212,15 @@ class UIItemInventoryDynamicList(
private val upDownButtonGapToDots = 7 // apparent gap may vary depend on the texture itself
override fun render(batch: SpriteBatch, camera: Camera) {
val posXDelta = posX - oldPosX
itemGrid.forEach { it.posX += posXDelta }
itemList.forEach { it.posX += posXDelta }
gridModeButtons.forEach { it.posX += posXDelta }
scrollUpButton.posX += posXDelta
scrollDownButton.posX += posXDelta
fun getScrollDotYHeight(i: Int) = scrollUpButton.posY + 10 + upDownButtonGapToDots + 10 * i
scrollDownButton.posY = getScrollDotYHeight(itemPageCount) + upDownButtonGapToDots
@@ -221,6 +246,8 @@ class UIItemInventoryDynamicList(
}
super.render(batch, camera)
oldPosX = posX
}

View File

@@ -8,6 +8,7 @@ import net.torvald.terrarum.gameactors.ActorWBMovable
import net.torvald.terrarum.itemproperties.GameItem
import net.torvald.terrarum.itemproperties.ItemCodex
import net.torvald.terrarum.modulebasegame.gameactors.ActorInventory
import net.torvald.terrarum.modulebasegame.ui.ItemSlotImageFactory.CELLCOLOUR_BLACK
import net.torvald.terrarum.ui.UIItem
/**
@@ -21,12 +22,12 @@ class UIItemInventoryEquippedView(
override var posY: Int
) : UIItem(parentUI) {
override val width = 104
override val height = 384
override val width = WIDTH
override val height = HEIGHT
companion object {
val width = 104
val height = 384
val WIDTH = 2 * UIItemInventoryElemSimple.height + UIItemInventoryDynamicList.listGap
val HEIGHT = UIItemInventoryDynamicList.HEIGHT
}
private val listGap = 8
@@ -37,9 +38,9 @@ class UIItemInventoryEquippedView(
lateinit var inventorySortList: Array<GameItem?>
private var rebuildList = true
val spriteViewBackCol: Color; get() = Color(0x404040_88.toInt())//Color(0xd4d4d4_ff.toInt())
val spriteViewBackCol: Color = CELLCOLOUR_BLACK
private val itemGrid = Array<UIItemInventoryCellBase>(2 * 5) {
private val itemGrid = Array<UIItemInventoryCellBase>(2 * 6) {
UIItemInventoryElemSimple(
parentUI = parentUI,
posX = this.posX + (UIItemInventoryElemSimple.height + listGap) * ((it + 4) % 2),
@@ -49,7 +50,7 @@ class UIItemInventoryEquippedView(
itemImage = null,
mouseoverBackCol = Color(0x282828_ff),
mouseoverBackBlendMode = BlendMode.SCREEN,
backCol = Color(0x404040_88),
backCol = CELLCOLOUR_BLACK,
backBlendMode = BlendMode.NORMAL,
drawBackOnNull = true
)
@@ -60,7 +61,18 @@ class UIItemInventoryEquippedView(
itemGrid.forEach { it.update(delta) }
}
private val spriteDrawCol = Color(0xddddddff.toInt())
// deal with the moving position
override var oldPosX = posX
override var oldPosY = posY
override fun render(batch: SpriteBatch, camera: Camera) {
val posXDelta = posX - oldPosX
itemGrid.forEach { it.posX += posXDelta }
// sprite background
blendNormal(batch)
batch.color = spriteViewBackCol
@@ -74,51 +86,49 @@ class UIItemInventoryEquippedView(
sprite?.let {
blendNormal(batch)
it.render(
batch,
batch.color = spriteDrawCol
batch.draw(
it.textureRegion.get(0, 0),
posX + (width - it.cellWidth).div(2).toFloat(),
posY + (width - it.cellHeight).div(2).toFloat()
) }
)
}
// TODO inscribe slot image on each cells HERE
itemGrid.forEach { it.render(batch, camera) }
oldPosX = posX
}
internal fun rebuild() {
inventorySortList = inventory.itemEquipped.clone()
rebuildList = false
// sort by equip position
// fill the grid from fastest index, make no gap in-between of slots
var listPushCnt = 0
for (k in 0 until itemGrid.size) {
val it = inventorySortList[k]
val item = inventory.itemEquipped[k]
if (it != null) {
val itemRecord = inventory.getByDynamicID(it.dynamicID)!!
if (item == null) {
itemGrid[listPushCnt].item = it
itemGrid[listPushCnt].amount = itemRecord.amount
itemGrid[listPushCnt].itemImage = ItemCodex.getItemImage(it)
itemGrid[listPushCnt].quickslot = null // don't need to be displayed
itemGrid[listPushCnt].equippedSlot = null // don't need to be displayed
listPushCnt++
itemGrid[k].item = null
itemGrid[k].amount = 0
itemGrid[k].itemImage = null
itemGrid[k].quickslot = null
itemGrid[k].equippedSlot = null
}
}
else {
val itemRecord = inventory.getByDynamicID(item.dynamicID)!!
// empty out un-filled grids from previous garbage
for (m in listPushCnt until itemGrid.size) {
itemGrid[m].item = null
itemGrid[m].amount = 0
itemGrid[m].itemImage = null
itemGrid[m].quickslot = null
itemGrid[m].equippedSlot = null
itemGrid[k].item = item
itemGrid[k].amount = itemRecord.amount
itemGrid[k].itemImage = ItemCodex.getItemImage(item)
itemGrid[k].quickslot = null // don't need to be displayed
itemGrid[k].equippedSlot = null // don't need to be displayed
}
}
}

View File

@@ -18,6 +18,10 @@ class UIItemModuleInfoCell(
override var posY: Int
) : UIItem(parent) {
// deal with the moving position
override var oldPosX = posX
override var oldPosY = posY
override val height: Int = Terrarum.fontGame.lineHeight.toInt() * 2
private val numberAreaWidth = Terrarum.fontSmallNumbers.W * 3 + 4

View File

@@ -20,6 +20,10 @@ class UIItemSavegameInfoCell(
override var posY: Int
) : UIItem(parent) {
// deal with the moving position
override var oldPosX = posX
override var oldPosY = posY
override val height: Int = Terrarum.fontGame.lineHeight.toInt() * 2
override fun render(batch: SpriteBatch, camera: Camera) {

View File

@@ -41,6 +41,8 @@ class UIQuickslotBar : UICanvas() {
override fun updateUI(delta: Float) {
}
private val drawColor = Color(1f,1f,1f,1f)
override fun renderUI(batch: SpriteBatch, camera: Camera) {
for (i in 0..SLOT_COUNT - 1) {
@@ -55,7 +57,8 @@ class UIQuickslotBar : UICanvas() {
val slotY = cellSize / 2
// draw slots
batch.color = Color(1f, 1f, 1f, handler.opacity * DISPLAY_OPACITY)
drawColor.a = handler.opacity * DISPLAY_OPACITY
batch.color = drawColor
image.draw(batch, slotX, slotY)
}

View File

@@ -8,9 +8,7 @@ import net.torvald.terrarum.*
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
import net.torvald.terrarum.modulebasegame.gameworld.GameWorldExtension
import net.torvald.terrarum.modulebasegame.gameworld.WorldTime
import net.torvald.terrarum.modulebasegame.imagefont.Watch7SegMain
import net.torvald.terrarum.modulebasegame.imagefont.Watch7SegSmall
import net.torvald.terrarum.modulebasegame.imagefont.WatchDotAlph
import net.torvald.terrarum.modulebasegame.imagefont.WatchFont
import net.torvald.terrarum.ui.UICanvas
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
@@ -18,28 +16,26 @@ import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
* Created by minjaesong on 2017-06-11.
*/
class UITierOneWatch(private val player: ActorHumanoid?) : UICanvas() {
override var width = 77
override var height = 53
override var width = 160
override var height = 23
override var openCloseTime: Second = 0f
private var ELuptimer = 10f // init value higher than uptime: to make the light turned off by default
private val ELuptime = 4f
private var ELon = false
private var atlas = TextureRegionPack(ModMgr.getPath("basegame", "gui/watchface2_atlas.tga"), width, height)
private var atlas = TextureRegionPack(ModMgr.getPath("basegame", "gui/watchface_atlas.tga"), width, height)
private var littleFont = Watch7SegSmall
private var timeFont = Watch7SegMain
private var textFont = WatchDotAlph
private var watchFont = WatchFont
private var moonDial = TextureRegionPack(ModMgr.getPath("basegame", "fonts/watch_17pxmoondial.tga"), 17, 17)
private var moonDialCount = moonDial.horizontalCount
private val drawCol = Color(1f,1f,1f,0.5f)
private val lcdLitColELoff = Color(0x141414_aa)
private val lcdLitColELon = Color(0x141414_ff)
private val drawCol = Color(1f,1f,1f,UIQuickslotBar.DISPLAY_OPACITY)
private val lcdLitColELoff = Color(0xc0c0c0ff.toInt()) mul drawCol
private val lcdLitColELon = Color(0x404040ff) mul drawCol
private val lcdLitCol: Color
get() = if (ELon) lcdLitColELon else lcdLitColELoff
private val lcdLitCol: Color = lcdLitColELoff
//get() = if (ELon) lcdLitColELon else lcdLitColELoff
private val worldTime: WorldTime
get() = (Terrarum.ingame!!.world as GameWorldExtension).time
@@ -62,33 +58,30 @@ class UITierOneWatch(private val player: ActorHumanoid?) : UICanvas() {
override fun renderUI(batch: SpriteBatch, camera: Camera) {
// light overlay or EL
/*blendNormal(batch)
if (ELon) {
blendNormal(batch)
batch.draw(atlas.get(0, 2), 0f, 0f)
}
else {
// backplate
batch.color = drawCol
batch.draw(atlas.get(0, 0), 0f, 0f)
}
// LCD back
blendNormal(batch)
batch.draw(atlas.get(0, 3), 0f, 0f)
}*/
// disabling light button
batch.color = drawCol
batch.draw(atlas.get(0, 0), 0f, 0f)
// day name
batch.color = lcdLitCol
textFont.draw(batch, worldTime.getDayNameShort().toUpperCase(), 9f, 5f)
watchFont.draw(batch, worldTime.getDayNameShort().toUpperCase(), 73f, 7f)
// day
littleFont.draw(batch, worldTime.days.toString().padStart(2, ' '), 54f, 4f)
watchFont.draw(batch, worldTime.days.toString().padStart(2, '@'), 107f, 7f)
// hour
timeFont.draw(batch, worldTime.hours.toString().padStart(2, '/'), 25f, 31f)
watchFont.draw(batch, worldTime.hours.toString().padStart(2, '@'), 27f, 7f)
// minute
timeFont.draw(batch, worldTime.minutes.toString().padStart(2, '0'), 53f, 31f)
watchFont.draw(batch, worldTime.minutes.toString().padStart(2, '0'), 49f, 7f)
// season marker
batch.draw(atlas.get(1, worldTime.months - 1), 0f, 0f)
@@ -97,7 +90,7 @@ class UITierOneWatch(private val player: ActorHumanoid?) : UICanvas() {
// moon dial
val moonPhase = (worldTime.moonPhase * moonDialCount).roundInt() % moonDialCount
batch.color = lcdLitCol
batch.draw(moonDial.get(moonPhase, 0), 4f, 19f)
batch.draw(moonDial.get(moonPhase, 0), 6f, 3f)
}
override fun doOpening(delta: Float) {

View File

@@ -1,9 +1,7 @@
package net.torvald.terrarum.modulebasegame.ui
import net.torvald.terrarum.AppLoader
import net.torvald.terrarum.QNDTreeNode
import net.torvald.terrarum.Yaml
import java.util.*
@@ -24,12 +22,14 @@ object UITitleRemoConYaml {
- MENU_OPTIONS
- MENU_OPTIONS_GRAPHICS
- MENU_OPTIONS_CONTROLS
- MENU_CONTROLS_KEYBOARD
- MENU_CONTROLS_GAMEPAD
- MENU_LABEL_RETURN
- MENU_OPTIONS_SOUND
- MENU_LABEL_LANGUAGE : net.torvald.terrarum.modulebasegame.ui.UITitleLanguage
- MENU_LABEL_RETURN
- MENU_MODULES : net.torvald.terrarum.modulebasegame.ui.UITitleModules
- MENU_LABEL_RETURN
- MENU_LABEL_LANGUAGE : net.torvald.terrarum.modulebasegame.ui.UITitleLanguage
- MENU_LABEL_RETURN
- MENU_LABEL_CREDITS : net.torvald.terrarum.modulebasegame.ui.UITitleCredits
- MENU_LABEL_CREDITS : net.torvald.terrarum.modulebasegame.ui.UITitleCredits
- MENU_CREDIT_GPL_DNT : net.torvald.terrarum.modulebasegame.ui.UITitleGPL3

View File

@@ -57,6 +57,8 @@ class uiQuickslotPie : UICanvas() {
}
}
private val drawColor = Color(1f,1f,1f,1f)
override fun renderUI(batch: SpriteBatch, camera: Camera) {
// draw radial thingies
for (i in 0..slotCount - 1) {
@@ -75,7 +77,8 @@ class uiQuickslotPie : UICanvas() {
val slotX = slotCentrePoint.x.toInt()
val slotY = slotCentrePoint.y.toInt()
batch.color = Color(1f, 1f, 1f, handler.opacity * UIQuickslotBar.DISPLAY_OPACITY)
drawColor.a = handler.opacity * UIQuickslotBar.DISPLAY_OPACITY
batch.color = drawColor
image.draw(batch, slotX, slotY)
}

View File

@@ -2,25 +2,26 @@ package net.torvald.terrarum.modulebasegame.weather
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Input
import com.badlogic.gdx.graphics.*
import com.badlogic.gdx.utils.GdxRuntimeException
import net.torvald.terrarum.utils.JsonFetcher
import net.torvald.colourutil.*
import com.badlogic.gdx.graphics.Camera
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.Texture
import net.torvald.colourutil.CIELuvUtil
import net.torvald.random.HQRNG
import net.torvald.terrarum.*
import net.torvald.terrarum.console.CommandDict
import net.torvald.terrarum.console.SetGlobalLightOverride
import net.torvald.terrarum.GdxColorMap
import net.torvald.terrarum.ModMgr
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.gameactors.ActorWithBody
import net.torvald.terrarum.modulebasegame.gameactors.ParticleMegaRain
import net.torvald.terrarum.gamecontroller.KeyToggler
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.modulebasegame.Ingame
import net.torvald.terrarum.modulebasegame.RNGConsumer
import net.torvald.terrarum.modulebasegame.gameactors.ParticleMegaRain
import net.torvald.terrarum.modulebasegame.gameworld.GameWorldExtension
import net.torvald.terrarum.modulebasegame.gameworld.WorldTime
import net.torvald.terrarum.modulebasegame.worldgenerator.WorldGenerator
import net.torvald.terrarum.utils.JsonFetcher
import net.torvald.terrarum.worlddrawer.FeaturesDrawer
import net.torvald.terrarum.worlddrawer.WorldCamera
import net.torvald.terrarum.modulebasegame.worldgenerator.WorldGenerator
import java.io.File
import java.util.*
@@ -96,7 +97,7 @@ internal object WeatherMixer : RNGConsumer {
// test rain toggled by F2
if (KeyToggler.isOn(Input.Keys.F2)) {
if (KeyToggler.isOn(Input.Keys.F2) && Terrarum.ingame is Ingame) {
val playerPosX = player.hitbox.centeredX
val playerPosY = player.hitbox.centeredY
kotlin.repeat(7) {

View File

@@ -0,0 +1,62 @@
import kotlin.system.measureNanoTime
/**
* Created by minjaesong on 2019-01-27.
*/
class FixedMathTest {
fun invoke() {
val testSet = (1..100000).toList().shuffled()
val m1 = measureNanoTime {
testSet.forEach {
val x = (it * 1.41421356f)
}
}
val testSet2 = (1..100000).toList().shuffled()
val m2 = measureNanoTime {
testSet2.forEach {
val x2 = it.mulSqrt2()
}
}
val m3 = measureNanoTime {
testSet.forEach {
val x = (it * 1.41421356f)
}
}
val m4 = measureNanoTime {
testSet2.forEach {
val x2 = it.mulSqrt2()
}
}
println(m3)
println(m4)
println(m3.toDouble() / m4)
}
fun Int.mulSqrt2(): Int {
val xl = this
val yl = 92681
val xlo = xl and 0x0000FFFF
val xhi = xl shr 16
val ylo = yl and 0x0000FFFF
val yhi = yl shr 16
val lolo = xlo * ylo
val lohi = xlo * yhi
val hilo = xhi * ylo
val hihi = xhi * yhi
val loResult = lolo shr 16
val hiResult = hihi shl 16
val sum = loResult + lohi + hilo + hiResult
return sum
}
}
fun main(args: Array<String>) {
FixedMathTest().invoke()
}

View File

@@ -1,11 +1,12 @@
package net.torvald.terrarum.tests
import com.badlogic.gdx.*
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.InputAdapter
import com.badlogic.gdx.ScreenAdapter
import com.badlogic.gdx.backends.lwjgl.LwjglApplication
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.OrthographicCamera
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.glutils.ShaderProgram
import net.torvald.terrarum.*

View File

@@ -8,6 +8,7 @@ import com.jme3.math.FastMath
import net.torvald.terrarum.*
import net.torvald.terrarum.Terrarum.mouseTileX
import net.torvald.terrarum.Terrarum.mouseTileY
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.modulebasegame.Ingame
import net.torvald.terrarum.modulebasegame.gameworld.GameWorldExtension
import net.torvald.terrarum.worlddrawer.FeaturesDrawer
@@ -19,8 +20,8 @@ import net.torvald.terrarum.worlddrawer.WorldCamera
*/
class BasicDebugInfoWindow : UICanvas() {
override var width: Int = Terrarum.WIDTH
override var height: Int = Terrarum.HEIGHT
override var width: Int = AppLoader.screenW
override var height: Int = AppLoader.screenH
override var openCloseTime: Float = 0f
@@ -30,14 +31,17 @@ class BasicDebugInfoWindow : UICanvas() {
private var xdelta = 0.0
private var ydelta = 0.0
private val ingame = Terrarum.ingame!! as Ingame
private val ingame: IngameInstance?
get() = Terrarum.ingame
private val world: GameWorldExtension
get() = Terrarum.ingame!!.world as GameWorldExtension
private val world: GameWorld?
get() = Terrarum.ingame?.world
private val world2: GameWorldExtension?
get() = Terrarum.ingame?.world as GameWorldExtension?
override fun updateUI(delta: Float) {
val player = ingame.actorNowPlaying
val player = ingame?.actorNowPlaying
val hitbox = player?.hitbox
if (hitbox != null) {
@@ -65,7 +69,7 @@ class BasicDebugInfoWindow : UICanvas() {
}
override fun renderUI(batch: SpriteBatch, camera: Camera) {
val player = ingame.actorNowPlaying
val player = ingame?.actorNowPlaying
batch.color = Color(0xFFEE88FF.toInt())
@@ -108,11 +112,11 @@ class BasicDebugInfoWindow : UICanvas() {
+ ccG
+ "${WorldCamera.y}")
printLine(batch, 3, "veloX reported $ccG${player.externalForce.x}")
printLine(batch, 4, "veloY reported $ccG${player.externalForce.y}")
printLine(batch, 3, "veloX reported $ccG${player.externalV.x}")
printLine(batch, 4, "veloY reported $ccG${player.externalV.y}")
printLine(batch, 5, "p_WalkX $ccG${player.controllerMoveDelta?.x}")
printLine(batch, 6, "p_WalkY $ccG${player.controllerMoveDelta?.y}")
printLine(batch, 5, "p_WalkX $ccG${player.controllerV?.x}")
printLine(batch, 6, "p_WalkY $ccG${player.controllerV?.y}")
printLineColumn(batch, 2, 3, "veloX measured $ccG${xdelta}")
printLineColumn(batch, 2, 4, "veloY measured $ccG${ydelta}")
@@ -144,11 +148,14 @@ class BasicDebugInfoWindow : UICanvas() {
else "$rawR $rawG $rawB $rawA"
printLine(batch, 8, "light@cursor $ccG$lightVal")
val tileNum = ingame.world.getTileFromTerrain(mouseTileX, mouseTileY) ?: -1
val fluid = ingame.world.getFluid(mouseTileX, mouseTileY)
if (ingame != null) {
val tileNum = ingame!!.world.getTileFromTerrain(mouseTileX, mouseTileY) ?: -1
val fluid = ingame!!.world.getFluid(mouseTileX, mouseTileY)
printLine(batch, 9, "tile@cursor $ccG$tileNum ($mtX, $mtY)")
printLine(batch, 10, "fluid@cursor ${ccY}Type $ccM${fluid.type.value} ${ccY}Fill $ccG${fluid.amount}f")
printLine(batch, 9, "tile@cursor $ccG$tileNum ($mtX, $mtY)")
printLine(batch, 10, "fluid@cursor ${ccY}Type $ccM${fluid.type.value} ${ccY}Fill $ccG${fluid.amount}f")
}
// print time
@@ -166,8 +173,10 @@ class BasicDebugInfoWindow : UICanvas() {
//printLineColumn(batch, 2, 1, "VSync $ccG" + Terrarum.appgc.isVSyncRequested)
//printLineColumn(batch, 2, 2, "Env colour temp $ccG" + FeaturesDrawer.colTemp)
printLineColumn(batch, 2, 5, "Time $ccG${world.time.todaySeconds.toString().padStart(5, '0')}" +
" (${world.time.getFormattedTime()})")
if (world != null) {
printLineColumn(batch, 2, 5, "Time $ccG${world2!!.time.todaySeconds.toString().padStart(5, '0')}" +
" (${world2!!.time.getFormattedTime()})")
}
if (player != null) {
printLineColumn(batch, 2, 6, "Mass $ccG${player.mass}")
@@ -182,10 +191,10 @@ class BasicDebugInfoWindow : UICanvas() {
batch.color = Color.WHITE
if (Terrarum.controller != null) {
if (AppLoader.gamepad != null) {
drawGamepadAxis(batch,
Terrarum.controller!!.getAxisValue(3),
Terrarum.controller!!.getAxisValue(2),
AppLoader.gamepad!!.getAxisValue(3),
AppLoader.gamepad!!.getAxisValue(2),
Terrarum.WIDTH - 135,
40
)
@@ -216,15 +225,18 @@ class BasicDebugInfoWindow : UICanvas() {
* Bottom left
*/
Terrarum.fontSmallNumbers.draw(batch, "${ccY}Actors total $ccG${ingame.actorContainer.size + ingame.actorContainerInactive.size}",
2f, Terrarum.HEIGHT - 10f)
Terrarum.fontSmallNumbers.draw(batch, "${ccY}Active $ccG${ingame.actorContainer.size}",
(2 + 17*8).toFloat(), Terrarum.HEIGHT - 10f)
Terrarum.fontSmallNumbers.draw(batch, "${ccY}Dormant $ccG${ingame.actorContainerInactive.size}",
(2 + 28*8).toFloat(), Terrarum.HEIGHT - 10f)
Terrarum.fontSmallNumbers.draw(batch, "${ccM}Particles $ccG${ingame.particlesActive}",
(2 + 41*8).toFloat(), Terrarum.HEIGHT - 10f)
if (ingame != null) {
Terrarum.fontSmallNumbers.draw(batch, "${ccY}Actors total $ccG${ingame!!.actorContainer.size + ingame!!.actorContainerInactive.size}",
2f, Terrarum.HEIGHT - 10f)
Terrarum.fontSmallNumbers.draw(batch, "${ccY}Active $ccG${ingame!!.actorContainer.size}",
(2 + 17 * 8).toFloat(), Terrarum.HEIGHT - 10f)
Terrarum.fontSmallNumbers.draw(batch, "${ccY}Dormant $ccG${ingame!!.actorContainerInactive.size}",
(2 + 28 * 8).toFloat(), Terrarum.HEIGHT - 10f)
if (ingame is Ingame) {
Terrarum.fontSmallNumbers.draw(batch, "${ccM}Particles $ccG${(ingame as Ingame).particlesActive}",
(2 + 41 * 8).toFloat(), Terrarum.HEIGHT - 10f)
}
}
/**
* Bottom right
@@ -235,8 +247,8 @@ class BasicDebugInfoWindow : UICanvas() {
(Terrarum.WIDTH - 2 - totalHardwareName.length * 8).toFloat(), Terrarum.HEIGHT - 10f)
}
private val processorName = Terrarum.processor.replace(Regex(""" Processor|( CPU)? @ [0-9.]+GHz"""), "")
private val rendererName = Terrarum.renderer
private val processorName = AppLoader.processor.replace(Regex(""" Processor|( CPU)? @ [0-9.]+GHz"""), "")
private val rendererName = AppLoader.renderer
private val totalHardwareName = "$processorName $rendererName"
private fun printLine(batch: SpriteBatch, l: Int, s: String) {
@@ -304,8 +316,8 @@ class BasicDebugInfoWindow : UICanvas() {
val pointDX = axisX * halfW
val pointDY = axisY * halfH
val padName = if (Terrarum.controller!!.name.isEmpty()) "Gamepad"
else Terrarum.controller!!.name
val padName = if (AppLoader.gamepad!!.name.isEmpty()) "Gamepad"
else AppLoader.gamepad!!.name
blendNormal(batch)

View File

@@ -3,6 +3,7 @@ package net.torvald.terrarum.ui
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.Camera
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.utils.Disposable
import net.torvald.terrarum.AppLoader
import net.torvald.terrarum.Second
import net.torvald.terrarum.Terrarum
@@ -21,7 +22,7 @@ abstract class UICanvas(
// UI positions itself? (you must g.flush() yourself after the g.translate(Int, Int))
customPositioning: Boolean = false, // mainly used by vital meter
doNotWarnConstant: Boolean = false
) {
): Disposable {
abstract var width: Int
abstract var height: Int
@@ -36,7 +37,7 @@ abstract class UICanvas(
/**
* Usage: (in StateInGame:) uiHandlerField.ui.handler = uiHandlerField
*/
protected val handler = UIHandler(toggleKeyLiteral, toggleButtonLiteral, customPositioning, doNotWarnConstant)
val handler = UIHandler(toggleKeyLiteral, toggleButtonLiteral, customPositioning, doNotWarnConstant)
init {
@@ -59,12 +60,14 @@ abstract class UICanvas(
get() = Terrarum.mouseScreenY - handler.posY
/** If mouse is hovering over it regardless of its visibility */
val mouseUp: Boolean
get() = relativeMouseX in 0..width - 1 && relativeMouseY in 0..height - 1
open val mouseUp: Boolean
get() = _mouseUpThis || handler.mouseUp
/** If mouse is hovering over it and mouse is down */
val mousePushed: Boolean
get() = mouseUp && Gdx.input.isButtonPressed(AppLoader.getConfigInt("mouseprimary"))
private val _mouseUpThis: Boolean
get() = relativeMouseX in 0..width - 1 && relativeMouseY in 0..height - 1
/** Called by the screen */
fun update(delta: Float) {
@@ -88,6 +91,9 @@ abstract class UICanvas(
*
* Under normal circumstances, draws are automatically translated as per the handler's X/Y position.
* This means, don't write like: ```draw(posX + 4, posY + 32)```, do instead: ```draw(4, 32)``` unless you have a good reason to do so.
*
* The transparency of the handler is independent of the draw, you must specified the color yourself
* using handler.opacity or handler.opacityColour
*/
abstract fun renderUI(batch: SpriteBatch, camera: Camera)
@@ -111,7 +117,7 @@ abstract class UICanvas(
*/
abstract fun endClosing(delta: Float)
abstract fun dispose()
abstract override fun dispose()
fun addItem(uiItem: UIItem) {
uiItems.add(uiItem)
@@ -200,7 +206,7 @@ abstract class UICanvas(
// handler func aliases //
fun setPosition(x: Int, y: Int) {
open fun setPosition(x: Int, y: Int) {
handler.setPosition(x, y)
}
@@ -208,15 +214,15 @@ abstract class UICanvas(
handler.setAsAlwaysVisible()
}
fun setAsOpen() {
open fun setAsOpen() {
handler.setAsOpen()
}
fun setAsClose() {
open fun setAsClose() {
handler.setAsClose()
}
fun toggleOpening() {
open fun toggleOpening() {
handler.toggleOpening()
}
@@ -254,7 +260,7 @@ abstract class UICanvas(
const val OPENCLOSE_GENERIC = 0.2f
fun doOpeningFade(ui: UICanvas, openCloseTime: Second) {
ui.handler.opacity = ui.handler.openCloseCounter / openCloseTime
ui.handler.opacity = maxOf(0f, ui.handler.openCloseCounter - 0.02f) / openCloseTime // fade start 1/50 sec late, it's intended
}
fun doClosingFade(ui: UICanvas, openCloseTime: Second) {
ui.handler.opacity = (openCloseTime - ui.handler.openCloseCounter) / openCloseTime

View File

@@ -3,8 +3,9 @@ package net.torvald.terrarum.ui
import com.badlogic.gdx.graphics.Camera
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.terrarum.modulebasegame.Ingame
import com.badlogic.gdx.utils.Disposable
import net.torvald.terrarum.gamecontroller.KeyToggler
import net.torvald.terrarum.modulebasegame.Ingame
/**
* UIHandler is a handler for UICanvas. It opens/closes the attached UI, moves the "window" (or "canvas")
@@ -20,7 +21,7 @@ class UIHandler(//var UI: UICanvas,
// UI positions itself? (you must g.flush() yourself after the g.translate(Int, Int))
var customPositioning: Boolean = false, // mainly used by vital meter
var doNotWarnConstant: Boolean = false
) {
): Disposable {
// X/Y Position relative to the game window.
var posX: Int = 0
@@ -54,8 +55,14 @@ class UIHandler(//var UI: UICanvas,
var closeFired = false
var opacity = 1f
set(value) {
field = value
opacityColour.set(1f,1f,1f,opacity)
}
var scale = 1f
val opacityColour = Color(1f,1f,1f,opacity)
var openCloseCounter = 0f
init {
@@ -69,6 +76,15 @@ class UIHandler(//var UI: UICanvas,
val subUIs = ArrayList<UICanvas>()
val mouseUp: Boolean
get() {
for (k in 0 until subUIs.size) {
val ret2 = subUIs[k].mouseUp
if (ret2) return true
}
return false
}
fun addSubUI(ui: UICanvas) {
if (subUIs.contains(ui))
throw IllegalArgumentException(
@@ -174,13 +190,18 @@ class UIHandler(//var UI: UICanvas,
ui.renderUI(batch, camera)
//ingameGraphics.flush()
batch.color = Color.WHITE
setCameraPosition(batch, camera, 0f, 0f)
}
subUIs.forEach { it.render(batch, camera) }
subUIs.forEach {
it.render(batch, camera)
batch.color = Color.WHITE
}
}
fun setPosition(x: Int, y: Int) {
@@ -341,4 +362,10 @@ class UIHandler(//var UI: UICanvas,
return false
}
}
/** Don't dispose common assets, this function is called when the ingame does hide() */
override fun dispose() {
toggleKey?.let { KeyToggler.forceSet(it, false) }
toggleButton?.let { /* ButtonToggler.forceSet(it, false) */ }
}
}

Some files were not shown because too many files have changed in this diff Show More