{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "0d9e929f",
   "metadata": {},
   "source": [
    "# 20-04 · Движение и клавиши\n",
    "\n",
    "Практика к разделу [«Перемещаем персонажей. События клавиш»](../../site/chapters/glava-20/20-04-peremeshenie-klavishi.html)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "24c38dfb",
   "metadata": {},
   "source": [
    "## Цель\n",
    "\n",
    "Двигать персонажа изменением координат и обработать событие клавиши."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b90dfc7c",
   "metadata": {},
   "source": [
    "## Про игровой цикл в этом ноутбуке\n",
    "\n",
    "В обычном `.py`-файле игровой цикл — это `while rabotaet:`, где `rabotaet` становится `False`, когда пользователь закрывает окно. В автоматически выполняемом ноутбуке некому закрыть окно, поэтому здесь мы прогоняем фиксированное число кадров через `for _ in range(N):` — логика каждого отдельного кадра (движение, отрисовка, `clock.tick()`) при этом точно такая же, как в настоящей игре."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5821ff80",
   "metadata": {},
   "source": [
    "## Рабочий пример — движение"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "4576a4b7",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-14T20:59:23.969912Z",
     "iopub.status.busy": "2026-08-14T20:59:23.969742Z",
     "iopub.status.idle": "2026-08-14T20:59:24.302092Z",
     "shell.execute_reply": "2026-08-14T20:59:24.301010Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "pygame-ce 2.5.8 (SDL 2.32.10, Python 3.14.6)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Позиция игрока после 10 кадров: 100\n"
     ]
    }
   ],
   "source": [
    "import pygame\n",
    "\n",
    "pygame.init()\n",
    "screen = pygame.display.set_mode((600, 400))\n",
    "clock = pygame.time.Clock()\n",
    "\n",
    "x_igroka = 50\n",
    "skorost_x = 5\n",
    "\n",
    "for kadr in range(10):\n",
    "    x_igroka += skorost_x\n",
    "    screen.fill((0, 0, 0))\n",
    "    pygame.draw.rect(screen, (100, 200, 255), (x_igroka, 180, 40, 40))\n",
    "    pygame.display.flip()\n",
    "    clock.tick(60)\n",
    "\n",
    "print(\"Позиция игрока после 10 кадров:\", x_igroka)\n",
    "pygame.quit()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dc6a448b",
   "metadata": {},
   "source": [
    "## Проверка результата"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "ac189c9f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-14T20:59:24.305947Z",
     "iopub.status.busy": "2026-08-14T20:59:24.305599Z",
     "iopub.status.idle": "2026-08-14T20:59:24.310141Z",
     "shell.execute_reply": "2026-08-14T20:59:24.309516Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Верно: игрок сдвинулся на 50 пикселей за 10 кадров.\n"
     ]
    }
   ],
   "source": [
    "assert x_igroka == 50 + 5 * 10\n",
    "print(\"Верно: игрок сдвинулся на\", 5 * 10, \"пикселей за 10 кадров.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f39c9e02",
   "metadata": {},
   "source": [
    "## Эксперимент 1 — событие KEYDOWN"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "4225ab0e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-14T20:59:24.311965Z",
     "iopub.status.busy": "2026-08-14T20:59:24.311643Z",
     "iopub.status.idle": "2026-08-14T20:59:24.472551Z",
     "shell.execute_reply": "2026-08-14T20:59:24.471461Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Прыжок! (клавиша SPACE обработана)\n"
     ]
    }
   ],
   "source": [
    "import pygame\n",
    "\n",
    "pygame.init()\n",
    "screen = pygame.display.set_mode((600, 400))\n",
    "\n",
    "# программно создаём событие нажатия клавиши, как это сделала бы клавиатура\n",
    "sobytie = pygame.event.Event(pygame.KEYDOWN, key=pygame.K_SPACE)\n",
    "pygame.event.post(sobytie)\n",
    "\n",
    "for event in pygame.event.get():\n",
    "    if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:\n",
    "        print(\"Прыжок! (клавиша SPACE обработана)\")\n",
    "\n",
    "pygame.quit()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3ea24940",
   "metadata": {},
   "source": [
    "## Эксперимент 2 — get_pressed() для непрерывного движения"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "895fe9f3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-14T20:59:24.483839Z",
     "iopub.status.busy": "2026-08-14T20:59:24.483601Z",
     "iopub.status.idle": "2026-08-14T20:59:24.637411Z",
     "shell.execute_reply": "2026-08-14T20:59:24.636069Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Тип результата get_pressed(): <class 'pygame.key.ScancodeWrapper'>\n",
      "Стрелка влево зажата: False\n"
     ]
    }
   ],
   "source": [
    "import pygame\n",
    "\n",
    "pygame.init()\n",
    "screen = pygame.display.set_mode((600, 400))\n",
    "\n",
    "klavishi = pygame.key.get_pressed()\n",
    "# в реальном приложении это будет True, если клавиша действительно зажата;\n",
    "# здесь просто проверяем, что функция возвращает объект, с которым можно так работать\n",
    "print(\"Тип результата get_pressed():\", type(klavishi))\n",
    "print(\"Стрелка влево зажата:\", klavishi[pygame.K_LEFT])\n",
    "pygame.quit()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Cartesian Python 3.14",
   "language": "python",
   "name": "cartesian-python314"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.14.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
