Skip to content

Instantly share code, notes, and snippets.

@FlorianCassayre
Created February 7, 2018 18:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FlorianCassayre/ef23492f52d19ba7b992d0eaf37bbed2 to your computer and use it in GitHub Desktop.
Save FlorianCassayre/ef23492f52d19ba7b992d0eaf37bbed2 to your computer and use it in GitHub Desktop.
import scala.util.Random
import Fiddle.draw._
import org.scalajs.dom.{Event, EventTarget, MouseEvent}
import scala.collection.mutable.ArrayBuffer
val square = 50
val (width, height) = (Fiddle.canvas.width, Fiddle.canvas.height)
val (mapWidth, mapHeight) = (20 * square, 20 * square)
val (borderLeft, borderRight, borderTop, borderBottom) = (0, mapWidth, 0, mapHeight)
var center = Point(mapWidth / 2, mapHeight / 2)
var (directionX: Double, directionY: Double) = (0.0, 0.0)
var allVertices: List[Vertex] = _
val player: Cell = Cell(center, 100, "rgb(255, 0, 0)")
val cells: List[Cell] = player :: (for (i <- 0 until 50) yield Cell(Point(Random.nextInt(borderRight - borderLeft + 1) + borderLeft, Random.nextInt(borderBottom - borderTop + 1) + borderTop), if (Random.nextInt(10) == 0) 25 else 5)).toList
case class Point(x: Double, y: Double) {
def isInside: Boolean = x >= borderLeft && x <= borderRight && y >= borderTop && y <= borderBottom
def distanceSquared(point: Point): Double = sq(x - point.x) + sq(y - point.y)
private def sq(x: Double): Double = x * x
}
case class Vertex(cell: Cell, position: Point, distance: Double, velocity: Double)
case class Cell(var position: Point, var size: Double, color: String = randomColor, var vertices: ArrayBuffer[Vertex] = ArrayBuffer()) {
val initialAngle = Random.nextDouble * 2 * Math.PI
for (i <- 0 until pointsCount) vertices += Vertex(this, position, size, Random.nextDouble() - 0.5)
def pointsCount: Int = Math.ceil(size).toInt
def movePoints(): Unit = {
val n = vertices.size
val copy = vertices.clone
for (i <- copy.indices) {
val limit = 10
val (current, before, after) = (vertices(i), vertices((i - 1 + n) % n), vertices((i + 1) % n))
val acc = (before.velocity + after.velocity + 8 * Math.min(Math.max((current.velocity + Random.nextDouble - 0.5) * 0.7, -limit), limit)) / 10.0
val distanceThreshold = 25
val collision = !current.position.isInside || allVertices.exists((v: Vertex) => v.cell != current.cell && current.position.distanceSquared(v.position) <= distanceThreshold)
val accAdd = if (collision) Math.min(acc, 0) - 1 else acc
val radius = (before.distance + after.distance + 8 * (9 * Math.max(current.distance + accAdd, 0) + size) / 10) / 10
val angle = 2 * i * Math.PI / n + initialAngle
vertices(i) = current.copy(position = Point(position.x + Math.cos(angle) * radius, position.y + Math.sin(angle) * radius), distance = radius, velocity = accAdd)
}
}
def draw(): Unit = {
val corner = Point(center.x - width / 2, center.y - height / 2)
movePoints()
fillStyle = color
strokeStyle = color
lineWidth = 7
beginPath
val n: Int = vertices.size
for (i <- 0 until n) {
val radius = vertices(i).distance
val angle: Double = 2 * Math.PI * i.toDouble / n + initialAngle
lineTo(position.x + Math.cos(angle) * radius - corner.x, position.y + Math.sin(angle) * radius - corner.y)
}
closePath
fill
stroke
}
}
def drawBackground(): Unit = {
val corner = Point(center.x - width / 2, center.y - height / 2)
beginPath
fillStyle = "white"
rect(0, 0, width, height)
fill
strokeStyle = "lightgray"
lineWidth = 1
beginPath
for (i <- 0 to Math.floorDiv(width, square) + 1) {
val j = i * square - (corner.x % square)
moveTo(j, 0)
lineTo(j, height)
}
for (i <- 0 to Math.floorDiv(height, square) + 1) {
val j = i * square - (corner.y % square)
moveTo(0, j)
lineTo(width, j)
}
stroke
}
def drawCells(): Unit = {
Fiddle.draw.lineCap = "round"
for (cell <- cells.sortBy(_.size)) {
cell.draw()
}
}
Fiddle.canvas.addEventListener("mousemove", (e: MouseEvent) => {
val mouse = Point(e.clientX - width / 2, e.clientY - width / 2)
val distance = Math.sqrt(mouse.distanceSquared(Point(0, 0)))
val thresh = 100
val mult = if (distance < thresh) distance / thresh else 1
directionX = mouse.x / distance * mult
directionY = mouse.y / distance * mult
})
Fiddle.schedule(5) {
val a = 1.0
player.position = player.position.copy(x = Math.max(Math.min(player.position.x + a * directionX, borderRight), borderLeft), y = Math.max(Math.min(player.position.y + a * directionY, borderBottom), borderTop))
center = player.position
drawBackground()
allVertices = cells.flatMap(_.vertices)
drawCells()
}
def randomColor = s"hsl(${Random.nextInt(360)}, 100%, 50%)"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment