sprite and spriteassembler update

This commit is contained in:
minjaesong
2021-10-03 16:35:25 +09:00
parent abb46f410a
commit ea2525e4df
17 changed files with 181 additions and 128 deletions

View File

@@ -1,37 +1,45 @@
# complete file name is: SPRITESHEET + bodypart name + EXTENSION
SPRITESHEET=mods/basegame/sprites/test_werebeastf/taimu_
EXTENSION=.tga
# defines frame size and origin point. Origin point is given as: (originx, size.y - 1)
# ORIGINY is deduced from the sprite size as shown in above; you only need to set ORIGINX
# defines frame size and origin point. Origin point is given as: (originx, 0)
CONFIG=SIZE 64,98;ORIGINX 40
# note to self: don't implement skeleton hierarchy: there's too many exceptions
# besides, you have "ALL" key.
! a skeleton also defines what body parts (images) be used.
! you can also write multiline text using reverse solidus; this is a feature of .properties
! A skeleton also defines what body parts (images) be used.
! You can also write multiline text using reverse solidus; this is a feature of .properties
! skeleton joints are ordered: foremost-drawn object comes first, which means lowermost object IN THIS LIST
! are painted first, and any object that comes before it will paint over it. In other words, this list is
! first reversed then being iterated.
! Joints' original point is defined in the document sprite_joints.psd. It also has visual representations.
# TODO right now accessory points are explicitly defined. Should they be injected in run-time?
SKELETON_STAND=HEADGEAR 0,32;\
ARM_REST_LEFT -9,49;HELD_ITEM -6,11;\
HEAD 2,83;\
BUST_0 4,60;\
TORSO_0 0,55;\
TORSO_1 0,55;\
LEG_REST_RIGHT -6,22;\
LEG_REST_LEFT 7,22;\
ARM_REST_RIGHT 12,51;\
TAIL_0 -11,27
! Some keywords are considered special within the game, they are:
! HEADGEAR, HELD_ITEM, BOOT_L, BOOT_R, GAUNTLET_L, GAUNTLET_R and ARMOUR_* (star means any number starting from zero)
BODYPARTS=HEADGEAR 13,14;\
HEAD 13,14;\
ARM_REST_RIGHT 5,3;\
ARM_REST_LEFT 6,3;\
LEG_REST_RIGHT 12,6;\
LEG_REST_LEFT 8,6;\
TORSO_0 18,19;\
TORSO_1 18,19;\
TAIL_0 30,2;\
BUST_0 11,2;\
HELD_ITEM 0,0
SKELETON_STAND=HEADGEAR 0,78;\
ARM_REST_RIGHT -15,66;\
HELD_ITEM -11,33;\
HEAD 0,78;\
BUST_0 0,63;\
TORSO_0 0,54;\
TORSO_1 0,54;\
LEG_REST_RIGHT -5,41;\
LEG_REST_LEFT 3,41;\
ARM_REST_LEFT 8,66;\
TAIL_0 2,40
# skeleton_stand is used for testing purpose
ANIM_RUN=DELAY 0.3;ROW 2;SKELETON SKELETON_STAND
ANIM_RUN_1=LEG_REST_RIGHT 2,2;LEG_REST_LEFT -2,0;TAIL_0 1,0
ANIM_RUN_2=ALL 0,2;LEG_REST_RIGHT 0,-2;LEG_REST_LEFT 0,2;TAIL_0 -1,0
ANIM_RUN_3=LEG_REST_RIGHT -2,0;LEG_REST_LEFT 2,2;TAIL_0 -1,0
ANIM_RUN_4=ALL 0,2;LEG_REST_RIGHT 0,2;LEG_REST_LEFT 0,-2;TAIL_0 1,0
ANIM_RUN_1=LEG_REST_RIGHT 2,2;LEG_REST_LEFT -2,0;TAIL_0 1,0;TORSO_1 0,-999
ANIM_RUN_2=ALL 0,2;LEG_REST_RIGHT 0,-2;LEG_REST_LEFT 0,2;TAIL_0 -1,0;TORSO_1 0,-999
ANIM_RUN_3=LEG_REST_RIGHT -2,0;LEG_REST_LEFT 2,2;TAIL_0 -1,0;TORSO_1 0,-999
ANIM_RUN_4=ALL 0,2;LEG_REST_RIGHT 0,2;LEG_REST_LEFT 0,-2;TAIL_0 1,0;TORSO_1 0,-999
ANIM_IDLE=DELAY 2;ROW 1;SKELETON SKELETON_STAND
ANIM_IDLE_1=TORSO_1 0,-999;HEAD 0,-1

