Code Sketch


yadnesh
By: Mhalsakant School
Category: Programming
// ============================================================
// ? ULTRA CRICKET 2.5D - KOJO + SCALA
// ============================================================
//
// SPACE = Bowl
// W     = Pull Shot
// S     = Straight Drive
// A     = Cover Drive
// D     = Defence
// Q     = Lofted Shot
// R     = Restart
// P     = Pause
//
// ============================================================

cleari()
drawStage(ColorMaker.darkGreen)
disablePanAndZoom()

val cb = canvasBounds

// ============================================================
// GAME STATE
// ============================================================

var score = 0
var wickets = 0
var balls = 0

val totalBalls = 30
val maxWickets = 5

var active = false
var hit = false
var shotPlayed = false
var gameOver = false
var paused = false

var message = "SPACE = BOWL"
var scoreText = "SCORE 0/0   OVER 0.0"

// ============================================================
// STADIUM
// ============================================================

val stadium = Picture.circle(650)
stadium.setFillColor(ColorMaker.green)
stadium.setPosition(
  cb.x + cb.width / 2,
  cb.y + 250
)
draw(stadium)

val boundary = Picture.circle(540)
boundary.setFillColor(ColorMaker.darkGreen)
boundary.setPosition(
  cb.x + cb.width / 2,
  cb.y + 250
)
draw(boundary)

// ============================================================
// PERSPECTIVE PITCH
// ============================================================

val pitch = Picture.rectangle(150, 500)
pitch.setFillColor(ColorMaker.tan)
pitch.setPosition(
  cb.x + cb.width / 2 - 75,
  cb.y + 30
)
draw(pitch)

// Pitch centre

val centreLine = Picture.rectangle(4, 500)
centreLine.setFillColor(ColorMaker.lightGray)
centreLine.setPosition(
  cb.x + cb.width / 2 - 2,
  cb.y + 30
)
draw(centreLine)

// ============================================================
// CREASES
// ============================================================

val topCrease = Picture.rectangle(150, 5)
topCrease.setFillColor(ColorMaker.white)
topCrease.setPosition(
  cb.x + cb.width / 2 - 75,
  cb.y + 90
)
draw(topCrease)

val bottomCrease = Picture.rectangle(150, 5)
bottomCrease.setFillColor(ColorMaker.white)
bottomCrease.setPosition(
  cb.x + cb.width / 2 - 75,
  cb.y + 410
)
draw(bottomCrease)

// ============================================================
// STUMPS
// ============================================================

val stump1 = Picture.rectangle(6, 45)
stump1.setFillColor(ColorMaker.saddleBrown)
stump1.setPosition(
  cb.x + cb.width / 2 - 15,
  cb.y + 50
)
draw(stump1)

val stump2 = Picture.rectangle(6, 45)
stump2.setFillColor(ColorMaker.saddleBrown)
stump2.setPosition(
  cb.x + cb.width / 2 - 3,
  cb.y + 50
)
draw(stump2)

val stump3 = Picture.rectangle(6, 45)
stump3.setFillColor(ColorMaker.saddleBrown)
stump3.setPosition(
  cb.x + cb.width / 2 + 9,
  cb.y + 50
)
draw(stump3)

// ============================================================
// BATSMAN SHADOW
// ============================================================

val batsmanShadow = Picture.ellipse(45, 15)
batsmanShadow.setFillColor(ColorMaker.black)
batsmanShadow.setPosition(
  cb.x + cb.width / 2,
  cb.y + 85
)
draw(batsmanShadow)

// ============================================================
// BATSMAN
// ============================================================

class Batsman {

  val body = Picture.rectangle(25, 50)
  body.setFillColor(ColorMaker.blue)

  val head = Picture.circle(22)
  head.setFillColor(ColorMaker.saddleBrown)
  head.setPosition(0, -35)

  val helmet = Picture.circle(25)
  helmet.setFillColor(ColorMaker.black)
  helmet.setPosition(0, -37)

  val bat = Picture.rectangle(8, 65)
  bat.setFillColor(ColorMaker.saddleBrown)
  bat.setPosition(-18, -20)

