1- import Draggable , { DraggableData , DraggableEvent } from 'react-draggable' ;
2- import React , { useState } from 'react' ;
1+ // Created by Copilot
2+ // This code is a simple drag-and-drop game using React and react-dnd.
3+ import React , { useState , useEffect } from "react" ;
4+ import { DndProvider , useDrag , useDrop } from "react-dnd" ;
5+ import { HTML5Backend } from "react-dnd-html5-backend" ;
36
4- // Remove after fix:
5- // https://github.com/react-grid-layout/react-draggable/pull/648#issuecomment-1100110050
6- declare module 'react-draggable' {
7- export interface DraggableProps {
8- children : React . ReactNode ;
9- }
10- }
7+ const ItemTypes = {
8+ CIRCLE : "circle" ,
9+ BOX : "box" ,
10+ } ;
1111
12- export function DragGame ( ) {
13- const goal = {
14- top : 500 ,
15- left : 100 ,
16- width : 130 ,
17- height : 130 ,
18- } ;
19- const onCircleDrag = ( e : DraggableEvent , position : DraggableData ) => {
20- const { x, y } = position ;
21- if ( y >= 430 && y <= 465 && x >= 95 && x <= 130 ) {
22- setCircleInTheGoal ( true ) ;
12+ const DraggableItem = ( { id, type, x, y } ) => {
13+ const [ { isDragging } , drag ] = useDrag ( ( ) => ( {
14+ type,
15+ item : { id, type } ,
16+ collect : ( monitor ) => ( {
17+ isDragging : monitor . isDragging ( ) ,
18+ } ) ,
19+ } ) ) ;
20+
21+ return (
22+ < div
23+ id = { type === ItemTypes . CIRCLE ? "red-circle" : "blue-box" } // Add id for red circle and blue box
24+ ref = { drag }
25+ style = { {
26+ position : "absolute" ,
27+ left : x ,
28+ top : y ,
29+ width : type === ItemTypes . CIRCLE ? 50 : 160 , // Doubled width for blue box
30+ height : type === ItemTypes . CIRCLE ? 50 : 160 , // Doubled height for blue box
31+ backgroundColor : type === ItemTypes . CIRCLE ? "red" : "blue" ,
32+ borderRadius : type === ItemTypes . CIRCLE ? "50%" : "0" ,
33+ opacity : isDragging ? 0.5 : 1 ,
34+ cursor : "move" ,
35+ } }
36+ />
37+ ) ;
38+ } ;
39+
40+ const DropZone = ( { onDrop, onGoal } ) => {
41+ const [ , drop ] = useDrop ( ( ) => ( {
42+ accept : [ ItemTypes . CIRCLE , ItemTypes . BOX ] ,
43+ drop : ( item , monitor ) => {
44+ const offset = monitor . getClientOffset ( ) ;
45+ if ( offset ) {
46+ const isInGoal =
47+ offset . x >= 300 &&
48+ offset . x <= 400 &&
49+ offset . y >= 300 &&
50+ offset . y <= 400 ;
51+
52+ if ( isInGoal && item . type === ItemTypes . CIRCLE ) {
53+ onGoal ( ) ;
54+ } else {
55+ onDrop ( item . id , offset . x , offset . y ) ;
2356 }
24- setCirclePosition ( { x, y } ) ;
25- } ;
26- const [ circlePosition , setCirclePosition ] = useState ( { x : 70 , y : 70 } ) ;
27- const [ circleInTheGoal , setCircleInTheGoal ] = useState ( false ) ;
28- return (
29- < div >
30- < h2 > { circleInTheGoal ? 'GOAL!!' : 'Put the circle in the goal' } </ h2 >
31- < div className = "game-area" >
32- < Draggable position = { circlePosition } onDrag = { onCircleDrag } >
33- < div
34- className = "circle"
35- style = { {
36- width : 100 ,
37- height : 100 ,
38- borderRadius : 50 ,
39- background : 'red' ,
40- display : 'flex' ,
41- justifyContent : 'center' ,
42- alignItems : 'center' ,
43- position : 'absolute' ,
44- } }
45- >
46- < span > Circle</ span >
47- </ div >
48- </ Draggable >
49- < Draggable >
50- < div
51- className = "obstacle"
52- style = { {
53- width : 200 ,
54- height : 200 ,
55- background : 'blue' ,
56- display : 'flex' ,
57- justifyContent : 'center' ,
58- alignItems : 'center' ,
59- position : 'absolute' ,
60- } }
61- >
62- < span > Obstacle</ span >
63- </ div >
64- </ Draggable >
65- < div
66- className = "goal"
67- style = { {
68- ...goal ,
69- border : '3px solid black' ,
70- display : 'flex' ,
71- justifyContent : 'center' ,
72- alignItems : 'center' ,
73- position : 'absolute' ,
74- zIndex : - 1 ,
75- } }
76- >
77- < span > Goal</ span >
78- </ div >
79- </ div >
80- </ div >
57+ }
58+ } ,
59+ } ) ) ;
60+
61+ return (
62+ < div
63+ ref = { drop }
64+ style = { {
65+ position : "relative" ,
66+ width : "100vw" ,
67+ height : "100vh" ,
68+ border : "1px solid black" ,
69+ } }
70+ >
71+ < div
72+ id = "goal" // Add id for the goal
73+ style = { {
74+ position : "absolute" ,
75+ left : 300 ,
76+ top : 300 ,
77+ width : 100 ,
78+ height : 100 ,
79+ backgroundColor : "yellow" ,
80+ border : "2px dashed black" ,
81+ } }
82+ >
83+ Goal
84+ </ div >
85+ </ div >
86+ ) ;
87+ } ;
88+
89+ const Game = ( ) => {
90+ const [ items , setItems ] = useState ( [
91+ { id : 1 , type : ItemTypes . CIRCLE , x : 10 , y : 10 } , // Red circle
92+ { id : 2 , type : ItemTypes . BOX , x : 10 , y : - 70 } , // Blue box starts entirely above the red circle
93+ ] ) ;
94+ const [ goalMessage , setGoalMessage ] = useState ( "Put the circle in the goal" ) ;
95+
96+ useEffect ( ( ) => {
97+ document . title = "Drag game" ; // Set the page title
98+ } , [ ] ) ;
99+
100+ const handleDrop = ( id , x , y ) => {
101+ setItems ( ( prevItems ) =>
102+ prevItems . map ( ( item ) =>
103+ item . id === id ? { ...item , x, y } : item
104+ )
81105 ) ;
82- }
106+ } ;
107+
108+ const handleGoal = ( ) => {
109+ setGoalMessage ( "GOAL!!!" ) ;
110+ } ;
111+
112+ return (
113+ < DndProvider backend = { HTML5Backend } >
114+ < DropZone onDrop = { handleDrop } onGoal = { handleGoal } />
115+ { items . map ( ( item ) => (
116+ < DraggableItem
117+ key = { item . id }
118+ id = { item . id }
119+ type = { item . type }
120+ x = { item . x }
121+ y = { item . y }
122+ />
123+ ) ) }
124+ < h2
125+ style = { {
126+ position : "absolute" ,
127+ top : 20 ,
128+ left : "50%" ,
129+ transform : "translateX(-50%)" ,
130+ fontSize : "24px" ,
131+ fontWeight : "bold" ,
132+ color : goalMessage === "GOAL!!!" ? "green" : "black" ,
133+ } }
134+ >
135+ { goalMessage }
136+ </ h2 >
137+ < div
138+ id = "invisible-element"
139+ style = { {
140+ position : "absolute" ,
141+ top : 60 , // Adjusted to be below the h2 element
142+ left : "50%" ,
143+ transform : "translateX(-50%)" ,
144+ width : "100px" ,
145+ height : "20px" ,
146+ visibility : "hidden" , // Makes the element invisible
147+ } }
148+ >
149+ Invisible Element
150+ </ div >
151+ </ DndProvider >
152+ ) ;
153+ } ;
154+
155+ export default Game ;
0 commit comments