Project

General

Profile

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

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

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 void randomizeScrambles()
100
    {
101
    int absAngle, angle, axis, row, basicDegrees, totalDegrees = 0;
102

    
103
    for(int scramble=0; scramble<mNumScrambles; scramble++)
104
      {
105
      mObject.randomizeNewScramble(mScrambles, mRnd, scramble, mNumScrambles);
106
      axis  = mScrambles[scramble][0];
107
      row   = mScrambles[scramble][1];
108
      angle = mScrambles[scramble][2];
109
      absAngle = (angle<0 ? -angle : angle);
110
      basicDegrees = 360/mBasicAngle[axis][row];
111
      totalDegrees += absAngle*basicDegrees;
112
      }
113

    
114
    mDurationPerDegree = mTotalDuration/(2*totalDegrees);
115
    }
116

    
117
///////////////////////////////////////////////////////////////////////////////////////////////////
118

    
119
  private void addNewScramble()
120
    {
121
    if( mScrambleForward )
122
      {
123
      if( mCurrScramble==0 )
124
        {
125
        Thread thread = new Thread()
126
          {
127
          public void run()
128
            {
129
            randomizeScrambles();
130
            try { sleep(EXTRA_DURATION); }
131
            catch(InterruptedException ex) { }
132
            addRotation(true);
133
            }
134
          };
135

    
136
        thread.start();
137
        }
138
      else
139
        {
140
        addRotation(true);
141
        }
142
      }
143
    else
144
      {
145
      if( mCurrScramble>=mNumScrambles )
146
        {
147
        Thread thread = new Thread()
148
          {
149
          public void run()
150
            {
151
            try { sleep(EXTRA_DURATION); }
152
            catch(InterruptedException ex) { }
153
            addRotation(false);
154
            }
155
          };
156

    
157
        thread.start();
158
        }
159
      else
160
        {
161
        addRotation(false);
162
        }
163
      }
164
    }
165

    
166
///////////////////////////////////////////////////////////////////////////////////////////////////
167

    
168
  private void addRotation(boolean forward)
169
    {
170
    if( !forward ) mCurrScramble--;
171

    
172
    int axis = mScrambles[mCurrScramble][0];
173
    int row  = mScrambles[mCurrScramble][1];
174
    int angle= mScrambles[mCurrScramble][2];
175

    
176
    if( !forward ) angle = -angle;
177

    
178
    mPre.addRotation(this, axis, (1<<row), angle, mDurationPerDegree);
179

    
180
    if( forward ) mCurrScramble++;
181

    
182
    if( mCurrScramble>=mNumScrambles ) mScrambleForward=false;
183
    if( mCurrScramble<=0             ) mScrambleForward=true;
184
    }
185

    
186
///////////////////////////////////////////////////////////////////////////////////////////////////
187

    
188
  private void assignEffects()
189
    {
190
    for(int i=0; i<mCubeEffectNumber; i++)
191
      {
192
      mObject.applyEffect(mCubeEffects[i],mCubeEffectPosition[i]);
193
      mCubeEffects[i].notifyWhenFinished(this);
194
      }
195

    
196
    DistortedEffects nodeEffects = mObjectNode.getEffects();
197

    
198
    for(int i=0; i<mNodeEffectNumber; i++)
199
      {
200
      nodeEffects.apply(mNodeEffects[i],mNodeEffectPosition[i]);
201
      mNodeEffects[i].notifyWhenFinished(this);
202
      }
203
    }
204

    
205
///////////////////////////////////////////////////////////////////////////////////////////////////
206
// PUBLIC API
207
///////////////////////////////////////////////////////////////////////////////////////////////////
208

    
209
  @SuppressWarnings("unused")
210
  public static String[] getNames()
211
    {
212
    String[] names = new String[NUM_EFFECTS];
213

    
214
    for( int i=0; i<NUM_EFFECTS; i++)
215
      {
216
      names[i] = types[i].name();
217
      }
218

    
219
    return names;
220
    }
221

    
222
///////////////////////////////////////////////////////////////////////////////////////////////////
223

    
224
  @SuppressWarnings("unused")
225
  public static PresentEffect create(int ordinal) throws InstantiationException, IllegalAccessException
226
    {
227
    return types[ordinal].effect.newInstance();
228
    }
229

    
230
///////////////////////////////////////////////////////////////////////////////////////////////////
231

    
232
  public void onActionFinished(final long effectID)
233
    {
234
    addNewScramble();
235
    }
236

    
237
///////////////////////////////////////////////////////////////////////////////////////////////////
238

    
239
  public void effectFinished(final long effectID)
240
    {
241

    
242
    }
243

    
244
///////////////////////////////////////////////////////////////////////////////////////////////////
245

    
246
  @SuppressWarnings("unused")
247
  public long start(int duration, ObjectPreRender pre)
248
    {
249
    mObject     = pre.getObject();
250
    mObjectNode = pre.getObjectNode();
251
    mPre        = pre;
252

    
253
    // NOT mController.solve() !! This would be a very subtle bug. We need to do this immediately,
254
    // because here we are already inside the mController.preRender() function (doing 'scrambleObjectNow')
255
    // and doing a delayed 'solve()' here would mean we'd be sometimes first doing the first rotation,
256
    // and only after it - the solve.
257
    mObject.solve();
258

    
259
    mBasicAngle = mObject.getBasicAngles();
260

    
261
    int numScrambles = pre.getNumScrambles();
262
    mScrambles = new int[numScrambles][3];
263
    mTotalDuration = (int)(duration*Math.pow(numScrambles,0.66f));
264
    createBaseEffects(numScrambles);
265
    createEffects(mTotalDuration,numScrambles);
266

    
267
    if( mCubeEffectNumber==0 && mNodeEffectNumber==0 )
268
      {
269
      throw new RuntimeException("Cube and Node Plugin Effects not created!");
270
      }
271

    
272
    assignEffects();
273

    
274
    return FAKE_EFFECT_ID;
275
    }
276

    
277
///////////////////////////////////////////////////////////////////////////////////////////////////
278

    
279
  @SuppressWarnings("unused")
280
  public static void enableEffects()
281
    {
282
    Method method;
283

    
284
    for(PresentEffect.Type type: PresentEffect.Type.values())
285
      {
286
      try
287
        {
288
        method = type.effect.getDeclaredMethod("enable"); // enable not public, thus getDeclaredMethod
289
        }
290
      catch(NoSuchMethodException ex)
291
        {
292
        android.util.Log.e("PresentEffect", type.effect.getSimpleName()+": exception getting method: "+ex.getMessage());
293
        method = null;
294
        }
295

    
296
      try
297
        {
298
        if( method!=null ) method.invoke(null);
299
        }
300
      catch(Exception ex)
301
        {
302
        android.util.Log.e("PresentEffect", type.effect.getSimpleName()+": exception invoking method: "+ex.getMessage());
303
        }
304
      }
305
    }
306
}
(1-1/2)