View File

@@ -1,37 +1,45 @@
# complete file name is: SPRITESHEET + bodypart name + EXTENSION
SPRITESHEET=mods/basegame/sprites/test_werebeastf/taimuglow_
EXTENSION=.tga
# defines frame size and origin point. Origin point is given as: (originx, size.y - 1)
# ORIGINY is deduced from the sprite size as shown in above; you only need to set ORIGINX
# defines frame size and origin point. Origin point is given as: (originx, 0)
CONFIG=SIZE 64,98;ORIGINX 40
# note to self: don't implement skeleton hierarchy: there's too many exceptions
# besides, you have "ALL" key.
! a skeleton also defines what body parts (images) be used.
! you can also write multiline text using reverse solidus; this is a feature of .properties
! A skeleton also defines what body parts (images) be used.
! You can also write multiline text using reverse solidus; this is a feature of .properties
! skeleton joints are ordered: foremost-drawn object comes first, which means lowermost object IN THIS LIST
! are painted first, and any object that comes before it will paint over it. In other words, this list is
! first reversed then being iterated.
! Joints' original point is defined in the document sprite_joints.psd. It also has visual representations.
# TODO right now accessory points are explicitly defined. Should they be injected in run-time?
SKELETON_STAND=HEADGEAR 0,32;\
ARM_REST_LEFT -8,49;HELD_ITEM -6,11;\
HEAD 2,83;\
BUST_0 4,60;\
TORSO_0 0,55;\
TORSO_1 0,55;\
LEG_REST_RIGHT -5,22;\
LEG_REST_LEFT 6,22;\
ARM_REST_RIGHT 11,51;\
TAIL_0 -11,27
! Some keywords are considered special within the game, they are:
! HEADGEAR, HELD_ITEM, BOOT_L, BOOT_R, GAUNTLET_L, GAUNTLET_R and ARMOUR_* (star means any number starting from zero)
BODYPARTS=HEADGEAR 13,14;\
HEAD 13,14;\
ARM_REST_RIGHT 5,3;\
ARM_REST_LEFT 6,3;\
LEG_REST_RIGHT 12,6;\
LEG_REST_LEFT 8,6;\
TORSO_0 18,19;\
TORSO_1 18,19;\
TAIL_0 30,2;\
BUST_0 11,2;\
HELD_ITEM 0,0
SKELETON_STAND=HEADGEAR 0,78;\
ARM_REST_RIGHT -15,66;\
HELD_ITEM -11,33;\
HEAD 0,78;\
BUST_0 0,63;\
TORSO_0 0,54;\
TORSO_1 0,54;\
LEG_REST_RIGHT -5,41;\
LEG_REST_LEFT 3,41;\
ARM_REST_LEFT 8,66;\
TAIL_0 2,40
# skeleton_stand is used for testing purpose
ANIM_RUN=DELAY 0.3;ROW 2;SKELETON SKELETON_STAND
ANIM_RUN_1=LEG_REST_RIGHT 2,2;LEG_REST_LEFT -2,0;TAIL_0 1,0
ANIM_RUN_2=ALL 0,2;LEG_REST_RIGHT 0,-2;LEG_REST_LEFT 0,2;TAIL_0 -1,0
ANIM_RUN_3=LEG_REST_RIGHT -2,0;LEG_REST_LEFT 2,2;TAIL_0 -1,0
ANIM_RUN_4=ALL 0,2;LEG_REST_RIGHT 0,2;LEG_REST_LEFT 0,-2;TAIL_0 1,0
ANIM_RUN_1=LEG_REST_RIGHT 2,2;LEG_REST_LEFT -2,0;TAIL_0 1,0;TORSO_1 0,-999
ANIM_RUN_2=ALL 0,2;LEG_REST_RIGHT 0,-2;LEG_REST_LEFT 0,2;TAIL_0 -1,0;TORSO_1 0,-999
ANIM_RUN_3=LEG_REST_RIGHT -2,0;LEG_REST_LEFT 2,2;TAIL_0 -1,0;TORSO_1 0,-999
ANIM_RUN_4=ALL 0,2;LEG_REST_RIGHT 0,2;LEG_REST_LEFT 0,-2;TAIL_0 1,0;TORSO_1 0,-999
ANIM_IDLE=DELAY 2;ROW 1;SKELETON SKELETON_STAND
ANIM_IDLE_1=TORSO_1 0,-999;HEAD 0,-1

