Code Sketch


sniper_0718
By: Mhalsakant School
Category: Art
cleari()

// --- Game Dimensions ---
val canvasWidth = 800
val canvasHeight = 600
val roadWidth = 340

// --- Realistic Terrain Background ---
val bg = Picture.rectangle(canvasWidth, canvasHeight)
bg.setFillColor(new java.awt.Color(10, 25, 10, 255))
bg.setPenColor(noColor)
bg.setPosition(-canvasWidth / 2, -canvasHeight / 2)
bg.draw()

val road = Picture.rectangle(roadWidth, canvasHeight * 5)
road.setFillColor(new java.awt.Color(35, 35, 38, 255))
road.setPenColor(noColor)
road.setPosition(-roadWidth / 2, -canvasHeight / 2)
road.draw()

// --- Road Boundary Marking Lines ---
val lineLeft = Picture.rectangle(6, canvasHeight * 5)
lineLeft.setFillColor(white)
lineLeft.setPenColor(noColor)
lineLeft.setPosition(-roadWidth / 2 + 5, -canvasHeight / 2)
lineLeft.draw()

val lineRight = Picture.rectangle(6, canvasHeight * 5)
lineRight.setFillColor(white)
lineRight.setPenColor(noColor)
lineRight.setPosition(roadWidth / 2 - 11, -canvasHeight / 2)
lineRight.draw()

// --- Fast Animated Lane Markers ---
val dashCount = 30
val dashHeight = 40
val dashGap = 50
var dashOffset = 0.0

val yellowDashesL = Array.fill(dashCount) {
  val d = Picture.rectangle(4, dashHeight)
  d.setFillColor(new java.awt.Color(255, 204, 0, 255))
  d.setPenColor(noColor)
  d.draw()
  d
}

val yellowDashesR = Array.fill(dashCount) {
  val d = Picture.rectangle(4, dashHeight)
  d.setFillColor(new java.awt.Color(255, 204, 0, 255))
  d.setPenColor(noColor)
  d.draw()
  d
}

def updateDashes(speed: Double): Unit = {
  dashOffset = (dashOffset - speed) % (dashHeight + dashGap)
  for (i <- 0 until dashCount) {
    val yPos = (canvasHeight / 2) - (i * (dashHeight + dashGap)) + dashOffset
    yellowDashesL(i).setPosition(-5, yPos)
    yellowDashesR(i).setPosition(1, yPos)
  }
}

// --- Night Overlay ---
val nightOverlay = Picture.rectangle(canvasWidth, canvasHeight)
nightOverlay.setFillColor(new java.awt.Color(0, 0, 0, 160))
nightOverlay.setPenColor(noColor)
nightOverlay.setPosition(-canvasWidth / 2, -canvasHeight / 2)
nightOverlay.draw()

// --- Player Fortuner Car ---
val playerBody = Picture.rectangle(52, 95)
playerBody.setFillColor(new java.awt.Color(245, 245, 250, 255))
playerBody.setPenColor(black)

val playerRoof = Picture.rectangle(46, 34)
playerRoof.setFillColor(new java.awt.Color(230, 230, 235, 255))
playerRoof.setPenColor(gray)

val playerGlass = Picture.rectangle(44, 20)
playerGlass.setFillColor(new java.awt.Color(20, 40, 60, 255))
playerGlass.setPenColor(noColor)

val playerTailL = Picture.rectangle(8, 6)
playerTailL.setFillColor(new java.awt.Color(220, 20, 20, 255))
playerTailL.setPenColor(noColor)

val playerTailR = Picture.rectangle(8, 6)
playerTailR.setFillColor(new java.awt.Color(220, 20, 20, 255))
playerTailR.setPenColor(noColor)

val playerHeadL = Picture.rectangle(9, 6)
playerHeadL.setFillColor(gray)
playerHeadL.setPenColor(noColor)

val playerHeadR = Picture.rectangle(9, 6)
playerHeadR.setFillColor(gray)
playerHeadR.setPenColor(noColor)

playerBody.draw()
playerRoof.draw()
playerGlass.draw()
playerTailL.draw()
playerTailR.draw()
playerHeadL.draw()
playerHeadR.draw()

// --- Player Character (Banda) ---
var manX = 60.0
var manY = -220.0
val manSpeed = 5.0
var inCar = false
var toggleCooldown = 0
var hasGun = false
var shootCooldown = 0
var killCount = 0
var distanceTraveled = 0.0

val manHead = Picture.circle(5)
manHead.setFillColor(new java.awt.Color(235, 185, 145, 255))
manHead.setPenColor(noColor)

val manTorso = Picture.rectangle(14, 22)
manTorso.setFillColor(new java.awt.Color(220, 50, 50, 255))
manTorso.setPenColor(noColor)

val manPants = Picture.rectangle(12, 18)
manPants.setFillColor(new java.awt.Color(25, 45, 95, 255))
manPants.setPenColor(noColor)

