{ "cells": [ { "cell_type": "markdown", "id": "3efee1fe", "metadata": {}, "source": [ "(ch:classes_instances_objects)=\n", "# 클래스, 인스턴스, 객체" ] }, { "cell_type": "markdown", "id": "059cfda7", "metadata": {}, "source": [ "**감사의 글** \n", "\n", "아래 내용은 [(유튜브) Python Game Coding: Introduction to Collision Detection](https://www.youtube.com/watch?v=bFURdsszto0)의 내용을 참고합니다." ] }, { "cell_type": "markdown", "id": "eba16e26", "metadata": {}, "source": [ "**준비사항**\n", "\n", "여기서 사용하는 코드는 두 객체의 충돌을 감지하는 다양한 방법을 보여주며,\n", "[(레플릿) 충돌 감지](https://replit.com/@codingrg/collisiondetection#main.py)에서\n", "확인하고 직접 실행할 수 있다.\n", "오프라인 환경에서 실행하려면 먼저 아래 코드의 실행에 필요한 \n", "[이미지 파일과 소스코드](https://github.com/codingalzi/pybook/raw/master/jupyter-book/codes/collision_detection.zip)를\n", "다운로드해서 압축을 푼 다음에 `collision_dection.py` 파일을 실행하면 된다." ] }, { "cell_type": "markdown", "id": "e0041e8e", "metadata": {}, "source": [ "## 주요 내용" ] }, { "cell_type": "markdown", "id": "eaaf059e", "metadata": {}, "source": [ "### 객체 교감: 충돌 감지" ] }, { "cell_type": "markdown", "id": "0cd5a955", "metadata": {}, "source": [ "객체의 이동과 충돌 감지를 지원하는 클래스를 선언하고 활용하는 \n", "과정을 상세히 소개한다." ] }, { "cell_type": "markdown", "id": "4b7c797b", "metadata": {}, "source": [ "**충돌이 감지되는 경우**" ] }, { "cell_type": "markdown", "id": "de7b9ea0", "metadata": {}, "source": [ "아래 두 그림은 팩맨 객체와 체리 객체의 충돌 이전과 이후를 보여준다.\n", "오른쪽 팩맨이 체리와 접촉하는 순간 체리가 X 자로 변하여 잡아먹히는 장면이다." ] }, { "cell_type": "markdown", "id": "3140b553", "metadata": {}, "source": [ "\n", " \n", " \n", " \n", " \n", "
\n", "
\n", " \n", "
충돌 전
\n", "
\n", "
\n", "
\n", " \n", "
충돌 후
\n", "
\n", "
" ] }, { "cell_type": "markdown", "id": "05770767", "metadata": {}, "source": [ "**충돌이 감지되지 못하는 경우**" ] }, { "cell_type": "markdown", "id": "0312e95b", "metadata": {}, "source": [ "반면에 아래 두 그림은 팩맨 객체와 체리 객체가 서로의 충돌을 감지하지 못하여 그냥 통과하는 장면을 보여준다." ] }, { "cell_type": "markdown", "id": "c746d1b9", "metadata": {}, "source": [ "\n", " \n", " \n", " \n", " \n", "
\n", "
\n", " \n", "
충돌 미감지
\n", "
\n", "
\n", "
\n", " \n", "
그냥 통과
\n", "
\n", "
" ] }, { "cell_type": "markdown", "id": "c8bcc8d0", "metadata": {}, "source": [ "### 클래스, 인스턴스, 객체?" ] }, { "cell_type": "markdown", "id": "2aa431c6", "metadata": {}, "source": [ "객체object는 특정 클래스class의 인스턴스로 생성된다.\n", "즉, 클래스는 활용하고자 하는 객체object를\n", "인스턴스instance로 생성할 때 사용되는 설계도에 해당하며,\n", "생성되는 인스턴스가 갖는 속성을 지정하고 활용하는 함수를 정의한다.\n", "\n", "* 속성attribute: 클래스에서 선언된 변수. 인스턴스의 속성 저장.\n", "* 메서드method: 클래스에서 선언된 함수. 인스턴스의 기능 지정.\n", "\n", "클래스의 인스턴스를 생성할 때 속성이 지정되며,\n", "생성된 인스턴스는 해당 클래스의 모든 메서드(기능)를 사용할 수 있다." ] }, { "cell_type": "markdown", "id": "82dabbb6", "metadata": {}, "source": [ "## 클래스 선언과 생성자" ] }, { "cell_type": "markdown", "id": "a8143fcd", "metadata": {}, "source": [ "아래 그림에 있는 스프라이트 객체를 생성할 때 사용되는 클래스를 선언하면서\n", "클래스 선언에 필요한 요소들을 하나씩 살펴 본다." ] }, { "cell_type": "markdown", "id": "10f4a97a", "metadata": {}, "source": [ "

" ] }, { "cell_type": "markdown", "id": "149cafbc", "metadata": {}, "source": [ "**기본 세팅**" ] }, { "cell_type": "markdown", "id": "b296809a", "metadata": {}, "source": [ "도화지 객체 `wn`과 거북이 객체 `pen`을 준비한다.\n", "또한 스프라이트에 사용될 사진 7 개를 거북이 객체의 모양 라이브러리에 추가한다." ] }, { "cell_type": "markdown", "id": "5ccfe4ac", "metadata": {}, "source": [ "```python\n", "import turtle\n", "import math\n", "\n", "# 도화지 객체 설정\n", "wn = turtle.Screen()\n", "wn.bgcolor(\"black\")\n", "wn.title(\"Collision Detection\")\n", "wn.tracer(0) # 도화지 내용 한 번에 업데이트 되도록 지정\n", "\n", "# 거북이 객체 설정\n", "pen = turtle.Turtle()\n", "pen.speed(0) # 가장 빠르게 이동\n", "pen.hideturtle() # 숨김\n", "\n", "# 스프라이트 이미지 7개 등\n", "shapes = [\"wizard.gif\", \"goblin.gif\", \n", " \"pacman.gif\", \"cherry.gif\",\n", " \"bar.gif\", \"ball.gif\", \"x.gif\"]\n", "\n", "for shape in shapes:\n", " wn.register_shape(shape)\n", "```" ] }, { "cell_type": "markdown", "id": "10950e16", "metadata": {}, "source": [ "위 코드에 사용된 객체와 메서드의 기능은 다음과 같다.\n", "\n", "- 거북이 객체 `pen`: 모양은 마우스를 이용하여 선택된 스프라이트의 이미지로 지정된다. \n", " 마우스 클릭으로 선택된 스프라이트의 이동은 따라서 `pen` 객체를 지정된 위치로 이동 시킨 후 도장을 찍는 방식으로 구현한다.\n", "\n", "- `pen.hideturtle()`: 거북이 객체 `pen`을 보이지 않도록 지정하기에 이동할 때 선은 그려지지 않는다.\n", "\n", "- `pen.speed(0)`: 거북이 객체의 이동 속도를 가장 빠르게 지정. 1이면 가장 느리고, 10일 때 빨라진다.\n", "\n", "- `wn.tracer(0)`: 거북이 객체 `pen`이 지정된 위치로 이동할 때마다 찍는 스프라이트 이미지를 하나씩이 아닌 \n", " 화면이 전환될 때마다 한꺼번에 실행되도록 설정한다.\n", "\n", "- `wn.register_shape()`: 거북이 객체의 모양으로 활용될 수 이미지를 등록한다." ] }, { "cell_type": "markdown", "id": "084b735b", "metadata": {}, "source": [ "### 클래스 선언" ] }, { "cell_type": "markdown", "id": "032f0b08", "metadata": {}, "source": [ "스프라이트들의 클래스를 정의해보자.\n", "클래스 정의는 다음 형식으로 이루어진다." ] }, { "cell_type": "markdown", "id": "8ea2ac38", "metadata": {}, "source": [ "```python\n", "class Sprite:\n", " ...\n", " # 속성 지정 및 메서드 선언\n", "```" ] }, { "cell_type": "markdown", "id": "0cf5be4c", "metadata": {}, "source": [ "`Sprite` 클래스의 속성으로 스프라이트의 모양에 대한 정보 등이 저장된다.\n", "`Sprite` 클래스가 제공해야 하는 메서드로\n", "예를 들어 스프라이트의 이동, 충돌감지 기능 등이 포함된다." ] }, { "cell_type": "markdown", "id": "f8cb6e9c", "metadata": {}, "source": [ "### 생성자" ] }, { "cell_type": "markdown", "id": "38d315bf", "metadata": {}, "source": [ "모든 파이썬 클래스는 해당 클래스의 **인스턴스**instance를 생성하는 **생성자**를 포함해야 한다.\n", "파이썬 클래스의 생성자는 항상 `__init__()` 함수로 구현된다.\n", "생성자는 인자로 받는 값을 생성하는 인스턴스의 속성attributes으로 지정한다.\n", "예를 들어 아래 코드에서 선언되는 `Sprite` 클래스의 생성자는 생성되는 객체의 처음 위치, 크기, 모양 등을 결정하는 요소를 지정한다." ] }, { "cell_type": "markdown", "id": "dac6ea90", "metadata": {}, "source": [ "```python\n", "class Sprite:\n", " # 생성자: 스프라이트의 위치, 가로/세로 크기, 이미지 지정\n", " def __init__(self, x, y, width, height, image):\n", " \"\"\"\n", " x: x-좌표\n", " y: y-좌표\n", " width: 가로 크기\n", " height: 세로 크기\n", " image: 모양\n", " \"\"\"\n", "\n", " self.x = x\n", " self.y = y\n", " self.width = width\n", " self.height = height\n", " self.image = image\n", "```" ] }, { "cell_type": "markdown", "id": "42cec8ca", "metadata": {}, "source": [ ":::{admonition} 인스턴스 초기 설정\n", ":class: info\n", "\n", "엄밀히 말하면 `__init__()` 함수는 객체를 생성하는 게 아니라\n", "생성되는 객체의 초기 설정을 담당하지만\n", "생성자라는 표현이 일반적으로 사용된다.\n", ":::" ] }, { "cell_type": "markdown", "id": "90a26680", "metadata": {}, "source": [ "## 인스턴스와 객체" ] }, { "cell_type": "markdown", "id": "5d6a5ce9", "metadata": {}, "source": [ "**객체**object는 특정 클래스의 인스턴스를 부를 때 사용한다.\n", "`Sprite` 클래스의 인스턴스를 이용하여 객체가 갖는 속성과 기능을 설명한다." ] }, { "cell_type": "markdown", "id": "a9af534b", "metadata": {}, "source": [ "### 인스턴스 생성" ] }, { "cell_type": "markdown", "id": "f5a0ee42", "metadata": {}, "source": [ "`Sprite` 클래스의 **인스턴스**instance를 생성하는 방식은 다음과 같다." ] }, { "cell_type": "markdown", "id": "944d7415", "metadata": {}, "source": [ "```python\n", "wizard = Sprite(-128, 200, 128, 128, \"wizard.gif\")\n", "```" ] }, { "cell_type": "markdown", "id": "fe150640", "metadata": {}, "source": [ "그러면 생성자 함수 `__init__()`가 아래 인자들과 함께 호출된다.\n", "\n", " -128, 200, 128, 128, \"wizard.gif\"" ] }, { "cell_type": "markdown", "id": "fcca7c3c", "metadata": {}, "source": [ "메모리 상에서 `wizard` 변수가 가리키는 스프라이트 객체는 아래와 같이 구성된다." ] }, { "cell_type": "markdown", "id": "8cf6666d", "metadata": {}, "source": [ "

" ] }, { "cell_type": "markdown", "id": "cce84f7d", "metadata": {}, "source": [ "**`self`의 기능**\n", "\n", "`wizard = Sprite(-128, 200, 128, 128, \"wizard.gif\")` 방식으로 변수 할당이 실행되면\n", "파이썬 실행기interpreter는 다음을 싱행한다.\n", "\n", "```python\n", "__init__(wizard, -128, 200, 128, 128, \"wizard.gif\")\n", "```\n", "\n", "즉, `self` 매개변수는 현재 생성되는 객체를 인자로 사용한다." ] }, { "cell_type": "markdown", "id": "463ac91d", "metadata": {}, "source": [ "### 인스턴스 변수와 속성" ] }, { "cell_type": "markdown", "id": "833c15a1", "metadata": {}, "source": [ "**인스턴스 변수**instance variable는\n", "클래스 내부에서 `self`와 함께 선언된 변수를 가리킨다.\n", "앞서 선언된 `Sprite` 클래스의 인스턴스 변수는 아래 방식으로 선언된 `x`, `y`, `width`, `height`, `image` 다섯 개다.\n", "\n", "```python\n", "self.x\n", "self.y\n", "self.width\n", "self.height\n", "self.image\n", "```\n", "\n", "인스턴스 변수는 해당 클래스의 영역scope에서만 의미를 가지며,\n", "일반적으로 생성자가 실행되는 동안 선언되지만\n", "클래스 내부 어디에서도 선언될 수 있다.\n", "\n", "클래스의 인스턴스는 인스턴스 변수가 가리키는 값을 속성으로 갖는다.\n", "이런 의미에서 인스턴스 변수가 가리키는 값을 \n", "**인스턴스 속성**instance attribute이라 부른다.\n", "즉, 인스턴스 속성은 클래스의 인스턴스가 생성될 때만 의미를 갖는다.\n", "\n", "인스턴스 변수 이외에 `self` 를 사용하지 않는 \n", "**클래스 변수**class variable 가 선언될 수도 있지만\n", "여기서는 다루지 않는다." ] }, { "cell_type": "markdown", "id": "19e80078", "metadata": {}, "source": [ "**`__init__()` 함수의 매개 변수와 인스턴스 변수**" ] }, { "cell_type": "markdown", "id": "460a0ee1", "metadata": {}, "source": [ "함수를 호출할 때 매개 변수를 통해 함수 내부로 전달되는 인자는 해당 함수의 본문에서만 사용될 수 있다.\n", "반면에 `self.x`, `self.width` 처럼 클래스 내부 어딘가에서 선언되는 인스턴스 변수는 클래스 내부 어디에서든 사용될 수 있다.\n", "\n", "`Sprite` 클래스의 생성자인 `__init__()` 함수 내부에서 선언된 다섯 개의 인스턴스 변수명이 동일하지만\n", "이것은 의무사항이 아니다. \n", "여기서는 함수 내부에서 굳이 다른 변수명을 사용할 이유가 없기에 동일한 변수명을 사용했을 뿐이다.\n", "실제로 함수의 매개 변수와 클래스 내부에서 선언된 변수의 기능은 완전히 다르기 때문에 서로 충돌하지 않는다.\n", "\n", "프로그래밍 입문자에게 조금은 난해할` 수도 있기 때문에 아래와 같이 다른 변수명을 사용할 수도 있어지만 일부러 그러지 않았다.\n", "이유는 많은 프로그래머가 유사한 방식으로 인스턴스 변수를 선언하기 때문이다. \n", "\n", "```python\n", " def __init__(self, x_param, y_param, width_param, height_param, image_param):\n", " self.x = x_param\n", " self.y = y_param\n", " self.width = width_param\n", " self.height = height_param\n", " self.image = image_param\n", "```" ] }, { "cell_type": "markdown", "id": "413a710b", "metadata": {}, "source": [ "### 인스턴스 메서드" ] }, { "cell_type": "markdown", "id": "a2f534fe", "metadata": {}, "source": [ "생성자 `__init__()` 함수처럼 클래스 내부에 선언된 함수를 **메서드**method라 부른다.\n", "메서드는 크게 인스턴스 메서드, 클래스 메서드, 정적 메서드로 나뉘며 여기서는 인스턴스 메서드만 소개한다.\n", "\n", "인스턴스 메서드의 첫재 매개 변수가 항상 `self`이며, \n", "생성자 `__init__()` 함수 또한 이런 의미에서 인스턴스 메서드다.\n", "아래 코드는 `render()` 인스턴스 메서드를 추가하는 방식으로 `Sprite` 클래스를 새로 정의한다." ] }, { "cell_type": "markdown", "id": "5ee03eb6", "metadata": {}, "source": [ "```python\n", "class Sprite():\n", " \n", " # 생성자: 스프라이트의 위치, 가로/세로 크기, 이미지 지정\n", " def __init__(self, x, y, width, height, image):\n", " \"\"\"\n", " x: x-좌표\n", " y: y-좌표\n", " width: 가로 크기\n", " height: 세로 크기\n", " image: 모양\n", " \"\"\"\n", "\n", " self.x = x\n", " self.y = y\n", " self.width = width\n", " self.height = height\n", " self.image = image\n", " \n", " # 지정된 위치로 스프라이트 이동 후 도장 찍기\n", " def render(self, pen):\n", " pen.goto(self.x, self.y)\n", " pen.shape(self.image)\n", " pen.stamp()\n", "```" ] }, { "cell_type": "markdown", "id": "1d6ededd", "metadata": {}, "source": [ "## 스프라이트 충돌" ] }, { "cell_type": "markdown", "id": "650d5ce3", "metadata": {}, "source": [ "스프라이트들의 충동을 감지하는 전체 코드를 확인한다." ] }, { "cell_type": "markdown", "id": "41c5c09e", "metadata": {}, "source": [ "각 스프라이트 객체는 지정된 위치로의 이동 및 자신의 이미지를 보여주는 기능을\n", "수행하는 `render()` 메서드와 함께\n", "다른 스프라이트와의 충돌을 감지하는 기능을 갖는 세 종류의 메서드를 갖는다." ] }, { "cell_type": "markdown", "id": "5f1a7ed6", "metadata": {}, "source": [ "```python\n", "class Sprite():\n", " \n", " ## 생성자: 스프라이트의 위치, 가로/세로 크기, 이미지 지정\n", " \n", " def __init__(self, x, y, width, height, image):\n", " self.x = x\n", " self.y = y\n", " self.width = width\n", " self.height = height\n", " self.image = image\n", "\n", " ## 스프라이트 메서드\n", " \n", " # 지정된 위치로 스프라이트 이동 후 도장 찍기\n", " def render(self, pen):\n", " pen.goto(self.x, self.y)\n", " pen.shape(self.image)\n", " pen.stamp()\n", " \n", " # 충돌 감지 방법 1: 두 스프라이트의 중심이 일치할 때 충돌 발생\n", " def is_overlapping_collision(self, other):\n", " if self.x == other.x and self.y == other.y:\n", " return True\n", " else:\n", " return False\n", " \n", " # 충돌 감지 방법 2: 두 스프라이트 사이의 거리가 두 객체의 너비의 평균값 보다 작을 때 충돌 발생\n", " def is_distance_collision(self, other):\n", " distance = (((self.x-other.x) ** 2) + ((self.y-other.y) ** 2)) ** 0.5\n", " if distance < (self.width + other.width)/2.0:\n", " return True\n", " else:\n", " return False\n", " \n", " # 충돌 감지 방법 3: 각각의 스프라이트를 둘러썬 경계상자가 겹칠 때 충돌 발생\n", " # aabb: Axis Aligned Bounding Box\n", " def is_aabb_collision(self, other):\n", " x_collision = (math.fabs(self.x - other.x) * 2) < (self.width + other.width)\n", " y_collision = (math.fabs(self.y - other.y) * 2) < (self.height + other.height)\n", " return (x_collision and y_collision)\n", "```" ] }, { "cell_type": "markdown", "id": "c650c698", "metadata": {}, "source": [ ":::{admonition} `self` 와 `other`\n", "\n", "`f14.__add__(f12)` 이 실행되면 실제로는 `__add__()` 메서드가 다음과 같이 호출된다.\n", "\n", "```python\n", "__add__(f14, f12)\n", "```\n", "\n", "즉, `self=f14`, `other=f12` 가 인자로 사용된다.\n", "하지만 `f14` 를 기준(self)으로 해서 다른 값(other)과의 연산을 실행한다는 의미를\n", "강조하기 위해 관행적으로 `self` 와 `other` 를 매개변수로 사용한다.\n", "\n", "이런 관행은 덧셈과 동등성 비교 등 모든 이항 연산자를 정의할 때 활용된다.\n", "예를 들어 `f1 == f2`, \n", "즉 `f1.__eq__(f2)`는 파이썬 실행기의 내부에서 `__eq__(f1, f2)` 로 처리된다.\n", ":::" ] }, { "cell_type": "markdown", "id": "85e36f6d", "metadata": {}, "source": [ "**스프라이트 객체 생성**\n", "\n", "위 그림에 포함된 6 종류의 스프라이트 객체를 생성한다.\n", "스프라이트 중심의 x, y 좌표, 길이와 너비, 이미지 등이 지정된다." ] }, { "cell_type": "markdown", "id": "04ba0c88", "metadata": {}, "source": [ "```python\n", "wizard = Sprite(-128, 200, 128, 128, \"wizard.gif\")\n", "goblin = Sprite(128, 200, 108, 128, \"goblin.gif\")\n", "\n", "pacman = Sprite(-128, 0, 128, 128, \"pacman.gif\")\n", "cherry = Sprite(128, 0, 128, 128, \"cherry.gif\")\n", "\n", "bar = Sprite(0, -400, 128, 24, \"bar.gif\")\n", "ball = Sprite(0,-200, 32, 32, \"ball.gif\")\n", "\n", "# 스프라이트 모음 리스트\n", "sprites = [wizard, goblin, pacman, cherry, bar, ball]\n", "```" ] }, { "cell_type": "markdown", "id": "32a76a57", "metadata": {}, "source": [ "**이벤트와 콜백 함수**\n", "\n", "마우스 클릭, 버튼 누루기, 키 입력 등을 사용하여 \n", "영향을 미치는 사건을 **이벤트**event라 부르며, \n", "이벤트에 반응하도록 프로그램을 작성하는 것이 \n", "**이벤트 처리**다.\n", "여기서는 `goblin`, `pacman`, `ball` 객체를 각각 왼쪽, 오른쪽, 아래 방향으로\n", "움직이도록 하는 이벤트를 설정한다.\n", "\n", "이벤트 처리에 사용되는 함수를 **콜백**callback라 부르는데\n", "사용하는 패키지, 모듈 등에 따라 콜백 함수가 사용되는 방식이 달라진다.\n", "`turtle` 모듈의 경우 `Screen.listen()` 메서드를 이용한다." ] }, { "cell_type": "markdown", "id": "738bafdb", "metadata": {}, "source": [ "```python\n", "# 고블린 이동\n", "def move_goblin():\n", " goblin.x -= 64\n", "\n", "# 팩맨 이동\n", "def move_pacman():\n", " pacman.x += 30\n", " \n", "# 야구공 이동\n", "def move_ball():\n", " ball.y -= 24\n", "\n", "# 이벤트 처리\n", "wn.listen()\n", "wn.onkeypress(move_goblin, \"Left\") # 왼쪽 방향 화살표 입력\n", "wn.onkeypress(move_pacman, \"Right\") # 오른쪽 방향 화살표 입력\n", "wn.onkeypress(move_ball, \"Down\") # 아래방향 화살표 입력\n", "```" ] }, { "cell_type": "markdown", "id": "954c72ee", "metadata": {}, "source": [ "**게임 실행**\n", "\n", "게임 실행 중에 화살표 키가 입력될 때마다 지정된 콜백 함수가 실행되어\n", "의도된 스프라이트가 이동한다.\n", "이동하다가 다른 스프라이트와 충돌하면 해당 스프라이트가 X 모양의 이미지로 변경된다." ] }, { "cell_type": "markdown", "id": "f0b34017", "metadata": {}, "source": [ "

" ] }, { "cell_type": "markdown", "id": "114286e1", "metadata": {}, "source": [ "```python\n", "while True:\n", " \n", " # 각 스프라이트 위치 이동 및 도장 찍기\n", " for sprite in sprites:\n", " sprite.render(pen)\n", " \n", " # 충돌 여부 확인\n", " if wizard.is_overlapping_collision(goblin):\n", " wizard.image = \"x.gif\"\n", " \n", " if pacman.is_overlapping_collision(cherry):\n", " cherry.image = \"x.gif\"\n", " \n", " if bar.is_overlapping_collision(ball):\n", " ball.image = \"x.gif\"\n", " \n", " wn.update() # 화면 업데이트\n", " pen.clear() # 스프라이트 이동흔적 삭제\n", "```" ] }, { "cell_type": "markdown", "id": "726bd311", "metadata": {}, "source": [ ":::{admonition} 프레임\n", ":class: info\n", "\n", "앞선 코드의 `while` 반복문이 한 번 실행되는 과정을 **프레임**frame이라 부른다.\n", "1초 길이의 동영상에 사용된 사진의 수로 동영상의 프레임을 지정하는 방식과 유사한 개념이다.\n", "컴퓨터의 경우 초당 훨씬 많은 수의 프레임이 돌아갈 수 있지만 '\n", "프레임에 포함된 코드의 실행 시간에 따라 다르다.\n", ":::" ] }, { "cell_type": "markdown", "id": "0143c613", "metadata": {}, "source": [ "## OOP의 핵심" ] }, { "cell_type": "markdown", "id": "3dc7c1a4", "metadata": {}, "source": [ "매 프레임마다 아래 코드가 반복적으로 실행된다.\n", "\n", "```python\n", "if wizard.is_overlapping_collision(goblin):\n", " wizard.image = \"x.gif\"\n", "```\n", "\n", "즉, `wizard` 가 `goblin` 과 충돌하면 마법사의 이미지를 X 모양으로 변경한다.\n", "그런데 마법사가 고블린과 충돌하는지를 어떻게 감지하는가?\n", "`wizard` 객체의 `is_overlapping_collision()` 메서드가\n", "자신과 `goblin` 객체의 위치, 길이, 너비 정보를 이용하여 알아낸다.\n", "즉, 두 객체 사이에 정보를 주고 받는다.\n", "\n", "이처럼 객체들 사이에 주고 받을 수 있는 정보를 이용하여 객체의 상태와 행동을\n", "결정하는 프로그래밍 기법이 바로 객체 지향 프로그래밍이다." ] }, { "cell_type": "markdown", "id": "22be2e2c", "metadata": {}, "source": [ "## 연습문제" ] }, { "cell_type": "markdown", "id": "31b9be77", "metadata": {}, "source": [ "참고: [(실습) 사례 연구: 객체 지향 프로그래밍](https://colab.research.google.com/github/codingalzi/pybook/blob/master/practices/practice-casestudy_oop.ipynb)" ] }, { "cell_type": "markdown", "id": "e569f38b", "metadata": {}, "source": [ "## 연습문제" ] }, { "cell_type": "markdown", "id": "3a28f405", "metadata": {}, "source": [ "참고: [(실습) 클래스, 인스턴스, 객체](https://colab.research.google.com/github/codingalzi/pybook/blob/master/practices/practice-classes_instances_objects.ipynb)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "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.11.5" } }, "nbformat": 4, "nbformat_minor": 5 }