View File

@@ -1,20 +1,29 @@
# complete file name is: SPRITESHEET + bodypart name + EXTENSION
SPRITESHEET=mods/basegame/sprites/sprite_assembler_test_assets/test_
EXTENSION=.tga
# defines frame size and origin point. Origin point is given as: (originx, size.y - 1)
# ORIGINY is deduced from the sprite size as shown in above; you only need to set ORIGINX
# defines frame size and origin point. Origin point is given as: (originx, 0)
CONFIG=SIZE 48,56;ORIGINX 29
# note to self: don't implement skeleton hierarchy: there's too many exceptions
# besides, you have "ALL" key.
! a skeleton also defines what body parts (images) be used.
! you can also write multiline text using reverse solidus; this is a feature of .properties
! A skeleton also defines what body parts (images) be used.
! You can also write multiline text using reverse solidus; this is a feature of .properties
! skeleton joints are ordered: foremost-drawn object comes first, which means lowermost object IN THIS LIST
! are painted first, and any object that comes before it will paint over it. In other words, this list is
! first reversed then being iterated.
! Joints' original point is defined in the document sprite_joints.psd. It also has visual representations.
# TODO right now accessory points are explicitly defined. Should they be injected in run-time? In that case, certain names (e.g. headgear, held_item) will act as an anchor.
! Some keywords are considered special within the game, they are:
! HEADGEAR, HELD_ITEM, BOOT_L, BOOT_R, GAUNTLET_L, GAUNTLET_R and ARMOUR_* (star means any number starting from zero)
BODYPARTS=ARM_REST_RIGHT 3,8;\
ARM_REST_LEFT 3,8;\
FOOT_LEFT 4,2;\
FOOT_RIGHT 4,2;\
UPPER_TORSO 9,4;\
LOWER_TORSO 7,4;\
LEG_REST_RIGHT 3,7;\
LEG_REST_LEFT 3,7;\
HEAD 8,7;\
HAND_REST_RIGHT 3,3;\
HAND_REST_LEFT 3,3;\
HAIR 20,12;\
HAIR_FORE 20,12
SKELETON_STAND=HEADGEAR 0,32;HAIR_FORE 0,32;\
ARM_REST_RIGHT -7,23;HAND_REST_RIGHT -6,11;HELD_ITEM -6,11;\
HAIR 0,32;HEAD 0,32;\

View File