val manLeftShoe = Picture.rectangle(4, 6)
manLeftShoe.setFillColor(black)
manLeftShoe.setPenColor(noColor)

val manRightShoe = Picture.rectangle(4, 6)
manRightShoe.setFillColor(black)
manRightShoe.setPenColor(noColor)

// Gun graphic in hand
val gunPic = Picture.rectangle(10, 4)
gunPic.setFillColor(gray)
gunPic.setPenColor(noColor)

manHead.draw()
manTorso.draw()
manPants.draw()
manLeftShoe.draw()
manRightShoe.draw()

// --- Enemy Setup (Exact 300m, 600m, 900m, 1200m, 1500m fixed positions with cars) ---
case class Enemy(car: Picture, manHead: Picture, manTorso: Picture, manPants: Picture, var isAlive: Boolean, targetDist: Double)

val enemyDistances = scala.List(300.0, 600.0, 900.0, 1200.0, 1500.0)
val enemies = enemyDistances.map { dist =>
  val eCar = Picture.rectangle(52, 95)
  eCar.setFillColor(new java.awt.Color(100, 100, 110, 255))
  eCar.setPenColor(black)
  eCar.setPosition(-100.0, -220.0 + (dist * 1.5))
  eCar.draw()

  val eHead = Picture.circle(5)
  eHead.setFillColor(new java.awt.Color(235, 185, 145, 255))
  eHead.setPenColor(noColor)
  eHead.setPosition(-70.0, -220.0 + (dist * 1.5) + 38)
  eHead.draw()

  val eTorso = Picture.rectangle(14, 22)
  eTorso.setFillColor(new java.awt.Color(50, 200, 50, 255))
  eTorso.setPenColor(noColor)
  eTorso.setPosition(-73.0, -220.0 + (dist * 1.5) + 14)
  eTorso.draw()

  val ePants = Picture.rectangle(12, 18)
  ePants.setFillColor(new java.awt.Color(40, 40, 40, 255))
  ePants.setPenColor(noColor)
  ePants.setPosition(-72.0, -220.0 + (dist * 1.5) - 4)
  ePants.draw()

  Enemy(eCar, eHead, eTorso, ePants, true, dist)
}

// --- Interaction Prompt Message ---
val promptText = Picture.text("Press F to go inside", 16)
promptText.setFillColor(new java.awt.Color(255, 255, 0, 255))
var promptVisible = false

// --- Right Corner Square Box & Targets Menu ---
val menuBox = Picture.rectangle(160, 180)
menuBox.setFillColor(new java.awt.Color(20, 20, 30, 230))
menuBox.setPenColor(new java.awt.Color(0, 230, 255, 255))
menuBox.setPosition(210, 80)
menuBox.draw()

val menuTitle = Picture.text("Targets [Click]", 12)
menuTitle.setFillColor(new java.awt.Color(255, 255, 0, 255))
menuTitle.setPosition(225, 230)
menuTitle.draw()

var showNames = false

val name1 = Picture.text("1. Ganesh", 12)
name1.setFillColor(white)
name1.setPosition(225, 200)

val name2 = Picture.text("2. Shlok", 12)
name2.setFillColor(white)
name2.setPosition(225, 175)

val name3 = Picture.text("3. Samarth", 12)
name3.setFillColor(white)
name3.setPosition(225, 150)

val name4 = Picture.text("4. Soham", 12)
name4.setFillColor(white)
name4.setPosition(225, 125)

val name5 = Picture.text("5. Atharva", 12)
name5.setFillColor(white)
name5.setPosition(225, 100)

menuBox.onMouseClick { (x, y) =>
  showNames = !showNames
  if (showNames) {
    name1.draw()
    name2.draw()
    name3.draw()
    name4.draw()
    name5.draw()
  } else {
    name1.erase()
    name2.erase()
    name3.erase()
    name4.erase()
    name5.erase()
  }
}

// --- Movement Variables ---
var carX = -26.0
val carY = -220.0
val carSteerSpeed = 15.0

def updatePlayerPos(): Unit = {
  playerBody.setPosition(carX, carY)
  playerRoof.setPosition(carX + 3, carY + 28)
  playerGlass.setPosition(carX + 4, carY + 58)
  playerTailL.setPosition(carX + 2, carY + 2)
  playerTailR.setPosition(carX + 42, carY + 2)
  playerHeadL.setPosition(carX + 2, carY + 88)
  playerHeadR.setPosition(carX + 41, carY + 88)
}

def updateManPos(): Unit = {
  manHead.setPosition(manX + 3, manY + 38)
  manTorso.setPosition(manX, manY + 14)
  manPants.setPosition(manX + 1, manY - 4)
  manLeftShoe.setPosition(manX, manY - 10)
  manRightShoe.setPosition(manX + 10, manY - 10)
  if (hasGun) {
    gunPic.setPosition(manX + 12, manY + 15)
  } else {
    gunPic.setPosition(-1000, -1000)
  }
}

