Compare commits
No commits in common. "07df031670c33f8f4ae2eb8eb4f22ec2907a98a2" and "2474879831af2013baa9bbe73cd42ef7f463814f" have entirely different histories.
07df031670
...
2474879831
@ -1,7 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.ComboBox?>
|
||||
<?import javafx.scene.control.ListView?>
|
||||
<?import javafx.scene.control.ScrollPane?>
|
||||
<?import javafx.scene.image.ImageView?>
|
||||
@ -11,7 +10,7 @@
|
||||
<?import javafx.scene.layout.RowConstraints?>
|
||||
<?import javafx.scene.layout.TilePane?>
|
||||
|
||||
<GridPane xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fmon.builder.AnimationBuilder">
|
||||
<GridPane xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fmon.builder.AnimationBuilder">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="234.0" minWidth="10.0" prefWidth="127.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="308.0" minWidth="10.0" prefWidth="308.0" />
|
||||
@ -24,15 +23,10 @@
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<ListView fx:id="animationList" prefWidth="150.0" />
|
||||
<HBox alignment="CENTER_LEFT" GridPane.rowIndex="1">
|
||||
<children>
|
||||
<Button mnemonicParsing="false" onAction="#addAnimation" text="+" />
|
||||
<Button mnemonicParsing="false" onAction="#quickBuildAnimation" text="Build" />
|
||||
</children>
|
||||
</HBox>
|
||||
<Button mnemonicParsing="false" onAction="#addAnimation" text="+" GridPane.rowIndex="1" />
|
||||
<ImageView fx:id="viewpane" fitHeight="269.0" fitWidth="308.0" pickOnBounds="true" preserveRatio="true" GridPane.columnIndex="1" />
|
||||
<ListView fx:id="frameList" prefWidth="150.0" GridPane.columnIndex="2" />
|
||||
<HBox alignment="CENTER_LEFT" prefHeight="100.0" prefWidth="200.0" GridPane.columnIndex="2" GridPane.rowIndex="1">
|
||||
<HBox prefHeight="100.0" prefWidth="200.0" GridPane.columnIndex="2" GridPane.rowIndex="1">
|
||||
<children>
|
||||
<Button mnemonicParsing="false" onAction="#playAnimation" text="Play" />
|
||||
<Button mnemonicParsing="false" onAction="#addFrame" text="+" />
|
||||
@ -41,9 +35,8 @@
|
||||
</HBox>
|
||||
<ScrollPane GridPane.columnSpan="3" GridPane.rowIndex="2">
|
||||
<content>
|
||||
<TilePane fx:id="tiles" hgap="5.0" vgap="5.0" />
|
||||
<TilePane fx:id="tiles" hgap="5.0" prefHeight="121.0" prefWidth="600.0" vgap="5.0" />
|
||||
</content>
|
||||
</ScrollPane>
|
||||
<ComboBox fx:id="fileChooser" prefWidth="150.0" GridPane.columnIndex="1" GridPane.rowIndex="1" />
|
||||
</children>
|
||||
</GridPane>
|
||||
|
@ -14,118 +14,56 @@ import scalafx.beans.property._
|
||||
import scalafx.collections.ObservableBuffer
|
||||
import scalafx.scene.control._
|
||||
import scalafx.scene.image.ImageView
|
||||
import scalafx.scene.input.MouseEvent
|
||||
import scalafx.scene.paint.Color
|
||||
import scalafx.scene.layout._
|
||||
import scalafx.util.Duration
|
||||
import scalafx.util.StringConverter
|
||||
|
||||
import fmon.draw._
|
||||
import fmon.util.YamlHelper
|
||||
import fmon.draw.Palette
|
||||
|
||||
class ObsAnimation(name_ : String) {
|
||||
val name = new StringProperty(this, "name", name_)
|
||||
val frames = new ObservableBuffer[Frame]()
|
||||
|
||||
def toToken = {
|
||||
val filename = frames(0).file.getName
|
||||
val indices = frames.map(_.index).toIndexedSeq
|
||||
AnimationToken(filename, indices)
|
||||
}
|
||||
val frames = new ObservableBuffer[FrameToken]()
|
||||
|
||||
override def toString = name()
|
||||
}
|
||||
|
||||
class Frame(val img: StillImg, val file: File, val index: Int) {
|
||||
def toToken = ImageToken(file.getName, index)
|
||||
|
||||
override def toString = s"${file.getName} ${index}"
|
||||
}
|
||||
|
||||
|
||||
|
||||
case class ImageToken(val filename: String, val index: Int) {
|
||||
def toFrame(dir: File) = {
|
||||
val file = new File(s"${dir.getPath}/$filename")
|
||||
val pal = Palette.square(new FileInputStream(file), 5).images(5)
|
||||
}
|
||||
override def toString = s"${filename} ${index}"
|
||||
case class FrameToken() {
|
||||
}
|
||||
|
||||
class AnimationBuilder extends Savable {
|
||||
@FXML var animationList: jfxsc.ListView[ObsAnimation] = _
|
||||
@FXML var frameList: jfxsc.ListView[Frame] = _
|
||||
@FXML var frameList: jfxsc.ListView[FrameToken] = _
|
||||
@FXML var viewpane: javafx.scene.image.ImageView = _
|
||||
@FXML var tiles: javafx.scene.layout.TilePane = _
|
||||
@FXML var fileChooser: jfxsc.ComboBox[File] = _
|
||||
|
||||
val animations = ObservableBuffer[ObsAnimation]()
|
||||
val imgFiles = ObservableBuffer[File]()
|
||||
|
||||
val imgdir = raw"C:\Users\dalyj\Documents\Design\Images\TimmahLexusX reduced\Reduced Animations"
|
||||
|
||||
@FXML
|
||||
def initialize(): Unit = {
|
||||
fileChooser.items = imgFiles
|
||||
fileChooser.selectionModel().selectedIndex.onChange(selectImageFile)
|
||||
|
||||
fileChooser.converter = new StringConverter[File] {
|
||||
override def toString(f: File) = f.getName
|
||||
override def fromString(s: String) = new File(s)
|
||||
}
|
||||
val dir = new File(imgdir)
|
||||
imgFiles ++= dir.listFiles()
|
||||
|
||||
animationList.items = animations
|
||||
animationList.selectionModel().selectedIndex.onChange(selectionChange)
|
||||
frameList.selectionModel().selectedIndex.onChange(selectFrame)
|
||||
val palette = new Palette(new FileInputStream(raw"C:\Users\James\Documents\Design\Images\TimmahLexusX\Standalone Animations\Fireball.png"), 5, 3)
|
||||
//for (x <- 0 until palette.numAcross; y <- 0 until palette.numDown) {
|
||||
|
||||
//addAnimation()
|
||||
animationList.selectionModel().selectFirst()
|
||||
fileChooser.selectionModel().selectFirst()
|
||||
}
|
||||
|
||||
def currFile = fileChooser.selectionModel().getSelectedItem
|
||||
def palette = Palette.square(new FileInputStream(currFile), 5)
|
||||
|
||||
def selectImageFile(): Unit = {
|
||||
val images = palette.images
|
||||
val children = images.zipWithIndex.map{case (img, i) => {
|
||||
val children = for (y <- 0 until palette.numDown; x <- 0 until palette.numAcross) yield {
|
||||
val img = palette(x, y)
|
||||
val imgView = new ImageView() {
|
||||
scaleX = 0.5
|
||||
scaleY = 0.5
|
||||
image = img.croppedImage()
|
||||
|
||||
}
|
||||
imgView.handleEvent(MouseEvent.Any) {
|
||||
e: MouseEvent => if (e.clickCount == 2 && e.eventType == MouseEvent.MouseClicked) {
|
||||
addFrame(img, i)
|
||||
}
|
||||
}
|
||||
imgView.delegate
|
||||
}}
|
||||
tiles.children.clear()
|
||||
//imgView.autosize()
|
||||
//println(imgView.getBoundsInParent)
|
||||
//img.draw(imgView)
|
||||
//imgView.resize(100, 100)
|
||||
}
|
||||
|
||||
tiles.children ++= children
|
||||
tiles.prefTileWidth = 96 // TODO : I think this has to do with how the image is scaled
|
||||
tiles.prefTileHeight = 96
|
||||
}
|
||||
|
||||
def addAnimation(): Unit = {
|
||||
addAnimation("Animation")
|
||||
}
|
||||
|
||||
def addAnimation(name: String): Unit = {
|
||||
animations += new ObsAnimation(name)
|
||||
animationList.selectionModel().selectLast()
|
||||
}
|
||||
|
||||
def quickBuildAnimation(): Unit = {
|
||||
val filename = currFile.getName
|
||||
val name = filename.split('.')(0)
|
||||
animations += new ObsAnimation(name)
|
||||
animationList.selectionModel().selectLast()
|
||||
palette.images.zipWithIndex.foreach{case (img, i) => addFrame(img, i)}
|
||||
animations += new ObsAnimation("Animation")
|
||||
}
|
||||
|
||||
def selectionChange(): Unit = {
|
||||
@ -133,43 +71,24 @@ class AnimationBuilder extends Savable {
|
||||
}
|
||||
|
||||
def playAnimation(): Unit = {
|
||||
val images = frameList.items().map(f => f.img).toIndexedSeq
|
||||
val animated = new AnimatedImage(images)
|
||||
val duration = new Duration(50 * images.size)
|
||||
val animator = new SpriteAnimation(viewpane, animated, duration)
|
||||
animator.play()
|
||||
|
||||
}
|
||||
|
||||
def addFrame(): Unit = {
|
||||
//println("New frame")
|
||||
//selected.frames += new FrameToken
|
||||
}
|
||||
|
||||
def addFrame(img: StillImg, index: Int): Unit = {
|
||||
selected.frames += new Frame(img, currFile, index)
|
||||
println("New frame")
|
||||
selected.frames += new FrameToken
|
||||
}
|
||||
|
||||
def removeFrame(): Unit = {
|
||||
frameList.items() --= frameList.selectionModel().getSelectedItems
|
||||
}
|
||||
|
||||
def selectFrame(): Unit = {
|
||||
val frame = frameList.selectionModel().getSelectedItem
|
||||
frame.img.draw(viewpane, 0)
|
||||
}
|
||||
|
||||
override def saveTo(file: File): Unit = {
|
||||
val aniMap = animations.map(a => (a.name(), a.toToken)).toMap
|
||||
YamlHelper.writeMap(new FileOutputStream(file), aniMap)
|
||||
|
||||
}
|
||||
|
||||
override def openFrom(file: File): Unit = {
|
||||
val aniMap = YamlHelper.extractMap[AnimationToken](new FileInputStream(file))
|
||||
aniMap.foreach{case (name, token) => {
|
||||
addAnimation(name)
|
||||
val frames = AnimationBuilder.toFrames(token, new File(imgdir))
|
||||
animationList.selectionModel().getSelectedItem.frames ++= frames
|
||||
}}
|
||||
|
||||
}
|
||||
|
||||
private def selected: ObsAnimation = {
|
||||
@ -200,11 +119,4 @@ object AnimationBuilder {
|
||||
def main(args: Array[String]): Unit = {
|
||||
Application.launch(classOf[ABA], args: _*)
|
||||
}
|
||||
|
||||
def toFrames(token: AnimationToken, dir: File) = {
|
||||
val file = new File(s"${dir.getPath}/${token.filename}")
|
||||
val palette = Palette.square(new FileInputStream(file), 5)
|
||||
val images = palette.images
|
||||
token.indices.map(i => new Frame(images(i), file, i))
|
||||
}
|
||||
}
|
@ -1,126 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.Menu?>
|
||||
<?import javafx.scene.control.MenuBar?>
|
||||
<?import javafx.scene.control.MenuItem?>
|
||||
<?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?>
|
||||
<?import javafx.scene.layout.TilePane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.paint.Color?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
|
||||
<VBox prefHeight="600.0" prefWidth="900.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fmon.builder.MapBuilder">
|
||||
<children>
|
||||
<MenuBar VBox.vgrow="NEVER">
|
||||
<menus>
|
||||
<Menu mnemonicParsing="false" text="File">
|
||||
<items>
|
||||
<MenuItem mnemonicParsing="false" text="New" />
|
||||
<MenuItem mnemonicParsing="false" onAction="#open" text="Open…" />
|
||||
<Menu mnemonicParsing="false" text="Open Recent" />
|
||||
<SeparatorMenuItem mnemonicParsing="false" />
|
||||
<MenuItem mnemonicParsing="false" text="Close" />
|
||||
<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…" />
|
||||
<SeparatorMenuItem mnemonicParsing="false" />
|
||||
<MenuItem mnemonicParsing="false" text="Quit" />
|
||||
</items>
|
||||
</Menu>
|
||||
<Menu mnemonicParsing="false" text="Edit">
|
||||
<items>
|
||||
<MenuItem mnemonicParsing="false" text="Undo" />
|
||||
<MenuItem mnemonicParsing="false" text="Redo" />
|
||||
<SeparatorMenuItem mnemonicParsing="false" />
|
||||
<MenuItem mnemonicParsing="false" text="Cut" />
|
||||
<MenuItem mnemonicParsing="false" text="Copy" />
|
||||
<MenuItem mnemonicParsing="false" text="Paste" />
|
||||
<MenuItem mnemonicParsing="false" text="Delete" />
|
||||
<SeparatorMenuItem mnemonicParsing="false" />
|
||||
<MenuItem mnemonicParsing="false" text="Select All" />
|
||||
<MenuItem mnemonicParsing="false" text="Unselect All" />
|
||||
</items>
|
||||
</Menu>
|
||||
<Menu mnemonicParsing="false" text="Help">
|
||||
<items>
|
||||
<MenuItem mnemonicParsing="false" text="About MyHelloApp" />
|
||||
</items>
|
||||
</Menu>
|
||||
</menus>
|
||||
</MenuBar>
|
||||
<SplitPane dividerPositions="0.2505567928730512, 0.7505567928730512" focusTraversable="true" prefHeight="-1.0" prefWidth="-1.0" VBox.vgrow="ALWAYS">
|
||||
<items>
|
||||
<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">
|
||||
<children>
|
||||
<TilePane fx:id="gameMap" hgap="1.0" layoutX="14.0" layoutY="28.0" prefColumns="10" prefRows="10" vgap="1.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
||||
</children>
|
||||
</AnchorPane>
|
||||
</content>
|
||||
</ScrollPane>
|
||||
<AnchorPane>
|
||||
<children>
|
||||
<Label alignment="CENTER" layoutX="14.0" layoutY="14.0" style=" " text="Details" textAlignment="CENTER" wrapText="false">
|
||||
<font>
|
||||
<Font size="18.0" fx:id="x1" />
|
||||
</font>
|
||||
<textFill>
|
||||
<Color blue="0.624" green="0.624" red="0.624" fx:id="x2" />
|
||||
</textFill></Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
</items>
|
||||
</SplitPane>
|
||||
<HBox id="HBox" alignment="CENTER_LEFT" spacing="5.0" VBox.vgrow="NEVER">
|
||||
<children>
|
||||
<Label maxHeight="1.7976931348623157E308" maxWidth="-1.0" text="Left status" HBox.hgrow="ALWAYS">
|
||||
<font>
|
||||
<Font size="11.0" fx:id="x3" />
|
||||
</font>
|
||||
<textFill>
|
||||
<Color blue="0.625" green="0.625" red="0.625" fx:id="x4" />
|
||||
</textFill>
|
||||
</Label>
|
||||
<Pane prefHeight="-1.0" prefWidth="-1.0" HBox.hgrow="ALWAYS" />
|
||||
<Label font="$x3" maxWidth="-1.0" text="Right status" textFill="$x4" HBox.hgrow="NEVER" />
|
||||
</children>
|
||||
<padding>
|
||||
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
|
||||
</padding>
|
||||
</HBox>
|
||||
</children>
|
||||
</VBox>
|
@ -1,221 +0,0 @@
|
||||
package fmon.builder
|
||||
|
||||
import java.io._
|
||||
import java.util.prefs.Preferences
|
||||
|
||||
import scala.util.Properties
|
||||
|
||||
import javafx.application.Application
|
||||
import javafx.fxml.FXML
|
||||
import javafx.fxml.FXMLLoader
|
||||
import javafx.fxml.JavaFXBuilderFactory
|
||||
import javafx.scene.{control => jfxsc, layout => jfxsl, Parent, Scene}
|
||||
import javafx.stage.Stage
|
||||
|
||||
import scalafx.Includes._
|
||||
import scalafx.beans.property._
|
||||
import scalafx.collections.ObservableBuffer
|
||||
import scalafx.scene.control._
|
||||
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._
|
||||
|
||||
import scala.math.{min, max}
|
||||
|
||||
class MapBuilder {
|
||||
@FXML var tileSelector: jfxsl.TilePane = _
|
||||
@FXML var doodadSelector: jfxsl.TilePane = _
|
||||
@FXML var gameMap: jfxsl.TilePane = _
|
||||
|
||||
var imgSeq: IndexedSeq[ImageView] = _
|
||||
|
||||
var tileset: Tileset = _
|
||||
var currTile: AutoTile = _
|
||||
|
||||
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 = {
|
||||
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) {
|
||||
currTile = t
|
||||
}
|
||||
}
|
||||
view.delegate
|
||||
})
|
||||
tileSelector.children.clear()
|
||||
tileSelector.children ++= icons
|
||||
currTile = tileset.groundTiles.head
|
||||
|
||||
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)
|
||||
level.tiles = level.tiles.updated(index, currTile)
|
||||
autotile(x, y)
|
||||
}
|
||||
}
|
||||
view
|
||||
}
|
||||
gameMap.children.clear()
|
||||
gameMap.prefColumns = level.width
|
||||
gameMap.prefRows = level.height
|
||||
gameMap.children ++= imgSeq.map(_.delegate)
|
||||
|
||||
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, level.height - 1);
|
||||
xx <- max(x - 1, 0) to min(x + 1, level.width - 1)) {
|
||||
smoothTile(xx, yy)
|
||||
}
|
||||
}
|
||||
|
||||
def smoothTile(x: Int, y: Int) = {
|
||||
val i = point2index(x, y)
|
||||
val dirs = scala.collection.mutable.Set[Direction.Value]()
|
||||
|
||||
val onLeft = x == 0
|
||||
val onRight = x + 1 == level.width
|
||||
val onTop = y == 0
|
||||
val onBottom = y + 1 == level.height
|
||||
|
||||
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 = level.tiles(index).build(dirs.toSet).croppedImage()
|
||||
}
|
||||
|
||||
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 - level.width
|
||||
def down(i: Int) = i + level.width
|
||||
}
|
||||
|
||||
object MapBuilder {
|
||||
class MBA extends Application {
|
||||
override def start(primaryStage: Stage): Unit = {
|
||||
val frameLoader = new FXMLLoader(getClass.getResource("MapBuilder.fxml"))
|
||||
val root: Parent = frameLoader.load()
|
||||
val controller = frameLoader.getController[MapBuilder]()
|
||||
|
||||
//val builderLoader = new FXMLLoader(getClass.getResource("ElementBuilder.fxml"))
|
||||
//val builder: Parent = builderLoader.load()
|
||||
//val builderController = builderLoader.getController[ElementBuilder]()
|
||||
|
||||
//controller.pane.children = builder
|
||||
//controller.builder = builderController
|
||||
|
||||
val scene: Scene = new Scene(root)
|
||||
primaryStage.setScene(scene)
|
||||
primaryStage.show()
|
||||
}
|
||||
}
|
||||
|
||||
def main(args: Array[String]): Unit = {
|
||||
Application.launch(classOf[MBA], args: _*)
|
||||
}
|
||||
}
|
@ -9,8 +9,7 @@ case class Config(
|
||||
val resistMult: Double,
|
||||
val weakMult: Double,
|
||||
val immuneMult: Double,
|
||||
val maxBoost: Int,
|
||||
val tileSize: Int
|
||||
val maxBoost: Int
|
||||
) {
|
||||
|
||||
}
|
||||
@ -25,5 +24,4 @@ object Config {
|
||||
def weakMult = config.weakMult
|
||||
def immuneMult = config.immuneMult
|
||||
def maxBoost = config.maxBoost
|
||||
def tileSize = config.tileSize
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
package fmon.battle
|
||||
|
||||
import java.io._
|
||||
import java.util.concurrent.locks.{Condition, ReentrantLock}
|
||||
|
||||
import javafx.application.Platform
|
||||
@ -24,7 +23,6 @@ import scalafx.scene.transform.Rotate
|
||||
import scalafx.util.Duration
|
||||
|
||||
import fmon.battle.msg._
|
||||
import fmon.draw._
|
||||
import fmon.stat._
|
||||
import fmon.stat.Statistic._
|
||||
|
||||
@ -80,7 +78,6 @@ class BattleUI extends SignalConsumer {
|
||||
lock.lock()
|
||||
try {
|
||||
msg match {
|
||||
case AnimateMsg(ani, target) => playAnimation(ani, target)
|
||||
case Message(text) => messages.text = s"${messages.text()}${text}\n"
|
||||
case DamageMsg(dmg, target, element) => playDamage(dmg, target, element)
|
||||
}
|
||||
@ -96,29 +93,6 @@ class BattleUI extends SignalConsumer {
|
||||
|
||||
}
|
||||
|
||||
private def playAnimation(aniname: String, target: Monster): Unit = {
|
||||
numPlaying += 1
|
||||
def helper = {
|
||||
val animation = AnimationToken(aniname).load(new File(raw"C:\Users\dalyj\Documents\Design\Images\TimmahLexusX reduced\Reduced Animations"))
|
||||
val imgView = new ImageView
|
||||
animationPane.children += imgView
|
||||
|
||||
val center = findCenter(target)
|
||||
imgView.translateX = center.x - 96 // TODO : Compute result
|
||||
imgView.translateY = center.y - 96
|
||||
|
||||
val duration = Duration(animation.frames.size * 50)
|
||||
val transition = new SpriteAnimation(imgView, animation, duration)
|
||||
transition.onFinished = handle{
|
||||
animationPane.children -= imgView
|
||||
finishPlay()
|
||||
}
|
||||
transition.play()
|
||||
}
|
||||
val task = Task(helper)
|
||||
Platform.runLater(task)
|
||||
}
|
||||
|
||||
private def playDamage(damage: Int, target: Monster, element: Element): Unit = {
|
||||
numPlaying += 1
|
||||
def helper = {
|
||||
|
@ -1,25 +0,0 @@
|
||||
package fmon.battle.msg
|
||||
|
||||
import fmon.stat.{Element, Monster}
|
||||
|
||||
case class AnimateMsg(val animation: String, target: Monster) extends Signal {
|
||||
|
||||
}
|
||||
|
||||
object AnimateMsg {
|
||||
def apply(element: Element, target: Monster): AnimateMsg = {
|
||||
val ani = element.name match {
|
||||
case "Poison" => "Poison Bubble"
|
||||
case "Electric" => "Lightning Lines"
|
||||
case "Fire" => "Rising Fire 1"
|
||||
case "Rock" => "Rock Blast"
|
||||
case "Ground" => "Stalagmites"
|
||||
case "Water" => "Rain"
|
||||
case "Flying" => "Gale"
|
||||
case "Ice" => "Glacier"
|
||||
case "Fairy" => "Light and Glass"
|
||||
case _ => "Buster"
|
||||
}
|
||||
AnimateMsg(ani, target)
|
||||
}
|
||||
}
|
@ -6,4 +6,3 @@ resistMult: 0.5
|
||||
immuneMult: 0.0
|
||||
maxBoost: 6
|
||||
newday: 02:00
|
||||
tileSize: 32
|
||||
|
@ -1,7 +1,5 @@
|
||||
package fmon.draw
|
||||
|
||||
import java.io.{File, FileInputStream}
|
||||
|
||||
import javafx.animation.{Transition => JTransition}
|
||||
|
||||
import scalafx.Includes._
|
||||
@ -9,8 +7,6 @@ import scalafx.animation._
|
||||
import scalafx.scene.image.ImageView
|
||||
import scalafx.util.Duration
|
||||
|
||||
import fmon.util.YamlHelper
|
||||
|
||||
class SpriteAnimation(val view: ImageView, val image: Drawable, val duration: Duration) extends JTransition {
|
||||
setCycleDuration(duration)
|
||||
setInterpolator(Interpolator.Linear)
|
||||
@ -28,20 +24,4 @@ class AnimatedImage(val frames: IndexedSeq[Drawable]) extends Drawable {
|
||||
val index = Math.min((frames.size * t).toInt, frames.size - 1)
|
||||
frames(index).draw(view, t)
|
||||
}
|
||||
}
|
||||
|
||||
case class AnimationToken(val filename: String, val indices: IndexedSeq[Int]) {
|
||||
def load(dir: File) = {
|
||||
val file = new File(s"${dir.getPath}/${filename}")
|
||||
val palette = Palette.square(new FileInputStream(file), 5)
|
||||
val images = palette.images
|
||||
val frames = indices.map(i => images(i))
|
||||
new AnimatedImage(frames)
|
||||
}
|
||||
}
|
||||
|
||||
object AnimationToken {
|
||||
val tokens = YamlHelper.extractMap[AnimationToken](new FileInputStream(raw"C:\Users\dalyj\Documents\Design\animations.yaml"))
|
||||
|
||||
def apply(name: String) = tokens(name)
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package fmon.draw
|
||||
|
||||
import java.io._
|
||||
import java.io.InputStream
|
||||
|
||||
import scalafx.geometry.Rectangle2D
|
||||
import scalafx.scene.image._
|
||||
@ -23,7 +23,6 @@ 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
|
||||
@ -42,30 +41,4 @@ class Palette(val image: Image, val numAcross: Int, val numDown: Int) {
|
||||
def apply(cells : Box): StillImg = {
|
||||
this(cells.x, cells.y, cells.width, cells.height)
|
||||
}
|
||||
|
||||
def images = {
|
||||
for (y <- 0 until numDown; x <- 0 until numAcross) yield {
|
||||
this(x, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object Palette {
|
||||
def square(stream: InputStream, numAcross: Int) = {
|
||||
val img = new Image(stream)
|
||||
val size = img.width() / numAcross
|
||||
val numDown = img.height() / size
|
||||
new Palette(img, numAcross, numDown.toInt)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
@ -1,216 +0,0 @@
|
||||
package fmon.draw.tile
|
||||
|
||||
import java.io.{File, FileInputStream}
|
||||
|
||||
import scalafx.scene.SnapshotParameters
|
||||
import scalafx.scene.canvas.Canvas
|
||||
import scalafx.scene.image._
|
||||
import scalafx.scene.paint.Color
|
||||
|
||||
import fmon.draw._
|
||||
import fmon.util._
|
||||
|
||||
import Direction._
|
||||
|
||||
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)
|
||||
|
||||
def build(dirs: Set[Direction.Value]) = {
|
||||
val canvas = new scalafx.scene.canvas.Canvas(size, size)
|
||||
val g = canvas.graphicsContext2D
|
||||
|
||||
val ne = getNE(dirs)
|
||||
val nw = getNW(dirs)
|
||||
val se = getSE(dirs)
|
||||
val sw = getSW(dirs)
|
||||
|
||||
canvas.graphicsContext2D.drawImage(nw, 0, 0)
|
||||
canvas.graphicsContext2D.drawImage(ne, size / 2, 0)
|
||||
canvas.graphicsContext2D.drawImage(sw, 0, size / 2)
|
||||
canvas.graphicsContext2D.drawImage(se, size / 2, size / 2)
|
||||
|
||||
val wi = new WritableImage(size, size)
|
||||
val parameters = new SnapshotParameters(){
|
||||
fill = Color.Transparent
|
||||
}
|
||||
val img = canvas.snapshot(parameters, wi)
|
||||
StillImg(img, 0, 0, size, size)
|
||||
}
|
||||
|
||||
private def getNE(dirs: Set[Direction.Value]): Image = {
|
||||
if (!dirs(Northeast) && dirs(North) && dirs(East)) {
|
||||
palette(3, 0).croppedImage()
|
||||
} else {
|
||||
val x = if (dirs(East)) 1 else 3
|
||||
val y = if (dirs(North)) 4 else 2
|
||||
palette(x, y).croppedImage
|
||||
}
|
||||
}
|
||||
|
||||
private def getNW(dirs: Set[Direction.Value]): Image = {
|
||||
if (!dirs(Northwest) && dirs(North) && dirs(West)) {
|
||||
palette(2, 0).croppedImage()
|
||||
} else {
|
||||
val x = if (dirs(West)) 2 else 0
|
||||
val y = if (dirs(North)) 4 else 2
|
||||
palette(x, y).croppedImage
|
||||
}
|
||||
}
|
||||
|
||||
private def getSE(dirs: Set[Direction.Value]): Image = {
|
||||
if (!dirs(Southeast) && dirs(South) && dirs(East)) {
|
||||
palette(3, 1).croppedImage()
|
||||
} else {
|
||||
val x = if (dirs(East)) 1 else 3
|
||||
val y = if (dirs(South)) 3 else 5
|
||||
palette(x, y).croppedImage
|
||||
}
|
||||
}
|
||||
|
||||
private def getSW(dirs: Set[Direction.Value]): Image = {
|
||||
if (!dirs(Southwest) && dirs(South) && dirs(West)) {
|
||||
palette(2, 1).croppedImage()
|
||||
} else {
|
||||
val x = if (dirs(West)) 2 else 0
|
||||
val y = if (dirs(South)) 3 else 5
|
||||
palette(x, y).croppedImage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
val ul = palette.apply(0, 0)
|
||||
val ur = palette.apply(3, 0)
|
||||
val ll = palette.apply(0, 3)
|
||||
val lr = palette.apply(3, 3)
|
||||
|
||||
canvas.graphicsContext2D.drawImage(ul.croppedImage(), 0, 0)
|
||||
canvas.graphicsContext2D.drawImage(ur.croppedImage(), size / 2, 0)
|
||||
canvas.graphicsContext2D.drawImage(ll.croppedImage(), 0, size / 2)
|
||||
canvas.graphicsContext2D.drawImage(lr.croppedImage(), size / 2, size / 2)
|
||||
|
||||
val wi = new WritableImage(size, size)
|
||||
val parameters = new SnapshotParameters(){
|
||||
fill = Color.Transparent
|
||||
}
|
||||
val img = canvas.snapshot(parameters, wi)
|
||||
StillImg(img, 0, 0, size, size)
|
||||
}
|
||||
|
||||
def build(dirs: Set[Direction.Value]) = {
|
||||
val canvas = new scalafx.scene.canvas.Canvas(size, size)
|
||||
val g = canvas.graphicsContext2D
|
||||
|
||||
val ul = buildUL(dirs)
|
||||
val ur = buildUR(dirs)
|
||||
val ll = buildLL(dirs)
|
||||
val lr = buildLR(dirs)
|
||||
|
||||
canvas.graphicsContext2D.drawImage(ul.croppedImage(), 0, 0)
|
||||
canvas.graphicsContext2D.drawImage(ur.croppedImage(), size / 2, 0)
|
||||
canvas.graphicsContext2D.drawImage(ll.croppedImage(), 0, size / 2)
|
||||
canvas.graphicsContext2D.drawImage(lr.croppedImage(), size / 2, size / 2)
|
||||
|
||||
val wi = new WritableImage(size, size)
|
||||
val parameters = new SnapshotParameters(){
|
||||
fill = Color.Transparent
|
||||
}
|
||||
val img = canvas.snapshot(parameters, wi)
|
||||
StillImg(img, 0, 0, size, size)
|
||||
}
|
||||
|
||||
private def buildUL(dirs: Set[Direction.Value]) = {
|
||||
val x = if (dirs(West)) 2 else 0
|
||||
val y = if (dirs(North)) 2 else 0
|
||||
palette(x, y)
|
||||
}
|
||||
|
||||
private def buildUR(dirs: Set[Direction.Value]) = {
|
||||
val x = if (dirs(East)) 1 else 3
|
||||
val y = if (dirs(North)) 2 else 0
|
||||
palette(x, y)
|
||||
}
|
||||
|
||||
private def buildLL(dirs: Set[Direction.Value]) = {
|
||||
val x = if (dirs(West)) 2 else 0
|
||||
val y = if (dirs(South)) 1 else 3
|
||||
palette(x, y)
|
||||
}
|
||||
|
||||
private def buildLR(dirs: Set[Direction.Value]) = {
|
||||
val x = if (dirs(East)) 1 else 3
|
||||
val y = if (dirs(South)) 1 else 3
|
||||
palette(x, y)
|
||||
}
|
||||
}
|
||||
|
||||
class AutoTilePalette(val palette: Palette, val size: Int) {
|
||||
def this(file: File, size: Int = 48) = this(Palette.bySize(new FileInputStream(file), size, size), size)
|
||||
|
||||
def apply(x: Int, y: Int) = {
|
||||
val img = palette.apply(x * 2, y * 3, 2, 3).croppedImage()
|
||||
new AutoFloorTile(new Palette(img, 4, 6), size)
|
||||
}
|
||||
}
|
||||
|
||||
import scalafx.Includes._
|
||||
import scalafx.application.JFXApp
|
||||
import scalafx.scene._
|
||||
import scalafx.scene.image.ImageView
|
||||
import scalafx.scene.layout.TilePane
|
||||
import scalafx.scene.paint.Color
|
||||
|
||||
import Color._
|
||||
|
||||
object AutoTileDemo extends JFXApp {
|
||||
final val MaxX = 3
|
||||
final val MaxY = 3
|
||||
|
||||
val file = raw"C:\Users\dalyj\Documents\Design\Images\AutoTiles\tilea2.png"
|
||||
val palette = new AutoTilePalette(new File(file), 32)
|
||||
val tile = palette(2, 0)
|
||||
val imgs = for (y <- 0 to MaxY; x <- 0 to MaxX) yield {
|
||||
val dirs = (x, y) match {
|
||||
case (0, 0) => Set(East, South)
|
||||
case (MaxX, MaxY) => Set(West, North)
|
||||
case (0, MaxY) => Set(East, North)
|
||||
case (MaxX, 0) => Set(West, South)
|
||||
case (0, _) => Set(East, North, South)
|
||||
case (MaxX, _) => Set(West, North, South)
|
||||
case (_, 0) => Set(East, West, South)
|
||||
case (_, MaxY) => Set(East, West, North)
|
||||
case (_, _) => Set(East, West, North, South)
|
||||
}
|
||||
tile.build(dirs)
|
||||
}
|
||||
val tiles = imgs.map(i => new ImageView(i.croppedImage()).delegate)
|
||||
|
||||
|
||||
val pane = new TilePane(){
|
||||
prefColumns = MaxX + 1
|
||||
prefRows = MaxY + 1
|
||||
}
|
||||
pane.children ++= tiles
|
||||
pane.children += new ImageView(tile.icon.croppedImage())
|
||||
|
||||
stage = new JFXApp.PrimaryStage {
|
||||
title.value = "Hello Stage"
|
||||
width = 600
|
||||
height = 450
|
||||
scene = new Scene {
|
||||
fill = LightGreen
|
||||
content = pane
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -83,7 +83,6 @@ abstract class Move extends MoveTurn {
|
||||
reader ! Message(s"$user used $name.")
|
||||
if (onTryMove(user, this, target, reader, rng)) {
|
||||
if (attackRoll(user, target)) {
|
||||
reader ! AnimateMsg(element, target)
|
||||
if (pow > 0 || powCallback != null || damageCallback != null) {
|
||||
val dmg = damageRoll(user, target)
|
||||
val actualDmg = target.takeDamage(dmg)
|
||||
|
@ -1,7 +0,0 @@
|
||||
package fmon.util
|
||||
|
||||
object Direction extends Enumeration {
|
||||
val North, Northeast, East, Southeast, South, Southwest, West, Northwest = Value
|
||||
|
||||
val cardinals = Set(North, East, South, West)
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
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