Project

General

Profile

Download (9.3 KB) Statistics
| Branch: | Revision:

distorted-objectlib / src / main / java / org / distorted / objectlib / effects / present / PresentEffect.java @ b26ea579

1 826d293e Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2022 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8
///////////////////////////////////////////////////////////////////////////////////////////////////
9
10
package org.distorted.objectlib.effects.present;
11
12
import java.lang.reflect.Method;
13
import java.util.Random;
14
15
import org.distorted.library.effect.Effect;
16
import org.distorted.library.main.DistortedEffects;
17
import org.distorted.library.message.EffectListener;
18
19
import org.distorted.objectlib.main.ObjectPreRender;
20
import org.distorted.objectlib.main.TwistyObject;
21
import org.distorted.objectlib.effects.BaseEffect;
22
import org.distorted.objectlib.helpers.MovesFinished;
23
import org.distorted.objectlib.main.TwistyObjectNode;
24
25
///////////////////////////////////////////////////////////////////////////////////////////////////
26
27
public abstract class PresentEffect extends BaseEffect implements EffectListener, MovesFinished
28
{
29
  public enum Type
30
    {
31
    SPIN (PresentEffectSpin.class),
32
    ;
33
34
    final Class<? extends PresentEffect> effect;
35
36
    Type(Class<? extends PresentEffect> effect)
37
      {
38
      this.effect= effect;
39
      }
40
    }
41
42
  private static final int NUM_EFFECTS = PresentEffect.Type.values().length;
43
  private static final int FAKE_EFFECT_ID  = -6;
44 8801b933 Leszek Koltunski
  private static final int EXTRA_DURATION = 3000;
45 826d293e Leszek Koltunski
  private static final PresentEffect.Type[] types;
46
47
  static
48
    {
49
    int i=0;
50
    types = new PresentEffect.Type[NUM_EFFECTS];
51
52
    for(PresentEffect.Type type: PresentEffect.Type.values())
53
      {
54
      types[i++] = type;
55
      }
56
    }
57
58
  private int mDurationPerDegree;
59
  private final Random mRnd;
60
  private int[][] mBasicAngle;
61 8801b933 Leszek Koltunski
  private boolean mScrambleForward;
62
  private int mTotalDuration;
63 826d293e Leszek Koltunski
64
  ObjectPreRender mPre;
65
  TwistyObject mObject;
66
  TwistyObjectNode mObjectNode;
67
  Effect[] mNodeEffects;
68
  int[] mNodeEffectPosition;
69
  Effect[] mCubeEffects;
70
  int[] mCubeEffectPosition;
71
  int mCubeEffectNumber, mNodeEffectNumber;
72 8801b933 Leszek Koltunski
  int mNumScrambles, mCurrScramble;
73 826d293e Leszek Koltunski
  int[][] mScrambles;
74
75
///////////////////////////////////////////////////////////////////////////////////////////////////
76
77
  PresentEffect()
78
    {
79
    mRnd = new Random( System.currentTimeMillis() );
80
    }
81
82
///////////////////////////////////////////////////////////////////////////////////////////////////
83
84
  abstract void createEffects(int duration, int numScrambles);
85
86
///////////////////////////////////////////////////////////////////////////////////////////////////
87
88 8801b933 Leszek Koltunski
  private void createBaseEffects(int numScrambles)
89
    {
90
    mNumScrambles = numScrambles;
91
    mCurrScramble = 0;
92
    mScrambleForward = true;
93
    randomizeScrambles();
94
    addNewScramble();
95
    }
96
97 00057bb1 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
98
99
  private int computeRowFromBitmap(int rowBitmap)
100
    {
101
    int index = 0;
102
103
    while(index<32)
104
      {
105
      if( (rowBitmap&0x1) != 0 ) return index;
106
      rowBitmap>>=1;
107
      index++;
108
      }
109
    return 0;
110
    }
111
112 8801b933 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
113
114
  private void randomizeScrambles()
115 826d293e Leszek Koltunski
    {
116
    int absAngle, angle, axis, row, basicDegrees, totalDegrees = 0;
117
118 8801b933 Leszek Koltunski
    for(int scramble=0; scramble<mNumScrambles; scramble++)
119 826d293e Leszek Koltunski
      {
120 8801b933 Leszek Koltunski
      mObject.randomizeNewScramble(mScrambles, mRnd, scramble, mNumScrambles);
121 00057bb1 Leszek Koltunski
      int[] s = mScrambles[scramble];
122
      axis  = s[0];
123
      row   = computeRowFromBitmap(s[1]);
124
      angle = s[2];
125 826d293e Leszek Koltunski
      absAngle = (angle<0 ? -angle : angle);
126
      basicDegrees = 360/mBasicAngle[axis][row];
127
      totalDegrees += absAngle*basicDegrees;
128
      }
129
130 8801b933 Leszek Koltunski
    mDurationPerDegree = mTotalDuration/(2*totalDegrees);
131 826d293e Leszek Koltunski
    }
132
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134
135
  private void addNewScramble()
136
    {
137 8801b933 Leszek Koltunski
    if( mScrambleForward )
138 826d293e Leszek Koltunski
      {
139 8801b933 Leszek Koltunski
      if( mCurrScramble==0 )
140
        {
141
        Thread thread = new Thread()
142
          {
143
          public void run()
144
            {
145
            randomizeScrambles();
146
            try { sleep(EXTRA_DURATION); }
147
            catch(InterruptedException ex) { }
148
            addRotation(true);
149
            }
150
          };
151
152
        thread.start();
153
        }
154
      else
155
        {
156
        addRotation(true);
157
        }
158 826d293e Leszek Koltunski
      }
159
    else
160
      {
161 8801b933 Leszek Koltunski
      if( mCurrScramble>=mNumScrambles )
162 826d293e Leszek Koltunski
        {
163 8801b933 Leszek Koltunski
        Thread thread = new Thread()
164 b1370e3b Leszek Koltunski
          {
165 8801b933 Leszek Koltunski
          public void run()
166 b1370e3b Leszek Koltunski
            {
167 8801b933 Leszek Koltunski
            try { sleep(EXTRA_DURATION); }
168
            catch(InterruptedException ex) { }
169
            addRotation(false);
170
            }
171
          };
172
173
        thread.start();
174 826d293e Leszek Koltunski
        }
175
      else
176
        {
177 8801b933 Leszek Koltunski
        addRotation(false);
178 826d293e Leszek Koltunski
        }
179
      }
180
    }
181
182 b1370e3b Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
183
184
  private void addRotation(boolean forward)
185
    {
186 8801b933 Leszek Koltunski
    if( !forward ) mCurrScramble--;
187 b1370e3b Leszek Koltunski
188 8801b933 Leszek Koltunski
    int axis = mScrambles[mCurrScramble][0];
189
    int row  = mScrambles[mCurrScramble][1];
190
    int angle= mScrambles[mCurrScramble][2];
191 b1370e3b Leszek Koltunski
192
    if( !forward ) angle = -angle;
193
194 00057bb1 Leszek Koltunski
    mPre.addRotation(this, axis, row, angle, mDurationPerDegree);
195 b1370e3b Leszek Koltunski
196 8801b933 Leszek Koltunski
    if( forward ) mCurrScramble++;
197
198
    if( mCurrScramble>=mNumScrambles ) mScrambleForward=false;
199
    if( mCurrScramble<=0             ) mScrambleForward=true;
200 b1370e3b Leszek Koltunski
    }
201
202 826d293e Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
203
204
  private void assignEffects()
205
    {
206
    for(int i=0; i<mCubeEffectNumber; i++)
207
      {
208
      mObject.applyEffect(mCubeEffects[i],mCubeEffectPosition[i]);
209
      mCubeEffects[i].notifyWhenFinished(this);
210
      }
211
212
    DistortedEffects nodeEffects = mObjectNode.getEffects();
213
214
    for(int i=0; i<mNodeEffectNumber; i++)
215
      {
216
      nodeEffects.apply(mNodeEffects[i],mNodeEffectPosition[i]);
217
      mNodeEffects[i].notifyWhenFinished(this);
218
      }
219
    }
220
221
///////////////////////////////////////////////////////////////////////////////////////////////////
222
// PUBLIC API
223
///////////////////////////////////////////////////////////////////////////////////////////////////
224
225
  @SuppressWarnings("unused")
226
  public static String[] getNames()
227
    {
228
    String[] names = new String[NUM_EFFECTS];
229
230
    for( int i=0; i<NUM_EFFECTS; i++)
231
      {
232
      names[i] = types[i].name();
233
      }
234
235
    return names;
236
    }
237
238
///////////////////////////////////////////////////////////////////////////////////////////////////
239
240
  @SuppressWarnings("unused")
241
  public static PresentEffect create(int ordinal) throws InstantiationException, IllegalAccessException
242
    {
243
    return types[ordinal].effect.newInstance();
244
    }
245
246
///////////////////////////////////////////////////////////////////////////////////////////////////
247
248
  public void onActionFinished(final long effectID)
249
    {
250
    addNewScramble();
251
    }
252
253
///////////////////////////////////////////////////////////////////////////////////////////////////
254
255
  public void effectFinished(final long effectID)
256
    {
257
258
    }
259
260
///////////////////////////////////////////////////////////////////////////////////////////////////
261
262
  @SuppressWarnings("unused")
263
  public long start(int duration, ObjectPreRender pre)
264
    {
265
    mObject     = pre.getObject();
266
    mObjectNode = pre.getObjectNode();
267
    mPre        = pre;
268
269
    // NOT mController.solve() !! This would be a very subtle bug. We need to do this immediately,
270
    // because here we are already inside the mController.preRender() function (doing 'scrambleObjectNow')
271
    // and doing a delayed 'solve()' here would mean we'd be sometimes first doing the first rotation,
272
    // and only after it - the solve.
273
    mObject.solve();
274
275
    mBasicAngle = mObject.getBasicAngles();
276
277
    int numScrambles = pre.getNumScrambles();
278
    mScrambles = new int[numScrambles][3];
279 8801b933 Leszek Koltunski
    mTotalDuration = (int)(duration*Math.pow(numScrambles,0.66f));
280
    createBaseEffects(numScrambles);
281
    createEffects(mTotalDuration,numScrambles);
282 826d293e Leszek Koltunski
283
    if( mCubeEffectNumber==0 && mNodeEffectNumber==0 )
284
      {
285
      throw new RuntimeException("Cube and Node Plugin Effects not created!");
286
      }
287
288
    assignEffects();
289
290
    return FAKE_EFFECT_ID;
291
    }
292
293
///////////////////////////////////////////////////////////////////////////////////////////////////
294
295
  @SuppressWarnings("unused")
296
  public static void enableEffects()
297
    {
298
    Method method;
299
300
    for(PresentEffect.Type type: PresentEffect.Type.values())
301
      {
302
      try
303
        {
304
        method = type.effect.getDeclaredMethod("enable"); // enable not public, thus getDeclaredMethod
305
        }
306
      catch(NoSuchMethodException ex)
307
        {
308
        android.util.Log.e("PresentEffect", type.effect.getSimpleName()+": exception getting method: "+ex.getMessage());
309
        method = null;
310
        }
311
312
      try
313
        {
314
        if( method!=null ) method.invoke(null);
315
        }
316
      catch(Exception ex)
317
        {
318
        android.util.Log.e("PresentEffect", type.effect.getSimpleName()+": exception invoking method: "+ex.getMessage());
319
        }
320
      }
321
    }
322
}