  val pic = picBatch(
    body,
    head,
    helmet,
    bat
  )

  pic.setPosition(
    cb.x + cb.width / 2 - 12,
    cb.y + 75
  )

  var swinging = false
  var timer = 0
  var swing = ""

  def swingBat(kind: String): Unit = {

    if (!swinging) {

      swinging = true
      timer = 8
      swing = kind

      if (kind == "pull") {
        pic.rotate(-55)
      }

      if (kind == "straight") {
        pic.rotate(45)
      }

      if (kind == "cover") {
        pic.rotate(-40)
      }

      if (kind == "defence") {
        pic.rotate(15)
      }

      if (kind == "loft") {
        pic.rotate(70)
      }
    }
  }

  def update(): Unit = {

    if (timer > 0) {

      timer -= 1

      if (timer == 0) {

        if (swing == "pull") {
          pic.rotate(55)
        }

        if (swing == "straight") {
          pic.rotate(-45)
        }

        if (swing == "cover") {
          pic.rotate(40)
        }

        if (swing == "defence") {
          pic.rotate(-15)
        }

        if (swing == "loft") {
          pic.rotate(-70)
        }

        swinging = false
      }
    }
  }
}

val batsman = new Batsman()
draw(batsman.pic)

// ============================================================
// BALL + SHADOW
// ============================================================

val ballShadow = Picture.ellipse(22, 8)
ballShadow.setFillColor(ColorMaker.black)

ballShadow.setPosition(
  cb.x + cb.width / 2,
  cb.y + cb.height - 100
)

draw(ballShadow)

val ball = Picture.circle(12)
ball.setFillColor(ColorMaker.white)

ball.setPosition(
  cb.x + cb.width / 2,
  cb.y + cb.height - 100
)

draw(ball)

// ============================================================
// SCOREBOARD
// ============================================================

val scoreDisplay = Picture.text(scoreText, 22)
scoreDisplay.setFillColor(ColorMaker.white)
scoreDisplay.setPosition(
  cb.x + 20,
  cb.y + cb.height - 30
)
draw(scoreDisplay)

val messageDisplay = Picture.text(message, 16)
messageDisplay.setFillColor(ColorMaker.yellow)
messageDisplay.setPosition(
  cb.x + 20,
  cb.y + cb.height - 60
)
draw(messageDisplay)

// ============================================================
// BALL VARIABLES
// ============================================================

var ballX = cb.x + cb.width / 2
var ballY = cb.y + cb.height - 100

var ballVX = 0.0
var ballVY = 0.0

// ============================================================
// SCORE UPDATE
// ============================================================

def updateScore(): Unit = {

  val over = balls / 6
  val ballNo = balls % 6

  scoreText =
    "? SCORE " +
    score +
    "/" +
    wickets +
    "   OVER " +
    over +
    "." +
    ballNo
}

// ============================================================
// RESET BALL
// ============================================================

def resetBall(): Unit = {

  active = false
  hit = false
  shotPlayed = false

  balls += 1

  ballX =
    cb.x + cb.width / 2

  ballY =
    cb.y + cb.height - 100

  ballVX = 0
  ballVY = 0

  ball.setPosition(
    ballX,
    ballY
  )

  ballShadow.setPosition(
    ballX,
    ballY + 8
  )

  updateScore()

  if (
    balls >= totalBalls ||
    wickets >= maxWickets
  ) {

    gameOver = true

    message =
      "? MATCH OVER! " +
      score +
      "/" +
      wickets

  } else {

    message =
      "SPACE = NEXT BALL"
  }
}

// ============================================================
// BOWL
// ============================================================

def bowl(): Unit = {

  if (
    !active &&
    !gameOver &&
    !paused
  ) {

    ballX =
      cb.x + cb.width / 2

    ballY =
      cb.y + cb.height - 100

    ballVX = 0

    ballVY = -6.0

    active = true
    hit = false
    shotPlayed = false

    message =
      "? BALL COMING!"
  }
}