@@ -1,20 +1,29 @@
# complete file name is: SPRITESHEET + bodypart name + EXTENSION
SPRITESHEET=mods/basegame/sprites/sprite_assembler_test_assets/testglow_
EXTENSION=.tga
# defines frame size and origin point. Origin point is given as: (originx, size.y - 1)
# ORIGINY is deduced from the sprite size as shown in above; you only need to set ORIGINX
# defines frame size and origin point. Origin point is given as: (originx, 0)
CONFIG=SIZE 48,56;ORIGINX 29
# note to self: don't implement skeleton hierarchy: there's too many exceptions
# besides, you have "ALL" key.
! a skeleton also defines what body parts (images) be used.
! you can also write multiline text using reverse solidus; this is a feature of .properties
! A skeleton also defines what body parts (images) be used.
! You can also write multiline text using reverse solidus; this is a feature of .properties
! skeleton joints are ordered: foremost-drawn object comes first, which means lowermost object IN THIS LIST
! are painted first, and any object that comes before it will paint over it. In other words, this list is
! first reversed then being iterated.
! Joints' original point is defined in the document sprite_joints.psd. It also has visual representations.
# TODO right now accessory points are explicitly defined. Should they be injected in run-time? In that case, certain names (e.g. headgear, held_item) will act as an anchor.
! Some keywords are considered special within the game, they are:
! HEADGEAR, HELD_ITEM, BOOT_L, BOOT_R, GAUNTLET_L, GAUNTLET_R and ARMOUR_* (star means any number starting from zero)
BODYPARTS=ARM_REST_RIGHT 3,8;\
ARM_REST_LEFT 3,8;\
FOOT_LEFT 4,2;\
FOOT_RIGHT 4,2;\
UPPER_TORSO 9,4;\
LOWER_TORSO 7,4;\
LEG_REST_RIGHT 3,7;\
LEG_REST_LEFT 3,7;\
HEAD 8,7;\
HAND_REST_RIGHT 3,3;\
HAND_REST_LEFT 3,3;\
HAIR 20,12;\
HAIR_FORE 20,12
SKELETON_STAND=HEADGEAR 0,32;HAIR_FORE 0,32;\
ARM_REST_RIGHT -7,23;HAND_REST_RIGHT -6,11;HELD_ITEM -6,11;\
HAIR 0,32;HEAD 0,32;\

View File

