키트에서 게임 만들기
expo-game 템플릿에는 이미 엔진(고정 타임스텝 루프, 키보드 및 터치 입력, 카메라, 충돌 헬퍼, HUD, 메뉴, 일시정지, 결과, 잠금 해제, 저장된 진행 상황, 작동하는 샘플 게임(Coin Dash))이 포함되어 있습니다. 당신의 임무는 샘플 콘텐츠를 사용자의 게임으로 대체하는 것입니다. 엔진을 설계하거나 작성하지 마십시오.
이 빌드의 규칙
- 첫 번째 턴에 코드를 작성하십시오. 길게 계획하지 마십시오. 최대 10줄의 생각으로 게임 규칙을 결정한 다음 파일을 편집하십시오. 문제는 실행 후에 해결하십시오.
- 각 턴을 작게 유지하십시오: 하나의 파일 또는 하나의 기능, 그런 다음
bun run typecheck를 실행하십시오. 코드 없이 긴 추론 과정은 실패입니다. - 키트에 이미 있는 것(루프, 입력, 충돌, 카메라, HUD, 화면, 저장소)을 다시 구현하지 마십시오.
- 메뉴, 아트 또는 잠금 해제를 추가하기 전에 게임을 실시간으로 플레이 가능하게 만드십시오. 샘플에는 이미 메뉴가 있습니다.
프로젝트
omg_create_project와 template: "expo-game"을 사용하여 프로젝트를 만드십시오. 첫 번째 미리보기를 위해 omg-app-builder 스킬의 Expo 빠른 경로를 따르십시오. 그런 다음 편집하십시오.
편집할 파일(순서대로)
src/game/theme.ts: 디자인의 색상.src/games/<your-game>/logic.ts:coin-dash/logic.ts를 복사하십시오. 순수 규칙:createGame(),stepGame(game, input, dt),finalScore(),UNLOCKS. React, 그리기,Date.now()는 사용하지 마십시오.axisX/axisY/wasTapped(input, "p1" | "p2", ...)를 통해서만 입력을 읽으십시오. 무작위성에seeded()를 사용하십시오.src/games/<your-game>/game-view.tsx:coin-dash/game-view.tsx를 복사하십시오.World와Sprite(색상 모양, 이모지label또는react-native-svg)를 사용하여 그리십시오. 월드 단위를 사용하십시오. 카메라가 변환합니다.src/app/play.tsx: coin-dash에서 게임으로 임포트를 변경하십시오.TouchControls에kind(dpad,stick,steer)와buttons({ action: "a", label: "JUMP" })를 설정하십시오. 루프, 키보드, 일시정지 및 완료 연결은 그대로 유지하십시오.src/app/index.tsx,results.tsx,unlocks.tsx: 제목, 텍스트 및UNLOCKS임포트. 사용자가 요청하지 않는 한 자동화된 테스트를 작성하지 마십시오. 대신 자체 점검으로 확인하십시오(마무리 참조).
키트 버그가 막지 않는 한 src/game/loop.ts, input.ts, collision.ts, camera.ts, progress.ts를 편집하지 마십시오. 게임 폴더에 헬퍼를 추가하십시오.
키트 API(이 이름들을 사용하십시오)
createLoop({ step })및useGameLoop(update, { paused }): 업데이트는 고정 1/60초 단계로 실행됩니다.createInput(),axisX/axisY,wasTapped,endFrame,setAction,setStick.useKeyboard(input, players, onEscape): P1 = WASD + Space/E; 2인 모드에서 P2 = 방향키 + Enter.TouchControls players={1|2} kind="dpad|stick|steer" buttons={[...]}: 2인 모드는 P1 왼쪽, P2 오른쪽으로 분할합니다. 분할 화면의 경우 두 개의GameView를 렌더링하고 각각 하나의 카메라를 사용하십시오(play.tsx참조).circlesOverlap,rectsOverlap,circleRectOverlap,pushCircleOutOfRect,keepCircleInside,angleDiff,seeded,clamp,lerp.createCamera,followCamera(cam, target, dt, { velocity, lookAhead, world, viewW, viewH }).profileStore.finishRun({ gameId, score, stats }, UNLOCKS),useProfile(),profileStore.select(group, id),setSettings.- 화면:
MenuScreen,PauseOverlay,ResultsScreen,UnlocksScreen,SettingsRow,GameButton. HUD:Hud,HudStat,HudBar,Banner.
웹 함정
useViewSize()(onLayout)로 게임 영역을 측정하십시오.useWindowDimensions()는 정적 웹 내보내기에서 크기 조정 전까지 0입니다.- 버튼이 있는
Alert.alert는 웹에서 아무 효과가 없습니다.PauseOverlay또는 화면 내 모달을 사용하십시오. - 진행 상황을 컴포넌트 상태가 아닌
profileStore에 유지하십시오: 다시 로드해도 최고 점수와 잠금 해제가 유지되어야 합니다. - 게임 시간에
setInterval또는Date.now()를 사용하지 마십시오. 루프dt를 계산하십시오. - 프레임별 상태를 React
useState에 넣지 마십시오. 게임 객체(ref)에 유지하십시오. 훅은 매 프레임 다시 그립니다.
3D 게임
키트는 2D입니다. 3D 게임(스타일 선택이 아닌 실제 필요)의 경우 루프, 입력, HUD 및 화면을 유지하고 game-view.tsx만 대체하십시오.
bunx expo install three @react-three/fiber expo-gl && bun add -d @types/three
동일한 내보내기를 가진 두 개의 작은 파일을 작성하여 Metro가 올바른 파일을 선택하도록 하십시오:
src/components/scene.web.tsx:import { Canvas, useFrame } from "@react-three/fiber"src/components/scene.tsx:from "@react-three/fiber/native"를 사용한 동일한 코드
<Canvas camera={{ position: [0, 0, 4] }}>를 ambientLight, directionalLight 및 게임 객체당 하나의 <mesh>(박스, 구, 평면, 단색)와 함께 배치하십시오. 각 렌더링에서 게임 객체의 위치를 복사하십시오. useGameLoop에서 stepGame을 실행하고 useFrame에서는 실행하지 마십시오. HUD 및 컨트롤은 캔버스 위에 일반 React Native 뷰로 유지하십시오. 캔버스에는 크기가 있는 부모(flex: 1)가 필요합니다.
키트 스파이크에서 확인됨: 3D 장면이 Expo Web에서 렌더링되고 Android JS 번들이 컴파일됩니다. 장치 또는 Expo Go에서 렌더링되는 것은 확인되지 않았습니다. 최종 메시지에서 이를 언급하십시오.
마무리
bun run typecheck 및 bun run build를 실행하십시오. 사용자가 요청하지 않는 한 자동화된 테스트를 작성하지 마십시오. 그런 다음 bun run check:ui를 실행하십시오: 390x844에서 모든 경로를 열고 경로당 하나의 PNG를 .omg/ui-check/에 저장하고 빈 페이지, 오류 경계, 콘솔 오류, 실패한 요청 및 다른 요소로 덮인 버튼을 보고합니다. 각 PNG를 열고 요청 및 디자인 참조와 비교하고 잘못된 것을 수정한 다음 보고서가 깨끗해질 때까지 다시 실행하십시오. 검사는 게임을 플레이하지 않으므로 Expo Web에서도 확인하십시오: 키로 움직이고, 종료되고, 결과 화면을 표시하고, 다시 로드 후 최고 점수를 유지해야 합니다. 테스트한 표면을 말하십시오. 웹 실행은 네이티브 동작의 증거가 아닙니다. 게시 후 라이브 URL을 휴대폰 크기로 여십시오. omg 설치 표시줄은 게임 아래에 위치하며, 게임은 그 위에 카드가 되므로 표시줄이 게임 컨트롤을 덮지 않습니다. 이동하거나 숨기지 마십시오.