Now capable of saving and loading stages
This commit is contained in:
parent
8e7937b3c6
commit
07df031670
@ -8,6 +8,8 @@
|
||||
<?import javafx.scene.control.ScrollPane?>
|
||||
<?import javafx.scene.control.SeparatorMenuItem?>
|
||||
<?import javafx.scene.control.SplitPane?>
|
||||
<?import javafx.scene.control.Tab?>
|
||||
<?import javafx.scene.control.TabPane?>
|
||||
<?import javafx.scene.layout.AnchorPane?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
@ -23,12 +25,12 @@
|
||||
<Menu mnemonicParsing="false" text="File">
|
||||
<items>
|
||||
<MenuItem mnemonicParsing="false" text="New" />
|
||||
<MenuItem mnemonicParsing="false" text="Open…" />
|
||||
<MenuItem mnemonicParsing="false" onAction="#open" text="Open…" />
|
||||
<Menu mnemonicParsing="false" text="Open Recent" />
|
||||
<SeparatorMenuItem mnemonicParsing="false" />
|
||||
<MenuItem mnemonicParsing="false" text="Close" />
|
||||
<MenuItem mnemonicParsing="false" text="Save" />
|
||||
<MenuItem mnemonicParsing="false" text="Save As…" />
|
||||
<MenuItem mnemonicParsing="false" onAction="#save" text="Save" />
|
||||
<MenuItem mnemonicParsing="false" onAction="#saveAs" text="Save As…" />
|
||||
<MenuItem mnemonicParsing="false" text="Revert" />
|
||||
<SeparatorMenuItem mnemonicParsing="false" />
|
||||
<MenuItem mnemonicParsing="false" text="Preferences…" />
|
||||
@ -59,11 +61,28 @@
|
||||
</MenuBar>
|
||||
<SplitPane dividerPositions="0.2505567928730512, 0.7505567928730512" focusTraversable="true" prefHeight="-1.0" prefWidth="-1.0" VBox.vgrow="ALWAYS">
|
||||
<items>
|
||||
<AnchorPane>
|
||||
<children>
|
||||
<TilePane fx:id="tileSelector" hgap="2.0" prefHeight="542.0" prefWidth="222.0" vgap="2.0" />
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<TabPane>
|
||||
<tabs>
|
||||
<Tab closable="false" text="A">
|
||||
<content>
|
||||
<AnchorPane>
|
||||
<children>
|
||||
<TilePane fx:id="tileSelector" hgap="2.0" prefColumns="8" vgap="2.0" />
|
||||
</children>
|
||||
</AnchorPane>
|
||||
</content>
|
||||
</Tab>
|
||||
<Tab closable="false" text="B">
|
||||
<content>
|
||||
<AnchorPane>
|
||||
<children>
|
||||
<TilePane fx:id="doodadSelector" hgap="2.0" prefColumns="8" vgap="2.0" />
|
||||
</children>
|
||||
</AnchorPane>
|
||||
</content>
|
||||
</Tab>
|
||||
</tabs>
|
||||
</TabPane>
|
||||
<ScrollPane prefHeight="-1.0" prefWidth="-1.0">
|
||||
<content>
|
||||
<AnchorPane id="Content" minHeight="-1.0" minWidth="-1.0" prefHeight="545.0" prefWidth="430.0">
|
||||
|
@ -1,6 +1,9 @@
|
||||
package fmon.builder
|
||||
|
||||
import java.io._
|
||||
import java.util.prefs.Preferences
|
||||
|
||||
import scala.util.Properties
|
||||
|
||||
import javafx.application.Application
|
||||
import javafx.fxml.FXML
|
||||
@ -17,9 +20,14 @@ import scalafx.scene.image.ImageView
|
||||
import scalafx.scene.input.MouseEvent
|
||||
import scalafx.scene.paint.Color
|
||||
import scalafx.scene.layout._
|
||||
import scalafx.stage.FileChooser
|
||||
import FileChooser.ExtensionFilter
|
||||
|
||||
import fmon._
|
||||
import fmon.draw.Palette
|
||||
import fmon.draw.tile._
|
||||
import fmon.util.Direction
|
||||
import fmon.world._
|
||||
|
||||
import Direction._
|
||||
|
||||
@ -27,24 +35,41 @@ import scala.math.{min, max}
|
||||
|
||||
class MapBuilder {
|
||||
@FXML var tileSelector: jfxsl.TilePane = _
|
||||
@FXML var doodadSelector: jfxsl.TilePane = _
|
||||
@FXML var gameMap: jfxsl.TilePane = _
|
||||
|
||||
var tileSeq: IndexedSeq[AutoFloorTile] = _
|
||||
var imgSeq: IndexedSeq[ImageView] = _
|
||||
|
||||
var currTile: AutoFloorTile = _
|
||||
var tileset: Tileset = _
|
||||
var currTile: AutoTile = _
|
||||
|
||||
val numRows = 10
|
||||
val numCols = 10
|
||||
var level: GameMap = _
|
||||
|
||||
var lastFile: File = _
|
||||
|
||||
def lastDir(): String = {
|
||||
val prefs = Preferences.userNodeForPackage(classOf[MapBuilder])
|
||||
prefs.get("dir", Properties.userDir)
|
||||
}
|
||||
|
||||
def rememberDir(file: File): Unit = {
|
||||
val dir = if (file.isDirectory()) file.getPath else file.getParent
|
||||
if (dir != lastDir) {
|
||||
val prefs = Preferences.userNodeForPackage(classOf[MapBuilder])
|
||||
prefs.put("dir", dir)
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
def initialize(): Unit = {
|
||||
val file = new File(raw"C:\Users\dalyj\Documents\Design\Images\AutoTiles\tilea2.png")
|
||||
val palette = new AutoTilePalette(file, 32)
|
||||
val tiles = for (y <- 0 until 4; x <- 0 until 8) yield {
|
||||
palette(x, y)
|
||||
}
|
||||
val icons = tiles.zipWithIndex.map{case(t, i) => {
|
||||
tileset = new Tileset(new TilesetToken(raw"C:\Users\dalyj\Documents\Design\Images\AutoTiles\tilea2.png"))
|
||||
level = new GameMap(10, 10, tileset)
|
||||
setup()
|
||||
}
|
||||
|
||||
def setup(): Unit = {
|
||||
|
||||
val icons = tileset.groundTiles.map(t => {
|
||||
val view = new ImageView(t.icon.croppedImage())
|
||||
view.handleEvent(MouseEvent.Any) {
|
||||
e: MouseEvent => if (e.eventType == MouseEvent.MouseClicked) {
|
||||
@ -52,33 +77,45 @@ class MapBuilder {
|
||||
}
|
||||
}
|
||||
view.delegate
|
||||
}}
|
||||
})
|
||||
tileSelector.children.clear()
|
||||
tileSelector.children ++= icons
|
||||
currTile = tiles.head
|
||||
currTile = tileset.groundTiles.head
|
||||
|
||||
tileSeq = for (y <- 0 until numRows; x <- 0 until numCols) yield currTile
|
||||
imgSeq = for (y <- 0 until numRows; x <- 0 until numCols) yield {
|
||||
val doodadFile = new File(raw"C:\Users\dalyj\Documents\Design\Images\Icons\equipment-icons-tileset.png")
|
||||
val doodadPalette = Palette.bySize(doodadFile, Config.tileSize, Config.tileSize)
|
||||
|
||||
val doodads = doodadPalette.images.map(d => {
|
||||
val view = new ImageView(d.croppedImage())
|
||||
view.delegate
|
||||
})
|
||||
doodadSelector.children.clear()
|
||||
doodadSelector.children ++= doodads
|
||||
|
||||
imgSeq = for (y <- 0 until level.height; x <- 0 until level.width) yield {
|
||||
val view = new ImageView(currTile.icon.croppedImage()) // TODO Tile with adjacent
|
||||
view.handleEvent(MouseEvent.Any) {
|
||||
e: MouseEvent => if (e.eventType == MouseEvent.MouseClicked) {
|
||||
val index = point2index(x, y)
|
||||
tileSeq = tileSeq.updated(index, currTile)
|
||||
level.tiles = level.tiles.updated(index, currTile)
|
||||
autotile(x, y)
|
||||
}
|
||||
}
|
||||
view
|
||||
}
|
||||
gameMap.prefColumns = numCols
|
||||
gameMap.prefRows = numRows
|
||||
gameMap.children.clear()
|
||||
gameMap.prefColumns = level.width
|
||||
gameMap.prefRows = level.height
|
||||
gameMap.children ++= imgSeq.map(_.delegate)
|
||||
|
||||
for (y <- 0 until numRows; x <- 0 until numCols) {
|
||||
for (y <- 0 until level.height; x <- 0 until level.width) {
|
||||
smoothTile(x, y)
|
||||
}
|
||||
}
|
||||
|
||||
def autotile(x: Int, y: Int) = {
|
||||
for (yy <- max(y - 1, 0) to min(y + 1, numCols - 1); xx <- max(x - 1, 0) to min(x + 1, numRows - 1)) {
|
||||
for (yy <- max(y - 1, 0) to min(y + 1, level.height - 1);
|
||||
xx <- max(x - 1, 0) to min(x + 1, level.width - 1)) {
|
||||
smoothTile(xx, yy)
|
||||
}
|
||||
}
|
||||
@ -88,28 +125,74 @@ class MapBuilder {
|
||||
val dirs = scala.collection.mutable.Set[Direction.Value]()
|
||||
|
||||
val onLeft = x == 0
|
||||
val onRight = x + 1 == numCols
|
||||
val onRight = x + 1 == level.width
|
||||
val onTop = y == 0
|
||||
val onBottom = y + 1 == numRows
|
||||
val onBottom = y + 1 == level.height
|
||||
|
||||
if (onLeft || tileSeq(left(i)) == tileSeq(i)) dirs += West
|
||||
if (onRight || tileSeq(right(i)) == tileSeq(i)) dirs += East
|
||||
if (onTop || tileSeq(up(i)) == tileSeq(i)) dirs += North
|
||||
if (onBottom || tileSeq(down(i)) == tileSeq(i)) dirs += South
|
||||
if (onLeft || onTop || tileSeq(left(up(i))) == tileSeq(i)) dirs += Northwest
|
||||
if (onLeft || onBottom || tileSeq(down(left(i))) == tileSeq(i)) dirs += Southwest
|
||||
if (onTop || onRight || tileSeq(right(up(i))) == tileSeq(i)) dirs += Northeast
|
||||
if (onBottom || onRight || tileSeq(right(down(i))) == tileSeq(i)) dirs += Southeast
|
||||
if (onLeft || level.tiles(left(i)) == level.tiles(i)) dirs += West
|
||||
if (onRight || level.tiles(right(i)) == level.tiles(i)) dirs += East
|
||||
if (onTop || level.tiles(up(i)) == level.tiles(i)) dirs += North
|
||||
if (onBottom || level.tiles(down(i)) == level.tiles(i)) dirs += South
|
||||
if (onLeft || onTop || level.tiles(left(up(i))) == level.tiles(i)) dirs += Northwest
|
||||
if (onLeft || onBottom || level.tiles(down(left(i))) == level.tiles(i)) dirs += Southwest
|
||||
if (onTop || onRight || level.tiles(right(up(i))) == level.tiles(i)) dirs += Northeast
|
||||
if (onBottom || onRight || level.tiles(right(down(i))) == level.tiles(i)) dirs += Southeast
|
||||
val index = point2index(x, y)
|
||||
imgSeq(index).image = tileSeq(index).build(dirs.toSet).croppedImage()
|
||||
imgSeq(index).image = level.tiles(index).build(dirs.toSet).croppedImage()
|
||||
}
|
||||
|
||||
def point2index(x: Int, y: Int) = y * numCols + x
|
||||
def save() = {
|
||||
if (lastFile != null) {
|
||||
level saveTo lastFile
|
||||
} else {
|
||||
saveAs()
|
||||
}
|
||||
}
|
||||
|
||||
def saveAs() = {
|
||||
val fileChooser = new FileChooser {
|
||||
title = "Open Resource File"
|
||||
initialDirectory = new File(lastDir())
|
||||
extensionFilters ++= Seq(
|
||||
new ExtensionFilter("MAP Files", "*.map"),
|
||||
new ExtensionFilter("All Files", "*.*")
|
||||
)
|
||||
}
|
||||
|
||||
val selectedFile = fileChooser.showSaveDialog(null)
|
||||
if (selectedFile != null) {
|
||||
rememberDir(selectedFile)
|
||||
level saveTo selectedFile
|
||||
lastFile = selectedFile
|
||||
}
|
||||
}
|
||||
|
||||
def open() = {
|
||||
val fileChooser = new FileChooser {
|
||||
title = "Open Resource File"
|
||||
initialDirectory = new File(lastDir())
|
||||
extensionFilters ++= Seq(
|
||||
new ExtensionFilter("MAP Files", "*.map"),
|
||||
new ExtensionFilter("All Files", "*.*")
|
||||
)
|
||||
}
|
||||
|
||||
val selectedFile = fileChooser.showOpenDialog(null)
|
||||
if (selectedFile != null) {
|
||||
rememberDir(selectedFile)
|
||||
level = GameMap loadFrom selectedFile
|
||||
tileset = level.tileset
|
||||
setup()
|
||||
lastFile = selectedFile
|
||||
}
|
||||
}
|
||||
|
||||
def point2index(x: Int, y: Int) = level.pt2index(x, y)
|
||||
|
||||
def left(i: Int) = i - 1
|
||||
def right(i: Int) = i + 1
|
||||
def up(i: Int) = i - numCols
|
||||
def down(i: Int) = i + numCols
|
||||
def up(i: Int) = i - level.width
|
||||
def down(i: Int) = i + level.width
|
||||
}
|
||||
|
||||
object MapBuilder {
|
||||
|
@ -9,7 +9,8 @@ case class Config(
|
||||
val resistMult: Double,
|
||||
val weakMult: Double,
|
||||
val immuneMult: Double,
|
||||
val maxBoost: Int
|
||||
val maxBoost: Int,
|
||||
val tileSize: Int
|
||||
) {
|
||||
|
||||
}
|
||||
@ -24,4 +25,5 @@ object Config {
|
||||
def weakMult = config.weakMult
|
||||
def immuneMult = config.immuneMult
|
||||
def maxBoost = config.maxBoost
|
||||
def tileSize = config.tileSize
|
||||
}
|
@ -6,3 +6,4 @@ resistMult: 0.5
|
||||
immuneMult: 0.0
|
||||
maxBoost: 6
|
||||
newday: 02:00
|
||||
tileSize: 32
|
||||
|
@ -1,6 +1,6 @@
|
||||
package fmon.draw
|
||||
|
||||
import java.io.InputStream
|
||||
import java.io._
|
||||
|
||||
import scalafx.geometry.Rectangle2D
|
||||
import scalafx.scene.image._
|
||||
@ -23,6 +23,7 @@ case class StillImg(val image: Image, val x: Double, val y: Double, val width: D
|
||||
class Palette(val image: Image, val numAcross: Int, val numDown: Int) {
|
||||
def this(url: String, numAcross: Int, numDown: Int) = this(new Image(url), numAcross, numDown)
|
||||
def this(stream: InputStream, numAcross: Int, numDown: Int) = this(new Image(stream), numAcross, numDown)
|
||||
def this(file: File, numAcross: Int, numDown: Int) = this(new FileInputStream(file), numAcross, numDown)
|
||||
|
||||
val imgWidth = image.width() / numAcross
|
||||
val imgHeight = image.height() / numDown
|
||||
@ -57,10 +58,14 @@ object Palette {
|
||||
new Palette(img, numAcross, numDown.toInt)
|
||||
}
|
||||
|
||||
def bySize(stream: InputStream, width: Double, height: Double) = {
|
||||
def bySize(stream: InputStream, width: Double, height: Double): Palette = {
|
||||
val img = new Image(stream)
|
||||
val numAcross = img.width() / width
|
||||
val numDown = img.height() / height
|
||||
new Palette(img, numAcross.toInt, numDown.toInt)
|
||||
}
|
||||
|
||||
def bySize(file: File, width: Double, height: Double): Palette = {
|
||||
bySize(new FileInputStream(file), width, height)
|
||||
}
|
||||
}
|
@ -12,7 +12,12 @@ import fmon.util._
|
||||
|
||||
import Direction._
|
||||
|
||||
class AutoFloorTile(val palette: Palette, val size: Int = 48) {
|
||||
trait AutoTile {
|
||||
def icon: StillImg
|
||||
def build(dirs: Set[Direction.Value]): StillImg
|
||||
}
|
||||
|
||||
class AutoFloorTile(val palette: Palette, val size: Int = 48) extends AutoTile {
|
||||
|
||||
def icon: StillImg = palette.apply(0, 0, 2, 2)
|
||||
|
||||
@ -79,7 +84,7 @@ class AutoFloorTile(val palette: Palette, val size: Int = 48) {
|
||||
}
|
||||
}
|
||||
|
||||
class AutoWallTile(val palette: Palette, val size: Int = 48) {
|
||||
class AutoWallTile(val palette: Palette, val size: Int = 48) extends AutoTile {
|
||||
def icon: StillImg = {
|
||||
val canvas = new scalafx.scene.canvas.Canvas(size, size)
|
||||
val g = canvas.graphicsContext2D
|
||||
|
41
FakeMon/src/fmon/world/GameMap.scala
Normal file
41
FakeMon/src/fmon/world/GameMap.scala
Normal file
@ -0,0 +1,41 @@
|
||||
package fmon.world
|
||||
|
||||
import java.io._
|
||||
|
||||
import fmon.draw.tile._
|
||||
import fmon.util._
|
||||
|
||||
class GameMap(val width: Int, val height: Int, val tileset: Tileset) {
|
||||
|
||||
var tiles: IndexedSeq[AutoTile] = for (y <- 0 until height; x <- 0 until width) yield tileset.groundTiles.head
|
||||
|
||||
def saveTo(file: File): Unit = {
|
||||
val ostream = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))
|
||||
ostream.writeInt(width)
|
||||
ostream.writeInt(height)
|
||||
ostream.writeObject(tileset.token.a2)// Tileset
|
||||
val tileIndices = tileset.groundTiles.zipWithIndex.toMap
|
||||
tiles.foreach(t => ostream.writeInt(tileIndices(t)))
|
||||
//ostream.writeObject(tiles.map(tileIndices(_)).mkString(" "))
|
||||
ostream.close()
|
||||
}
|
||||
|
||||
def pt2index(x: Int, y: Int) = y * width + x
|
||||
def index2x(i: Int) = i % width
|
||||
def index2y(i: Int) = i / width
|
||||
}
|
||||
|
||||
object GameMap {
|
||||
def loadFrom(file: File): GameMap = {
|
||||
//val istream = new BufferedReader(new FileReader(file))
|
||||
val istream = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)))
|
||||
val width = istream.readInt()
|
||||
val height = istream.readInt()
|
||||
val tileset = new Tileset(new TilesetToken(istream.readObject().toString))
|
||||
val indices = for (y <- 0 until height; x <- 0 until width) yield istream.readInt()
|
||||
val map = new GameMap(width, height, tileset)
|
||||
val tiles = indices.map(i => tileset.groundTiles(i))
|
||||
map.tiles = tiles
|
||||
map
|
||||
}
|
||||
}
|
18
FakeMon/src/fmon/world/Tileset.scala
Normal file
18
FakeMon/src/fmon/world/Tileset.scala
Normal file
@ -0,0 +1,18 @@
|
||||
package fmon.world
|
||||
|
||||
import java.io._
|
||||
|
||||
import fmon.Config
|
||||
import fmon.draw.tile._
|
||||
|
||||
class Tileset(val token: TilesetToken) {
|
||||
val groundTiles: IndexedSeq[AutoTile] = {
|
||||
val file = new File(token.a2)
|
||||
val palette = new AutoTilePalette(file, Config.tileSize)
|
||||
for (y <- 0 until 4; x <- 0 until 8) yield {
|
||||
palette(x, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class TilesetToken(val a2: String)
|
Loading…
x
Reference in New Issue
Block a user