Add new mobs and new towers
|
@ -69,7 +69,7 @@ Un sprite est une image de taille 16x16, qui contient des informations sur l'end
|
|||
Un Mob est une classe abstraite contenant des informations abstraites (détaillées plus haut). Un type de mob sera donc
|
||||
une classe héritant de `Mob`, telles que `Mob1`, `Mob2` et `MobCancer`.
|
||||
|
||||
Il en est de même pour les tours, avec `BasicTower`, `NullTower` et `AutoTower`.
|
||||
Il en est de même pour les tours, avec `BasicTower`, `WallTower` et `AutoTower`.
|
||||
|
||||
L'intérêt de l'héritage par rapport à un type donné à une classe Mob (paramètres donnés dans une enumération `MobType`
|
||||
par exemple) est de pouvoir mieux personnaliser les fonctions, par exemple en imaginant des dégâts aléatoires.
|
||||
|
|
Before Width: | Height: | Size: 697 B After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 697 B After Width: | Height: | Size: 697 B |
Before Width: | Height: | Size: 696 B After Width: | Height: | Size: 696 B |
Before Width: | Height: | Size: 760 B After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 731 B After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 732 B After Width: | Height: | Size: 732 B |
|
@ -325,16 +325,34 @@
|
|||
"mob2": [
|
||||
[0, 0]
|
||||
],
|
||||
"mobcancer": [
|
||||
"mobstrong": [
|
||||
[0, 0]
|
||||
],
|
||||
"mobhealer": [
|
||||
[0, 0]
|
||||
],
|
||||
"mobbreaker": [
|
||||
[0, 0]
|
||||
],
|
||||
"mobspeeder": [
|
||||
[0, 0]
|
||||
],
|
||||
"basictower": [
|
||||
[0, 0]
|
||||
],
|
||||
"nulltower": [
|
||||
"walltower": [
|
||||
[0, 0]
|
||||
],
|
||||
"autotower": [
|
||||
"freezertower": [
|
||||
[0, 0]
|
||||
],
|
||||
"explodertower": [
|
||||
[0, 0]
|
||||
],
|
||||
"upgradetower": [
|
||||
[0, 0]
|
||||
],
|
||||
"lasertower": [
|
||||
[0, 0]
|
||||
]
|
||||
}
|
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 697 B |
|
@ -8,7 +8,7 @@ import fr.ynerant.leveleditor.api.editor.sprites.SpriteRegister
|
|||
import fr.ynerant.leveleditor.api.editor.{Collision, RawMap}
|
||||
import fr.ynerant.leveleditor.editor.CollidPanel
|
||||
import fr.ynerant.leveleditor.game.mobs.Mob
|
||||
import fr.ynerant.leveleditor.game.towers.{AutoTower, BasicTower, NullTower, Tower}
|
||||
import fr.ynerant.leveleditor.game.towers._
|
||||
import javax.swing._
|
||||
|
||||
import scala.collection.mutable.ListBuffer
|
||||
|
@ -23,8 +23,11 @@ class GameFrame(val map: RawMap) extends JFrame("Jeu") {
|
|||
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
|
||||
final private var wallTower = null: JRadioButton
|
||||
final private var freezerTower = null: JRadioButton
|
||||
final private var explodeTower = null: JRadioButton
|
||||
final private var upgradeTower = null: JRadioButton
|
||||
final private var laserTower = null: JRadioButton
|
||||
final private var waveLabel = null: JLabel
|
||||
final private var nbMobsLabel = null: JLabel
|
||||
final private var hpLabel = null: JLabel
|
||||
|
@ -53,12 +56,21 @@ class GameFrame(val map: RawMap) extends JFrame("Jeu") {
|
|||
basicTower.setSelected(true)
|
||||
towerSelect.add(basicTower)
|
||||
pane.add(basicTower)
|
||||
nullTower = new JRadioButton("Tour nulle (" + new NullTower(0, 0).getPrice + " pièces)")
|
||||
towerSelect.add(nullTower)
|
||||
pane.add(nullTower)
|
||||
autoTower = new JRadioButton("Tour automatique (" + new AutoTower(0, 0).getPrice + " pièces)")
|
||||
towerSelect.add(autoTower)
|
||||
pane.add(autoTower)
|
||||
wallTower = new JRadioButton("Tour-mur (" + new WallTower(0, 0).getPrice + " pièces)")
|
||||
towerSelect.add(wallTower)
|
||||
pane.add(wallTower)
|
||||
freezerTower = new JRadioButton("Tour froide (" + new FreezerTower(0, 0).getPrice + " pièces)")
|
||||
towerSelect.add(freezerTower)
|
||||
pane.add(freezerTower)
|
||||
explodeTower = new JRadioButton("Tour explosive (" + new ExploderTower(0, 0).getPrice + " pièces)")
|
||||
towerSelect.add(explodeTower)
|
||||
pane.add(explodeTower)
|
||||
upgradeTower = new JRadioButton("Tour d'amélioration (" + new UpgradeTower(0, 0).getPrice + " pièces)")
|
||||
towerSelect.add(upgradeTower)
|
||||
pane.add(upgradeTower)
|
||||
laserTower = new JRadioButton("Tour laser (" + new LaserTower(0, 0).getPrice + " pièces)")
|
||||
towerSelect.add(laserTower)
|
||||
pane.add(laserTower)
|
||||
waveLabel = new JLabel
|
||||
pane.add(waveLabel)
|
||||
nbMobsLabel = new JLabel
|
||||
|
@ -92,6 +104,12 @@ class GameFrame(val map: RawMap) extends JFrame("Jeu") {
|
|||
|
||||
def getMap: RawMap = map
|
||||
|
||||
def getMobs: ListBuffer[Mob] = mobs
|
||||
|
||||
def getTowers: ListBuffer[Tower] = towers
|
||||
|
||||
def breakTower(tower: Tower): Unit = towers -= tower
|
||||
|
||||
def getPathFinder: PathFinder = pathFinder
|
||||
|
||||
def tick(): Unit = {
|
||||
|
@ -107,11 +125,7 @@ class GameFrame(val map: RawMap) extends JFrame("Jeu") {
|
|||
mobs += mob
|
||||
}
|
||||
}
|
||||
towers.foreach(tower => {
|
||||
tower.filterDetectedMobs(mobs).foreach(mob => {
|
||||
mob.hit(tower.getDamagePerShot)
|
||||
})
|
||||
})
|
||||
towers.foreach(tower => tower.shot(this))
|
||||
mobs.foreach(mob => {
|
||||
getMap.getCase(mob.getX, mob.getY).setCollision(Collision.ANY)
|
||||
mob.tick(this)
|
||||
|
@ -148,9 +162,11 @@ class GameFrame(val map: RawMap) extends JFrame("Jeu") {
|
|||
val x = event.getX / 32
|
||||
val y = event.getY / 32
|
||||
val tower = if (basicTower.isSelected) new BasicTower(x, y)
|
||||
else if (nullTower.isSelected) new NullTower(x, y)
|
||||
|
||||
else if (autoTower.isSelected) new AutoTower(x, y)
|
||||
else if (wallTower.isSelected) new WallTower(x, y)
|
||||
else if (freezerTower.isSelected) new FreezerTower(x, y)
|
||||
else if (explodeTower.isSelected) new ExploderTower(x, y)
|
||||
else if (upgradeTower.isSelected) new UpgradeTower(x, y)
|
||||
else if (laserTower.isSelected) new LaserTower(x, y)
|
||||
else null
|
||||
if (tower == null || tower.getPrice > reward) return
|
||||
val c = getMap.getCase(x, y)
|
||||
|
|
|
@ -1,35 +1,48 @@
|
|||
package fr.ynerant.leveleditor.game.mobs
|
||||
|
||||
import java.util.Random
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.RawCase
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.{Sprite, SpriteRegister}
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
|
||||
import scala.util.Random
|
||||
|
||||
object Mob {
|
||||
private val RANDOM = new Random
|
||||
|
||||
def getRandomMob: Mob = RANDOM.nextInt(3) match {
|
||||
case 1 =>
|
||||
def getRandomMob: Mob = RANDOM.nextInt(6) match {
|
||||
case 0 =>
|
||||
new Mob1
|
||||
case 2 =>
|
||||
case 1 =>
|
||||
new Mob2
|
||||
case _ =>
|
||||
new MobCancer
|
||||
case 2 =>
|
||||
new MobStrong
|
||||
case 3 =>
|
||||
new MobHealer
|
||||
case 4 =>
|
||||
new MobBreaker
|
||||
case 5 =>
|
||||
new MobSpeeder
|
||||
}
|
||||
}
|
||||
|
||||
abstract class Mob() {
|
||||
private var hp = getMaxHP
|
||||
private var tickRemains = getSlowness
|
||||
private var tickRemains = 0L
|
||||
private var sprite = null: Sprite
|
||||
private var x = 0
|
||||
private var y = 0
|
||||
private var freezeTime = 0
|
||||
private var speedMultiplier = 1
|
||||
|
||||
tickRemains = getSlowness
|
||||
|
||||
def getMaxHP: Int
|
||||
|
||||
def getSlowness: Long
|
||||
def _getSlowness: Long
|
||||
|
||||
def getSlowness: Long = {
|
||||
(_getSlowness * Random.between(0.95, 1.05) * (if (freezeTime > 0) 2 else 1) / speedMultiplier).toLong
|
||||
}
|
||||
|
||||
def getReward: Int
|
||||
|
||||
|
@ -49,6 +62,18 @@ abstract class Mob() {
|
|||
this.y = y
|
||||
}
|
||||
|
||||
def freeze(time: Int): Unit = {
|
||||
if (freezeTime == 0)
|
||||
tickRemains *= 2
|
||||
freezeTime = time
|
||||
}
|
||||
|
||||
def speedup(multiplier: Int): Unit = speedMultiplier = multiplier
|
||||
|
||||
def heal(hp: Int): Unit = {
|
||||
this.hp = Math.min(hp + 1, getMaxHP)
|
||||
}
|
||||
|
||||
def getHP: Int = hp
|
||||
|
||||
def isDead: Boolean = hp <= 0
|
||||
|
@ -65,7 +90,13 @@ abstract class Mob() {
|
|||
false
|
||||
}
|
||||
|
||||
/**
|
||||
* Called each game tick
|
||||
*/
|
||||
def tick(game: GameFrame): Unit = {
|
||||
if (freezeTime > 0)
|
||||
freezeTime -= 1
|
||||
|
||||
if (tickRemains > 0) tickRemains -= 1
|
||||
else {
|
||||
tickRemains = getSlowness
|
||||
|
@ -75,10 +106,17 @@ abstract class Mob() {
|
|||
return
|
||||
}
|
||||
|
||||
_tick(game)
|
||||
|
||||
val newCase: RawCase = game.getPathFinder.nextPos(getX, getY)
|
||||
move(newCase.getPosX, newCase.getPosY)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom mobs override this function to do some custom stuff
|
||||
*/
|
||||
def _tick(game: GameFrame): Unit = ()
|
||||
|
||||
override def toString: String = "Mob{" + "sprite=" + sprite + ", x=" + x + ", y=" + y + '}'
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package fr.ynerant.leveleditor.game.mobs
|
|||
class Mob1 extends Mob {
|
||||
override def getMaxHP = 2
|
||||
|
||||
override def getSlowness = 60
|
||||
override def _getSlowness = 50
|
||||
|
||||
override def getReward = 10
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ package fr.ynerant.leveleditor.game.mobs
|
|||
class Mob2 extends Mob {
|
||||
override def getMaxHP = 6
|
||||
|
||||
override def getSlowness = 20
|
||||
override def _getSlowness = 20
|
||||
|
||||
override def getReward = 20
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package fr.ynerant.leveleditor.game.mobs
|
||||
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
|
||||
class MobBreaker extends Mob {
|
||||
override def getMaxHP = 40
|
||||
|
||||
override def _getSlowness = 120
|
||||
|
||||
override def getReward = 70
|
||||
|
||||
override def getName = "mobhealer"
|
||||
|
||||
override def _tick(game: GameFrame): Unit = {
|
||||
game.getTowers.filter(tower => Math.abs(tower.getX - getX) + Math.abs(tower.getY - getY) <= 1).foreach(tower => game.breakTower(tower))
|
||||
game.getPathFinder.invalidate
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package fr.ynerant.leveleditor.game.mobs
|
||||
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
|
||||
class MobHealer extends Mob {
|
||||
override def getMaxHP = 20
|
||||
|
||||
override def _getSlowness = 60
|
||||
|
||||
override def getReward = 20
|
||||
|
||||
override def getName = "mobhealer"
|
||||
|
||||
override def _tick(game: GameFrame): Unit = {
|
||||
game.getMobs.filter(mob => Math.pow(mob.getX - getX, 2) + Math.pow(mob.getY - getY, 2) <= 9).foreach(mob => mob.heal(1))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package fr.ynerant.leveleditor.game.mobs
|
||||
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
|
||||
class MobSpeeder extends Mob {
|
||||
override def getMaxHP = 25
|
||||
|
||||
override def _getSlowness = 60
|
||||
|
||||
override def getReward = 30
|
||||
|
||||
override def getName = "mobspeeder"
|
||||
|
||||
override def _tick(game: GameFrame): Unit = {
|
||||
game.getMobs.filter(mob => Math.pow(mob.getX - getX, 2) + Math.pow(mob.getY - getY, 2) <= 9).foreach(mob => mob.speedup(3))
|
||||
}
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
package fr.ynerant.leveleditor.game.mobs
|
||||
|
||||
class MobCancer extends Mob {
|
||||
class MobStrong extends Mob {
|
||||
override def getMaxHP = 50
|
||||
|
||||
override def getSlowness = 100
|
||||
override def _getSlowness = 100
|
||||
|
||||
override def getReward = 100
|
||||
|
||||
override def getName = "mobcancer"
|
||||
override def getName = "mobstrong"
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
package fr.ynerant.leveleditor.game.towers
|
||||
|
||||
import fr.ynerant.leveleditor.game.mobs.Mob
|
||||
|
||||
|
||||
class AutoTower(override val x: Int, override val y: Int) extends Tower(x, y) {
|
||||
override def getName = "autotower"
|
||||
|
||||
override def getDamagePerShot = 20
|
||||
|
||||
override def getPeriod = 10
|
||||
|
||||
override def getPrice = 142
|
||||
|
||||
override private[towers] def _filterDetectedMobs(mobs: Iterable[Mob]) = mobs
|
||||
}
|
|
@ -1,18 +1,23 @@
|
|||
package fr.ynerant.leveleditor.game.towers
|
||||
|
||||
import fr.ynerant.leveleditor.game.mobs.Mob
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
|
||||
import scala.util.Random
|
||||
|
||||
|
||||
class BasicTower(override val x: Int, override val y: Int) extends Tower(x, y) {
|
||||
override def getName = "basictower"
|
||||
|
||||
override def getDamagePerShot = 1
|
||||
override def getDamagePerShot = if (isUpgraded) 3 else 1
|
||||
|
||||
override def getPeriod = 5
|
||||
|
||||
override def getPrice = 10
|
||||
|
||||
override private[towers] def _filterDetectedMobs(mobs: Iterable[Mob]) = {
|
||||
mobs.filter(mob => (mob.getX == getX || mob.getY == getY) && Math.abs(mob.getX - getX) <= 3 && Math.abs(mob.getY - getY) <= 3)
|
||||
override private[towers] def _shot(game: GameFrame): Unit = {
|
||||
var l = game.getMobs.filter(mob => Math.pow(mob.getX - getX, 2) + Math.pow(mob.getY - getY, 2) <= 9).toList
|
||||
l = Random.shuffle(l)
|
||||
if (l.nonEmpty)
|
||||
l.head.hit(getDamagePerShot)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package fr.ynerant.leveleditor.game.towers
|
||||
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
|
||||
import scala.util.Random
|
||||
|
||||
class ExploderTower(override val x: Int, override val y: Int) extends Tower(x, y) {
|
||||
override def getName = "explodertower"
|
||||
|
||||
override def getDamagePerShot = if (isUpgraded) 7 else 3
|
||||
|
||||
override def getPeriod = 20
|
||||
|
||||
override def getPrice = 70
|
||||
|
||||
override private[towers] def _shot(game: GameFrame): Unit = {
|
||||
var l = game.getMobs.filter(mob => Math.pow(mob.getX - getX, 2) + Math.pow(mob.getY - getY, 2) <= 25).toList
|
||||
l = Random.shuffle(l)
|
||||
if (l.nonEmpty) {
|
||||
val target = l.head
|
||||
target.hit(getDamagePerShot)
|
||||
game.getMobs.filter(mob => Math.pow(mob.getX - target.getX, 2) + Math.pow(mob.getX - target.getX, 2) <= 9)
|
||||
.foreach(mob => mob.hit(getDamagePerShot))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package fr.ynerant.leveleditor.game.towers;
|
||||
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
|
||||
class FreezerTower(override val x: Int, override val y: Int) extends Tower(x, y) {
|
||||
override def getName = "freezertower"
|
||||
|
||||
override def getDamagePerShot = if (isUpgraded) 1 else 0
|
||||
|
||||
override def getPeriod = 10
|
||||
|
||||
override def getPrice = 40
|
||||
|
||||
override private[towers] def _shot(game: GameFrame): Unit = {
|
||||
game.getMobs.filter(mob => Math.abs(mob.getX - getX) <= 3 && Math.abs(mob.getY - getY) <= 3).foreach(mob => mob.freeze(if (isUpgraded) 100 else 40))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package fr.ynerant.leveleditor.game.towers
|
||||
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
|
||||
|
||||
class LaserTower(override val x: Int, override val y: Int) extends Tower(x, y) {
|
||||
override def getName = "lasertower"
|
||||
|
||||
override def getDamagePerShot = 3
|
||||
|
||||
override def getPeriod = 40
|
||||
|
||||
override def getPrice = 80
|
||||
|
||||
override private[towers] def _shot(game: GameFrame): Unit = {
|
||||
game.getMobs.filter(mob => mob.getX == getX || mob.getY == getY).foreach(mob => mob.hit(getDamagePerShot))
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
package fr.ynerant.leveleditor.game.towers
|
||||
|
||||
import fr.ynerant.leveleditor.game.mobs.Mob
|
||||
|
||||
|
||||
class NullTower(override val x: Int, override val y: Int) extends Tower(x, y) {
|
||||
override def getName = "nulltower"
|
||||
|
||||
override def getDamagePerShot: Int = Integer.MAX_VALUE
|
||||
|
||||
override def getPeriod = 1
|
||||
|
||||
override def getPrice = 5
|
||||
|
||||
override private[towers] def _filterDetectedMobs(mobs: Iterable[Mob]) = Nil
|
||||
}
|
|
@ -3,8 +3,7 @@ package fr.ynerant.leveleditor.game.towers
|
|||
import java.util.Random
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.{Sprite, SpriteRegister}
|
||||
import fr.ynerant.leveleditor.game.mobs.Mob
|
||||
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
|
||||
object Tower {
|
||||
private val RANDOM = new Random
|
||||
|
@ -13,6 +12,7 @@ object Tower {
|
|||
abstract class Tower(val x: Int, val y: Int) {
|
||||
final private val sprite = SpriteRegister.getCategory(getName).getSprites.head
|
||||
private var remainingTicks = 0L
|
||||
private var upgraded = false
|
||||
|
||||
def getSprite: Sprite = sprite
|
||||
|
||||
|
@ -24,16 +24,18 @@ abstract class Tower(val x: Int, val y: Int) {
|
|||
|
||||
def getPrice: Int
|
||||
|
||||
def filterDetectedMobs(mobs: Iterable[Mob]): Iterable[Mob] = if (remainingTicks > 0) {
|
||||
def upgrade: Unit = upgraded = true
|
||||
|
||||
def isUpgraded: Boolean = upgraded
|
||||
|
||||
def shot(game: GameFrame): Unit = if (remainingTicks > 0)
|
||||
remainingTicks -= 1
|
||||
Nil
|
||||
}
|
||||
else {
|
||||
remainingTicks = getPeriod
|
||||
_filterDetectedMobs(mobs)
|
||||
_shot(game)
|
||||
}
|
||||
|
||||
private[towers] def _filterDetectedMobs(mobs: Iterable[Mob]): Iterable[Mob]
|
||||
private[towers] def _shot(game: GameFrame): Unit
|
||||
|
||||
def getX: Int = x
|
||||
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
package fr.ynerant.leveleditor.game.towers
|
||||
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
|
||||
import scala.util.Random
|
||||
|
||||
class UpgradeTower(override val x: Int, override val y: Int) extends Tower(x, y) {
|
||||
override def getName = "upgradetower"
|
||||
|
||||
override def getDamagePerShot = if (isUpgraded) 1 else 0
|
||||
|
||||
override def getPeriod = 60
|
||||
|
||||
override def getPrice = 65
|
||||
|
||||
override private[towers] def _shot(game: GameFrame): Unit = {
|
||||
game.getTowers.filter(tower => Math.pow(tower.getX - getX, 2) + Math.pow(tower.getY - getY, 2) <= 25 && tower != this).foreach(tower => tower.upgrade)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package fr.ynerant.leveleditor.game.towers
|
||||
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
|
||||
|
||||
class WallTower(override val x: Int, override val y: Int) extends Tower(x, y) {
|
||||
override def getName = "walltower"
|
||||
|
||||
override def getDamagePerShot: Int = Integer.MAX_VALUE
|
||||
|
||||
override def getPeriod = 1
|
||||
|
||||
override def getPrice = 5
|
||||
|
||||
override private[towers] def _shot(game: GameFrame): Unit = ()
|
||||
}
|