Skip to content

Instantly share code, notes, and snippets.

@Hammer2900
Created May 5, 2025 08:37
Show Gist options
  • Save Hammer2900/a63c992b65df3aba6ce1c86a276f549a to your computer and use it in GitHub Desktop.
Save Hammer2900/a63c992b65df3aba6ce1c86a276f549a to your computer and use it in GitHub Desktop.
snake nim nico
# --- Imports ---
import nico
import nico/controller
import nico/keycodes
import random
import sequtils
import strutils # Для $score
# --- Constants ---
const SCREEN_WIDTH: Pint = 64
const SCREEN_HEIGHT: Pint = 64
const PIXEL_SCALE: Pint = 8
const GAME_SPEED: int = 6
const COLOR_BACKGROUND: ColorId = 0
const COLOR_SNAKE: ColorId = 11
const COLOR_FOOD: ColorId = 20
const COLOR_SCORE_TEXT: ColorId = 6
const COLOR_GAMEOVER_TEXT: ColorId = 19
const ORG_NAME = "lazareus1"
const APP_NAME = "app1"
# --- Types ---
type
Pos = object
x, y: Pint
Direction = enum
dirUp, dirDown, dirLeft, dirRight
GameState = enum
gsPlaying, gsGameOver
# --- Global State ---
var snake: seq[Pos]
var direction: Direction
var nextDirection: Direction
var food: Pos
var score: int
var gameState: GameState
var moveTimer: int
# --- Procedures ---
proc placeFood() =
while true:
food = Pos(x: rnd(SCREEN_WIDTH - 1), y: rnd(SCREEN_HEIGHT - 1))
if not snake.any(proc(s: Pos): bool = (s.x == food.x and s.y == food.y)):
break
proc resetGame() =
score = 0
moveTimer = 0
gameState = gsPlaying
direction = dirRight
nextDirection = dirRight
let startX = SCREEN_WIDTH div 2
let startY = SCREEN_HEIGHT div 2
snake = @[
Pos(x: startX - 2, y: startY),
Pos(x: startX - 1, y: startY),
Pos(x: startX, y: startY)
]
placeFood()
proc gameInit() =
createWindow("Nico Snake", SCREEN_WIDTH, SCREEN_HEIGHT, PIXEL_SCALE)
# loadFont(0, "font.png") # Раскомментируй, если есть файл font.png
loadDefaultFont(0) # Используем стандартный шрифт, если нет своего
setPalette(loadPalettePico8Extra()) # Используем расширенную палитру
fps(60)
setFont(0)
srand()
resetGame()
proc gameUpdate(dt: float32) =
if keyp(K_ESCAPE):
shutdown()
return
case gameState
of gsPlaying:
# Handle Input
if btnp(pcUp) and direction != dirDown: nextDirection = dirUp
elif btnp(pcDown) and direction != dirUp: nextDirection = dirDown
elif btnp(pcLeft) and direction != dirRight: nextDirection = dirLeft
elif btnp(pcRight) and direction != dirLeft: nextDirection = dirRight
# Move Snake (Tick-based)
moveTimer += 1
if moveTimer < GAME_SPEED: return
moveTimer = 0
direction = nextDirection
# Calculate New Head Position
let head = snake[^1]
var newHead: Pos
case direction:
of dirUp: newHead = Pos(x: head.x, y: head.y - 1)
of dirDown: newHead = Pos(x: head.x, y: head.y + 1)
of dirLeft: newHead = Pos(x: head.x - 1, y: head.y)
of dirRight: newHead = Pos(x: head.x + 1, y: head.y)
# Check Collisions
let wallCollision = newHead.x < 0 or newHead.x >= SCREEN_WIDTH or
newHead.y < 0 or newHead.y >= SCREEN_HEIGHT
let selfCollision = snake.any(proc(s: Pos): bool = (s.x == newHead.x and
s.y == newHead.y))
if wallCollision or selfCollision:
gameState = gsGameOver
return
# Process Movement & Eating
let ateFood = (newHead.x == food.x and newHead.y == food.y)
snake.add(newHead)
if ateFood:
score += 1
placeFood()
else:
snake.delete(0)
of gsGameOver:
# Handle Restart Input
if btnp(pcA) or btnp(pcB) or keyp(K_RETURN) or keyp(K_SPACE):
resetGame()
proc gameDraw() =
cls(COLOR_BACKGROUND)
# Draw Food
setColor(COLOR_FOOD)
pset(food.x, food.y)
# Draw Snake
setColor(COLOR_SNAKE)
for segment in snake:
pset(segment.x, segment.y)
# Draw Score
setColor(COLOR_SCORE_TEXT)
print("Score: " & $score, 1, 1)
# Draw Game Over Message
if gameState == gsGameOver:
setColor(COLOR_GAMEOVER_TEXT)
let midX = SCREEN_WIDTH div 2
let midY = SCREEN_HEIGHT div 2
printc("GAME OVER", midX, midY - 8)
setColor(COLOR_SCORE_TEXT) # Используем тот же цвет для подсказки
printc("Press A/Enter", midX, midY)
printc("to Restart", midX, midY + 8)
# --- Main Execution ---
nico.init(ORG_NAME, APP_NAME)
nico.run(gameInit, gameUpdate, gameDraw)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment