diff --git a/Builder/src/fmon/builder/MapBuilder.scala b/Builder/src/fmon/builder/MapBuilder.scala index ce2deea..32632c7 100644 --- a/Builder/src/fmon/builder/MapBuilder.scala +++ b/Builder/src/fmon/builder/MapBuilder.scala @@ -51,7 +51,7 @@ class MapBuilder { var doodadSeq: IndexedSeq[ImageView] = _ val tilesets = { - val dir = new File(raw"C:\Users\James\Documents\Design\Project\Progena\Data") + val dir = new File(Config.homedir + raw"Progena\Data") YamlHelper.extractSeq[TilesetToken](new FileInputStream(new File(dir, "Tilesets.yaml"))).map(t => (t.name, t)).toMap } var tileset: Tileset = _ @@ -77,7 +77,7 @@ class MapBuilder { @FXML def initialize(): Unit = { - val resourceDir = new File(raw"C:\Users\James\Documents\Design\Project\Progena\Resources\tilesets") + val resourceDir = new File(Config.homedir + raw"Progena\Resources\tilesets") tileset = tilesets("Outside").load(resourceDir) level = new GameMap(10, 10, tileset) setup() diff --git a/FakeMon/src/fmon/Config.scala b/FakeMon/src/fmon/Config.scala index dc3ef7c..61dd1a9 100644 --- a/FakeMon/src/fmon/Config.scala +++ b/FakeMon/src/fmon/Config.scala @@ -30,4 +30,6 @@ object Config { def tileSize = config.tileSize def moveSpeed = config.moveSpeed def yOffset = config.yOffset + + def homedir = raw"C:\Users\dalyj\Documents\Design\Project\" } \ No newline at end of file diff --git a/FakeMon/src/fmon/draw/tile/AutoFloorTile.scala b/FakeMon/src/fmon/draw/tile/AutoFloorTile.scala index c0bc18c..cb93add 100644 --- a/FakeMon/src/fmon/draw/tile/AutoFloorTile.scala +++ b/FakeMon/src/fmon/draw/tile/AutoFloorTile.scala @@ -7,6 +7,7 @@ import scalafx.scene.canvas.Canvas import scalafx.scene.image._ import scalafx.scene.paint.Color +import fmon._ import fmon.draw._ import fmon.util._ @@ -14,18 +15,18 @@ import Direction._ trait AutoTile { def icon: StillImg - def build(dirs: Set[Direction.Value]): StillImg + def build(dirs: Set[Direction]): StillImg } class BasicTile(val icon: StillImg) extends AutoTile { - def build(dirs: Set[Direction.Value]) = icon + def build(dirs: Set[Direction]) = icon } 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]) = { + def build(dirs: Set[Direction]) = { val canvas = new scalafx.scene.canvas.Canvas(size, size) val g = canvas.graphicsContext2D @@ -47,7 +48,7 @@ class AutoFloorTile(val palette: Palette, val size: Int = 48) extends AutoTile { StillImg(img, 0, 0, size, size) } - private def getNE(dirs: Set[Direction.Value]): Image = { + private def getNE(dirs: Set[Direction]): Image = { if (!dirs(Northeast) && dirs(North) && dirs(East)) { palette(3, 0).croppedImage() } else { @@ -57,7 +58,7 @@ class AutoFloorTile(val palette: Palette, val size: Int = 48) extends AutoTile { } } - private def getNW(dirs: Set[Direction.Value]): Image = { + private def getNW(dirs: Set[Direction]): Image = { if (!dirs(Northwest) && dirs(North) && dirs(West)) { palette(2, 0).croppedImage() } else { @@ -67,7 +68,7 @@ class AutoFloorTile(val palette: Palette, val size: Int = 48) extends AutoTile { } } - private def getSE(dirs: Set[Direction.Value]): Image = { + private def getSE(dirs: Set[Direction]): Image = { if (!dirs(Southeast) && dirs(South) && dirs(East)) { palette(3, 1).croppedImage() } else { @@ -77,7 +78,7 @@ class AutoFloorTile(val palette: Palette, val size: Int = 48) extends AutoTile { } } - private def getSW(dirs: Set[Direction.Value]): Image = { + private def getSW(dirs: Set[Direction]): Image = { if (!dirs(Southwest) && dirs(South) && dirs(West)) { palette(2, 1).croppedImage() } else { @@ -111,7 +112,7 @@ class AutoWallTile(val palette: Palette, val size: Int = 48) extends AutoTile { StillImg(img, 0, 0, size, size) } - def build(dirs: Set[Direction.Value]) = { + def build(dirs: Set[Direction]) = { val canvas = new scalafx.scene.canvas.Canvas(size, size) val g = canvas.graphicsContext2D @@ -133,25 +134,25 @@ class AutoWallTile(val palette: Palette, val size: Int = 48) extends AutoTile { StillImg(img, 0, 0, size, size) } - private def buildUL(dirs: Set[Direction.Value]) = { + private def buildUL(dirs: Set[Direction]) = { 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]) = { + private def buildUR(dirs: Set[Direction]) = { 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]) = { + private def buildLL(dirs: Set[Direction]) = { 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]) = { + private def buildLR(dirs: Set[Direction]) = { val x = if (dirs(East)) 1 else 3 val y = if (dirs(South)) 1 else 3 palette(x, y) diff --git a/FakeMon/src/fmon/package.scala b/FakeMon/src/fmon/package.scala index 319fa74..b0fc4a2 100644 --- a/FakeMon/src/fmon/package.scala +++ b/FakeMon/src/fmon/package.scala @@ -6,6 +6,7 @@ import fmon.stat._ import fmon.util.{Dice, IntFraction} package object fmon { + type Direction = fmon.util.Direction.Val implicit def rngDice(rng : Random) = new Dice(rng) implicit def int2Helper(x : Int) = new IntFraction(x) diff --git a/FakeMon/src/fmon/util/Direction.scala b/FakeMon/src/fmon/util/Direction.scala index ed16ffd..6c4ebdb 100644 --- a/FakeMon/src/fmon/util/Direction.scala +++ b/FakeMon/src/fmon/util/Direction.scala @@ -1,7 +1,18 @@ package fmon.util object Direction extends Enumeration { - val North, Northeast, East, Southeast, South, Southwest, West, Northwest = Value + case class Val protected(x: Int = 0, y: Int = 0) extends super.Val { + } + + val Stationary = Val() + val North = Val(y = -1) + val Northeast = Val(x = 1, y = -1) + val East = Val(x = 1) + val Southeast = Val(x = 1, y = 1) + val South = Val(y = 1) + val Southwest = Val(x = -1, y = 1) + val West = Val(x = -1) + val Northwest = Val(x = -1, y = -1) val cardinals = Set(North, East, South, West) } \ No newline at end of file diff --git a/FakeMon/src/fmon/world/Actor.scala b/FakeMon/src/fmon/world/Actor.scala index 44d268f..e44f214 100644 --- a/FakeMon/src/fmon/world/Actor.scala +++ b/FakeMon/src/fmon/world/Actor.scala @@ -1,10 +1,27 @@ package fmon.world -import fmon.draw._ +import scalafx.util.Duration -class Actor(val sprite: Sprite, var x: Double, var y: Double) { +import fmon._ +import fmon.draw._ +import fmon.util.Direction + +class Actor(val sprite: Sprite, var pos: Position, var move: Movement) { + def x: Int = pos.x + def y: Int = pos.y + def xreal: Double = x - move.direction.x * move.completion + def yreal: Double = y - move.direction.y * move.completion + def pose: String = sprite.pose def pose_=(p: String) = { sprite.pose = p } + + def slide(dt: Duration): Unit = { + move.completion -= dt.toSeconds() * Config.moveSpeed + if (move.completion <= 0) { + //pos += move.direction + move = new Movement(Direction.Stationary, 0) + } + } } \ No newline at end of file diff --git a/FakeMon/src/fmon/world/GameMap.scala b/FakeMon/src/fmon/world/GameMap.scala index 167eee6..79c0fa7 100644 --- a/FakeMon/src/fmon/world/GameMap.scala +++ b/FakeMon/src/fmon/world/GameMap.scala @@ -4,6 +4,8 @@ import scalafx.scene.image.Image import java.io._ +import fmon._ +import fmon.Config import fmon.draw._ import fmon.draw.tile._ import fmon.util._ @@ -16,6 +18,7 @@ class GameMap(val width: Int, val height: Int, val tileset: Tileset) { var doodads: IndexedSeq[AutoTile] = for (y <- 0 until height; x <- 0 until width) yield tileset.doodadTiles.head def tileInfo(index: Int) = tileset.infoOf(tiles(index)) + def tileInfo(pos: Position) = tileset.infoOf(this(pos)) def saveTo(file: File): Unit = { val ostream = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file))) @@ -32,10 +35,12 @@ class GameMap(val width: Int, val height: Int, val tileset: Tileset) { def apply(x: Int, y: Int): AutoTile = tiles(pt2index(x, y)) def doodad(x: Int, y: Int): AutoTile = doodads(pt2index(x, y)) + def apply(pos: Position): AutoTile = tiles(pt2index(pos.x, pos.y)) + def doodad(pos: Position): AutoTile = doodads(pt2index(pos.x, pos.y)) def smoothed(x: Int, y: Int): Image = { val i = pt2index(x, y) - val dirs = scala.collection.mutable.Set[Direction.Value]() + val dirs = scala.collection.mutable.Set[Direction]() val onLeft = x == 0 val onRight = x + 1 == width @@ -70,8 +75,8 @@ object GameMap { val istream = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file))) val width = istream.readInt() val height = istream.readInt() - val dir = new File(raw"C:\Users\James\Documents\Design\Project\Progena\Data") - val resourceDir = new File(raw"C:\Users\James\Documents\Design\Project\Progena\Resources\tilesets") + val dir = new File(Config.homedir + raw"Progena\Data") + val resourceDir = new File(Config.homedir + raw"Progena\Resources\tilesets") val tokens = YamlHelper.extractSeq[TilesetToken](new FileInputStream(new File(dir, "Tilesets.yaml"))).map(t => (t.name, t)).toMap val tileset = tokens("Outside").load(resourceDir) val indices = for (y <- 0 until height; x <- 0 until width) yield istream.readInt() diff --git a/FakeMon/src/fmon/world/Position.scala b/FakeMon/src/fmon/world/Position.scala new file mode 100644 index 0000000..9367217 --- /dev/null +++ b/FakeMon/src/fmon/world/Position.scala @@ -0,0 +1,15 @@ +package fmon.world + +import fmon._ +import fmon.util.Direction._ + +case class Position(val x: Int, val y: Int) { + def +(d: Direction): Position = { + Position(x + d.x, y + d.y) + } +} + +class Movement(val direction: Direction, var completion: Double) { + +} + diff --git a/FakeMon/src/fmon/world/ui/GameView.scala b/FakeMon/src/fmon/world/ui/GameView.scala index 9fdbb9b..c07f554 100644 --- a/FakeMon/src/fmon/world/ui/GameView.scala +++ b/FakeMon/src/fmon/world/ui/GameView.scala @@ -40,7 +40,7 @@ class GameView { var hero: Actor = _ var heroImg: AnimatedImageView = _ - var currDir: Option[Direction.Value] = None + var currDir: Option[Direction] = None var level: GameMap = _ @@ -67,8 +67,8 @@ class GameView { } doodads.children ++= dtiles - val heroFile = raw"C:\Users\James\Documents\Design\Project\Progena\Resources\characters\Actor1.png" - hero = new Actor(CharSet(new File(heroFile), 1), 5, 4) + val heroFile = Config.homedir + raw"Progena\Resources\characters\Actor1.png" + hero = new Actor(CharSet(new File(heroFile), 1), Position(5, 4), new Movement(Direction.Stationary, 0.0)) heroImg = new AnimatedImageView(hero.sprite, new Duration(600)) { x = hero.x * Config.tileSize @@ -98,13 +98,12 @@ class GameView { } } - def setDir(dir: Direction.Value): Unit = { - hero.pose = dir.toString() + def setDir(dir: Direction): Unit = { currDir = Some(dir) heroImg.play() } - def clearDir(dir: Direction.Value): Unit = { + def clearDir(dir: Direction): Unit = { if (currDir == Some(dir)) { currDir = None heroImg.stop() @@ -112,17 +111,34 @@ class GameView { } def act(dur: Duration): Unit = { - currDir match { + /*currDir match { case Some(North) => slide(hero, 0, -dur.toSeconds() * Config.moveSpeed) case Some(East) => slide(hero, dur.toSeconds() * Config.moveSpeed, 0) case Some(West) => slide(hero, -dur.toSeconds() * Config.moveSpeed, 0) case Some(South) => slide(hero, 0, +dur.toSeconds() * Config.moveSpeed) case _ => () + }*/ + if (hero.move.completion <= 0 && currDir.isDefined) { + val dir = currDir.get + + if (hero.pose != dir.toString()) { + hero.pose = dir.toString() + } else { + val info = level.tileInfo(hero.pos + dir) + val canPass = (dir.x < 0 && info.doesPassEast) || (dir.x > 0 && info.doesPassWest) || + (dir.y < 0 && info.doesPassSouth) || (dir.y > 0 && info.doesPassNorth) + if (canPass) { + hero.pos += dir + hero.move = new Movement(dir, 1.0) + } + } } - heroImg.x = hero.x * Config.tileSize - heroImg.y = hero.y * Config.tileSize + Config.yOffset + hero.slide(dur) + heroImg.x = hero.xreal * Config.tileSize + heroImg.y = hero.yreal * Config.tileSize + Config.yOffset } + /* def slide(actor: Actor, dx: Double, dy: Double): Unit = { // Need to do all corners val px = if (dx < 0) actor.x else actor.x + 1 @@ -150,9 +166,60 @@ class GameView { actor.x += dx actor.y += dy } + }*/ + + def lineIntersectionIndices(p: Point2D, q: Point2D): Seq[Int] = { + def p2i(pt: Point2D) = level.pt2index(pt.x.toInt, pt.y.toInt) + val dx = q.x - p.x + val dy = q.y - p.y + val nx = Math.abs(dx).toInt + val ny = Math.abs(dy).toInt + val sx = Math.signum(dx) + val sy = Math.signum(dy) + + var pts = Seq(p2i(p)) + var pt = p + var ix = 0 + var iy = 0 + while (ix < nx || iy < ny) { + if ((0.5+ix) * ny < (0.5+iy) * nx) { + // next step is horizontal + pt = new Point2D(pt.x + sx, pt.y) + ix += 1 + } else { + // next step is vertical + pt = new Point2D(pt.x, pt.y + sy) + ix += 1 + } + pts :+= p2i(pt) + } + pts + } + + def lineIntersectsGrid(p: Point2D, q: Point2D, gi: Int): Point2D = { + val gx = level.index2x(gi) + val gy = level.index2y(gi) + val dx = q.x - p.x + val dy = q.y - p.y + if (dx > 0) { + new Point2D(gx, p.y) + } else if (dx < 0) { + new Point2D(gx + 1.0, p.y) + } else if (dy > 0) { + new Point2D(p.x, gy) + } else if (dy < 0) { + new Point2D(p.x, gy + 1) + } else { + new Point2D(q.x, q.y) + } } def tilesOnLine(p: Point2D, q: Point2D): Seq[(Int, Point2D)] = { + val tileIndices = lineIntersectionIndices(p, q) + tileIndices.map(i => (i, lineIntersectsGrid(p, q, i))) + } + + def tilesOnLine_(p: Point2D, q: Point2D): Seq[(Int, Point2D)] = { val dx = q.x - p.x val dy = q.y - p.y val nx = Math.abs(dx).toInt @@ -188,7 +255,7 @@ object GameView { val root: Parent = frameLoader.load() val controller = frameLoader.getController[GameView]() - val stageFile = raw"C:\Users\James\Documents\Design\Project\Progena\Data\outside.map" + val stageFile = Config.homedir + raw"Progena\Data\outside.map" val level = GameMap.loadFrom(new File(stageFile)) controller.loadLevel(level) //val builderLoader = new FXMLLoader(getClass.getResource("ElementBuilder.fxml"))