Fix pathfinder, increase performance

This commit is contained in:
Yohann D'ANELLO 2020-04-05 00:30:12 +02:00
parent 3b55678835
commit 8b745c068a
4 changed files with 75 additions and 37 deletions

View File

@ -24,11 +24,11 @@ case class RawMap(var cases: List[RawCase], var width: Int, var height: Int) {
def getNeighbours(c: RawCase): Iterable[RawCase] = {
var list = Nil: List[RawCase]
list ::= getCase(c.getPosX, c.getPosY + 1)
list ::= getCase(c.getPosX + 1, c.getPosY)
list ::= getCase(c.getPosX, c.getPosY - 1)
list ::= getCase(c.getPosX + 1, c.getPosY)
list ::= getCase(c.getPosX, c.getPosY + 1)
list ::= getCase(c.getPosX - 1, c.getPosY)
list.filter((_c: RawCase) => _c != null && _c.getCollision.equals(Collision.ANY))
list.filter((_c: RawCase) => _c != null)
}
def getCase(x: Int, y: Int): RawCase = {

View File

@ -1,7 +1,7 @@
package fr.ynerant.leveleditor.game
import java.awt.event.{MouseEvent, MouseListener}
import java.awt._
import java.awt.event.{MouseEvent, MouseListener}
import java.util.Random
import fr.ynerant.leveleditor.api.editor.sprites.SpriteRegister
@ -21,6 +21,7 @@ class GameFrame(val map: RawMap) extends JFrame("Jeu") {
private var reward = 20
private var mobs = ListBuffer[Mob]()
private var towers = ListBuffer[Tower]()
private val pathFinder = PathFinder(this)
final private var basicTower = null: JRadioButton
final private var nullTower = null: JRadioButton
final private var autoTower = null: JRadioButton
@ -70,10 +71,16 @@ class GameFrame(val map: RawMap) extends JFrame("Jeu") {
pane.add(winLabel)
setVisible(true)
new Thread(() => {
while ( {
hp > 0 && (round < 4 || mobs.nonEmpty)
}) {
tick()
pathFinder.calculatePath()
while (hp > 0 && (round < 4 || mobs.nonEmpty)) {
try
tick()
catch {
case e: Throwable =>
e.printStackTrace()
}
try Thread.sleep(50L)
catch {
case e: InterruptedException =>
@ -85,10 +92,12 @@ class GameFrame(val map: RawMap) extends JFrame("Jeu") {
def getMap: RawMap = map
def getPathFinder: PathFinder = pathFinder
def tick(): Unit = {
if (mobs.isEmpty && round < 4) {
round += 1
val nb_mobs = round * (RANDOM.nextInt(16) + 1)
val nb_mobs = round * (RANDOM.nextInt(8) + 1)
for (_ <- 1 to nb_mobs) {
val mob = Mob.getRandomMob
do mob.move(RANDOM.nextInt(getMap.getWidth / 16), RANDOM.nextInt(getMap.getHeight / 16)) while ( {
@ -144,11 +153,23 @@ class GameFrame(val map: RawMap) extends JFrame("Jeu") {
else null
if (tower == null || tower.getPrice > reward) return
val c = getMap.getCase(x, y)
println(x + ", " + y + ", " + tower + ", " + c)
if (c == null || !c.getCollision.equals(Collision.ANY)) return
c.setCollision(Collision.FULL)
reward -= tower.getPrice
towers += tower
pathFinder.invalidate()
val accessible = getMap.getCases.filter(c => !Collision.FULL.equals(c.getCollision))
if (accessible.exists(c => c.getPosX > 0 && pathFinder.nextPos(c.getPosX, c.getPosY) == null) || !accessible.exists(c => c.getPosX == 0 && !c.getCollision.equals(Collision.FULL))) {
println(accessible.exists(c => c.getPosX > 0 && pathFinder.nextPos(c.getPosX, c.getPosY) == null))
println(!accessible.exists(c => c.getPosX == 0 && pathFinder.nextPos(c.getPosX, c.getPosY) != null))
// We ensure that the end of the game is accessible from everywhere, the tower should not block the game
c.setCollision(Collision.ANY)
pathFinder.invalidate()
}
else {
reward -= tower.getPrice
towers += tower
}
}
override def mouseClicked(event: MouseEvent): Unit = {

View File

@ -0,0 +1,40 @@
package fr.ynerant.leveleditor.game
import java.util
import fr.ynerant.leveleditor.api.editor.{Collision, RawCase}
case class PathFinder(game: GameFrame) {
var pred: Map[Int, RawCase] = Map(): Map[Int, RawCase]
def invalidate(): Unit = calculatePath()
def calculatePath(): Unit = {
pred = Map()
val queue = new util.ArrayDeque[RawCase]
for (i <- 0 until game.getMap.getHeight / 16) {
val start = game.getMap.getCase(0, i)
if (!start.getCollision.equals(Collision.FULL)) {
pred += (coords(start) -> null)
queue.add(start)
}
}
while (!queue.isEmpty) {
val visiting = queue.poll
game.getMap.getNeighbours(visiting).foreach(neighbour => {
if (neighbour != null && !neighbour.collision.equals(Collision.FULL) && !pred.contains(coords(neighbour))) {
pred += (coords(neighbour) -> visiting)
queue.add(neighbour)
}
})
}
}
def coords(rawCase: RawCase): Int = rawCase.getPosY * game.getMap.getWidth / 16 + rawCase.getPosX
def nextPos(x: Int, y: Int): RawCase = {
pred.getOrElse(y * game.getMap.getWidth / 16 + x, null)
}
}

View File

@ -1,6 +1,5 @@
package fr.ynerant.leveleditor.game.mobs
import java.util
import java.util.Random
import fr.ynerant.leveleditor.api.editor.RawCase
@ -76,30 +75,8 @@ abstract class Mob() {
return
}
var visited = Nil: List[RawCase]
val queue = new util.ArrayDeque[RawCase]
var pred = Map(): Map[RawCase, RawCase]
var last = null: RawCase
queue.add(current)
while (!queue.isEmpty) {
val visiting = queue.poll
visited ::= visiting
game.getMap.getNeighbours(visiting).foreach(neighbour => {
if (neighbour != null && !visited.contains(neighbour)) {
pred += (neighbour -> visiting)
queue.add(neighbour)
if (neighbour.getPosX == 0) {
last = neighbour
queue.clear()
return
}
}
})
if (last != null) {
while (pred(last) != current) last = pred(last)
move(last.getPosX, last.getPosY)
}
}
val newCase: RawCase = game.getPathFinder.nextPos(getX, getY)
move(newCase.getPosX, newCase.getPosY)
}
}