dvc890 commited on
Commit
a023416
·
verified ·
1 Parent(s): 9783eaf

Update pages/GameLucky.tsx

Browse files
Files changed (1) hide show
  1. pages/GameLucky.tsx +46 -32
pages/GameLucky.tsx CHANGED
@@ -70,29 +70,33 @@ const LuckyWheel = ({ config, isSpinning, result, onSpin }: {
70
  const angle = (seg.weight / totalWeight) * 360;
71
  const start = currentAngle;
72
  currentAngle += angle;
73
- return { ...seg, startAngle: start, endAngle: currentAngle, angle };
 
 
74
  });
75
 
76
  useEffect(() => {
77
  if (result && isSpinning) {
78
  // Find target slice index
79
- const targetIndex = slices.findIndex(s => s.name === result.prize);
80
- // Default to first if not found (shouldn't happen if config syncs)
81
- const safeIndex = targetIndex >= 0 ? targetIndex : slices.length - 1;
82
- const targetSlice = slices[safeIndex];
83
 
84
- // Calculate center of target slice
85
- const centerAngle = targetSlice.startAngle + (targetSlice.angle / 2);
 
 
 
86
 
87
- // We want this centerAngle to align with 0 (top) after rotation
88
- // Logic: Current rotation -> Add 5 full spins (1800) -> Add offset to align
89
- // To align X at top (0 deg), we need to rotate -(X).
90
- // SVG coordinate system usually 0 is right (3 o'clock).
91
- // We rotate wheel -90deg initially so 0 is top.
92
- // Target rotation = (360 - centerAngle).
93
 
94
- const spinRounds = 5 * 360;
95
- const finalRotation = rotation + spinRounds + (360 - centerAngle);
 
 
 
 
 
96
 
97
  setRotation(finalRotation);
98
  }
@@ -106,18 +110,10 @@ const LuckyWheel = ({ config, isSpinning, result, onSpin }: {
106
  };
107
 
108
  return (
109
- <div className="flex flex-col items-center justify-center h-full w-full max-w-lg mx-auto p-4">
110
- <div className="relative w-full aspect-square max-w-[400px]">
111
- {/* Pointer */}
112
- <div className="absolute -top-6 left-1/2 -translate-x-1/2 z-20 text-red-600 drop-shadow-lg animate-bounce">
113
- <ArrowDown size={40} fill="currentColor" strokeWidth={2} stroke="white"/>
114
- </div>
115
-
116
- {/* Wheel */}
117
- <div
118
- className="w-full h-full rounded-full border-8 border-yellow-400 shadow-2xl overflow-hidden relative transition-transform duration-[4000ms] cubic-bezier(0.2, 0.8, 0.2, 1)"
119
- style={{ transform: `rotate(${rotation}deg)` }}
120
- >
121
  <svg viewBox="-1 -1 2 2" style={{ transform: 'rotate(-90deg)' }} className="w-full h-full">
122
  {slices.map((slice, i) => {
123
  // Calculate SVG path
@@ -136,13 +132,14 @@ const LuckyWheel = ({ config, isSpinning, result, onSpin }: {
136
  <text
137
  x="0" y="0"
138
  fill="white"
139
- fontSize="0.1"
140
  fontWeight="bold"
141
  textAnchor="middle"
142
  dominantBaseline="middle"
143
  transform="rotate(90)"
 
144
  >
145
- {slice.name.length > 5 ? slice.name.substring(0,4)+'..' : slice.name}
146
  </text>
147
  </g>
148
  </g>
@@ -151,12 +148,29 @@ const LuckyWheel = ({ config, isSpinning, result, onSpin }: {
151
  </svg>
152
  </div>
153
 
154
- {/* Center Button */}
155
- <div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-10">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  <button
157
  onClick={onSpin}
158
  disabled={isSpinning}
159
- className="w-16 h-16 md:w-20 md:h-20 bg-gradient-to-b from-yellow-300 to-yellow-500 rounded-full border-4 border-white shadow-xl flex items-center justify-center font-black text-red-600 text-lg md:text-xl hover:scale-105 active:scale-95 disabled:grayscale transition-all"
160
  >
161
  {isSpinning ? '...' : '抽奖'}
162
  </button>
 
70
  const angle = (seg.weight / totalWeight) * 360;
71
  const start = currentAngle;
72
  currentAngle += angle;
73
+ // Center angle is where the pointer should land for this segment
74
+ const center = start + (angle / 2);
75
+ return { ...seg, startAngle: start, endAngle: currentAngle, angle, centerAngle: center };
76
  });
77
 
78
  useEffect(() => {
79
  if (result && isSpinning) {
80
  // Find target slice index
81
+ const targetSlice = slices.find(s => s.name === result.prize) || slices[slices.length - 1];
 
 
 
82
 
83
+ // Logic: Rotate the POINTER to align with the slice center
84
+ // Base rounds + Target Angle
85
+ // We need to ensure we always spin forward (clockwise)
86
+ const minSpins = 5;
87
+ const baseRotation = Math.floor(rotation / 360) * 360 + (minSpins * 360);
88
 
89
+ // Current effective angle
90
+ const currentMod = rotation % 360;
91
+ const targetMod = targetSlice.centerAngle;
 
 
 
92
 
93
+ let diff = targetMod - currentMod;
94
+ if (diff <= 0) diff += 360; // Ensure positive delta for clockwise spin
95
+
96
+ // Add a little randomness within the slice (-40% to +40% width) to simulate real physics
97
+ const jitter = (Math.random() - 0.5) * (targetSlice.angle * 0.8);
98
+
99
+ const finalRotation = rotation + (minSpins * 360) + diff + jitter;
100
 
101
  setRotation(finalRotation);
102
  }
 
110
  };
111
 
112
  return (
113
+ <div className="flex flex-col items-center justify-center h-full w-full max-w-2xl mx-auto p-4">
114
+ <div className="relative w-full aspect-square max-w-[500px] md:max-w-[600px]">
115
+ {/* Wheel (Static Background) */}
116
+ <div className="w-full h-full rounded-full border-8 border-yellow-400 shadow-2xl overflow-hidden relative bg-white">
 
 
 
 
 
 
 
 
117
  <svg viewBox="-1 -1 2 2" style={{ transform: 'rotate(-90deg)' }} className="w-full h-full">
118
  {slices.map((slice, i) => {
119
  // Calculate SVG path
 
132
  <text
133
  x="0" y="0"
134
  fill="white"
135
+ fontSize="0.08"
136
  fontWeight="bold"
137
  textAnchor="middle"
138
  dominantBaseline="middle"
139
  transform="rotate(90)"
140
+ style={{ textShadow: '1px 1px 2px rgba(0,0,0,0.3)' }}
141
  >
142
+ {slice.name.length > 6 ? slice.name.substring(0,5)+'..' : slice.name}
143
  </text>
144
  </g>
145
  </g>
 
148
  </svg>
149
  </div>
150
 
151
+ {/* Spinning Pointer Container (Centered) */}
152
+ <div
153
+ className="absolute inset-0 pointer-events-none flex items-center justify-center z-20"
154
+ style={{
155
+ transform: `rotate(${rotation}deg)`,
156
+ transition: isSpinning ? 'transform 4s cubic-bezier(0.2, 0.8, 0.2, 1)' : 'none'
157
+ }}
158
+ >
159
+ {/* The Needle Graphic (Extends UP from center) */}
160
+ <div className="relative w-0 h-0 -mt-[35%]">
161
+ {/* Needle Body */}
162
+ <div className="absolute bottom-0 left-1/2 -translate-x-1/2 w-4 md:w-6 h-32 md:h-48 bg-red-600 rounded-t-full shadow-lg border-2 border-white origin-bottom"></div>
163
+ {/* Needle Base Decoration */}
164
+ <div className="absolute bottom-[-10px] left-1/2 -translate-x-1/2 w-8 h-8 md:w-10 md:h-10 bg-red-700 rounded-full border-2 border-white shadow-md"></div>
165
+ </div>
166
+ </div>
167
+
168
+ {/* Center Button (Static Pivot) */}
169
+ <div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-30 pointer-events-auto">
170
  <button
171
  onClick={onSpin}
172
  disabled={isSpinning}
173
+ className="w-16 h-16 md:w-20 md:h-20 bg-gradient-to-b from-yellow-300 to-yellow-500 rounded-full border-4 border-white shadow-[0_4px_10px_rgba(0,0,0,0.3)] flex items-center justify-center font-black text-red-600 text-lg md:text-xl hover:scale-105 active:scale-95 disabled:grayscale transition-all active:shadow-inner"
174
  >
175
  {isSpinning ? '...' : '抽奖'}
176
  </button>