Code Sketch


Hill Towns
By: Gen Artist
Category: Art
size(900, 600)
cleari()
initRandomGenerator(818828412154425840L)
val cb = canvasBounds

val n = 6
def height = random(10, 50)
val width = cb.width / n

val groundZoneHeight = 220
val mountainZoneHeight = 200
val skyZoneHeight = 400

def backdropFill = cm.linearMultipleGradient(
    0, 0, 0, cb.height,
    Seq(0, 0.25, 0.67, 0.671, 1),
    Seq(
        ColorMaker.hsl(50, 0.8, 0.1),
        ColorMaker.hsl(60, 1.00, 0.07),
        ColorMaker.hsl(80, 1.00, 0.03),
        ColorMaker.hsl(30, 0.85, 0.65),
        ColorMaker.hsl(220, 0.81, 0.40),
    ),
    false
)

def backdrop = Picture.rectangle(cb.width, cb.height)
    .withPenColor(noColor)
    .withFillColor(backdropFill)
    .thatsTranslated(-cb.width / 2, -cb.height / 2)

def mountain(h: Double) = Picture.fromVertexShape { s =>
    import s._
    beginShape()
    curveVertex(-100, 0)
    curveVertex(0, 0)
    curveVertex(width / 2, h)
    curveVertex(width, 0)
    curveVertex(width + 100, 0)
    endShape()
}.withPenColor(ColorMaker.hsl(0, 0.60, 0.15)).withFillColor(mountainFill)

def mountains(n: Int): Picture = {
    if (n == 1) {
        mountain(height)
    }
    else {
        picStack(mountain(height), mountains(n - 1).withTranslation(width, 0))
    }
}

val mountainFill = cm.linearGradient(0, 0, ColorMaker.hsl(100, 1.00, 0.03), 0, 50, ColorMaker.hsl(120, 1.00, 0.01), false)

def lights(num: Int, width: Double, height: Double) = picStack(
    for {
        n <- 1 to num
        x = randomDouble(0, width)
        y = randomDouble(0, height)
        p = Picture.circle(.8).withFillColor(cm.gold).thatsTranslated(x, y).withPenColor(noColor)
    } yield p
)

def building = {
    val w = randomDouble(20, 40)
    val h = randomDouble(15, 40)
    val w10 = w / 10
    val h10 = h / 10
    def wdelta = randomDouble(-w10, w10)
    def hdelta = randomDouble(-h10, h10)
    picStack(
        Picture.rectangle(w, h).withPenColor(noColor)
            .withFillColor(ColorMaker.hsla(50, 1.00, 0.08, 0.80)),
        Picture.rectangle(3, 3).withPenColor(noColor).withFillColor(cm.gold)
            .thatsTranslated(w / 3 + wdelta, h / 2.0 + hdelta),
        Picture.rectangle(3, 3).withPenColor(noColor).withFillColor(cm.gold)
            .thatsTranslated(2 * w / 3 + wdelta, h / 2.0 + hdelta),
    )
}

def buildings(n: Int): Picture = {
    if (n == 1) {
        building
    }
    else {
        picStack(building, buildings(n - 1).withTranslation(random(20, 40), random(-7, 8)))
    }
}

def fgbs(n: Int): Picture = {
    if (n == 1) {
        Picture.rectangle(30, 70).withPenColor(black).withFillColor(black)
    }
    else {
        picStack(
            Picture.rectangle(30, 70).withPenColor(black).withFillColor(black),
            fgbs(n - 1).thatsTranslated(50, 0)
        )
    }
}

val drawing = picStack(
    backdrop,
    mountains(6).withTranslation(-cb.width / 2, 102),
    lights(50, 100, 50).thatsTranslated(-cb.width / 2 + 20, 50),
    lights(50, 100, 50).thatsTranslated(-cb.width / 2 + 180, 60),
    lights(50, 80, 40).thatsTranslated(-cb.width / 2 + 335, 70),
    lights(80, 150, 50).thatsTranslated(-cb.width / 2 + 460, 40),
    lights(110, 180, 50).thatsTranslated(-cb.width / 2 + 670, 40),
    lights(200, cb.width - 50, 20).thatsTranslated(-cb.width / 2 + 20, -30),
    buildings(30).withTranslation(-cb.width / 2 + 40, -90),
    buildings(29).withTranslation(-cb.width / 2 + 20, -120),
    fgbs(18).withTranslation(-cb.width / 2 + 10, -cb.height / 2),
    Picture.rectangle(cb.width, 20).withPenColor(noColor).withFillColor(black)
        .thatsTranslated(-cb.width / 2, -cb.height / 2 + 30)
)

draw(drawing)