11import React , { useState , useEffect } from 'react' ;
22
33const Stage1 = ( { onClose } ) => {
4- // State for answer and feedback
4+ // State for answer, feedback, hints, and drag
55 const [ answer , setAnswer ] = useState ( '' ) ;
66 const [ feedback , setFeedback ] = useState ( '' ) ;
7+ const [ hint , setHint ] = useState ( '' ) ;
8+ const [ hint1Used , setHint1Used ] = useState ( false ) ;
9+ const [ hint2Used , setHint2Used ] = useState ( false ) ;
10+ const [ draggingCard , setDraggingCard ] = useState ( null ) ;
11+ const [ offset , setOffset ] = useState ( { x : 0 , y : 0 } ) ;
712
813 // Card data for drag and drop
914 const cardData = [
10- { id : 1 , text : 'ㅅ' , width : 100 , height : 100 } ,
11- { id : 2 , text : 'ㅗ' , width : 100 , height : 100 } ,
12- { id : 3 , text : 'ㄹ' , width : 100 , height : 100 } ,
13- { id : 4 , text : 'ㅣ' , width : 100 , height : 100 } ,
14- { id : 5 , text : 'ㄱ' , width : 100 , height : 100 } ,
15- { id : 6 , text : 'ㅡ' , width : 100 , height : 100 } ,
16- { id : 7 , text : 'ㄹ' , width : 100 , height : 100 } ,
17- { id : 8 , text : 'ㅈ' , width : 100 , height : 100 } ,
18- { id : 9 , text : 'ㅏ' , width : 100 , height : 100 } ,
15+ { id : 1 , text : 'ㅅ' , width : 80 , height : 80 } ,
16+ { id : 2 , text : 'ㅗ' , width : 80 , height : 80 } ,
17+ { id : 3 , text : 'ㄹ' , width : 80 , height : 80 } ,
18+ { id : 4 , text : 'ㅣ' , width : 80 , height : 80 } ,
19+ { id : 5 , text : 'ㄱ' , width : 80 , height : 80 } ,
20+ { id : 6 , text : 'ㅡ' , width : 80 , height : 80 } ,
21+ { id : 7 , text : 'ㄹ' , width : 80 , height : 80 } ,
22+ { id : 8 , text : 'ㅈ' , width : 80 , height : 80 } ,
23+ { id : 9 , text : 'ㅏ' , width : 80 , height : 80 } ,
1924 ] ;
2025
2126 // Initialize card positions randomly
@@ -27,82 +32,121 @@ const Stage1 = ({ onClose }) => {
2732 } ) )
2833 ) ;
2934
30- // Reset the cards' positions and answer
3135 useEffect ( ( ) => {
3236 handleReset ( ) ;
3337 } , [ ] ) ;
3438
3539 const handleReset = ( ) => {
3640 setCards (
37- cards . map ( ( card ) => {
38- const randomX = Math . random ( ) * ( 800 - card . width ) ;
39- const randomY = Math . random ( ) * ( 400 - card . height ) ;
40- return { ... card , left : randomX , top : randomY } ;
41- } )
41+ cardData . map ( ( card ) => ( {
42+ ... card ,
43+ left : Math . random ( ) * ( 800 - card . width ) ,
44+ top : Math . random ( ) * ( 400 - card . height ) ,
45+ } ) )
4246 ) ;
4347 setAnswer ( '' ) ;
4448 setFeedback ( '' ) ;
49+ setHint ( '' ) ;
50+ setHint1Used ( false ) ;
51+ setHint2Used ( false ) ;
4552 } ;
4653
47- const handleDragStart = ( e , cardId ) => {
48- e . dataTransfer . setData ( 'text/plain' , cardId ) ;
49- } ;
50-
51- const handleDrop = ( e ) => {
52- e . preventDefault ( ) ;
53- const cardId = e . dataTransfer . getData ( 'text/plain' ) ;
54- const cardIndex = cards . findIndex ( ( card ) => card . id === Number ( cardId ) ) ;
55- const x = e . clientX - e . target . offsetLeft - cards [ cardIndex ] . width / 2 ;
56- const y = e . clientY - e . target . offsetTop - cards [ cardIndex ] . height / 2 ;
57-
58- setCards ( ( prevCards ) =>
59- prevCards . map ( ( card , index ) =>
60- index === cardIndex ? { ...card , left : x , top : y } : card
61- )
62- ) ;
54+ const handleHint = ( hintLevel ) => {
55+ if ( hintLevel === 1 ) {
56+ setHint ( '음성에 대응하는 문자를 가리키는 말' ) ;
57+ setHint1Used ( true ) ;
58+ } else if ( hintLevel === 2 && hint1Used ) {
59+ setHint ( '초성: ㅅㄹㄱㅈ' ) ;
60+ setHint2Used ( true ) ;
61+ } else if ( hintLevel === 3 && hint2Used ) {
62+ setHint ( '정답은 "소리글자"입니다.' ) ;
63+ }
6364 } ;
6465
65- const handleDragOver = ( e ) => {
66- e . preventDefault ( ) ;
66+ const handleCloseHint = ( ) => {
67+ setHint ( '' ) ;
6768 } ;
6869
6970 const handleSubmit = ( ) => {
7071 const correctAnswer = '소리글자' ;
7172 if ( answer === correctAnswer ) {
7273 setFeedback ( '정답입니다! 🎉' ) ;
7374 setTimeout ( ( ) => {
74- onClose ( ) ; // Navigate back to the dashboard
75+ onClose ( ) ;
7576 } , 1000 ) ;
7677 } else {
7778 setFeedback ( '틀렸습니다. 다시 시도하세요.' ) ;
7879 }
7980 } ;
8081
82+ const handleMouseDown = ( e , cardId ) => {
83+ const card = cards . find ( ( c ) => c . id === cardId ) ;
84+ if ( card ) {
85+ setDraggingCard ( cardId ) ;
86+ setOffset ( { x : e . clientX - card . left , y : e . clientY - card . top } ) ;
87+ }
88+ } ;
89+
90+ const handleMouseMove = ( e ) => {
91+ if ( draggingCard ) {
92+ setCards ( ( prevCards ) =>
93+ prevCards . map ( ( card ) =>
94+ card . id === draggingCard
95+ ? {
96+ ...card ,
97+ left : Math . min (
98+ Math . max ( 0 , e . clientX - offset . x ) ,
99+ 1500 - card . width
100+ ) ,
101+ top : Math . min (
102+ Math . max ( 0 , e . clientY - offset . y ) ,
103+ 800 - card . height
104+ ) ,
105+ }
106+ : card
107+ )
108+ ) ;
109+ }
110+ } ;
111+
112+ const handleMouseUp = ( ) => {
113+ setDraggingCard ( null ) ;
114+ } ;
115+
81116 return (
82- < div className = "stage-container" style = { { padding : '20px' } } >
117+ < div
118+ className = "stage-container"
119+ style = { {
120+ padding : '20px' ,
121+ userSelect : 'none' ,
122+ cursor : draggingCard ? 'grabbing' : 'default' ,
123+ } }
124+ onMouseMove = { handleMouseMove }
125+ onMouseUp = { handleMouseUp }
126+ >
83127 < header >
84128 < h1 > 훈민정음 맞추기 게임</ h1 >
85129 < p > 전통 문화를 느끼며 단어를 맞춰보세요!</ p >
86130 </ header >
87131
88132 < div
89133 className = "drop-area"
90- onDrop = { handleDrop }
91- onDragOver = { handleDragOver }
92134 style = { {
93135 position : 'relative' ,
94- width : '800px ' ,
95- height : '400px ' ,
136+ width : '1200px ' ,
137+ height : '450px ' ,
96138 border : '2px dashed #000' ,
97139 margin : '20px auto' ,
140+ backgroundImage : 'url(/images/stage1.png)' ,
141+ backgroundSize : 'cover' , // 이미지를 영역에 맞게 조정
142+ backgroundPosition : 'center' , // 이미지를 중앙에 배치
98143 } }
99144 >
100145 { cards . map ( ( card ) => (
101146 < div
102147 key = { card . id }
103148 className = "card"
104- draggable
105- onDragStart = { ( e ) => handleDragStart ( e , card . id ) }
149+ onMouseDown = { ( e ) => handleMouseDown ( e , card . id ) }
106150 style = { {
107151 position : 'absolute' ,
108152 left : `${ card . left } px` ,
@@ -112,8 +156,11 @@ const Stage1 = ({ onClose }) => {
112156 display : 'flex' ,
113157 justifyContent : 'center' ,
114158 alignItems : 'center' ,
115- backgroundColor : '#bebebe' ,
116- borderRadius : '5px' ,
159+ backgroundColor : '#ffe9b9c5' ,
160+ borderRadius : '20px' ,
161+ cursor : 'pointer' ,
162+ fontSize : '24px' ,
163+ fontWeight : 'bold' ,
117164 } }
118165 >
119166 { card . text }
@@ -143,8 +190,63 @@ const Stage1 = ({ onClose }) => {
143190 < button onClick = { onClose } style = { { margin : '5px' } } >
144191 돌아가기
145192 </ button >
193+ < button onClick = { ( ) => handleHint ( 1 ) } > 힌트1</ button >
194+ < button
195+ onClick = { ( ) => handleHint ( 2 ) }
196+ disabled = { ! hint1Used }
197+ style = { {
198+ backgroundColor : hint1Used ? '#007bff' : '#ccc' ,
199+ cursor : hint1Used ? 'pointer' : 'not-allowed' ,
200+ } }
201+ >
202+ 힌트2
203+ </ button >
204+ < button
205+ onClick = { ( ) => handleHint ( 3 ) }
206+ disabled = { ! hint2Used }
207+ style = { {
208+ backgroundColor : hint2Used ? '#28a745' : '#ccc' ,
209+ cursor : hint2Used ? 'pointer' : 'not-allowed' ,
210+ } }
211+ >
212+ 정답
213+ </ button >
146214 { feedback && < p > { feedback } </ p > }
147215 </ div >
216+
217+ { hint && (
218+ < div
219+ className = "hint-modal"
220+ style = { {
221+ position : 'fixed' ,
222+ top : '50%' ,
223+ left : '50%' ,
224+ transform : 'translate(-50%, -50%)' ,
225+ width : '400px' ,
226+ backgroundColor : 'white' ,
227+ padding : '20px' ,
228+ boxShadow : '0px 4px 8px rgba(0, 0, 0, 0.2)' ,
229+ borderRadius : '8px' ,
230+ zIndex : 1000 ,
231+ } }
232+ >
233+ < p > { hint } </ p >
234+ < button
235+ onClick = { handleCloseHint }
236+ style = { {
237+ position : 'absolute' ,
238+ top : '10px' ,
239+ right : '10px' ,
240+ background : 'transparent' ,
241+ border : 'none' ,
242+ fontSize : '18px' ,
243+ cursor : 'pointer' ,
244+ } }
245+ >
246+ ❌
247+ </ button >
248+ </ div >
249+ ) }
148250 </ div >
149251 ) ;
150252} ;
0 commit comments