@@ -29,9 +29,9 @@ interface HasAssembledSprite {
* ```
*/
fun reassembleSprite(sprite: SpriteAnimation, spriteGlow: SpriteAnimation? = null) {
_rebuild(ADProperties(Gdx.files.internal(animDescPath).read()), sprite)
_rebuild(ADProperties(Gdx.files.internal(animDescPath)), sprite)
if (animDescPathGlow != null && spriteGlow != null)
_rebuild(ADProperties(Gdx.files.internal(animDescPathGlow).read()), spriteGlow)
_rebuild(ADProperties(Gdx.files.internal(animDescPathGlow)), spriteGlow)
}
/*fun rebuild(animDescPath: String, spriteAnimation: SpriteAnimation) {

View File

@@ -1,11 +1,10 @@
package net.torvald.spriteassembler
import com.badlogic.gdx.files.FileHandle
import net.torvald.terrarum.linearSearchBy
import java.io.InputStream
import java.io.Reader
import java.util.*
import kotlin.collections.HashMap
import kotlin.collections.HashSet
internal data class Joint(val name: String, val position: ADPropertyObject.Vector2i) {
override fun toString() = "$name $position"
@@ -15,6 +14,7 @@ internal data class Skeleton(val name: String, val joints: List<Joint>) {
override fun toString() = "$name=$joints"
}
/**
* @param name You know it
* @param delay Delay between each frame in seconds
@@ -32,22 +32,25 @@ internal data class Transform(val joint: Joint, val translate: ADPropertyObject.
}
class ADProperties {
private var fileFrom = ""
private val javaProp = Properties()
/** Every key is CAPITALISED */
private val propTable = HashMap<String, List<ADPropertyObject>>()
/** list of bodyparts used by all the skeletons (HEAD, UPPER_TORSO, LOWER_TORSO) */
lateinit var bodyparts: List<String>; private set
// lateinit var bodyparts: List<String>; private set
lateinit var bodypartFiles: List<String>; private set
/** properties that are being used as skeletons (SKELETON_STAND) */
internal lateinit var skeletons: HashMap<String, Skeleton>; private set
/** properties that defines position of joint of the bodypart */
internal val bodyparts = HashMap<String, ADPropertyObject.Vector2i>()
/** properties that are recognised as animations (ANIM_RUN, ANIM)IDLE) */
internal lateinit var animations: HashMap<String, Animation>; private set
/** an "animation frame" property (ANIM_RUN_1, ANIM_RUN_2) */
internal lateinit var transforms: HashMap<String, List<Transform>>; private set
private val reservedProps = listOf("SPRITESHEET", "EXTENSION")
private val reservedProps = listOf("SPRITESHEET", "EXTENSION", "CONFIG", "BODYPARTS")
private val animMustContain = listOf("DELAY", "ROW", "SKELETON")
lateinit var baseFilename: String; private set
@@ -55,9 +58,8 @@ class ADProperties {
var frameWidth: Int = -1; private set
var frameHeight: Int = -1; private set
var originX: Int = -1; private set
var originY: Int = -1; private set
internal val origin: ADPropertyObject.Vector2i
get() = ADPropertyObject.Vector2i(originX, originY)
get() = ADPropertyObject.Vector2i(originX, 0)
private val animFrameSuffixRegex = Regex("""_[0-9]+""")
@@ -70,6 +72,12 @@ class ADProperties {
const val ALL_JOINT_SELECT_KEY = "ALL"
}
constructor(gdxFile: FileHandle) {
fileFrom = gdxFile.path()
javaProp.load(gdxFile.read())
continueLoad()
}
constructor(reader: Reader) {
javaProp.load(reader)
continueLoad()
@@ -85,6 +93,16 @@ class ADProperties {
}
private fun continueLoad() {
// sanity check
reservedProps.forEach {
try {
javaProp[it]!!
}
catch (e: NullPointerException) {
throw IllegalArgumentException("Prop '$it' not found from ${fileFrom.ifBlank { "(path unavailable)" }}", e)
}
}
javaProp.keys.forEach { propName ->
val propsStr = javaProp.getProperty(propName as String)
val propsList = propsStr.split(';').map { ADPropertyObject(it) }
@@ -99,11 +117,9 @@ class ADProperties {
frameWidth = frameSizeVec.x
frameHeight = frameSizeVec.y
originX = (get("CONFIG").linearSearchBy { it.name == "ORIGINX" }!!.input as Float).toInt()
originY = frameHeight - 1
var maxColFinder = -1
var maxRowFinder = -1
val bodyparts = HashSet<String>()
val skeletons = HashMap<String, Skeleton>()
val animations = HashMap<String, Animation>()
val animFrames = HashMap<String, Int>()
@@ -153,13 +169,6 @@ class ADProperties {
}
}
// populate the bodyparts using skeletons
skeletons.forEach { (_, prop: Skeleton) ->
prop.joints.forEach {
bodyparts.add(it.name)
}
}
// populate transforms
animations.forEach { t, u ->
for (fc in 1..u.frames) {
@@ -190,17 +199,28 @@ class ADProperties {
}
}
this.bodyparts = bodyparts.toList().sorted()
get("BODYPARTS").forEach {
try {
this.bodyparts[it.name] = (it.input as ADPropertyObject.Vector2i)
}
catch (e: NullPointerException) {
if (it.name.isBlank())
throw IllegalArgumentException("Empty Bodypart name on BODYPARTS; try removing trailing semicolon (';')?")
else
throw IllegalArgumentException("Bodyparts definition for '${it.name}' not found from ${fileFrom.ifBlank { "(path unavailable)" }}", e)
}
}
this.skeletons = skeletons
this.animations = animations
this.bodypartFiles = this.bodyparts.map { toFilename(it) }
this.bodypartFiles = this.bodyparts.keys.map { toFilename(it) }
this.transforms = transforms
cols = maxColFinder
rows = maxRowFinder
}
operator fun get(identifier: String) = propTable[identifier.toUpperCase()]!!
operator fun get(identifier: String): List<ADPropertyObject> = propTable[identifier.toUpperCase()]!!
val keys
get() = propTable.keys
fun containsKey(key: String) = propTable.containsKey(key)
@@ -299,6 +319,8 @@ class ADPropertyObject(propertyRaw: String) {
operator fun minus(other: Vector2i) = Vector2i(this.x - other.x, this.y - other.y)
fun invertY() = Vector2i(this.x, -this.y)
fun invertX() = Vector2i(-this.x, this.y)
fun invertXY() = Vector2i(-this.x, -this.y)
}
enum class ADPropertyType {

View File

@@ -3,7 +3,6 @@ package net.torvald.spriteassembler
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.Pixmap
import net.torvald.terrarum.linearSearch
import java.io.File
/**
* Assembles the single frame of the animation, outputs GDX Pixmap.
@@ -34,19 +33,11 @@ object AssembleSheetPixmap {
val theAnim = properties.getAnimByFrameName(frameName)
val skeleton = theAnim.skeleton.joints.reversed()
val transforms = properties.getTransform(frameName)
val bodyparts = Array<Pixmap?>(skeleton.size) {
// if file does not exist, null it
val file = File("assets/" + properties.toFilename(skeleton[it].name))
//printdbg(this, "Loading file ${file.absolutePath}, exists: ${file.exists()}")
/*return*/if (file.exists()) {
Pixmap(Gdx.files.internal(file.path))
}
else {
null
}
}
val bodypartOrigins = properties.bodyparts
val bodypartImages = properties.bodyparts.keys.map {
val file = Gdx.files.internal("assets/${properties.toFilename(it)}")
it to (if (file.exists()) Pixmap(file) else null)
}.toMap()
val transformList = AssembleFrameBase.makeTransformList(skeleton, transforms)
val animRow = theAnim.row
@@ -54,25 +45,26 @@ object AssembleSheetPixmap {
// AppLoader.printdbg(this, "Frame to draw: $frameName (R$animRow C$animFrame)")
drawFrame(animRow, animFrame, canvas, properties, bodyparts, transformList)
drawFrame(animRow, animFrame, canvas, properties, bodypartOrigins, bodypartImages, transformList)
bodyparts.forEach { it?.dispose() }
bodypartImages.values.forEach { it?.dispose() }
}
private fun drawFrame(row: Int, column: Int,
canvas: Pixmap,
props: ADProperties,
bodyparts: Array<Pixmap?>,
bodypartOrigins: HashMap<String, ADPropertyObject.Vector2i>,
bodypartImages: Map<String, Pixmap?>,
transformList: List<Pair<String, ADPropertyObject.Vector2i>>
) {
val tmpFrame = Pixmap(props.frameWidth, props.frameHeight, Pixmap.Format.RGBA8888)
bodyparts.forEachIndexed { index, image ->
if (image != null) {
val imgCentre = AssembleFrameBase.getCentreOf(image)
val drawPos = transformList[index].second.invertY() + props.origin - imgCentre
transformList.forEach { (name, pos) ->
bodypartImages[name]?.let { image ->
val imgCentre = bodypartOrigins[name]!!.invertX()
val drawPos = props.origin + pos + imgCentre
tmpFrame.drawPixmap(image, drawPos.x, drawPos.y)
tmpFrame.drawPixmap(image, drawPos.x, props.frameHeight - drawPos.y - 1)
}
}

View File

@@ -89,7 +89,9 @@ class SpriteAssemblerApp(val gdxWindow: SpriteAssemblerPreview) : JFrame() {
|GNU General Public License for more details.
|
|You should have received a copy of the GNU General Public License
|along with this program. If not, see <https://www.gnu.org/licenses/>.""".trimMargin()
|along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|Paste your Animation Description here and press 'Update'!""".trimMargin()
panelCode.addMouseListener(object : MouseAdapter() {
override fun mousePressed(e: MouseEvent?) {
if (panelCodeInit) {
@@ -116,14 +118,14 @@ class SpriteAssemblerApp(val gdxWindow: SpriteAssemblerPreview) : JFrame() {
panelProperties.model = DefaultTreeModel(DefaultMutableTreeNode(lang.getProperty("PROPERTIES_GO_HERE")))
val panelDataView = JSplitPane(JSplitPane.VERTICAL_SPLIT, JScrollPane(panelProperties), panelPartsList)
panelDataView.resizeWeight = 0.333
panelDataView.resizeWeight = 0.4
// to disable text wrap
//val panelCodeNoWrap = JPanel(BorderLayout())
//panelCodeNoWrap.add(panelCode)
val panelMain = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, JScrollPane(panelCode), panelDataView)
panelMain.resizeWeight = 0.666
panelMain.resizeWeight = 0.6
val menu = JMenuBar()
menu.add(JMenu("Update")).addMouseListener(object : MouseAdapter() {
@@ -158,8 +160,8 @@ class SpriteAssemblerApp(val gdxWindow: SpriteAssemblerPreview) : JFrame() {
(panelAnimationsList.model as DefaultListModel).addElement("${it.value}")
}
// populate bodyparts view
adProperties.bodyparts.forEach { partName ->
(panelBodypartsList.model as DefaultListModel).addElement(partName)
adProperties.bodyparts.toSortedMap().forEach { part ->
(panelBodypartsList.model as DefaultListModel).addElement("${part.key}: ${part.value}")
}
// populate image file list view
adProperties.bodypartFiles.forEach { partName ->
@@ -177,7 +179,7 @@ class SpriteAssemblerApp(val gdxWindow: SpriteAssemblerPreview) : JFrame() {
(panelStatList.model as DefaultListModel).addElement("Spritesheet rows: ${adProperties.rows}")
(panelStatList.model as DefaultListModel).addElement("Spritesheet columns: ${adProperties.cols}")
(panelStatList.model as DefaultListModel).addElement("Frame size: ${adProperties.frameWidth}, ${adProperties.frameHeight}")
(panelStatList.model as DefaultListModel).addElement("Origin position: ${adProperties.originX}, ${adProperties.originY}")
(panelStatList.model as DefaultListModel).addElement("Origin position: ${adProperties.origin}")
@@ -218,7 +220,7 @@ class SpriteAssemblerApp(val gdxWindow: SpriteAssemblerPreview) : JFrame() {
this.add(statBar, BorderLayout.SOUTH)
this.title = "Terrarum Sprite Assembler and Viewer"
this.isVisible = true
this.setSize(1154, 768)
this.setSize(1120, 768)
this.defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE
}
@@ -317,7 +319,7 @@ class SpriteAssemblerPreview: Game() {
fun main(args: Array<String>) {
val appConfig = Lwjgl3ApplicationConfiguration()
appConfig.setWindowedMode(800, 800)
appConfig.setWindowedMode(1024, 1024)
appConfig.setIdleFPS(5)
appConfig.setForegroundFPS(5)
appConfig.setResizable(false)

View File

@@ -7,6 +7,7 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.EMDASH
import net.torvald.terrarum.*
import net.torvald.terrarum.App.*
import net.torvald.terrarum.Terrarum.PLAYER_REF_ID
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
import net.torvald.terrarum.blockproperties.BlockPropUtil
@@ -293,7 +294,9 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) {
}
catch (e: NullPointerException) {
System.err.println("Could not read the actor ${it} from the disk")
// throw e // TODO don't rethrow -- let players play the corrupted world if it loads, they'll be able to cope with their losses even though there will be buncha lone actorblocks lying around...
e.printStackTrace()
if (it == PLAYER_REF_ID) throw e
// throw e // if not player, don't rethrow -- let players play the corrupted world if it loads, they'll be able to cope with their losses even though there will be buncha lone actorblocks lying around...
}
}

View File

@@ -69,7 +69,7 @@ object ReadActor {
if (actor is ActorWithBody && actor is HasAssembledSprite) {
actor.sprite = SpriteAnimation(actor)
if (actor.animDescPathGlow != null) actor.spriteGlow = SpriteAnimation(actor)
actor.reassembleSprite(actor.sprite!!, actor.spriteGlow)
actor.reassembleSprite(actor.sprite ?: throw InternalError("actor.sprite (type: SpriteAnimation) is null"), actor.spriteGlow)
}
return actor