// ============================================================
// SHOT SYSTEM
// ============================================================

def playShot(kind: String): Unit = {

  if (
    active &&
    !shotPlayed
  ) {

    shotPlayed = true
    hit = true

    if (kind == "pull") {

      batsman.swingBat("pull")

      score += 4

      ballVX = 4
      ballVY = 5

      message =
        "? PERFECT PULL! FOUR!"

    }

    if (kind == "straight") {

      batsman.swingBat("straight")

      score += 6

      ballVX = 0
      ballVY = 7

      message =
        "? MASSIVE SIX!"

    }

    if (kind == "cover") {

      batsman.swingBat("cover")

      score += 4

      ballVX = -4
      ballVY = 5

      message =
        "? COVER DRIVE! FOUR!"

    }

    if (kind == "defence") {

      batsman.swingBat("defence")

      score += 1

      ballVX = 1
      ballVY = 6

      message =
        "? DEFENCE! 1 RUN"

    }

    if (kind == "loft") {

      batsman.swingBat("loft")

      score += 6

      ballVX = 2
      ballVY = 7

      message =
        "? LOFTED SIX!"

    }

    updateScore()
  }
}

// ============================================================
// RESTART
// ============================================================

def restartGame(): Unit = {

  score = 0
  wickets = 0
  balls = 0

  active = false
  hit = false
  shotPlayed = false

  gameOver = false
  paused = false

  ballX =
    cb.x + cb.width / 2

  ballY =
    cb.y + cb.height - 100

  ball.setPosition(
    ballX,
    ballY
  )

  ballShadow.setPosition(
    ballX,
    ballY + 8
  )

  updateScore()

  message =
    "SPACE = BOWL"
}

// ============================================================
// GAME LOOP
// ============================================================

animate {

  // Restart

  if (isKeyPressed(Kc.VK_R)) {
    restartGame()
  }

  // Pause

  if (isKeyPressed(Kc.VK_P)) {
    paused = !paused
  }

  if (
    !paused &&
    !gameOver
  ) {

    // Bowl

    if (isKeyPressed(Kc.VK_SPACE)) {
      bowl()
    }

    // Ball movement

    if (active) {

      ballX += ballVX
      ballY += ballVY

      ball.setPosition(
        ballX,
        ballY
      )

      // Shadow gives depth effect

      ballShadow.setPosition(
        ballX,
        ballY + 10
      )

      // ------------------------------------------
      // BATTING ZONE
      // ------------------------------------------

      if (
        ballY > cb.y + 75 &&
        ballY < cb.y + 140 &&
        !shotPlayed
      ) {

        if (isKeyPressed(Kc.VK_W)) {

          playShot("pull")

        } else if (isKeyPressed(Kc.VK_S)) {

          playShot("straight")

        } else if (isKeyPressed(Kc.VK_A)) {

          playShot("cover")

        } else if (isKeyPressed(Kc.VK_D)) {

          playShot("defence")

        } else if (isKeyPressed(Kc.VK_Q)) {

          playShot("loft")
        }
      }

      // ------------------------------------------
      // MISSED BALL = WICKET
      // ------------------------------------------

      if (
        ballY < cb.y + 40 &&
        !shotPlayed
      ) {

        wickets += 1

        message =
          "? WICKET! BALL MISSED!"

        resetBall()
      }

      // ------------------------------------------
      // HIT COMPLETED
      // ------------------------------------------

      if (
        ballY > cb.y + cb.height - 40 &&
        hit
      ) {

        resetBall()
      }
    }

    batsman.update()
  }

  // IMPORTANT KOJO API
  // TextPic uses setText()

  scoreDisplay.setText(scoreText)
  messageDisplay.setText(message)
}

// ============================================================
// START
// ============================================================

println("======================================")
println("      ? ULTRA 2.5D CRICKET ?")
println("======================================")
println("SPACE = Bowl")
println("W = Pull Shot")
println("S = Straight Drive")
println("A = Cover Drive")
println("D = Defence")
println("Q = Lofted Shot")
println("P = Pause")
println("R = Restart")
println("======================================")