# PlayDrop 게임의 로컬 파티, 게임패드, 휴대폰 컨트롤러

sdk.device로 실제 게임패드와 PlayDrop 휴대폰 컨트롤러를 읽고, 로컬 플레이어 슬롯을 따르고, 컨트롤러 지원과 로컬 파티 인원수를 선언하세요.

Source: https://www.playdrop.ai/ko/create/learn/local-party

로컬 파티는 여러 사람이 화면 하나에서 각자 컨트롤러를 들고 함께 플레이하는 방식입니다. 컨트롤러는 실제 게임패드일 수도 있고, 코드를 스캔하면 PlayDrop이 컨트롤러로 바꿔 주는 휴대폰일 수도 있습니다. 게임은 웹사이트와 앱 모두에서 SDK를 통해 모든 컨트롤러를 같은 방식으로 읽습니다.

## 컨트롤러와 파티 인원수 선언하기

```json
{
  "types": ["solo", "party"],
  "party": { "local": [1, 2, 3, 4] },
  "controller": { "support": "optional", "type": "simpler" }
}
```

- `controller.support`는 `off`, `optional` 또는 `required`입니다. `off`를 포함해 모든 게임에 선언하세요.
- `controller.type`은 게임에 필요한 최소 조작 장치를 지정합니다. `any`(방향, 확인, 취소), `simpler`(스틱 1개, 페이스 버튼 4개, 메뉴. 휴대폰 컨트롤러가 해당됨) 또는 `standard`(방향 패드, 누를 수 있는 스틱 2개, 페이스 버튼 4개, 숄더 버튼 2개, 트리거 2개, 메뉴)입니다.
- `party.local`은 한 화면에서 플레이할 수 있는 정확한 인원수를 나열합니다. `1`이 있으면 `solo` 유형이 필요합니다. 컨트롤러 지원을 켜면 나열한 모든 인원수를 컨트롤러로 플레이할 수 있어야 합니다.

## 컨트롤러 읽기

```js
await sdk.device.enableControllerInput().catch(() => { /* keep keyboard and touch */ });

const stop = sdk.device.onButton(({ playerIndex, button, pressed }) => {
  if (button === "south" && pressed) jump(playerIndex);
});

function update() {
  for (const slot of sdk.device.localPlayers) {
    const pad = sdk.device.gamepad(slot.playerIndex);
    if (pad?.connected) move(slot.playerIndex, pad.axes[0], pad.axes[1]);
  }
  requestAnimationFrame(update);
}
update();
```

- `init()` 후에 `enableControllerInput()`을 한 번 호출하세요. 호스트가 입력을 제공할 수 없으면 `controller_input_unavailable` 또는 `controller_input_timeout`으로 거부되며, 게임은 계속 실행됩니다.
- `gamepad(playerIndex)`는 브라우저 표준 배치의 스냅샷을 반환합니다. `axes`(왼쪽 x/y, 오른쪽 x/y, -1~1), 버튼 17개가 담긴 `buttons`, `source`(`physical` 또는 `virtual`), `id`가 들어 있습니다. `playerIndex` 0은 플레이어 1입니다.
- 버튼에는 `south`, `east` 같은 위치 이름이 있습니다. `pad.label("south")`는 화면에 표시할 버튼 이름을 반환하며, 컨트롤러에 따라 "A", "Cross" 또는 "B"입니다. `pad.has("dpad")`는 해당 조작 장치가 있는지 알려 줍니다.
- 메뉴 버튼과 홈 버튼은 PlayDrop이 사용하며 항상 놓인 상태로 읽힙니다.
- `navigator.getGamepads()`를 절대 호출하지 마세요. 휴대폰 컨트롤러는 SDK를 통해서만 게임에 전달되며, PlayDrop이 경고를 기록합니다.

## 로컬 플레이어 슬롯

`sdk.device.localPlayers`는 플레이어가 고른 슬롯 `{ playerIndex, gamepadKey }`를 나열하며, `onLocalPlayersChange(callback)`이 변경을 알려 줍니다. 연결이 끊긴 컨트롤러도 슬롯을 유지합니다. 참가자 구성이 바뀌거나 비면 오류로 멈추지 말고 적절한 메뉴로 돌아가세요. 컨트롤러가 하나뿐이라면 파티가 아니라 일반 입력입니다.

버튼에서 `sdk.social.openParty({ mode: "local" })`를 호출하면 휴대폰용 QR 코드와 연결된 게임패드가 표시되는 PlayDrop 연결 창이 열립니다. 선언한 모드만 제공하세요.

## 로컬 또는 온라인, 둘 중 하나만

호스트는 게임을 로컬 파티나 온라인 파티 중 하나로만 시작하며, 둘을 동시에 쓰지 않습니다. 로컬 플레이어는 온라인 방에 참가할 수 없습니다. 친구와 온라인으로 플레이하려면 [온라인 파티와 음성 채팅](https://www.playdrop.ai/ko/create/learn/online-party)을 참고하세요.

## 소파에서 즐기도록 설계하기

플레이어마다 색상과 컨트롤러 버튼 안내를 표시하고, 누구든 버튼을 눌러 참가할 수 있게 하고, 소파에서도 HUD를 읽을 수 있게 하세요. 혼자 플레이할 때를 위해 터치와 키보드 조작은 유지하세요.

## 관련 가이드

- [온라인 파티와 음성 채팅](https://www.playdrop.ai/ko/create/learn/online-party): 친구들이 온라인에서 함께 플레이하게 하세요. 파티 인원수를 선언하고, PlayDrop 파티 창을 열고, sdk.multiplayer.join으로 예약된 방에 참가하고, 방 음성 채팅을 제어하세요.
- [전체 화면과 안전 영역](https://www.playdrop.ai/ko/create/learn/viewport): PlayDrop 게임이 화면을 꽉 채우게 하고, SDK가 측정한 reservedCorners로 HUD를 CSS 안전 영역 안에 두고 호스트 컨트롤과 겹치지 않게 하세요.
- [catalogue.json](https://www.playdrop.ai/ko/create/learn/catalogue-json): PlayDrop 게임이 쓰는 catalogue.json 필드: 식별 정보, 등록 정보, 플레이 방식, 화면, 로그인, 인스턴트, 미리 로드, 미디어, 번역, 점수, 서버.
