개발 환경 준비
프로젝트 수정과 실행에 필요한 프로그램 및 계정
프로그램 설치 및 계정 생성
VS Code에 GitHub 계정 연결
- VS Code를 실행한다.
- 왼쪽 아래의 사람 모양 계정 아이콘을 누른다.
- Sign in with GitHub를 선택한다.
- 브라우저에서 GitHub에 로그인하고 VS Code 연결을 승인한다.
- VS Code의 계정 메뉴에 GitHub 계정 이름이 표시되는지 확인한다.
Git 사용자 정보 설정
- Terminal → New Terminal을 선택한다.
- 아래 명령어의 이름과 이메일을 GitHub 계정 정보로 바꿔 입력한다.
git config --global user.name "GitHub 사용자 이름"
git config --global user.email "GitHub 가입 이메일"
소스코드 다운로드 및 열기
ZIP 파일을 내려받아 프로젝트 폴더로 연다.
- 소스코드 다운로드
- 다운로드한 ZIP 파일의 압축을 해제한다.
- 폴더 이름을 영문으로 변경한다. 예:
my-pet-game - VS Code에서 File → Open Folder를 선택한다.
- 압축을 해제한 프로젝트 폴더를 선택한다.
기본 프로젝트 실행
의존성 패키지를 설치하고 개발 서버를 실행한다.
- VS Code 상단 메뉴에서 Terminal → New Terminal을 선택한다.
-
npm install을 입력하고 Enter를 누른다. 설치가 진행되면서 터미널에 여러 문구가 표시된다. 입력할 수 있는 줄이 다시 나타날 때까지 기다린다. -
npm run dev를 입력하고 Enter를 누른다. 터미널에 표시된http://localhost:5173주소를 복사해 인터넷 브라우저 주소창에 붙여넣는다. - 개발 서버를 종료할 때는 터미널에서
Ctrl + C를 누른다. Mac에서도Control + C를 사용한다.
npm install
npm run dev
새 동물 추가
동물별 데이터와 이미지를 추가하는 과정
게임 파일이 나뉜 방식
src/data에는 게임에서 사용할 동물 이름, 문구, 행동 목록, 이미지 경로가 들어간다.
새 동물의 설정 파일은 src/data/pets에 만들고, 실제 이미지 파일은
public/assets/animals에 동물 이름으로 된 폴더를 만들어 저장한다.
하나의 동물 설정 파일과 같은 이름의 이미지 폴더가 한 쌍으로 연결된다.
src/data/
└── pets/
├── dog.js 강아지의 이미지 경로, 문구, 행동 설정
└── index.js 선택 화면과 게임에 사용할 동물 등록
public/assets/
└── animals/
└── dog/
├── pet.webp 선택 화면과 집에서 보이는 기본 강아지
├── menu/ 큰 행동 버튼 그림
│ ├── feed.webp 먹이주기 버튼
│ ├── play.webp 놀아주기 버튼
│ ├── walk.webp 산책하기 버튼
│ └── petting.webp 쓰다듬기 버튼
├── tools/ 상호작용 중 움직이는 그림
│ └── hand.webp 쓰다듬을 때 움직이는 손
├── actions/ 행동 중인 강아지
│ ├── eating-water.webp 물을 마시는 강아지
│ ├── eating-food.webp 사료를 먹는 강아지
│ ├── eating-snack.webp 간식을 먹는 강아지
│ ├── eating-medicine.webp 약을 먹는 강아지
│ ├── playing-rope.webp 로프를 가지고 노는 강아지
│ ├── playing-ball.webp 공을 가지고 노는 강아지
│ ├── playing-squeaky.webp 삑삑이를 가지고 노는 강아지
│ ├── playing-doll.webp 인형을 가지고 노는 강아지
│ └── walking.webp 산책하는 강아지
├── backgrounds/ 장소 배경
│ ├── place-home.webp 강아지의 집
│ ├── place-eat.webp 먹을 것을 선택하는 장소
│ ├── place-play.webp 장난감을 선택하는 장소
│ ├── place-walk.webp 산책 장소를 선택하는 화면
│ ├── place-town.webp 동네 산책 배경
│ ├── place-park.webp 공원 산책 배경
│ ├── place-river.webp 하천 산책 배경
│ └── place-forest.webp 숲길 산책 배경
└── items/ 세부 선택 버튼에 들어가는 그림
├── food-water.webp 물
├── food-food.webp 사료
├── food-snack.webp 간식
├── food-medicine.webp 약
├── toy-rope.webp 로프
├── toy-ball.webp 공
├── toy-squeaky.webp 삑삑이
└── toy-doll.webp 인형
4-1. 새 동물 이미지 폴더 만들기
public/assets/animals안에 새 동물의 영문 이름(한 단어)으로 폴더를 만든다.- 새 동물 폴더 안에
menu,tools,actions,backgrounds,items폴더를 만든다. - 동물의 기본 모습은
pet.webp라는 이름으로 새 동물 폴더에 넣는다. - 큰 행동 버튼 그림은
menu에 넣는다. - 마우스나 터치로 움직이는 그림은
tools에 넣는다. - 행동 중인 동물 이미지는
actions에 넣는다. - 집과 각 활동의 장소 이미지는
backgrounds에 넣는다. - 세부 선택 버튼에 표시할 이미지는
items에 넣는다.
4-2. 동물 설정 파일 만들기
(1) 파일 복사
src/data/pets/dog.js를 복사해 같은 폴더에 붙여넣는다.- 복사한 파일 이름을 새 동물의 영문 이름으로 변경한다.
(2) 아래 코드로 파일 전체 교체
큰 행동 4개가 들어 있는 공용 템플릿이다. 첫 번째부터 세 번째 행동에는 각각 세부 선택지 4개가 있고, 네 번째 행동은 세부 선택 없이 집 배경과 동물의 기본 모습을 유지한 채 10초 동안 바로 진행된다. 상호작용 방식과 순서는 수정하지 않고, 화살표가 표시된 이름, 문구, ID, 이미지 경로만 변경한다.
큰 행동과 세부 선택지 옆의 스피커 버튼을 누르면 해당 항목의 name이 음성으로 재생된다.
requests의 before, highlight, after를 합친 부탁 문구는 화면에 나타날 때 자동으로 재생되고, 문구 옆의 스피커 버튼을 누르면 다시 들을 수 있다. 별도의 음성 파일은 필요하지 않다.
const catAsset = (path) => `/assets/animals/cat/${path}`; // cat을 새 동물의 영문 이름으로 변경
// ↑ 새 동물 이름으로 변경 ↑ 새 동물 이미지 폴더명으로 변경
const catActions = [ // cat을 새 동물의 영문 이름으로 변경
// ↑ 새 동물 이름으로 변경
{
id: "cat-action-1", // cat을 새 동물의 영문 이름으로 변경
name: "첫 번째 큰 행동 버튼 문구 입력",
image: catAsset("menu/첫번째-큰-행동-버튼-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
},
{
id: "cat-action-2", // cat을 새 동물의 영문 이름으로 변경
name: "두 번째 큰 행동 버튼 문구 입력",
image: catAsset("menu/두번째-큰-행동-버튼-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
},
{
id: "cat-action-3", // cat을 새 동물의 영문 이름으로 변경
name: "세 번째 큰 행동 버튼 문구 입력",
image: catAsset("menu/세번째-큰-행동-버튼-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
},
{
id: "cat-action-4", // cat을 새 동물의 영문 이름으로 변경
name: "네 번째 큰 행동 버튼 문구 입력",
image: catAsset("menu/네번째-큰-행동-버튼-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
},
];
const activities = {
"cat-action-1": { // cat을 새 동물의 영문 이름으로 변경
// ↑ catActions의 첫 번째 ID와 동일하게 입력 // cat을 새 동물의 영문 이름으로 변경
interaction: "instant",
// 상호작용 방식 고정: 선택 즉시 반응
background: catAsset("backgrounds/첫-행동-배경-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
// ↑ 실제 파일명 입력
options: [
{
id: "cat-action-1-option-1", // cat을 새 동물의 영문 이름으로 변경
// ↑ 첫 번째 세부 행동 ID 입력
name: "첫 번째 세부 행동 버튼 문구 입력",
image: catAsset("items/첫-선택-버튼-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
// ↑ 실제 파일명 입력
actionImage: catAsset("actions/첫-행동-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
// ↑ 실제 파일명 입력
reaction: "첫 번째 세부 행동이 끝난 뒤 표시할 문구 입력",
},
{
id: "cat-action-1-option-2", // cat을 새 동물의 영문 이름으로 변경
name: "두 번째 세부 행동 버튼 문구 입력",
image: catAsset("items/두번째-선택-버튼-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
actionImage: catAsset("actions/두번째-행동-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
reaction: "두 번째 세부 행동이 끝난 뒤 표시할 문구 입력",
},
{
id: "cat-action-1-option-3", // cat을 새 동물의 영문 이름으로 변경
name: "세 번째 세부 행동 버튼 문구 입력",
image: catAsset("items/세번째-선택-버튼-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
actionImage: catAsset("actions/세번째-행동-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
reaction: "세 번째 세부 행동이 끝난 뒤 표시할 문구 입력",
},
{
id: "cat-action-1-option-4", // cat을 새 동물의 영문 이름으로 변경
name: "네 번째 세부 행동 버튼 문구 입력",
image: catAsset("items/네번째-선택-버튼-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
actionImage: catAsset("actions/네번째-행동-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
reaction: "네 번째 세부 행동이 끝난 뒤 표시할 문구 입력",
},
],
},
"cat-action-2": { // cat을 새 동물의 영문 이름으로 변경
// ↑ catActions의 두 번째 ID와 동일하게 입력 // cat을 새 동물의 영문 이름으로 변경
interaction: "place",
// 상호작용 방식 고정: 물건을 움직여 원하는 위치에 놓기
completionDelay: 1300,
background: catAsset("backgrounds/두번째-행동-배경-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
instruction: "물건을 움직일 때 표시할 안내 문구 입력",
progressMessage: "물건을 놓은 뒤 표시할 문구 입력",
options: [
{
id: "cat-action-2-option-1", // cat을 새 동물의 영문 이름으로 변경
name: "첫 번째 세부 행동 버튼 문구 입력",
image: catAsset("items/첫-선택-버튼-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
actionImage: catAsset("actions/첫-행동-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
reaction: "첫 번째 세부 행동이 끝난 뒤 표시할 문구 입력",
},
{
id: "cat-action-2-option-2", // cat을 새 동물의 영문 이름으로 변경
name: "두 번째 세부 행동 버튼 문구 입력",
image: catAsset("items/두번째-선택-버튼-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
actionImage: catAsset("actions/두번째-행동-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
reaction: "두 번째 세부 행동이 끝난 뒤 표시할 문구 입력",
},
{
id: "cat-action-2-option-3", // cat을 새 동물의 영문 이름으로 변경
name: "세 번째 세부 행동 버튼 문구 입력",
image: catAsset("items/세번째-선택-버튼-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
actionImage: catAsset("actions/세번째-행동-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
reaction: "세 번째 세부 행동이 끝난 뒤 표시할 문구 입력",
},
{
id: "cat-action-2-option-4", // cat을 새 동물의 영문 이름으로 변경
name: "네 번째 세부 행동 버튼 문구 입력",
image: catAsset("items/네번째-선택-버튼-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
actionImage: catAsset("actions/네번째-행동-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
reaction: "네 번째 세부 행동이 끝난 뒤 표시할 문구 입력",
},
],
},
"cat-action-3": { // cat을 새 동물의 영문 이름으로 변경
// ↑ catActions의 세 번째 ID와 동일하게 입력 // cat을 새 동물의 영문 이름으로 변경
interaction: "drag-timer",
// 상호작용 방식 고정: 동물을 일정 시간 드래그
duration: 10,
background: catAsset("backgrounds/세번째-행동-배경-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
instruction: "동물을 움직이는 동안 표시할 안내 문구 입력",
options: [
{
id: "cat-action-3-option-1", // cat을 새 동물의 영문 이름으로 변경
name: "첫 번째 세부 행동 버튼 문구 입력",
image: catAsset("items/첫-선택-버튼-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
background: catAsset("backgrounds/첫-선택-후-배경-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
actionImage: catAsset("actions/첫-행동-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
reaction: "첫 번째 세부 행동이 끝난 뒤 표시할 문구 입력",
},
{
id: "cat-action-3-option-2", // cat을 새 동물의 영문 이름으로 변경
name: "두 번째 세부 행동 버튼 문구 입력",
image: catAsset("items/두번째-선택-버튼-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
background: catAsset("backgrounds/두번째-선택-후-배경-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
actionImage: catAsset("actions/두번째-행동-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
reaction: "두 번째 세부 행동이 끝난 뒤 표시할 문구 입력",
},
{
id: "cat-action-3-option-3", // cat을 새 동물의 영문 이름으로 변경
name: "세 번째 세부 행동 버튼 문구 입력",
image: catAsset("items/세번째-선택-버튼-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
background: catAsset("backgrounds/세번째-선택-후-배경-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
actionImage: catAsset("actions/세번째-행동-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
reaction: "세 번째 세부 행동이 끝난 뒤 표시할 문구 입력",
},
{
id: "cat-action-3-option-4", // cat을 새 동물의 영문 이름으로 변경
name: "네 번째 세부 행동 버튼 문구 입력",
image: catAsset("items/네번째-선택-버튼-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
background: catAsset("backgrounds/네번째-선택-후-배경-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
actionImage: catAsset("actions/네번째-행동-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
reaction: "네 번째 세부 행동이 끝난 뒤 표시할 문구 입력",
},
],
},
"cat-action-4": { // cat을 새 동물의 영문 이름으로 변경
interaction: "pet-timer",
// 상호작용 방식 고정: 세부 선택 없이 10초 동안 도구를 움직임
duration: 10,
instruction: "상호작용하는 동안 표시할 안내 문구 입력",
toolImage: catAsset("tools/움직이는-도구-이미지-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
reaction: "10초 상호작용이 끝난 뒤 표시할 문구 입력",
},
};
const requests = [
{
activityId: "cat-action-1", // cat을 새 동물의 영문 이름으로 변경
// ↑ 연결할 큰 행동 ID 입력
optionId: "cat-action-1-option-1", // cat을 새 동물의 영문 이름으로 변경
// ↑ 연결할 세부 행동 ID 입력
before: "강조 문구 앞에 표시할 내용 입력",
highlight: "강조색으로 표시할 핵심 문구 입력",
after: "강조 문구 뒤에 표시할 내용 입력",
},
{
activityId: "cat-action-1", // cat을 새 동물의 영문 이름으로 변경
optionId: "cat-action-1-option-2", // cat을 새 동물의 영문 이름으로 변경
before: "강조 문구 앞에 표시할 내용 입력",
highlight: "강조색으로 표시할 핵심 문구 입력",
after: "강조 문구 뒤에 표시할 내용 입력",
},
{
activityId: "cat-action-1", // cat을 새 동물의 영문 이름으로 변경
optionId: "cat-action-1-option-3", // cat을 새 동물의 영문 이름으로 변경
before: "강조 문구 앞에 표시할 내용 입력",
highlight: "강조색으로 표시할 핵심 문구 입력",
after: "강조 문구 뒤에 표시할 내용 입력",
},
{
activityId: "cat-action-1", // cat을 새 동물의 영문 이름으로 변경
optionId: "cat-action-1-option-4", // cat을 새 동물의 영문 이름으로 변경
before: "강조 문구 앞에 표시할 내용 입력",
highlight: "강조색으로 표시할 핵심 문구 입력",
after: "강조 문구 뒤에 표시할 내용 입력",
},
{
activityId: "cat-action-2", // cat을 새 동물의 영문 이름으로 변경
optionId: "cat-action-2-option-1", // cat을 새 동물의 영문 이름으로 변경
before: "강조 문구 앞에 표시할 내용 입력",
highlight: "강조색으로 표시할 핵심 문구 입력",
after: "강조 문구 뒤에 표시할 내용 입력",
},
{
activityId: "cat-action-2", // cat을 새 동물의 영문 이름으로 변경
optionId: "cat-action-2-option-2", // cat을 새 동물의 영문 이름으로 변경
before: "강조 문구 앞에 표시할 내용 입력",
highlight: "강조색으로 표시할 핵심 문구 입력",
after: "강조 문구 뒤에 표시할 내용 입력",
},
{
activityId: "cat-action-2", // cat을 새 동물의 영문 이름으로 변경
optionId: "cat-action-2-option-3", // cat을 새 동물의 영문 이름으로 변경
before: "강조 문구 앞에 표시할 내용 입력",
highlight: "강조색으로 표시할 핵심 문구 입력",
after: "강조 문구 뒤에 표시할 내용 입력",
},
{
activityId: "cat-action-2", // cat을 새 동물의 영문 이름으로 변경
optionId: "cat-action-2-option-4", // cat을 새 동물의 영문 이름으로 변경
before: "강조 문구 앞에 표시할 내용 입력",
highlight: "강조색으로 표시할 핵심 문구 입력",
after: "강조 문구 뒤에 표시할 내용 입력",
},
{
activityId: "cat-action-3", // cat을 새 동물의 영문 이름으로 변경
optionId: "cat-action-3-option-1", // cat을 새 동물의 영문 이름으로 변경
before: "강조 문구 앞에 표시할 내용 입력",
highlight: "강조색으로 표시할 핵심 문구 입력",
after: "강조 문구 뒤에 표시할 내용 입력",
},
{
activityId: "cat-action-3", // cat을 새 동물의 영문 이름으로 변경
optionId: "cat-action-3-option-2", // cat을 새 동물의 영문 이름으로 변경
before: "강조 문구 앞에 표시할 내용 입력",
highlight: "강조색으로 표시할 핵심 문구 입력",
after: "강조 문구 뒤에 표시할 내용 입력",
},
{
activityId: "cat-action-3", // cat을 새 동물의 영문 이름으로 변경
optionId: "cat-action-3-option-3", // cat을 새 동물의 영문 이름으로 변경
before: "강조 문구 앞에 표시할 내용 입력",
highlight: "강조색으로 표시할 핵심 문구 입력",
after: "강조 문구 뒤에 표시할 내용 입력",
},
{
activityId: "cat-action-3", // cat을 새 동물의 영문 이름으로 변경
optionId: "cat-action-3-option-4", // cat을 새 동물의 영문 이름으로 변경
before: "강조 문구 앞에 표시할 내용 입력",
highlight: "강조색으로 표시할 핵심 문구 입력",
after: "강조 문구 뒤에 표시할 내용 입력",
},
{
activityId: "cat-action-4", // cat을 새 동물의 영문 이름으로 변경
optionId: null,
// 네 번째 행동에는 세부 선택지가 없으므로 null 유지
before: "강조 문구 앞에 표시할 내용 입력",
highlight: "강조색으로 표시할 핵심 문구 입력",
after: "강조 문구 뒤에 표시할 내용 입력",
},
];
export const cat = { // cat을 새 동물의 영문 이름으로 변경
// ↑ 새 동물의 영문 이름으로 변경
id: "cat", // cat을 새 동물의 영문 이름으로 변경
// ↑ 새 동물의 영문 ID로 변경
name: "화면에 표시할 동물 이름 입력",
selectionImage: catAsset("pet.webp"), // cat을 새 동물의 영문 이름으로 변경
defaultImage: catAsset("pet.webp"), // cat을 새 동물의 영문 이름으로 변경
homeBackground: catAsset("backgrounds/집-배경-파일명.webp"), // cat을 새 동물의 영문 이름으로 변경
available: true,
actions: catActions, // cat을 새 동물의 영문 이름으로 변경
// ↑ 새 동물 이름으로 변경
activities,
requests,
};
4-3. 선택 화면과 게임에 새 동물 등록
고양이를 추가한 src/data/pets/index.js의 전체 코드다.
import { dog } from "./dog";
import { cat } from "./cat"; // cat을 새 동물의 영문 이름으로 변경
// ↑ 다른 동물의 export 이름 ↑ 다른 동물의 설정 파일명
export const petCatalog = [
dog,
cat, // cat을 새 동물의 영문 이름으로 변경
// ↑ 다른 동물을 추가할 때 해당 동물의 export 이름 입력
{ id: "snail", name: "달팽이", emoji: "🐌", available: false },
{ id: "beetle", name: "장수풍뎅이", emoji: "🪲", available: false },
{ id: "chameleon", name: "카멜레온", emoji: "🦎", available: false },
];
export const petConfigs = {
dog,
cat, // cat을 새 동물의 영문 이름으로 변경
// ↑ 다른 동물을 추가할 때 해당 동물의 export 이름 입력
};
4-4. 저장하고 확인
- Terminal → New Terminal을 선택한다.
npm run dev를 입력하고 Enter를 누른다.- 확인을 마친 뒤 터미널에서
Ctrl + C를 눌러 개발 서버를 종료한다. Mac에서도Control + C를 사용한다.
GitHub 저장소 생성 및 업로드
VS Code의 Source Control 기능을 사용한다.
- VS Code 왼쪽의 가지 모양 Source Control 아이콘을 누른다.
- Initialize Repository를 선택한다.
- 변경 파일 목록 위의 + 버튼을 눌러 전체 파일을 스테이징한다.
- 메시지 칸에 작업한 내용을 입력한다.
- Commit을 누른다.
- Publish Branch 또는 Publish to GitHub를 선택한다.
- 저장소 이름을 입력하고 Public repository를 선택한다.
GitHub 프로필의 Repositories에서 생성한 저장소를 확인한다.
GitHub Pages 배포
GitHub에서 Pages 기능을 켜고 준비된 배포 작업을 실행한다.
- GitHub에서 5번 단계에서 만든 저장소를 연다.
- Settings → Pages로 이동한다.
- Build and deployment → Source에서 GitHub Actions를 선택한다.
- 저장소 위쪽의 Actions 탭을 연다.
- 왼쪽에서 GitHub Pages 배포를 선택한다.
- Run workflow → Run workflow를 누른다.
- 배포 작업에 초록색 체크가 표시될 때까지 기다린다.
- Settings → Pages로 돌아가 Visit site를 누른다.