Created
February 7, 2018 18:19
-
-
Save FlorianCassayre/ef23492f52d19ba7b992d0eaf37bbed2 to your computer and use it in GitHub Desktop.
Agar.io Cell Effect https://scalafiddle.io/sf/FMoNM7c/0
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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