한눈에 보기
- 무엇: 스크립트 API(JavaScript)로 아이템에 기능을 붙이는 예제 모음. 우클릭하면 순간이동·돌진·번개가 나가는 아이템, 나만의 인챈트, 확률 강화까지
- 누구: 스크립트 API를 한 번 적용해 본 교사, 중·고등학생·코딩 동아리(중급~고급)
- 몇 분: 짧은 예제(귀환서·대쉬·무한 채굴)는 코드 붙여 넣기와 값 바꾸기 1차시, 커스텀 인챈트·강화 시스템은 코드 읽기까지 2차시
- 결과물: 이름을 붙인 아이템이나 나침반·시계·네더의 별을 우클릭하면 동작하는 행동 팩
- 수업 흐름: 짧은 아이템 스크립트(이벤트 하나) → 스킬 아이템 템플릿(쿨타임) → 커스텀 인챈트(로어에 저장) → 강화 시스템(확률·비용)

기능 한눈에 고르기
| 기능 | 쓰임 | 영상 링크 |
| 귀환서 · 순간이동 나침반 | 정해 둔 곳(마을·상점)으로 한 번에 이동 | [귀환서](https://youtu.be/4JMuZ0zxfic) · [나침반](https://youtu.be/zJk_ZyHty0Y) |
| 대쉬 스크롤 · 화살비 폭발 | 전투·이동 스킬 아이템 | [대쉬](https://youtu.be/Cl5YR6uXACk) · [화살비](https://youtu.be/AkuA2vUqfAY) |
| 아이템 개수 세기 · 무한 채굴 | 반복문·블록 이벤트 연습 | [개수 세기](https://youtu.be/AAuMnEdEjxU) · [무한 채굴](https://youtu.be/ZcuU8gqtDRY) |
| 스킬 아이템 템플릿 · 로어 | 이름 붙인 아이템에 스킬·쿨타임, 아이템 설명 달기 | [스킬 아이템](https://youtu.be/84Ks1A9daqo) · [로어](https://youtu.be/eeeDPiqHaVo) |
| 커스텀 인챈트 시스템 | 네더의 별 UI로 나만의 인챈트 걸기 | [1편](https://youtu.be/n3YERMRSFRM) · [2편](https://youtu.be/VT0uEVlrOrI) · [3편](https://youtu.be/vXXeyBa3S5Q) |
| 아이템·플레이어 강화 | 에메랄드를 내고 확률로 강화(게임 경제) | [클릭 강화](https://youtu.be/3R-tee559Ho) · [강화 상점](https://youtu.be/CprkvlH63_s) · [4단계 강화](https://youtu.be/ONdQzLFpdTg) |
시작 전 준비: 아이템을 알아보는 세 가지 방법
| 알아보는 방법 | 코드 | 쓰는 예제 |
| 아이템 종류 | `item.typeId === "minecraft:compass"` | 순간이동 나침반, 화살비(시계), 개수 세기 |
| 모루로 붙인 이름 | `item.nameTag === "귀환서"` | 귀환서, 대쉬, 스킬 아이템 |
| 아이템 설명(로어) | `item.getLore()` 안의 `griswolds_curse_3` | 커스텀 인챈트, 거대함 곡괭이 |
교사용 메모 · 준비 메모: 정식·베타 API와 버전 차이
- 아이템 사용(
itemUse), 피해(entityHurt), 발사체 충돌(projectileHitBlock), 블록 파괴(playerBreakBlock) 이벤트는 공식 문서에서 정식(stable) 기능입니다(2026-10 확인). 아이템 우클릭으로 동작하는 예제는 베타 API 없이 쓸 수 있습니다. - 채팅으로 명령하는 예제(
!로어,!강화,강화상점)는 채팅 이벤트chatSend를 씁니다(로어는 화면에서world.beforeEvents.chatSend확인). chatSend는 공식 문서에서 실험(베타) 전용이라 월드의 ‘베타 API’ 실험 기능을 켜야 합니다. 교육용 에디션은 ‘베타 API’ 토글이 없고 베타 버전 종속성도 불러오지 않아(2026-07 실측) 채팅 명령 예제는 교육용 에디션에서 그대로는 동작하지 않습니다. 교육용 수업에는 아이템 우클릭 예제를 고르세요. beforeEvents안에서는 게임 상태를 바꾸는 함수(순간이동·소환 등)를 바로 쓸 수 없어system.run(() => { … })안에 넣습니다. 예제 코드에system.run이 자주 나오는 이유입니다.- 2024~2025년 영상 코드라
runCommandAsync와applyKnockback(x, z, 수평 세기, 수직 세기)(네 값) 형식을 씁니다.@minecraft/server2.0.0부터runCommandAsync는 없어지고runCommand를 쓰며,applyKnockback은({ x, z } 수평 힘, 수직 세기)두 값으로 바뀌었습니다. manifest 버전에 맞춰 고치세요. - 오류는 설정의 제작자 로그(콘텐츠 로그)로 확인하고, manifest의
@minecraft/server버전을 로그에 나온 버전으로 맞춥니다(웹소켓·스크립트 API 페이지).
귀환서: 이름 붙인 다이아몬드로 마을 귀환
- 모루에서 다이아몬드에 이름 ‘귀환서’를 붙이고 우클릭하면 정해 둔 좌표로 순간이동
- 조건 두 개를 모두(
&&) 만족할 때만: 아이템 종류가 다이아몬드이고, 이름이 ‘귀환서’ - 바꿀 값 네 가지: 아이템, 이름, 좌표(
tpTo), 메시지 ev.cancel = true로 아이템 원래 사용 동작은 취소(우클릭 신호만 씀)
import { world, system } from '@minecraft/server';
world.beforeEvents.itemUse.subscribe((ev) => {
const item = ev.itemStack;
const player = ev.source;
const itemType = "minecraft:diamond"; // 아이템 정하기
const desiredNameTag = "귀환서"; // 원하는 이름
const tpTo = { x: -2838, y: 76, z: 1628 }; // 좌표 정하기
const spawnMessage = "스폰으로 티피되었습니다."; // 메시지 정하기
if (item.typeId === itemType && item.nameTag === desiredNameTag) {
player.sendMessage(`${spawnMessage}`);
system.run(() => {
player.teleport(tpTo);
});
ev.cancel = true;
}
});

대쉬 스크롤: 바라보는 방향으로 돌진
- 모루에서 종이 이름을 ‘대쉬’로 바꾸면 대쉬 스크롤. 우클릭하면 앞으로 돌진하며 살짝 뜸(연속 사용 가능)
- 설정
DASH_SETTINGS: 아이템(minecraft:paper), 이름(‘대쉬’), 전방 세기forwardPower: 5, 수직 세기upwardPower: 0.5, 메시지 - 영상에서 세기를 두 배·열 배로 올려 비교. 너무 크면 아주 멀리 날아가니 조금씩 바꿔 보기(코드 주석)
const { x, z } = player.getViewDirection();
if (item.typeId === DASH_SETTINGS.itemType &&
(!DASH_SETTINGS.itemName || item.nameTag === DASH_SETTINGS.itemName)) {
player.applyKnockback(x, z,
DASH_SETTINGS.forwardPower, // 전방 이동 강도
DASH_SETTINGS.upwardPower); // 수직 이동 강도
player.sendMessage(DASH_SETTINGS.message);
}


순간이동 나침반: 버튼 UI로 여러 곳 이동
- 나침반(
minecraft:compass)을 우클릭하면 ‘순간 이동 장치’ 창: 마을로 이동·상점으로 이동·동굴로 이동 - 창은
@minecraft/server-ui의ActionFormData로 만들고, 누른 버튼 번호(response.selection)는 0부터 - 버튼마다 좌표를 정해
/tp와 액션바 메시지 실행: 마을 0 0 0, 상점 0 0 10, 동굴 0 0 20 - 장소 추가하기: 버튼 코드와 응답 조건문을 복사해 번호 3, 좌표 0 0 30, ‘항구 위치로 이동 완료’ →
/reload
// 마을 위치로 이동
if (response.selection === 0) {
playerPositionX = 0;
playerPositionY = 0;
playerPositionZ = 0;
player.runCommandAsync(`tp @s ${playerPositionX} ${playerPositionY} ${playerPositionZ}`);
player.runCommandAsync("title @a actionbar 마을 위치로 이동 완료");
}


아이템 개수 세기: 인벤토리 반복문
- 아이템을 들고 우클릭하면 소지품 전체에서 같은 아이템 개수를 알려 줌(핫바 9개 + 소지품 7개 쿠키 → 16개)
- 인벤토리 컴포넌트 →
container→ 칸 수(size)만큼for반복 → 같은typeId면amount더하기 - 변수·반복·조건이 한 번에 나와 첫 코드 읽기 수업에 알맞음
world.afterEvents.itemUse.subscribe((event) => {
const item = event.itemStack;
const player = event.source;
if (item) {
const itemTypeId = item.typeId;
const inventoryContainer = player.getComponent("minecraft:inventory").container;
let totalItems = 0;
for (let i = 0; i < inventoryContainer.size; i++) {
const inventoryItem = inventoryContainer.getItem(i);
if (inventoryItem && inventoryItem.typeId === itemTypeId) {
totalItems += inventoryItem.amount;
}
}
player.sendMessage(`전체 인벤토리에서 ${itemTypeId} 아이템이 총 ${totalItems}개 있습니다.`);
}
});


무한 채굴: 부순 블록이 다시 생기기
- 다이아몬드 광석을 부숴도 같은 자리에 다시 생김. 성급함 효과를 더하면 빠른 무한 채굴
- 다시 생길 블록 목록
RESPAWN_BLOCKS: 다이아몬드·철·금·석탄 광석, 돌(더 추가 가능) - 블록이 부서지면 원래 상태(
brokenBlockPermutation)와 위치를 저장 → 1틱 뒤 그 자리에 되돌려 놓기
world.afterEvents.playerBreakBlock.subscribe((event) => {
const block = event.brokenBlockPermutation;
const blockPos = event.block.location;
if (RESPAWN_BLOCKS.includes(block.type.id)) {
system.runTimeout(() => {
const dimension = event.player.dimension;
const blockAtPos = dimension.getBlock(blockPos);
blockAtPos.setPermutation(block);
}, 1);
}
});


화살비 폭발 아이템: 시계로 화살 여러 발
- 시계를 쓰면 화살 여러 개가 퍼지며 날아가고, 떨어진 곳에서 폭발
- 바꿀 값 네 가지:
itemType(기본minecraft:clock),baseSpeed(4),arrowCount(5),angleSpread(0.2). 영상에서 퍼짐 5, 화살 100개로 시험 - 시계로 쏜 화살에만 태그
clock_shot을 붙여, 보통 화살은 터지지 않게 함 → 폭발이 싫으면 충돌 부분 삭제
// 화살마다: 시선 방향 + 랜덤 퍼짐
const offsetY = viewDirection.y + Math.random() * angleSpread - angleSpread / 2;
const projectile = player.dimension.spawnEntity("minecraft:arrow", spawnPos);
projectile.applyImpulse({ x: offsetX * baseSpeed, y: offsetY * baseSpeed, z: offsetZ * baseSpeed });
projectile.addTag("clock_shot");
// 화살이 블록에 맞으면 폭발
world.afterEvents.projectileHitBlock.subscribe((event) => {
const projectile = event.projectile;
if (projectile.typeId === "minecraft:arrow" && projectile.hasTag("clock_shot")) {
const hitLocation = event.getBlockHit().block.location;
// system.run 안에서
projectile.dimension.createExplosion(hitLocation, 4, { causesFire: false, breaksBlocks: true });
}
});



스킬 아이템 템플릿과 쿨타임
- 아이템 이름이 목록의 이름과 정확히 같아야 스킬 발동: ‘그리스월드의 칼’(다이아몬드 검), ‘얼음지팡이’(막대)
- 그리스월드의 칼: 바라보는 쪽 5칸 앞에 번개 + 0.5초 뒤 폭발, 쿨타임 10초 / 얼음지팡이: 주변 몹 슬로우 + 눈덩이, 쿨타임 15초
- 쿨타임 중에는 화면에 ‘그리스월드의 칼 쿨타임: 4초’처럼 남은 시간 표시
- 나만의 스킬 아이템:
SKILL_ITEMS에 이름·type·cooldown·skill을 같은 형식으로 하나 더 추가
const SKILL_ITEMS = {
"그리스월드의 칼": {
type: "minecraft:diamond_sword",
cooldown: 10, // 10초 쿨타임
skill: (player) => {
if (isOnCooldown(player, "그리스월드의 칼")) return;
// 번개 소환 → 0.5초 뒤 폭발 → 메시지 → startCooldown(player, "그리스월드의 칼")
}
},
"얼음지팡이": { type: "minecraft:stick", cooldown: 15, /* … */ }
};
world.afterEvents.itemUse.subscribe((event) => {
const item = event.itemStack;
if (!item || !item.nameTag) return;
const skillItem = SKILL_ITEMS[item.nameTag];
if (skillItem && item.typeId === skillItem.type) skillItem.skill(event.source);
});


아이템 로어(설명) 정하기
- 로어(lore): 배경 이야기. 아이템 이름 아래 보라색으로 나오는 설명
- 아이템을 들고 채팅에
!로어 이 검은 최초에 스티브코딩이 사용했었습니다.→ 설명 추가 /!로어만 입력 → 설명 지우기(빈 배열) !아이템을 입력하면 들고 있는 아이템 ID를 알려 줌(코드에 함께 있음)- 아이템을 고칠 때는 새
ItemStack을 만들어 이름(nameTag)과 로어를 넣고 손에 든 칸에 다시 놓음
const newItem = new ItemStack(item.typeId, item.amount);
if (item.nameTag) {
newItem.nameTag = item.nameTag;
}
newItem.setLore([loreText]);
const inventory = player.getComponent("inventory");
inventory.container.setItem(player.selectedSlotIndex, newItem);


커스텀 인챈트 ① 네더의 별로 인챈트 걸기
- 네더의 별을 들고 우클릭 → ‘인챈트할 아이템 선택’ 창에 내 장비가 버튼으로 나옴
- 아이템을 고르면 그 아이템에 걸 수 있는 인챈트만 ‘인챈트 선택’ 창에 나옴
- 레벨을 정해 인챈트 → 비용은 에메랄드(레벨이 오를수록 비쌈)
- 실패도 있음: 실패하면 에메랄드만 소모, 운이 나쁘면 아이템이 부서짐
- 한 아이템에 인챈트 두 개를 걸 수 있고 효과·쿨타임이 함께 작동. 신고 있는 부츠는 목록에 안 나오니 잠깐 벗기




커스텀 인챈트 ② 설정값과 인챈트 정의
ENCHANT_CONFIG: UI를 여는 아이템, 최대 레벨, 실패 확률 20%, 파괴 확률 10%, 레벨당 비용 배율 2- 비용 =
baseCost × 2^(레벨-1)에메랄드(예: baseCost 10이면 1레벨 10개, 3레벨 40개) CUSTOM_ENCHANTS: 인챈트마다 id·이름·설명·기본 비용·최대 레벨·쿨타임(초)·걸 수 있는 아이템- 나만의 인챈트: 기존 항목을 복사해 id·이름·아이템만 바꾸고, 효과 부분(③)에 같은 id로 코드 추가
const ENCHANT_CONFIG = {
ENCHANT_ITEM: "minecraft:nether_star", // 인챈트 UI를 열 아이템
MAX_LEVEL: 5, // 최대 인챈트 레벨
FAIL_CHANCE: 0.2, // 실패 확률 (20%)
BREAK_CHANCE: 0.1, // 아이템 파괴 확률 (10%)
COST_MULTIPLIER: 2 // 레벨당 비용 증가 배율
};
const CUSTOM_ENCHANTS = {
SHEPHERDS_RAGE: {
id: "shepherds_rage",
name: "양치기의 분노",
description: "주변의 모든 엔티티를 양으로 변환합니다",
baseCost: 15,
maxLevel: 3,
cooldown: 20,
allowedItems: ["minecraft:diamond_hoe", "minecraft:netherite_hoe"]
},
// …
};

커스텀 인챈트 ③ 효과가 실행되는 네 자리
| 종류 | 이벤트 | 예 |
| 스킬형(우클릭) | `world.beforeEvents.itemUse` | 그리스월드의 저주, 역 반동 점프, 4차원 공간 |
| 패시브형(입고 있으면) | `system.runInterval`(1편 60틱=3초마다) | 신속의 부츠, 도약의 부츠, 아늑함 |
| 피격·타격형 | `world.afterEvents.entityHurt` | 맹독, 회피, 생존 본능 |
| 블록 파괴형 | `world.beforeEvents.playerBreakBlock` | 거대함(3×3×3 한 번에 파괴) |



커스텀 인챈트 19가지 목록
| 영상 | 인챈트(장비) — 효과 |
| 1편 ‘좀비가 양되는 중’ | 그리스월드의 저주(검) 보는 쪽 8칸 앞 번개·폭발 / 얼음의 유산(도끼) 슬로우·눈덩이 / 엘사의 격려(검) 주변 물을 얼음으로 / 철벽치기 주변 적 밀쳐내기 / 스티브의 추진력 바라보는 쪽 대시 / 양치기의 분노(괭이) 주변 엔티티를 양으로 / 신속의 부츠·도약의 부츠(부츠) 신속·점프 강화 |
| 2편 ‘슈퍼 히어로 랜딩’ | 검기(검) 앞쪽 적에게 데미지, 레벨이 오르면 범위↑ / 슈퍼히어로 랜딩(착용 장비) 높은 곳에서 착지하면 주변 몹 넉백 / 역 반동 점프(메이스) 반경 10칸 몹을 앞 2칸으로 끌어오고 나는 5칸(+레벨당 1) 위로, 쿨타임 9초 / 맹독(무기) 평타에 독, 높은 레벨은 위더 |
| 3편 ‘18가지 커스텀 인챈트’ | 기공파(검) 앞쪽 줄의 적만 넉백 / 회피(바지) 레벨×10% 확률로 피해 무효·회복 / 아늑함(흉갑) 재생 30초 / 티타늄 도배(방패) 방패를 들면 흡수+구속 / 4차원 공간(꾸러미) 반경 2칸 모두 즉사, 쿨타임 김 / 거대함(곡괭이) 3×3×3 한 번에 파기 / 생존 본능(갑옷) 체력 6(30%) 이하에서 저항·신속 |


클릭 두 번 아이템 강화
- 강화할 아이템을 들고 우클릭을 ‘하나, 둘’ 박자로 두 번 → 에메랄드 1개를 내고 강화 시도
- 성공 확률: +1 단계 100% → +2 80% → +3 60% → +4 40%. 실패하면 아이템이 부서짐, +4가 최대
- 단계마다 붙는 인챈트가 정해져 있음(예: 철 도끼 +1 효율 2·내구성 1 → +4 효율 3·내구성 3·날카로움 3·수선 1)
- 강화할 수 있는 아이템: 철·다이아몬드·네더라이트 검·곡괭이·도끼, 다이아몬드 활, 낚싯대, 방패(코드 주석)
- 모르는 함수는 코드를 복사해 GPT 같은 AI에 “설명해 줘”라고 물어보며 읽기
const ENHANCEMENT_CHANCES = { 0: 100, 1: 80, 2: 60, 3: 40 }; // 단계별 성공 확률(%)
const ENHANCEMENT_COST = {
item: "minecraft:emerald", // 강화에 필요한 아이템
count: 1, // 필요한 개수
displayName: "에메랄드" // 표시될 이름
};


강화 상점: 인챈트 그대로 장비 업그레이드
- 바꿀 장비를 첫 번째 칸에 두고 채팅에
강화상점→ ‘아이템 교환 상점’ 창에 한 단계 아래·위 버튼만 나옴 - 비용 에메랄드 5개. 업그레이드 확률: 나무→돌 100, 돌→철 90, 철→다이아 70, 다이아→네더라이트 50(%), 다운그레이드는 모두 100%
- 실패하면 아이템과 에메랄드 모두 사라짐. 성공하면 기존 인챈트를 그대로 옮겨 새 아이템 지급
- 교환 그룹: 검·곡괭이·도끼 / 아이템 등급 순서
TIER_ORDER= 나무·돌·철·다이아몬드·네더라이트 - 클릭 강화 스크립트와 함께 쓰기: main.js에서
import './Enhancement/itemEnhancement.js';
// 인챈트 정보 저장 (exchangeItem 함수 안)
const enchantable = currentItem.getComponent("minecraft:enchantable");
const enchantments = [];
if (enchantable) {
for (const enchant of enchantable.getEnchantments()) {
enchantments.push({
id: enchant.type.id.replace('minecraft:', ''),
level: enchant.level
});
}
}


목숨 건 4단계 플레이어 강화
- 채팅 명령:
!강화정보(현재·다음 등급, 재료, 확률),!강화(에메랄드를 내고 시도),!현타(수련으로 초기화) - 등급: 수련(흰색) → 각성(하늘색) → 정예(분홍색) → 전설(금색). 이름표에
[수련] 이름처럼 표시 - 비용·확률(코드 주석): 수련→각성 에메랄드 10개 40%, 각성→정예 20개 30%, 정예→전설 30개 20%(GitHub playerEnhancement.js 기준)
- 실패하면 수련으로 돌아가고 죽음(
kill @s), 쓴 에메랄드는 돌려주지 않음. 등급은 동적 속성에 저장 - 코드 읽기 포인트:
class와constructor,switch문, 확률Math.random() * 100 < successRate, 삼항 연산자success ? 20 : 60
switch (level) {
case 4: // 전설
player.runCommand(`effect @s health_boost 999999 4 true`);
player.runCommand(`effect @s resistance 999999 3 true`);
player.runCommand(`effect @s speed 999999 2 true`);
break;
// case 3: 정예(3·2·1), case 2: 각성(2·1·0)
}


수업 팁
- 값 바꾸기부터: 좌표·이름·세기·확률·쿨타임처럼 코드 위쪽 설정값만 바꿔 보고
/reload→ 결과 비교. 코드 전체를 이해하지 않아도 시작할 수 있습니다. - 명령어 먼저 시험: 인챈트 효과에 넣을 명령어(
effect,summon등)는 채팅창에서 먼저 쳐 보고 코드로 옮깁니다. - 게임 밸런스 토론: 강화 확률·비용·파괴 확률을 모둠별로 정하고 이유를 발표(경제·확률 교육과 연결).
- 나만의 인챈트·스킬 아이템 기획서: 이름·장비·효과·쿨타임을 먼저 표로 쓰고, 기존 항목을 복사해 하나만 추가.
- 안전 규칙: 4차원 공간·거대함·화살비 폭발은 다른 학생의 건축물과 플레이어도 망가뜨립니다. 시연은 교사 월드에서, 학생 월드에서는 빼거나 범위를 줄입니다.
- 코드 읽기는 AI와 함께: 모르는 함수·문법을 복사해 “설명해 줘”(클릭 강화 영상). 공식 문서 주소를 함께 주면 더 정확합니다.