From 512f077da8afb4390db05dce44355febe6d66d42 Mon Sep 17 00:00:00 2001 From: Brandon Elam Barker Date: Sat, 13 Jan 2018 04:38:34 -0500 Subject: [PATCH] adding the .kojo extension for Scala (#3960) --- lib/linguist/languages.yml | 1 + samples/Scala/car-ride.kojo | 205 +++++++++++++++++++++++++++ samples/Scala/fib-tree.kojo | 53 +++++++ samples/Scala/turtle-controller.kojo | 84 +++++++++++ 4 files changed, 343 insertions(+) create mode 100644 samples/Scala/car-ride.kojo create mode 100644 samples/Scala/fib-tree.kojo create mode 100644 samples/Scala/turtle-controller.kojo diff --git a/lib/linguist/languages.yml b/lib/linguist/languages.yml index 78cc88fe..50854668 100755 --- a/lib/linguist/languages.yml +++ b/lib/linguist/languages.yml @@ -4176,6 +4176,7 @@ Scala: color: "#c22d40" extensions: - ".scala" + - ".kojo" - ".sbt" - ".sc" interpreters: diff --git a/samples/Scala/car-ride.kojo b/samples/Scala/car-ride.kojo new file mode 100644 index 00000000..29ba686b --- /dev/null +++ b/samples/Scala/car-ride.kojo @@ -0,0 +1,205 @@ +// Kojo examples (files ending in .kojo) are licensed under The MIT License: + +// Copyright (C) 2009-2018 Lalit Pant and the Kojo Dev Team. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +// Use the four arrow keys to avoid the blue cars +// You gain energy every second, and lose energy for every collision +// You lose if your energy drops below zero, or you hit the edges of the screen +// You win if you stay alive for a minute +switchToDefault2Perspective() +val carHeight = 100 +val markerHeight = 80 +// The collision polygon for the (very similarly sized) car images car1.png and car2.png +val carE = trans(2, 14) -> Picture { + repeat(2) { + forward(70); right(45); forward(20); right(45) + forward(18); right(45); forward(20); right(45) + } +} +def car(img: String) = PicShape.image(img, carE) + +val cars = collection.mutable.Map.empty[Picture, Vector2D] +val carSpeed = 3 +val pResponse = 3 +var pVel = Vector2D(0, 0) +var disabledTime = 0L + +val bplayer = newMp3Player +val cplayer = newMp3Player + +def createCar() { + val c = trans(cb.x + random(cb.width.toInt), cb.y + cb.height) -> car("/media/car-ride/car2.png") + draw(c) + cars += c -> Vector2D(0, -carSpeed) +} +val markers = collection.mutable.Set.empty[Picture] +def createMarker() { + val mwidth = 20 + val m = fillColor(white) * penColor(white) * + trans(cb.x + cb.width / 2 - mwidth / 2, cb.y + cb.height) -> PicShape.rect(markerHeight, mwidth) + draw(m) + markers += m +} + +cleari() +drawStage(darkGray) +val cb = canvasBounds +val player = car("/media/car-ride/car1.png") +draw(player) +drawAndHide(carE) + +timer(1200) { + createMarker() + createCar() +} + +animate { + player.moveToFront() + val enabled = epochTimeMillis - disabledTime > 300 + if (enabled) { + if (isKeyPressed(Kc.VK_LEFT)) { + pVel = Vector2D(-pResponse, 0) + player.transv(pVel) + } + if (isKeyPressed(Kc.VK_RIGHT)) { + pVel = Vector2D(pResponse, 0) + player.transv(pVel) + } + if (isKeyPressed(Kc.VK_UP)) { + pVel = Vector2D(0, pResponse) + player.transv(pVel) + if (!isMp3Playing) { + playMp3Sound("/media/car-ride/car-accel.mp3") + } + } + else { + stopMp3() + } + if (isKeyPressed(Kc.VK_DOWN)) { + pVel = Vector2D(0, -pResponse) + player.transv(pVel) + if (!bplayer.isMp3Playing) { + bplayer.playMp3Sound("/media/car-ride/car-brake.mp3") + } + } + else { + bplayer.stopMp3() + } + } + else { + player.transv(pVel) + } + + if (player.collidesWith(stageLeft) || player.collidesWith(stageRight)) { + cplayer.playMp3Sound("/media/car-ride/car-crash.mp3") + player.setOpacity(0.5) + drawMessage("You Crashed!", red) + stopAnimation() + } + else if (player.collidesWith(stageTop)) { + pVel = Vector2D(0, -pResponse) + player.transv(pVel * 2) + disabledTime = epochTimeMillis + } + else if (player.collidesWith(stageBot)) { + pVel = Vector2D(0, pResponse) + player.transv(pVel * 2) + disabledTime = epochTimeMillis + } + + cars.foreach { cv => + val (c, vel) = cv + c.moveToFront() + if (player.collidesWith(c)) { + cplayer.playMp3Sound("/media/car-ride/car-crash.mp3") + pVel = bouncePicVectorOffPic(player, pVel - vel, c) / 2 + player.transv(pVel * 3) + c.transv(-pVel * 3) + disabledTime = epochTimeMillis + updateEnergyCrash() + } + else { + val newVel = Vector2D(vel.x + randomDouble(1) / 2 - 0.25, vel.y) + cars += c -> newVel + c.transv(newVel) + } + if (c.position.y + carHeight < cb.y) { + c.erase() + cars -= c + } + } + markers.foreach { m => + m.translate(0, -carSpeed * 2) + if (m.position.y + markerHeight < cb.y) { + m.erase() + markers -= m + } + } +} + +var energyLevel = 0 +def energyText = s"Energy: $energyLevel" +val energyLabel = trans(cb.x + 10, cb.y + cb.height - 10) -> PicShape.textu(energyText, 20, blue) +def updateEnergyTick() { + energyLevel += 2 + energyLabel.update(energyText) +} +def updateEnergyCrash() { + energyLevel -= 10 + energyLabel.update(energyText) + if (energyLevel < 0) { + drawMessage("You're out of energy! You Lose", red) + stopAnimation() + } +} + +def drawMessage(m: String, c: Color) { + val te = textExtent(m, 30) + val pic = penColor(c) * trans(cb.x + (cb.width - te.width) / 2, 0) -> PicShape.text(m, 30) + draw(pic) +} + +def manageGameScore() { + var gameTime = 0 + val timeLabel = trans(cb.x + 10, cb.y + 50) -> PicShape.textu(gameTime, 20, blue) + draw(timeLabel) + draw(energyLabel) + timeLabel.forwardInputTo(stageArea) + + timer(1000) { + gameTime += 1 + timeLabel.update(gameTime) + updateEnergyTick() + + if (gameTime == 60) { + drawMessage("Time up! You Win", green) + stopAnimation() + } + } +} + +manageGameScore() +playMp3Loop("/media/car-ride/car-move.mp3") +activateCanvas() + +// Car images, via google images, from http://motor-kid.com/race-cars-top-view.html +// and www.carinfopic.com +// Car sounds from http://soundbible.com diff --git a/samples/Scala/fib-tree.kojo b/samples/Scala/fib-tree.kojo new file mode 100644 index 00000000..5e0ac3d0 --- /dev/null +++ b/samples/Scala/fib-tree.kojo @@ -0,0 +1,53 @@ +// Kojo examples (files ending in .kojo) are licensed under The MIT License: + +// Copyright (C) 2009-2018 Lalit Pant and the Kojo Dev Team. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + + +// Example from http://lalitpant.blogspot.in/2012/05/recursive-drawing-with-kojo.html +// This example is based on Kojo Pictures +val size = 100 +def S = Picture { + repeat (4) { + forward(size) + right() + } +} + +def stem = scale(0.13, 1) * penColor(noColor) * fillColor(black) -> S + +clear() +setBackground(Color(255, 170, 29)) +invisible() + +def drawing(n: Int): Picture = { + if (n == 1) + stem + else + GPics(stem, + trans(2, size-5) * brit(0.05) -> GPics( + rot(25) * scale(0.72) -> drawing(n-1), + rot(25) * trans(0, size * 0.72) * rot(-75) * scale(0.55) -> drawing(n-1) + ) + ) +} + +val pic = trans(0, -100) -> drawing(10) +draw(pic) \ No newline at end of file diff --git a/samples/Scala/turtle-controller.kojo b/samples/Scala/turtle-controller.kojo new file mode 100644 index 00000000..27f97b2a --- /dev/null +++ b/samples/Scala/turtle-controller.kojo @@ -0,0 +1,84 @@ +// Kojo examples (files ending in .kojo) are licensed under The MIT License: + +// Copyright (C) 2009-2018 Lalit Pant and the Kojo Dev Team. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +// Run this program to get basic control over the turtle via some buttons +// Useful for smaller kids + +// Change these value to tweak the behavior of the buttons +val fdStep = 50 +val fdStep2 = 10 +val rtStep = 90 +val rtStep2 = 10 +val bgColor = white +val sBgColor = "white" +// End tweak region + +clear() +clearOutput() +beamsOn() +val width = canvasBounds.width +val height = canvasBounds.height + +setBackground(bgColor) +setPenColor(purple) + +def action(code: String) { + interpret(code); println(code) +} + +val cmd = Map( + "forward1" -> s"forward($fdStep)", + "forward2" -> s"forward($fdStep2)", + "hop1" -> s"hop($fdStep)", + "hop2" -> s"hop($fdStep2)", + "right1" -> s"right($rtStep)", + "right2" -> s"right($rtStep2)", + "left1" -> s"left($rtStep)", + "left2" -> s"left($rtStep2)" +) + +def eraseCmds(n: Int) = + s"saveStyle(); setPenColor($sBgColor); setPenThickness(4); back($n); restoreStyle()" + +def button(forcmd: String) = PicShape.button(cmd(forcmd)) { action(cmd(forcmd)) } + +val panel = trans(-width / 2, -height / 2) * scale(1.4) -> VPics( + HPics( + button("left2"), + button("forward2"), + button("right2"), + button("hop2"), + PicShape.button(s"erase($fdStep2)") { action(eraseCmds(fdStep2)) } + ), + HPics( + button("left1"), + button("forward1"), + button("right1"), + button("hop1"), + PicShape.button(s"erase($fdStep)") { action(eraseCmds(fdStep)) } + ) +) + +draw(panel) +println("// Paste the generated program below into the script editor") +println("// and run it -- to reproduce your drawing") +println("clear()")