Project

General

Profile

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

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

1
///////////////////////////////////////////////////////////////////////////////////////////////////
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
  private static final int EXTRA_DURATION = 3000;
45
  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
  private boolean mScrambleForward;
62
  private int mTotalDuration;
63

    
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
  int mNumScrambles, mCurrScramble;
73
  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
  private void createBaseEffects(int numScrambles)
89
    {
90
    mNumScrambles = numScrambles;
91
    mCurrScramble = 0;
92
    mScrambleForward = true;
93
    randomizeScrambles();
94
    addNewScramble();
95
    }
96

    
97
///////////////////////////////////////////////////////////////////////////////////////////////////
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
///////////////////////////////////////////////////////////////////////////////////////////////////
113

    
114
  private void randomizeScrambles()
115
    {
116
    int absAngle, angle, axis, row, basicDegrees, totalDegrees = 0;
117

    
118
    for(int scramble=0; scramble<mNumScrambles; scramble++)
119
      {
120
      mObject.randomizeNewScramble(mScrambles, mRnd, scramble, mNumScrambles);
121
      int[] s = mScrambles[scramble];
122
      axis  = s[0];
123
      row   = computeRowFromBitmap(s[1]);
124
      angle = s[2];
125
      absAngle = (angle<0 ? -angle : angle);
126
      basicDegrees = 360/mBasicAngle[axis][row];
127
      totalDegrees += absAngle*basicDegrees;
128
      }
129

    
130
    mDurationPerDegree = mTotalDuration/(2*totalDegrees);
131
    }
132

    
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134

    
135
  private void addNewScramble()
136
    {
137
    if( mScrambleForward )
138
      {
139
      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
      }
159
    else
160
      {
161
      if( mCurrScramble>=mNumScrambles )
162
        {
163
        Thread thread = new Thread()
164
          {
165
          public void run()
166
            {
167
            try { sleep(EXTRA_DURATION); }
168
            catch(InterruptedException ex) { }
169
            addRotation(false);
170
            }
171
          };
172

    
173
        thread.start();
174
        }
175
      else
176
        {
177
        addRotation(false);
178
        }
179
      }
180
    }
181

    
182
///////////////////////////////////////////////////////////////////////////////////////////////////
183

    
184
  private void addRotation(boolean forward)
185
    {
186
    if( !forward ) mCurrScramble--;
187

    
188
    int axis = mScrambles[mCurrScramble][0];
189
    int row  = mScrambles[mCurrScramble][1];
190
    int angle= mScrambles[mCurrScramble][2];
191

    
192
    if( !forward ) angle = -angle;
193

    
194
    mPre.addRotation(this, axis, row, angle, mDurationPerDegree);
195

    
196
    if( forward ) mCurrScramble++;
197

    
198
    if( mCurrScramble>=mNumScrambles ) mScrambleForward=false;
199
    if( mCurrScramble<=0             ) mScrambleForward=true;
200
    }
201

    
202
///////////////////////////////////////////////////////////////////////////////////////////////////
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
    mTotalDuration = (int)(duration*Math.pow(numScrambles,0.66f));
280
    createBaseEffects(numScrambles);
281
    createEffects(mTotalDuration,numScrambles);
282

    
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
}
(1-1/2)