Skip to content

Commit

Permalink
Merge branch 'release-1.3.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
gturi committed Sep 13, 2018
2 parents a92e232 + 74304a2 commit 90af280
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 153 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'org.scoverage'
apply plugin: 'com.github.maiflai.scalatest'

version '1.3.0'
version '1.3.1'

mainClassName = 'it.unibo.osmos.redux.main.AppLauncher'
sourceCompatibility = 1.8
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/levels/singlePlayer/4.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "4",
"victoryRule": {
"victoryRule": "Become the biggest"
"victoryRule": "Absorb the attractors"
},
"levelMap": {
"mapShape": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ case class EndGameSystem(levelContext: GameStateHolder, victoryRules: VictoryRul
private val victoryCondition = victoryRules match {
case VictoryRules.becomeTheBiggest => BecomeTheBiggestVictoryCondition()
case VictoryRules.becomeHuge => BecomeHugeVictoryCondition()
case VictoryRules.absorbTheAttractors => AbsorbCellsWithTypeVictoryCondition(EntityType.Attractive)
case VictoryRules.absorbTheRepulsors => AbsorbCellsWithTypeVictoryCondition(EntityType.Repulsive)
case VictoryRules.absorbTheHostileCells => AbsorbCellsWithTypeVictoryCondition(EntityType.Sentient)
case _ => throw new NotImplementedError()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package it.unibo.osmos.redux.mvc.controller.levels.structure
object VictoryRules extends Enumeration {
val becomeTheBiggest: VictoryRules.Value = Value("Become the biggest")
val becomeHuge: VictoryRules.Value = Value("Become huge")
val absorbTheAttractors: VictoryRules.Value = Value("Absorb the attractors")
val absorbTheRepulsors: VictoryRules.Value = Value("Absorb the repulsors")
val absorbTheHostileCells: VictoryRules.Value = Value("Absorb the hostile cells")
val absorbAllOtherPlayers: VictoryRules.Value = Value("Absorb all other players")
Expand Down
3 changes: 2 additions & 1 deletion src/main/scala/it/unibo/osmos/redux/mvc/view/View.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ object View {
class ViewImpl(private val app: JFXApp) extends View with PrimaryStageListener {

/** Implicit executor */
implicit val ec: ExecutionContextExecutor = ExecutionContext.global
implicit val executionContextExecutor: ExecutionContextExecutor = ExecutionContext.global

/** Setting the primary stage */
app.stage = OsmosReduxPrimaryStage(this)
private var controller: Option[Controller] = Option.empty
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package it.unibo.osmos.redux.mvc.view.components.level

import it.unibo.osmos.redux.ecs.entities.EntityType
import it.unibo.osmos.redux.mvc.view.ViewConstants
import it.unibo.osmos.redux.mvc.view.ViewConstants.Entities.Textures._
import it.unibo.osmos.redux.mvc.view.drawables.{CellDrawable, CellWithSpeedDrawable, DrawableWrapper}
import it.unibo.osmos.redux.mvc.view.loaders.ImageLoader
import it.unibo.osmos.redux.utils.MathUtils.normalize
import it.unibo.osmos.redux.utils.Point
import scalafx.application.Platform
import scalafx.scene.canvas.Canvas
import scalafx.scene.image.Image
import scalafx.scene.paint.Color

/** Class which encapsulates all the required methods and procedures to draw the level entities
*
* @param canvas the canvas on which the level entities will be drawn
*/
class LevelEntitiesDrawer(val canvas: Canvas) {

/** Level images */
private object LevelDrawables {
val cellDrawable: CellDrawable = new CellDrawable(ImageLoader.getImage(CellTexture), canvas.graphicsContext2D)
val playerCellDrawable: CellDrawable = new CellWithSpeedDrawable(ImageLoader.getImage(PlayerCellTexture), canvas.graphicsContext2D)
val attractiveDrawable: CellDrawable = new CellDrawable(ImageLoader.getImage(AttractiveTexture), canvas.graphicsContext2D)
val repulsiveDrawable: CellDrawable = new CellDrawable(ImageLoader.getImage(RepulsiveTexture), canvas.graphicsContext2D)
val antiMatterDrawable: CellDrawable = new CellDrawable(ImageLoader.getImage(AntiMatterTexture), canvas.graphicsContext2D)
val sentientDrawable: CellDrawable = new CellDrawable(ImageLoader.getImage(SentientTexture), canvas.graphicsContext2D)
val controlledDrawable: CellDrawable = new CellDrawable(ImageLoader.getImage(ControllerTexture), canvas.graphicsContext2D)
val backgroundImage: Image = ImageLoader.getImage(BackgroundTexture)
}

/** This method let the drawer calculate the new entities colour and then draws them
*
* @param playerEntity the player entity, which may be empty
* @param entities the entities
* @param playerCallback the callback called when the player entity gets drawn
*/
def drawEntities(playerEntity: Option[DrawableWrapper], entities: Seq[DrawableWrapper], playerCallback: Point => Unit): Unit = {

var entitiesWrappers: Seq[(DrawableWrapper, Color)] = Seq()

playerEntity match {
/** The player is present */
case Some(pe) => entitiesWrappers = calculateColors(entities, pe)

/** The player is not present */
case _ => entitiesWrappers = calculateColorsWithoutPlayer(entities)
}

/** We must draw to the screen the entire collection */
Platform.runLater({
/** Clear the screen */
canvas.graphicsContext2D.clearRect(0, 0, canvas.width.value, canvas.height.value)
canvas.graphicsContext2D.drawImage(LevelDrawables.backgroundImage, 0, 0, canvas.width.value, canvas.height.value)

/** Draw the entities */
playerEntity match {
case Some(pe) => entitiesWrappers foreach (e => e._1 match {
case `pe` =>
playerCallback(e._1.center)
LevelDrawables.playerCellDrawable.draw(e._1, e._2)
case _ => drawEntity(e._1, e._2)
})
case _ => entitiesWrappers foreach (e => drawEntity(e._1, e._2))
}
})
}

/** This method calculates the color of the input entities, interpolating and normalizing it according to the entities size
*
* @param minColor the base lower Color
* @param maxColor the base upper Color
* @param entities the input entities
* @return the sequence of pair where the first field is the entity and the second is the color
*/
private def calculateColorsWithoutPlayer(entities: Seq[DrawableWrapper], minColor: Color = Color.LightBlue, maxColor: Color = Color.DarkRed): Seq[(DrawableWrapper, Color)] = {
entities match {
case Nil => Seq()
case _ =>

/** Calculate the min and max radius among the entities */
val endRadius = getEntitiesExtremeRadiusValues(entities)

entities map (e => {
/** Normalize the entity radius */
val normalizedRadius = normalize(e.radius, endRadius._1, endRadius._2)

/** Create a pair where the second value is the interpolated color between the two base colors */
(e, minColor.interpolate(maxColor, normalizedRadius))
}) seq
}
}

/** This method calculates the color of the input entities when the player is present
*
* @param entities the input entities
* @param playerEntity the player entity
* @param minColor the base lower Color
* @param maxColor the base upper Color
* @param playerColor the player Color
* @return the sequence of pair where the first field is the entity and the second is the color
*/
private def calculateColors(entities: Seq[DrawableWrapper], playerEntity: DrawableWrapper,
minColor: Color = ViewConstants.Entities.Colors.DefaultEntityMinColor, maxColor: Color = ViewConstants.Entities.Colors.DefaultEntityMaxColor,
playerColor: Color = Color.Green): Seq[(DrawableWrapper, Color)] = {
entities match {
case Nil => Seq()
case _ =>

/** Calculate the min and max radius among the entities, considering the player */
entities map {
case e if e.radius == playerEntity.radius => (e, playerColor)

/** The entity is smaller than the player so it's color hue will approach the min one */
case e if e.radius < playerEntity.radius => (e, minColor)

/** The entity is larger than the player so it's color hue will approach the max one */
case e => (e, maxColor)
} seq
}
}

/** Used to draw the correct entity according to its type
*
* @param drawableWrapper the drawableWrapper
* @param color the border color
*/
private def drawEntity(drawableWrapper: DrawableWrapper, color: Color): Unit = {
drawableWrapper.entityType match {
case EntityType.Attractive => LevelDrawables.attractiveDrawable.draw(drawableWrapper, color)
case EntityType.Repulsive => LevelDrawables.repulsiveDrawable.draw(drawableWrapper, color)
case EntityType.AntiMatter => LevelDrawables.antiMatterDrawable.draw(drawableWrapper, color)
case EntityType.Sentient => LevelDrawables.sentientDrawable.draw(drawableWrapper, color)
case EntityType.Controlled => LevelDrawables.controlledDrawable.draw(drawableWrapper, color)
case _ => LevelDrawables.cellDrawable.draw(drawableWrapper, color)
}
}

/** This method returns a pair consisting of the min and the max radius found in the entities sequence
*
* @param entities a DrawableWrapper sequence
* @return a pair consisting of the min and the max radius found; an IllegalArgumentException on empty sequence
*/
private def getEntitiesExtremeRadiusValues(entities: Seq[DrawableWrapper]): (Double, Double) = {
/** Sorting the entities */
val sorted = entities.sortWith(_.radius < _.radius)

/** Retrieving the min and the max radius values */
sorted match {
case head +: _ :+ tail => (head.radius, tail.radius)
case head +: _ => (head.radius, head.radius)
case _ => throw new IllegalArgumentException("Could not determine the min and max radius from an empty sequence of entities")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ class LevelNode(override val listener: LevelNodeListener, override val levelInfo
/** The upper text */
override lazy val text: Text = new Text() {
margin = Insets(0, 0, 20, 0)
style = "-fx-fx-font-size: 20pt"
style = "-fx-font-size: 20pt"

if (levelInfo.isAvailable) {
text = "Level " + levelInfo.name
Expand Down
Loading

0 comments on commit 90af280

Please sign in to comment.