{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "9703a2e2",
   "metadata": {},
   "source": [
    "# 21-09 · Architektura: szkic klasy Player\n",
    "\n",
    "Praktyka do sekcji [„Dzielimy grę na klasy”](/pl/chapters/rozdzial-21/21-09-arhitektura-proekta.html)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7d2366fc",
   "metadata": {},
   "source": [
    "## Cel\n",
    "\n",
    "Zbudowanie klasy o minimalnym Player z pozycją Vector2- i Rect zsynchronizowanym z niej to ta sama zasada co w przypadku rzeczywistej space_shooter.py."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cb1073b3",
   "metadata": {},
   "source": [
    "## O pętli gier w tym laptopie\n",
    "\n",
    "W normalnym życiu `.py`pliku -plik, pętla gry to `while rabotaet:`to zależy od zdarzeń użytkownika (zamykanie okna, naciśnięcia klawiszy). W automatycznie wykonywanym laptopie nie ma nikogo, kto mógłby je tworzyć, więc tutaj uruchamiamy stałą liczbę klatek przez `for kadr in range(N):` — logika każdej pojedynczej klatki (ruch, kolizje, rysowanie) przy tym dokładnie taka sama, jak w prawdziwej grze z `projects/pygame/space-shooter/space_shooter.py`. Prędkość wciąż jest podana w pikselach na sekundę (px/s), a nie w pikselach na klatkę — ale aby wynik notatnika nie zależał od tego, jak szybko kod działa na konkretnym komputerze, `dt` tutaj nie jest zaczerpnięte z `clock.tick()`, ale jest ustalone z góry jako `1 / FPS`."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "35e501e5",
   "metadata": {},
   "source": [
    "## Sprawa robocza"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ca372973",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pygame\n",
    "\n",
    "pygame.init()\n",
    "screen = pygame.display.set_mode((480, 720))\n",
    "\n",
    "\n",
    "class Player:\n",
    "    def __init__(self, image, center):\n",
    "        self.image = image\n",
    "        self.rect = self.image.get_rect()\n",
    "        self.position = pygame.Vector2(center)\n",
    "        self.rect.center = (round(self.position.x), round(self.position.y))\n",
    "\n",
    "    def move(self, direction, dt, speed=200.0):\n",
    "        if direction.length_squared() > 0:\n",
    "            direction = direction.normalize()\n",
    "        self.position += direction * speed * dt\n",
    "        self.rect.center = (round(self.position.x), round(self.position.y))\n",
    "\n",
    "\n",
    "image = pygame.Surface((44, 44), pygame.SRCALPHA)\n",
    "pygame.draw.polygon(image, (60, 170, 255), [(22, 2), (40, 40), (4, 40)])\n",
    "\n",
    "player = Player(image, (240.0, 600.0))\n",
    "for _ in range(30):\n",
    "    player.move(pygame.Vector2(1, 0), 1 / 60)\n",
    "\n",
    "print(\"Позиция:\", player.position)\n",
    "print(\"Rect:\", player.rect)\n",
    "pygame.quit()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cdb6344d",
   "metadata": {},
   "source": [
    "## Sprawdzenie wyniku"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ac05b324",
   "metadata": {},
   "outputs": [],
   "source": [
    "import math\n",
    "\n",
    "assert math.isclose(player.position.x, 240.0 + 200.0 * 0.5, abs_tol=1e-6)\n",
    "assert player.rect.centerx == round(player.position.x)\n",
    "print(\"Верно: rect.center пересобран из position, а не обновлён напрямую.\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Cartesian Python 3.14",
   "language": "python",
   "name": "cartesian-python314"
  },
  "language_info": {
   "name": "python",
   "version": "3.14.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
