Use modern API of Kotlin 1.3 in JS canvas examples

This commit is contained in:
Ilya Gorbunov
2018-09-18 02:26:36 +03:00
parent 24e7bafa7d
commit 0ca59b3a40
4 changed files with 112 additions and 137 deletions
+30 -40
View File
@@ -1,13 +1,15 @@
/* /*
In this example strange creatures are watching the kotlin logo. You can drag'n'drop them as well as the logo. * In this example strange creatures are watching the kotlin logo.
Doubleclick to add more creatures but be careful. They may be watching you! * You can drag'n'drop them as well as the logo. Doubleclick to add
*/ * more creatures but be careful. They may be watching you!
*/
package creatures package creatures
import jquery.* import jquery.*
import kotlin.js.*
import kotlin.browser.window
import org.w3c.dom.* import org.w3c.dom.*
import kotlin.browser.document
import kotlin.browser.window
import kotlin.math.*
fun getImage(path: String): HTMLImageElement { fun getImage(path: String): HTMLImageElement {
@@ -30,7 +32,8 @@ abstract class Shape() {
abstract fun draw(state: CanvasState) abstract fun draw(state: CanvasState)
// these two abstract methods defines that our shapes can be dragged // these two abstract methods defines that our shapes can be dragged
abstract operator fun contains(mousePos: Vector): Boolean operator abstract fun contains(mousePos: Vector): Boolean
abstract var pos: Vector abstract var pos: Vector
var selected: Boolean = false var selected: Boolean = false
@@ -57,9 +60,9 @@ abstract class Shape() {
val Kotlin = Logo(v(250.0, 75.0)) val Kotlin = Logo(v(250.0, 75.0))
class Logo(override var pos: Vector) : Shape() { class Logo(override var pos: Vector) : Shape() {
val relSize: Double = 0.25 val relSize: Double = 0.15
val shadowOffset = v(-3.0, 3.0) val shadowOffset = v(-3.0, 3.0)
val imageSize = v(377.0, 393.0) val imageSize = v(200.0, 200.0)
var size: Vector = imageSize * relSize var size: Vector = imageSize * relSize
// get-only properties like this saves you lots of typing and are very expressive // get-only properties like this saves you lots of typing and are very expressive
val position: Vector val position: Vector
@@ -69,7 +72,7 @@ class Logo(override var pos: Vector) : Shape() {
fun drawLogo(state: CanvasState) { fun drawLogo(state: CanvasState) {
size = imageSize * (state.size.x / imageSize.x) * relSize size = imageSize * (state.size.x / imageSize.x) * relSize
// getKotlinLogo() is a 'magic' function here defined only for purposes of demonstration but in fact it just find an element containing the logo // getKotlinLogo() is a 'magic' function here defined only for purposes of demonstration but in fact it just find an element containing the logo
state.context.drawImage(getImage("http://kotlin-demo.jetbrains.com/static/images/kotlinlogowobackground.png"), 0.0, 0.0, state.context.drawImage(getImage("http://try.kotlinlang.org/static/images/canvas/Kotlin-logo.png"), 0.0, 0.0,
imageSize.x, imageSize.y, imageSize.x, imageSize.y,
position.x, position.y, position.x, position.y,
size.x, size.y) size.x, size.y)
@@ -82,8 +85,7 @@ class Logo(override var pos: Vector) : Shape() {
context.shadowed(shadowOffset, 0.2) { context.shadowed(shadowOffset, 0.2) {
drawLogo(state) drawLogo(state)
} }
} } else {
else {
drawLogo(state) drawLogo(state)
} }
} }
@@ -114,7 +116,7 @@ class Creature(override var pos: Vector, val state: CanvasState) : Shape() {
// defining more nice extension functions // defining more nice extension functions
fun CanvasRenderingContext2D.circlePath(position: Vector, rad: Double) { fun CanvasRenderingContext2D.circlePath(position: Vector, rad: Double) {
arc(position.x, position.y, rad, 0.0, 2 * Math.PI, false) arc(position.x, position.y, rad, 0.0, 2 * PI, false)
} }
//notice we can use an extension function we just defined inside another extension function //notice we can use an extension function we just defined inside another extension function
@@ -128,8 +130,7 @@ class Creature(override var pos: Vector, val state: CanvasState) : Shape() {
val context = state.context val context = state.context
if (!selected) { if (!selected) {
drawCreature(context) drawCreature(context)
} } else {
else {
drawCreatureWithShadow(context) drawCreatureWithShadow(context)
} }
} }
@@ -156,7 +157,7 @@ class Creature(override var pos: Vector, val state: CanvasState) : Shape() {
val tailDirection = -directionToLogo val tailDirection = -directionToLogo
val tailPos = position + tailDirection * radius * 1.0 val tailPos = position + tailDirection * radius * 1.0
val tailSize = radius * 1.6 val tailSize = radius * 1.6
val angle = Math.PI / 6.0 val angle = PI / 6.0
val p1 = tailPos + tailDirection.rotatedBy(angle) * tailSize val p1 = tailPos + tailDirection.rotatedBy(angle) * tailSize
val p2 = tailPos + tailDirection.rotatedBy(-angle) * tailSize val p2 = tailPos + tailDirection.rotatedBy(-angle) * tailSize
val middlePoint = position + tailDirection * radius * 1.0 val middlePoint = position + tailDirection * radius * 1.0
@@ -189,13 +190,13 @@ class Creature(override var pos: Vector, val state: CanvasState) : Shape() {
} }
class CanvasState(val canvas: HTMLCanvasElement) { class CanvasState(val canvas: HTMLCanvasElement) {
var width = canvas.width.toDouble() var width = canvas.width
var height = canvas.height.toDouble() var height = canvas.height
val size: Vector val size: Vector
get() = v(width, height) get() = v(width.toDouble(), height.toDouble())
val context = creatures.context val context = creatures.context
var valid = false var valid = false
var shapes = ArrayList<Shape>() var shapes = mutableListOf<Shape>()
var selection: Shape? = null var selection: Shape? = null
var dragOff = Vector() var dragOff = Vector()
val interval = 1000 / 30 val interval = 1000 / 30
@@ -246,7 +247,7 @@ class CanvasState(val canvas: HTMLCanvasElement) {
var element: HTMLElement? = canvas var element: HTMLElement? = canvas
while (element != null) { while (element != null) {
val el: HTMLElement = element val el: HTMLElement = element
offset += Vector(el.offsetLeft, el.offsetTop) offset += Vector(el.offsetLeft.toDouble(), el.offsetTop.toDouble())
element = el.offsetParent as HTMLElement? element = el.offsetParent as HTMLElement?
} }
return Vector(e.pageX, e.pageY) - offset return Vector(e.pageX, e.pageY) - offset
@@ -259,17 +260,17 @@ class CanvasState(val canvas: HTMLCanvasElement) {
fun clear() { fun clear() {
context.fillStyle = "#FFFFFF" context.fillStyle = "#FFFFFF"
context.fillRect(0.0, 0.0, width, height) context.fillRect(0.0, 0.0, width.toDouble(), height.toDouble())
context.strokeStyle = "#000000" context.strokeStyle = "#000000"
context.lineWidth = 4.0 context.lineWidth = 4.0
context.strokeRect(0.0, 0.0, width, height) context.strokeRect(0.0, 0.0, width.toDouble(), height.toDouble())
} }
fun draw() { fun draw() {
if (valid) return if (valid) return
clear() clear()
for (shape in shapes.reversed()) { for (shape in shapes.asReversed()) {
shape.draw(this) shape.draw(this)
} }
Kotlin.draw(this) Kotlin.draw(this)
@@ -278,7 +279,7 @@ class CanvasState(val canvas: HTMLCanvasElement) {
} }
class RadialGradientGenerator(val context: CanvasRenderingContext2D) { class RadialGradientGenerator(val context: CanvasRenderingContext2D) {
val gradients = ArrayList<Array<out Pair<Double, String>>>() val gradients = mutableListOf<Array<out Pair<Double, String>>>()
var current = 0 var current = 0
fun newColorStops(vararg colorStops: Pair<Double, String>) { fun newColorStops(vararg colorStops: Pair<Double, String>) {
@@ -302,29 +303,26 @@ class RadialGradientGenerator(val context: CanvasRenderingContext2D) {
} }
fun v(x: Double, y: Double) = Vector(x, y) fun v(x: Double, y: Double) = Vector(x, y)
fun v(x: Int, y: Int) = Vector(x.toDouble(), y.toDouble())
class Vector(val x: Double = 0.0, val y: Double = 0.0) { class Vector(val x: Double = 0.0, val y: Double = 0.0) {
constructor(x: Int, y: Int) : this(x.toDouble(), y.toDouble())
operator fun plus(v: Vector) = v(x + v.x, y + v.y) operator fun plus(v: Vector) = v(x + v.x, y + v.y)
operator fun unaryMinus() = v(-x, -y) operator fun unaryMinus() = v(-x, -y)
operator fun minus(v: Vector) = v(x - v.x, y - v.y) operator fun minus(v: Vector) = v(x - v.x, y - v.y)
operator fun times(koef: Double) = v(x * koef, y * koef) operator fun times(koef: Double) = v(x * koef, y * koef)
infix fun distanceTo(v: Vector) = Math.sqrt((this - v).sqr) infix fun distanceTo(v: Vector) = sqrt((this - v).sqr)
fun rotatedBy(theta: Double): Vector { fun rotatedBy(theta: Double): Vector {
val sin = Math.sin(theta) val sin = sin(theta)
val cos = Math.cos(theta) val cos = cos(theta)
return v(x * cos - y * sin, x * sin + y * cos) return v(x * cos - y * sin, x * sin + y * cos)
} }
fun isInRect(topLeft: Vector, size: Vector) = (x >= topLeft.x) && (x <= topLeft.x + size.x) && fun isInRect(topLeft: Vector, size: Vector) = (x >= topLeft.x) && (x <= topLeft.x + size.x) &&
(y >= topLeft.y) && (y <= topLeft.y + size.y) (y >= topLeft.y) && (y <= topLeft.y + size.y)
val sqr: Double val sqr: Double
get() = x * x + y * y get() = x * x + y * y
val normalized: Vector val normalized: Vector
get() = this * (1.0 / Math.sqrt(sqr)) get() = this * (1.0 / sqrt(sqr))
} }
fun main(args: Array<String>) { fun main(args: Array<String>) {
@@ -340,11 +338,3 @@ fun main(args: Array<String>) {
} }
} }
fun <T> List<T>.reversed(): List<T> {
val result = ArrayList<T>()
var i = size
while (i > 0) {
result.add(get(--i))
}
return result
}
@@ -6,10 +6,12 @@ Note that only a subset of the api is supported for now.
package fancylines package fancylines
import kotlin.js.*
import kotlin.browser.window
import org.w3c.dom.*
import jquery.* import jquery.*
import org.w3c.dom.CanvasRenderingContext2D
import org.w3c.dom.HTMLCanvasElement
import kotlin.browser.document
import kotlin.browser.window
import kotlin.random.*
fun main(args: Array<String>) { fun main(args: Array<String>) {
jq { jq {
@@ -26,25 +28,27 @@ class FancyLines() {
val context = canvas.getContext("2d") as CanvasRenderingContext2D val context = canvas.getContext("2d") as CanvasRenderingContext2D
val height = canvas.height.toDouble() val height = canvas.height.toDouble()
val width = canvas.width.toDouble() val width = canvas.width.toDouble()
var x = width * Math.random() fun nextX() = Random.nextDouble(width)
var y = height * Math.random() fun nextY() = Random.nextDouble(height)
var hue = 0; var x = nextX()
var y = nextY()
var hue = 0
fun line() { fun line() {
context.save(); context.save();
context.beginPath(); context.beginPath();
context.lineWidth = 20.0 * Math.random(); context.lineWidth = Random.nextDouble(20.0)
context.moveTo(x, y); context.moveTo(x, y);
x = width * Math.random(); x = nextX()
y = height * Math.random(); y = nextY()
context.bezierCurveTo(width * Math.random(), height * Math.random(), context.bezierCurveTo(nextX(), nextY(),
width * Math.random(), height * Math.random(), x, y); nextX(), nextY(), x, y)
hue += (Math.random() * 10).toInt(); hue += Random.nextInt(10)
context.strokeStyle = "hsl($hue, 50%, 50%)"; context.strokeStyle = "hsl($hue, 50%, 50%)";
@@ -3,10 +3,13 @@
*/ */
package hello package hello
import kotlin.js.*
import kotlin.browser.window
import org.w3c.dom.*
import jquery.* import jquery.*
import org.w3c.dom.CanvasRenderingContext2D
import org.w3c.dom.HTMLCanvasElement
import kotlin.browser.document
import kotlin.browser.window
import kotlin.random.*
import kotlin.math.*
val canvas: HTMLCanvasElement val canvas: HTMLCanvasElement
get() { get() {
@@ -19,21 +22,21 @@ val context: CanvasRenderingContext2D
} }
val width: Double val width: Int
get() { get() {
return canvas.width.toDouble() return canvas.width
} }
val height: Double val height: Int
get() { get() {
return canvas.height.toDouble() return canvas.height
} }
// class representing a floating text // class representing a floating text
class HelloKotlin() { class HelloKotlin() {
var relX = 0.2 + 0.2 * Math.random() var relX = Random.nextDouble(0.2, 0.4)
var relY = 0.4 + 0.2 * Math.random() var relY = Random.nextDouble(0.4, 0.6)
val absX: Double val absX: Double
get() = (relX * width) get() = (relX * width)
@@ -66,28 +69,25 @@ class HelloKotlin() {
fun move() { fun move() {
val relTextWidth = textWidthInPixels / width val relTextWidth = textWidthInPixels / width
if (relX > (1.0 - relTextWidth - relXVelocity.abs) || relX < relXVelocity.abs) { if (relX > (1.0 - relTextWidth - relXVelocity.absoluteValue) || relX < relXVelocity.absoluteValue) {
relXVelocity *= -1 relXVelocity *= -1
} }
val relTextHeight = textHeightInPixels / height val relTextHeight = textHeightInPixels / height
if (relY > (1.0 - relYVelocity.abs) || relY < relYVelocity.abs + relTextHeight) { if (relY > (1.0 - relYVelocity.absoluteValue) || relY < relYVelocity.absoluteValue + relTextHeight) {
relYVelocity *= -1 relYVelocity *= -1
} }
relX += relXVelocity relX += relXVelocity
relY += relYVelocity relY += relYVelocity
} }
fun randomVelocity() = 0.03 * Math.random() * (if (Math.random() < 0.5) 1 else -1) fun randomVelocity() = Random.nextDouble(-0.03, 0.03) // same as 0.03 * Math.random() * (if (Math.random() < 0.5) 1 else -1)
val Double.abs: Double
get() = if (this > 0) this else -this
} }
fun renderBackground() { fun renderBackground() {
context.save() context.save()
context.fillStyle = "#5C7EED" context.fillStyle = "#5C7EED"
context.fillRect(0.0, 0.0, width, height) context.fillRect(0.0, 0.0, width.toDouble(), height.toDouble())
context.restore() context.restore()
} }
@@ -107,3 +107,5 @@ fun main(args: Array<String>) {
}, interval) }, interval)
} }
} }
@@ -1,9 +1,16 @@
/*
* In this example you can see a crossroads. Traffic light change color by timer,
* but you can change it manually using controls at the right part of screen.
*/
package traffic package traffic
import kotlin.js.*
import kotlin.browser.window
import org.w3c.dom.*
import jquery.* import jquery.*
import org.w3c.dom.*
import kotlin.browser.document
import kotlin.browser.window
import kotlin.math.*
import kotlin.random.*
import kotlin.js.Date
fun getImage(path: String): HTMLImageElement { fun getImage(path: String): HTMLImageElement {
val image = window.document.createElement("img") as HTMLImageElement val image = window.document.createElement("img") as HTMLImageElement
@@ -22,22 +29,10 @@ val context: CanvasRenderingContext2D
} }
val PATH_TO_IMAGES = "http://kotlin-demo.jetbrains.com/static/images/canvas/" val PATH_TO_IMAGES = "http://try.kotlinlang.org/static/images/canvas/"
var _state: CanvasState? = null val state: CanvasState by lazy { CanvasState(canvas) }
val state: CanvasState
get() {
if (_state == null) {
_state = CanvasState(canvas)
}
return _state!!
}
val colors: Colors
get() {
return Colors()
}
var trafficLightUp = TrafficLight(v(180.0, 181.0), "up", "red") var trafficLightUp = TrafficLight(v(180.0, 181.0), "up", "red")
var trafficLightDown = TrafficLight(v(100.0, 77.0), "down", "red") var trafficLightDown = TrafficLight(v(100.0, 77.0), "down", "red")
@@ -63,7 +58,6 @@ fun main(args: Array<String>) {
} }
fun v(x: Double, y: Double) = Vector(x, y) fun v(x: Double, y: Double) = Vector(x, y)
fun v(x: Int, y: Int) = Vector(x, y)
class Image(val src: String, override var pos: Vector, var imageSize: Vector) : Shape() { class Image(val src: String, override var pos: Vector, var imageSize: Vector) : Shape() {
override fun draw() { override fun draw() {
@@ -73,7 +67,7 @@ class Image(val src: String, override var pos: Vector, var imageSize: Vector) :
imageSize.x, imageSize.y) imageSize.x, imageSize.y)
} }
operator fun contains(mousePos: Vector): Boolean = mousePos.isInRect(pos, imageSize) fun contains(mousePos: Vector): Boolean = mousePos.isInRect(pos, imageSize)
} }
class Button(val src: String, override var pos: Vector, var imageSize: Vector) : Shape() { class Button(val src: String, override var pos: Vector, var imageSize: Vector) : Shape() {
@@ -88,16 +82,14 @@ class Button(val src: String, override var pos: Vector, var imageSize: Vector) :
pos.x, pos.y, pos.x, pos.y,
imageSize.x, imageSize.y) imageSize.x, imageSize.y)
} }
} } else if (isMouseDown) {
else if (isMouseDown) {
state.context.shadowed(v(-3.0, 3.0), 0.8) { state.context.shadowed(v(-3.0, 3.0), 0.8) {
state.context.drawImage(getImage(src), 0.0, 0.0, state.context.drawImage(getImage(src), 0.0, 0.0,
imageSize.x, imageSize.y, imageSize.x, imageSize.y,
pos.x, pos.y, pos.x, pos.y,
imageSize.x, imageSize.y) imageSize.x, imageSize.y)
} }
} } else {
else {
state.context.drawImage(getImage(src), 0.0, 0.0, state.context.drawImage(getImage(src), 0.0, 0.0,
imageSize.x, imageSize.y, imageSize.x, imageSize.y,
pos.x, pos.y, pos.x, pos.y,
@@ -129,14 +121,14 @@ class Border() : Shape() {
override var pos = Vector(4.0, 4.0); override var pos = Vector(4.0, 4.0);
override fun draw() { override fun draw() {
state.context.fillStyle = colors.white state.context.fillStyle = Colors.white
state.context.fillRect(2.0, 4.0, 10.0, 292.0) state.context.fillRect(2.0, 4.0, 10.0, 292.0)
state.context.fillRect(330.0, 4.0, 370.0, 292.0) state.context.fillRect(330.0, 4.0, 370.0, 292.0)
state.context.fillRect(2.0, 2.0, 330.0, 10.0) state.context.fillRect(2.0, 2.0, 330.0, 10.0)
state.context.fillRect(4.0, 265.0, 340.0, 380.0) state.context.fillRect(4.0, 265.0, 340.0, 380.0)
state.context.strokeStyle = colors.black state.context.strokeStyle = Colors.black
state.context.lineWidth = 4.0 state.context.lineWidth = 4.0
state.context.strokeRect(0.0, 0.0, state.width, state.height) state.context.strokeRect(0.0, 0.0, state.width.toDouble(), state.height.toDouble())
} }
} }
@@ -149,7 +141,7 @@ class Timer(override var pos: Vector) : Shape() {
override fun draw() { override fun draw() {
timeLeftForChangeColor = ("" + (timerLength - (Date().getTime() - timeStartLastChangeColor) / 1000)).get(0) timeLeftForChangeColor = ("" + (timerLength - (Date().getTime() - timeStartLastChangeColor) / 1000)).get(0)
state.context.font = "bold 9px Arial, serif" state.context.font = "bold 9px Arial, serif"
state.context.fillStyle = colors.black state.context.fillStyle = Colors.black
state.context.fillText("" + timeLeftForChangeColor, pos.x, pos.y) state.context.fillText("" + timeLeftForChangeColor, pos.x, pos.y)
} }
@@ -160,7 +152,7 @@ class Timer(override var pos: Vector) : Shape() {
} }
//Colors constants //Colors constants
class Colors() { object Colors {
val black: String = "#000000" val black: String = "#000000"
val white = "#FFFFFF" val white = "#FFFFFF"
val grey = "#C0C0C0" val grey = "#C0C0C0"
@@ -170,12 +162,12 @@ class Colors() {
} }
class TrafficLight(override var pos: Vector, val direction: String, val startColor: String) : Shape() { class TrafficLight(override var pos: Vector, val direction: String, val startColor: String) : Shape() {
val list = ArrayList<TrafficLightItem>() val list = mutableListOf<TrafficLightItem>()
var size = Vector(27.0, 34.0); var size = Vector(27.0, 34.0);
var timer = Timer(Vector(pos.x + 6, pos.y + 12)) var timer = Timer(Vector(pos.x + 6, pos.y + 12))
var currentColor = startColor; var currentColor = startColor;
var isForceColorChange = false var isForceColorChange = false
private var changeColorForward = (startColor == "red") var shouldChangeColorForward = (startColor == "red")
init { init {
list.add(TrafficLightItem(v(pos.x, pos.y), PATH_TO_IMAGES + "red_color.png")) list.add(TrafficLightItem(v(pos.x, pos.y), PATH_TO_IMAGES + "red_color.png"))
@@ -211,11 +203,11 @@ class TrafficLight(override var pos: Vector, val direction: String, val startCol
} }
fun changeColor() { fun changeColor() {
if (changeColorForward) changeColorForward() else changeColorBackward() if (shouldChangeColorForward) changeColorForward() else changeColorBackward()
} }
fun changeColorForward() { fun changeColorForward() {
changeColorForward = false shouldChangeColorForward = false
currentColor = "yellow" currentColor = "yellow"
window.setTimeout({ window.setTimeout({
if (!isForceColorChange) timer.resetTimer() else isForceColorChange = false if (!isForceColorChange) timer.resetTimer() else isForceColorChange = false
@@ -226,7 +218,7 @@ class TrafficLight(override var pos: Vector, val direction: String, val startCol
fun changeColorBackward() { fun changeColorBackward() {
changeColorForward = true shouldChangeColorForward = true
currentColor = "green_flash" currentColor = "green_flash"
window.setTimeout({ window.setTimeout({
currentColor = "yellow" currentColor = "yellow"
@@ -261,12 +253,10 @@ class TrafficLightItem(override var pos: Vector, val imageSrc: String) : Shape()
if (countOfFlash > 6) { if (countOfFlash > 6) {
isFlashNow = false isFlashNow = false
countOfFlash = 0 countOfFlash = 0
} } else {
else {
countOfFlash++ countOfFlash++
} }
} } else {
else {
state.context.drawImage(getImage(PATH_TO_IMAGES + "green_color.png"), 0.0, 0.0, state.context.drawImage(getImage(PATH_TO_IMAGES + "green_color.png"), 0.0, 0.0,
imageSize.x, imageSize.y, imageSize.x, imageSize.y,
pos.x, pos.y, pos.x, pos.y,
@@ -274,13 +264,11 @@ class TrafficLightItem(override var pos: Vector, val imageSrc: String) : Shape()
if (countOfFlash > 6) { if (countOfFlash > 6) {
isFlashNow = true isFlashNow = true
countOfFlash = 0 countOfFlash = 0
} } else {
else {
countOfFlash++ countOfFlash++
} }
} }
} } else {
else {
state.context.drawImage(getImage(imageSrc), 0.0, 0.0, state.context.drawImage(getImage(imageSrc), 0.0, 0.0,
imageSize.x, imageSize.y, imageSize.x, imageSize.y,
pos.x, pos.y, pos.x, pos.y,
@@ -292,7 +280,8 @@ class TrafficLightItem(override var pos: Vector, val imageSrc: String) : Shape()
class Car(override var pos: Vector, val direction: String, val color: String) : Shape() { class Car(override var pos: Vector, val direction: String, val color: String) : Shape() {
val imageSize = v(25.0, 59.0) val imageSize = v(25.0, 59.0)
var speed = getRandomArbitary(2, 10); fun randomSpeed() = Random.nextDouble(2.0, 10.0)
var speed = randomSpeed()
override fun draw() { override fun draw() {
if (direction == "up" || direction == "down") { if (direction == "up" || direction == "down") {
@@ -302,21 +291,18 @@ class Car(override var pos: Vector, val direction: String, val color: String) :
imageSize.x, imageSize.y) imageSize.x, imageSize.y)
if ((!isNearStopLine()) || (trafficLightUp.canMove() && isNearStopLine()) ) { if ((!isNearStopLine()) || (trafficLightUp.canMove() && isNearStopLine()) ) {
move() move()
} else {
speed = randomSpeed()
} }
else { } else {
speed = getRandomArbitary(2, 10)
}
}
else {
state.context.drawImage(getImage(PATH_TO_IMAGES + color + "_car.png"), 0.0, 0.0, state.context.drawImage(getImage(PATH_TO_IMAGES + color + "_car.png"), 0.0, 0.0,
imageSize.y, imageSize.x, imageSize.y, imageSize.x,
pos.x, pos.y, pos.x, pos.y,
imageSize.y, imageSize.x) imageSize.y, imageSize.x)
if ((!isNearStopLine()) || (trafficLightLeft.canMove() && isNearStopLine()) ) { if ((!isNearStopLine()) || (trafficLightLeft.canMove() && isNearStopLine()) ) {
move() move()
} } else {
else { speed = randomSpeed()
speed = getRandomArbitary(2, 10)
} }
} }
@@ -368,13 +354,13 @@ class Map(override var pos: Vector) : Shape() {
class CanvasState(val canvas: HTMLCanvasElement) { class CanvasState(val canvas: HTMLCanvasElement) {
val context = traffic.context val context = traffic.context
var shapes = ArrayList<Shape>() var shapes = mutableListOf<Shape>()
var width = canvas.width.toDouble() var width = canvas.width
var height = canvas.height.toDouble() var height = canvas.height
val size: Vector val size: Vector
get() = v(width, height) get() = v(width.toDouble(), height.toDouble())
fun addShape(shape: Shape) { fun addShape(shape: Shape) {
shapes.add(shape) shapes.add(shape)
@@ -414,7 +400,6 @@ class CanvasState(val canvas: HTMLCanvasElement) {
val mousePos = mousePos(it) val mousePos = mousePos(it)
for (shape in shapes) { for (shape in shapes) {
if (shape is Button && mousePos in shape) { if (shape is Button && mousePos in shape) {
val name = shape.src
shape.mouseOver() shape.mouseOver()
} }
} }
@@ -440,7 +425,7 @@ class CanvasState(val canvas: HTMLCanvasElement) {
var element: HTMLElement? = canvas var element: HTMLElement? = canvas
while (element != null) { while (element != null) {
val el: HTMLElement = element val el: HTMLElement = element
offset += Vector(el.offsetLeft, el.offsetTop) offset += Vector(el.offsetLeft.toDouble(), el.offsetTop.toDouble())
element = el.offsetParent as HTMLElement? element = el.offsetParent as HTMLElement?
} }
return Vector(e.pageX, e.pageY) - offset return Vector(e.pageX, e.pageY) - offset
@@ -454,8 +439,8 @@ class CanvasState(val canvas: HTMLCanvasElement) {
} }
fun clear() { fun clear() {
context.fillStyle = colors.white context.fillStyle = Colors.white
context.fillRect(0.0, 0.0, width, height) context.fillRect(0.0, 0.0, width.toDouble(), height.toDouble())
} }
} }
@@ -484,28 +469,22 @@ abstract class Shape() {
} }
class Vector(val x: Double = 0.0, val y: Double = 0.0) { class Vector(val x: Double = 0.0, val y: Double = 0.0) {
constructor(x: Int, y: Int) : this(x.toDouble(), y.toDouble())
operator fun plus(v: Vector) = v(x + v.x, y + v.y) operator fun plus(v: Vector) = v(x + v.x, y + v.y)
operator fun unaryMinus() = v(-x, -y)
operator fun minus(v: Vector) = v(x - v.x, y - v.y) operator fun minus(v: Vector) = v(x - v.x, y - v.y)
operator fun times(koef: Double) = v(x * koef, y * koef) operator fun times(koef: Double) = v(x * koef, y * koef)
fun distanceTo(v: Vector) = Math.sqrt((this - v).sqr) fun distanceTo(v: Vector) = sqrt((this - v).sqr)
fun rotatedBy(theta: Double): Vector { fun rotatedBy(theta: Double): Vector {
val sin = Math.sin(theta) val sin = sin(theta)
val cos = Math.cos(theta) val cos = cos(theta)
return v(x * cos - y * sin, x * sin + y * cos) return v(x * cos - y * sin, x * sin + y * cos)
} }
fun isInRect(topLeft: Vector, size: Vector) = (x >= topLeft.x) && (x <= topLeft.x + size.x) && fun isInRect(topLeft: Vector, size: Vector) = (x >= topLeft.x) && (x <= topLeft.x + size.x) &&
(y >= topLeft.y) && (y <= topLeft.y + size.y) (y >= topLeft.y) && (y <= topLeft.y + size.y)
val sqr: Double val sqr: Double
get() = x * x + y * y get() = x * x + y * y
val normalized: Vector val normalized: Vector
get() = this * (1.0 / Math.sqrt(sqr)) get() = this * (1.0 / sqrt(sqr))
} }
fun getRandomArbitary(min: Int, max: Int): Double {
return Math.random() * (max - min) + min;
}