Code Sketch


swarali sandip sutar
By: Mhalsakant School
Category: Art
import javax.swing._
import java.awt._
import java.awt.event._
import java.awt.geom._
import scala.collection.mutable.ArrayBuffer

object SolarSystem3DApp {
  def main(args: Array[String]): Unit = {
    SwingUtilities.invokeLater(new Runnable {
      def run(): Unit = {
        val frame = new JFrame("3D Solar System Animation - Scala / Kojo")
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE)
        frame.setSize(1024, 768)
        frame.setLocationRelativeTo(null)

        val panel = new SolarSystemPanel()
        frame.setContentPane(panel)
        frame.setVisible(true)
      }
    })
  }
}

class Planet(val name: String, val distance: Double, val radius: Int, val speed: Double, val color: Color) {
  var angle: Double = java.lang.Math.random() * 2 * java.lang.Math.PI
}

class SolarSystemPanel extends JPanel {
  setBackground(new Color(10, 10, 20))

  // Initialize planets with orbital distance, radius, orbital speed, and color
  val planets = ArrayBuffer(
    new Planet("Mercury", 75, 5, 0.04, new Color(169, 169, 169)),
    new Planet("Venus", 120, 8, 0.015, new Color(218, 165, 32)),
    new Planet("Earth", 175, 10, 0.01, new Color(70, 130, 180)),
    new Planet("Mars", 235, 7, 0.008, new Color(205, 92, 92)),
    new Planet("Jupiter", 320, 18, 0.004, new Color(222, 184, 135)),
    new Planet("Saturn", 400, 15, 0.003, new Color(238, 232, 170)),
    new Planet("Uranus", 480, 12, 0.002, new Color(135, 206, 250)),
    new Planet("Neptune", 550, 12, 0.0015, new Color(65, 105, 225))
  )

  // Starfield background generation
  case class Star(x: Int, y: Int, size: Int, var brightness: Float)
  val stars = ArrayBuffer[Star]()
  for (_ <- 1 to 250) {
    stars += Star(
      (java.lang.Math.random() * 1200).toInt,
      (java.lang.Math.random() * 900).toInt,
      (java.lang.Math.random() * 3).toInt + 1,
      (java.lang.Math.random() * 0.7 + 0.3).toFloat
    )
  }

  // Animation Timer (approx. 30 FPS)
  val timer = new Timer(30, new ActionListener {
    override def actionPerformed(e: ActionEvent): Unit = {
      for (p <- planets) {
        p.angle += p.speed
      }
      // Twinkle stars slightly
      for (s <- stars) {
        s.brightness = java.lang.Math.max(0.2f, java.lang.Math.min(1.0f, s.brightness + (java.lang.Math.random() * 0.2 - 0.1).toFloat))
      }
      repaint()
    }
  })
  timer.start()

  override def paintComponent(g: Graphics): Unit = {
    super.paintComponent(g)
    val g2 = g.asInstanceOf[Graphics2D]
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)

    val w = getWidth
    val h = getHeight
    val cx = w / 2
    val cy = h / 2

    // 1. Draw Starfield
    for (s <- stars) {
      g2.setColor(Color.WHITE)
      g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, s.brightness))
      g2.fillOval(s.x, s.y, s.size, s.size)
    }
    g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f))

    // Pseudo-3D orbital tilt factor (isometric / perspective inclination)
    val tilt = 0.45

    // 2. Draw Dashed Orbit Paths
    g2.setColor(new Color(255, 255, 255, 35))
    g2.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1.0f, Array(5f, 5f), 0f))
    for (p <- planets) {
      val orbitW = (p.distance * 2).toInt
      val orbitH = (p.distance * 2 * tilt).toInt
      g2.drawOval(cx - p.distance.toInt, cy - (p.distance * tilt).toInt, orbitW, orbitH)
    }
    g2.setStroke(new BasicStroke(1.0f))

    // 3. Draw Sun with Glowing Radial Gradient
    val sunRadius = 38
    val sunGradient = new RadialGradientPaint(
      cx, cy, sunRadius * 1.8f,
      Array(0.0f, 0.5f, 1.0f),
      Array(Color.YELLOW, new Color(255, 140, 0, 220), new Color(255, 69, 0, 0))
    )
    g2.setPaint(sunGradient)
    g2.fillOval(cx - sunRadius * 2, cy - sunRadius * 2, sunRadius * 4, sunRadius * 4)
    g2.setColor(new Color(255, 220, 50))
    g2.fillOval(cx - sunRadius, cy - sunRadius, sunRadius * 2, sunRadius * 2)

    // 4. Calculate Planet Positions & Depth Sort for 3D Overlap
    case class RenderablePlanet(planet: Planet, x: Double, y: Double, depth: Double)
    val renderList = ArrayBuffer[RenderablePlanet]()

    for (p <- planets) {
      val px = cx + p.distance * java.lang.Math.cos(p.angle)
      val py = cy + (p.distance * java.lang.Math.sin(p.angle)) * tilt
      renderList += RenderablePlanet(p, px, py, py) // py acts as depth for sorting
    }

    // Sort by depth so background planets render behind foreground planets
    val sortedPlanets = renderList.sortBy(_.depth)

    // 5. Render Planets and Labels
    for (rp <- sortedPlanets) {
      val p = rp.planet
      val x = rp.x.toInt
      val y = rp.y.toInt

      // 3D Spherical Shading Gradient
      val planetGradient = new RadialGradientPaint(
        x - p.radius / 3, y - p.radius / 3, p.radius * 1.3f,
        Array(0.0f, 0.85f, 1.0f),
        Array(Color.WHITE, p.color, new Color(15, 15, 25))
      )
      g2.setPaint(planetGradient)
      g2.fillOval(x - p.radius, y - p.radius, p.radius * 2, p.radius * 2)

      // Saturn Rings Special Rendering
      if (p.name == "Saturn") {
        g2.setColor(new Color(210, 180, 140, 160))
        g2.setStroke(new BasicStroke(3.5f))
        g2.drawOval(x - p.radius * 2, y - p.radius / 2, p.radius * 4, p.radius)
      }

      // Planet Name Tag
      g2.setColor(new Color(200, 210, 230))
      g2.setFont(new Font("SansSerif", Font.BOLD, 11))
      g2.drawString(p.name, x + p.radius + 5, y + 4)
    }

    // Header Title
    g2.setColor(Color.WHITE)
    g2.setFont(new Font("SansSerif", Font.BOLD, 16))
    g2.drawString("SOLAR SYSTEM 3D ORBITAL SIMULATION", 25, 35)
  }
}

// Automatically start the application in Kojo or standard Scala
SolarSystem3DApp.main(Array())