Created
May 5, 2025 08:37
-
-
Save Hammer2900/a63c992b65df3aba6ce1c86a276f549a to your computer and use it in GitHub Desktop.
snake nim nico
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# --- 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