updatePlayerPos()
updateManPos()
gunPic.draw()

// --- HUD / Score Board ---
val helpText = Picture.text("WASD: Walk | F: Enter | G: Exit | H: Gun | Z: Shoot", 12)
helpText.setFillColor(new java.awt.Color(0, 230, 255, 255))
helpText.setPosition(-canvasWidth / 2 + 20, -canvasHeight / 2 + 20)
helpText.draw()

val scoreText = Picture.text("SPEED: 0 KM/H | DIST: 0m | KILLS: 0/5", 15)
scoreText.setFillColor(white)
scoreText.setPosition(-canvasWidth / 2 + 20, canvasHeight / 2 - 40)
scoreText.draw()

// --- Game Loop ---
animate {
  var currentSpeed = 0.0

  if (toggleCooldown > 0) toggleCooldown -= 1
  if (shootCooldown > 0) shootCooldown -= 1

  // Update fixed positions of enemies based on distanceTraveled
  for (e <- enemies) {
    if (e.isAlive) {
      val relDist = e.targetDist - distanceTraveled
      val screenY = -220.0 + (relDist * 1.5)
      e.car.setPosition(-100.0, screenY)
      e.manHead.setPosition(-70.0, screenY + 38)
      e.manTorso.setPosition(-73.0, screenY + 14)
      e.manPants.setPosition(-72.0, screenY - 4)
    }
  }

  val dist = Math.hypot(manX - carX, manY - carY)

  if (!inCar) {
    if (isKeyPressed(Kc.VK_W)) {
      manY += manSpeed
      distanceTraveled = Math.min(1500.0, distanceTraveled + 0.8)
    }
    if (isKeyPressed(Kc.VK_S)) {
      manY -= manSpeed
      distanceTraveled = Math.max(0.0, distanceTraveled - 0.8)
    }
    if (isKeyPressed(Kc.VK_A)) manX -= manSpeed
    if (isKeyPressed(Kc.VK_D)) manX += manSpeed

    if (isKeyPressed(Kc.VK_H) && toggleCooldown == 0) {
      hasGun = !hasGun
      toggleCooldown = 20
    }

    if (hasGun && isKeyPressed(Kc.VK_Z) && shootCooldown == 0) {
      shootCooldown = 25
      for (e <- enemies) {
        if (e.isAlive) {
          val relDist = e.targetDist - distanceTraveled
          val eScreenY = -220.0 + (relDist * 1.5)
          val eDist = Math.hypot(manX - (-70.0), manY - eScreenY)
          if (eDist < 120) {
            e.isAlive = false
            e.car.erase()
            e.manHead.erase()
            e.manTorso.erase()
            e.manPants.erase()
            killCount += 1
          }
        }
      }
    }

    updateManPos()

    if (dist < 70) {
      if (!promptVisible) {
        promptText.setPosition(carX - 45, carY + 110)
        promptText.draw()
        promptVisible = true
      }
      
      if (isKeyPressed(Kc.VK_F) && toggleCooldown == 0) {
        inCar = true
        toggleCooldown = 15
        hasGun = false
        
        if (promptVisible) {
          promptText.erase()
          promptVisible = false
        }
        
        manHead.erase()
        manTorso.erase()
        manPants.erase()
        manLeftShoe.erase()
        manRightShoe.erase()
        gunPic.erase()
      }
    } else {
      if (promptVisible) {
        promptText.erase()
        promptVisible = false
      }
    }

    scoreText.update(s"SPEED: 0 KM/H | DIST: ${distanceTraveled.toInt}m | KILLS: $killCount/5")

  } else {
    if (promptVisible) {
      promptText.erase()
      promptVisible = false
    }

    // Press 'G' to exit the car
    if (isKeyPressed(Kc.VK_G) && toggleCooldown == 0) {
      inCar = false
      toggleCooldown = 15
      
      manX = carX + 60
      manY = carY
      updateManPos()
      
      manHead.draw()
      manTorso.draw()
      manPants.draw()
      manLeftShoe.draw()
      manRightShoe.draw()
      gunPic.draw()
    }

    if (isKeyPressed(Kc.VK_UP)) {
      currentSpeed = 25.0
      distanceTraveled = Math.min(1500.0, distanceTraveled + 2.5)
    }

    if (isKeyPressed(Kc.VK_LEFT)) {
      carX -= carSteerSpeed
    }
    if (isKeyPressed(Kc.VK_RIGHT)) {
      carX += carSteerSpeed
    }

    val minX = -roadWidth / 2 + 12
    val maxX = roadWidth / 2 - 64
    if (carX < minX) carX = minX
    if (carX > maxX) carX = maxX

    updatePlayerPos()

    val displaySpeed = if (currentSpeed > 0) 120 else 0
    scoreText.update(s"SPEED: $displaySpeed KM/H | DIST: ${distanceTraveled.toInt}m | KILLS: $killCount/5")
  }

  updateDashes(currentSpeed)
}