├── dot.png ├── apple.png ├── head.png ├── README.md ├── Snake.kt └── Board.kt /dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janbodnar/Kotlin-Snake-Game/HEAD/dot.png -------------------------------------------------------------------------------- /apple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janbodnar/Kotlin-Snake-Game/HEAD/apple.png -------------------------------------------------------------------------------- /head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janbodnar/Kotlin-Snake-Game/HEAD/head.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kotlin-Snake-Game 2 | Snake game source code in Kotlin and Swing 3 | 4 | https://zetcode.com/kotlin/snake/ 5 | -------------------------------------------------------------------------------- /Snake.kt: -------------------------------------------------------------------------------- 1 | package com.zetcode 2 | 3 | import java.awt.EventQueue 4 | import javax.swing.JFrame 5 | 6 | class Snake : JFrame() { 7 | 8 | init { 9 | 10 | initUI() 11 | } 12 | 13 | private fun initUI() { 14 | 15 | add(Board()) 16 | 17 | title = "Snake" 18 | isResizable = false 19 | 20 | pack() 21 | 22 | setLocationRelativeTo(null) 23 | defaultCloseOperation = JFrame.EXIT_ON_CLOSE 24 | } 25 | 26 | companion object { 27 | 28 | @JvmStatic 29 | fun main(args: Array) { 30 | 31 | EventQueue.invokeLater { 32 | val ex = Snake() 33 | ex.isVisible = true 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Board.kt: -------------------------------------------------------------------------------- 1 | package com.zetcode 2 | 3 | import java.awt.* 4 | import java.awt.event.ActionEvent 5 | import java.awt.event.ActionListener 6 | import java.awt.event.KeyAdapter 7 | import java.awt.event.KeyEvent 8 | 9 | import javax.swing.ImageIcon 10 | import javax.swing.JPanel 11 | import javax.swing.Timer 12 | 13 | 14 | class Board : JPanel(), ActionListener { 15 | 16 | private val boardWidth = 300 17 | private val boardHeight = 300 18 | private val dotSize = 10 19 | private val allDots = 900 20 | private val randPos = 29 21 | private val delay = 140 22 | 23 | private val x = IntArray(allDots) 24 | private val y = IntArray(allDots) 25 | 26 | private var nOfDots: Int = 0 27 | private var appleX: Int = 0 28 | private var appleY: Int = 0 29 | 30 | private var leftDirection = false 31 | private var rightDirection = true 32 | private var upDirection = false 33 | private var downDirection = false 34 | private var inGame = true 35 | 36 | private var timer: Timer? = null 37 | private var ball: Image? = null 38 | private var apple: Image? = null 39 | private var head: Image? = null 40 | 41 | init { 42 | 43 | addKeyListener(TAdapter()) 44 | background = Color.black 45 | isFocusable = true 46 | 47 | preferredSize = Dimension(boardWidth, boardHeight) 48 | loadImages() 49 | initGame() 50 | } 51 | 52 | private fun loadImages() { 53 | 54 | val iid = ImageIcon("src/main/resources/dot.png") 55 | ball = iid.image 56 | 57 | val iia = ImageIcon("src/main/resources/apple.png") 58 | apple = iia.image 59 | 60 | val iih = ImageIcon("src/main/resources/head.png") 61 | head = iih.image 62 | } 63 | 64 | private fun initGame() { 65 | 66 | nOfDots = 3 67 | 68 | for (z in 0 until nOfDots) { 69 | x[z] = 50 - z * 10 70 | y[z] = 50 71 | } 72 | 73 | locateApple() 74 | 75 | timer = Timer(delay, this) 76 | timer!!.start() 77 | } 78 | 79 | public override fun paintComponent(g: Graphics) { 80 | super.paintComponent(g) 81 | 82 | doDrawing(g) 83 | } 84 | 85 | private fun doDrawing(g: Graphics) { 86 | 87 | if (inGame) { 88 | 89 | g.drawImage(apple, appleX, appleY, this) 90 | 91 | for (z in 0 until nOfDots) { 92 | if (z == 0) { 93 | g.drawImage(head, x[z], y[z], this) 94 | } else { 95 | g.drawImage(ball, x[z], y[z], this) 96 | } 97 | } 98 | 99 | Toolkit.getDefaultToolkit().sync() 100 | 101 | } else { 102 | 103 | gameOver(g) 104 | } 105 | } 106 | 107 | private fun gameOver(g: Graphics) { 108 | 109 | val msg = "Game Over" 110 | val small = Font("Helvetica", Font.BOLD, 14) 111 | val fontMetrics = getFontMetrics(small) 112 | 113 | val rh = RenderingHints( 114 | RenderingHints.KEY_ANTIALIASING, 115 | RenderingHints.VALUE_ANTIALIAS_ON) 116 | 117 | rh[RenderingHints.KEY_RENDERING] = RenderingHints.VALUE_RENDER_QUALITY 118 | 119 | (g as Graphics2D).setRenderingHints(rh) 120 | 121 | g.color = Color.white 122 | g.font = small 123 | g.drawString(msg, (boardWidth - fontMetrics.stringWidth(msg)) / 2, boardHeight / 2) 124 | } 125 | 126 | private fun checkApple() { 127 | 128 | if (x[0] == appleX && y[0] == appleY) { 129 | 130 | nOfDots++ 131 | locateApple() 132 | } 133 | } 134 | 135 | private fun move() { 136 | 137 | for (z in nOfDots downTo 1) { 138 | x[z] = x[z - 1] 139 | y[z] = y[z - 1] 140 | } 141 | 142 | if (leftDirection) { 143 | x[0] -= dotSize 144 | } 145 | 146 | if (rightDirection) { 147 | x[0] += dotSize 148 | } 149 | 150 | if (upDirection) { 151 | y[0] -= dotSize 152 | } 153 | 154 | if (downDirection) { 155 | y[0] += dotSize 156 | } 157 | } 158 | 159 | private fun checkCollision() { 160 | 161 | for (z in nOfDots downTo 1) { 162 | 163 | if (z > 4 && x[0] == x[z] && y[0] == y[z]) { 164 | inGame = false 165 | } 166 | } 167 | 168 | if (y[0] >= boardHeight) { 169 | inGame = false 170 | } 171 | 172 | if (y[0] < 0) { 173 | inGame = false 174 | } 175 | 176 | if (x[0] >= boardWidth) { 177 | inGame = false 178 | } 179 | 180 | if (x[0] < 0) { 181 | inGame = false 182 | } 183 | 184 | if (!inGame) { 185 | timer!!.stop() 186 | } 187 | } 188 | 189 | private fun locateApple() { 190 | 191 | var r = (Math.random() * randPos).toInt() 192 | appleX = r * dotSize 193 | 194 | r = (Math.random() * randPos).toInt() 195 | appleY = r * dotSize 196 | } 197 | 198 | override fun actionPerformed(e: ActionEvent) { 199 | 200 | if (inGame) { 201 | 202 | checkApple() 203 | checkCollision() 204 | move() 205 | } 206 | 207 | repaint() 208 | } 209 | 210 | private inner class TAdapter : KeyAdapter() { 211 | 212 | override fun keyPressed(e: KeyEvent?) { 213 | 214 | val key = e!!.keyCode 215 | 216 | if (key == KeyEvent.VK_LEFT && !rightDirection) { 217 | leftDirection = true 218 | upDirection = false 219 | downDirection = false 220 | } 221 | 222 | if (key == KeyEvent.VK_RIGHT && !leftDirection) { 223 | rightDirection = true 224 | upDirection = false 225 | downDirection = false 226 | } 227 | 228 | if (key == KeyEvent.VK_UP && !downDirection) { 229 | upDirection = true 230 | rightDirection = false 231 | leftDirection = false 232 | } 233 | 234 | if (key == KeyEvent.VK_DOWN && !upDirection) { 235 | downDirection = true 236 | rightDirection = false 237 | leftDirection = false 238 | } 239 | } 240 | } 241 | } 242 | --------------------------------------------------------------------------------