Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / effects / scramble / ScrambleEffect.java @ beee90ab

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2019 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is free software: you can redistribute it and/or modify                            //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Magic Cube is distributed in the hope that it will be useful,                                 //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

    
20
package org.distorted.objectlib.effects.scramble;
21

    
22
import java.lang.reflect.Method;
23
import java.util.Random;
24

    
25
import org.distorted.library.effect.Effect;
26
import org.distorted.library.main.DistortedEffects;
27
import org.distorted.library.message.EffectListener;
28

    
29
import org.distorted.objectlib.main.ObjectPreRender;
30
import org.distorted.objectlib.main.TwistyObject;
31
import org.distorted.objectlib.effects.BaseEffect;
32
import org.distorted.objectlib.helpers.MovesFinished;
33
import org.distorted.objectlib.main.TwistyObjectNode;
34

    
35
///////////////////////////////////////////////////////////////////////////////////////////////////
36

    
37
public abstract class ScrambleEffect extends BaseEffect implements EffectListener, MovesFinished
38
{
39
  public enum Type
40
    {
41
    NONE         (ScrambleEffectNone.class        ),
42
    ROTATIONS    (ScrambleEffectRotations.class   ),
43
    ;
44

    
45
    final Class<? extends ScrambleEffect> effect;
46

    
47
    Type(Class<? extends ScrambleEffect> effect)
48
      {
49
      this.effect= effect;
50
      }
51
    }
52

    
53
  private static final int NUM_EFFECTS = Type.values().length;
54
  private static final int FAKE_EFFECT_ID  = -3;
55
  private static final Type[] types;
56

    
57
  static
58
    {
59
    int i=0;
60
    types = new Type[NUM_EFFECTS];
61

    
62
    for(Type type: Type.values())
63
      {
64
      types[i++] = type;
65
      }
66
    }
67

    
68
  private int mEffectReturned;
69
  private int mNumScramblesLeft;
70
  private int mDurationPerDegree;
71
  private final Random mRnd;
72
  private int[][] mBasicAngle;
73
  private boolean mRotReady, mPluginReady;
74

    
75
  ObjectPreRender mPre;
76
  TwistyObject mObject;
77
  TwistyObjectNode mObjectNode;
78
  Effect[] mNodeEffects;
79
  int[] mNodeEffectPosition;
80
  Effect[] mCubeEffects;
81
  int[] mCubeEffectPosition;
82
  int mCubeEffectNumber, mNodeEffectNumber;
83
  int mNumScrambles;
84
  int[][] mScrambles;
85

    
86
///////////////////////////////////////////////////////////////////////////////////////////////////
87

    
88
  ScrambleEffect()
89
    {
90
    mRnd = new Random( System.currentTimeMillis() );
91
    }
92

    
93
///////////////////////////////////////////////////////////////////////////////////////////////////
94

    
95
  abstract void createEffects(int duration, int numScrambles);
96
  abstract void effectFinishedPlugin(final long effectID);
97

    
98
///////////////////////////////////////////////////////////////////////////////////////////////////
99

    
100
  private void createBaseEffects(int duration, int numScrambles)
101
    {
102
    mNumScramblesLeft = numScrambles;
103
    int absAngle, angle, axis, row, basicDegrees, totalDegrees = 0;
104

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

    
116
    mDurationPerDegree = duration/totalDegrees;
117
    mNumScrambles = 0;
118

    
119
    mRotReady    = false;
120
    mPluginReady = false;
121

    
122
    addNewScramble();
123
    }
124

    
125
///////////////////////////////////////////////////////////////////////////////////////////////////
126

    
127
  private void addNewScramble()
128
    {
129
    if( mNumScramblesLeft>0 )
130
      {
131
      int axis = mScrambles[mNumScrambles][0];
132
      int row  = mScrambles[mNumScrambles][1];
133
      int angle= mScrambles[mNumScrambles][2];
134

    
135
      mNumScramblesLeft--;
136
      mPre.addRotation(this, axis, (1<<row), angle, mDurationPerDegree);
137
      mNumScrambles++;
138
      }
139
    else
140
      {
141
      mRotReady = true;
142
      if( mPluginReady ) mPre.effectFinished(FAKE_EFFECT_ID);
143
      }
144
    }
145

    
146
///////////////////////////////////////////////////////////////////////////////////////////////////
147

    
148
  private void assignEffects()
149
    {
150
    for(int i=0; i<mCubeEffectNumber; i++)
151
      {
152
      mObject.apply(mCubeEffects[i],mCubeEffectPosition[i]);
153
      mCubeEffects[i].notifyWhenFinished(this);
154
      }
155

    
156
    DistortedEffects nodeEffects = mObjectNode.getEffects();
157

    
158
    for(int i=0; i<mNodeEffectNumber; i++)
159
      {
160
      nodeEffects.apply(mNodeEffects[i],mNodeEffectPosition[i]);
161
      mNodeEffects[i].notifyWhenFinished(this);
162
      }
163
    }
164

    
165
///////////////////////////////////////////////////////////////////////////////////////////////////
166

    
167
  private void disassignEffects()
168
    {
169
    for(int i=0; i<mCubeEffectNumber; i++)
170
      {
171
      mObject.remove(mCubeEffects[i].getID());
172
      }
173

    
174
    DistortedEffects nodeEffects = mObjectNode.getEffects();
175

    
176
    for(int i=0; i<mNodeEffectNumber; i++)
177
      {
178
      nodeEffects.abortById(mNodeEffects[i].getID());
179
      }
180
    }
181

    
182
///////////////////////////////////////////////////////////////////////////////////////////////////
183
// PUBLIC API
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185

    
186
  @SuppressWarnings("unused")
187
  public static String[] getNames()
188
    {
189
    String[] names = new String[NUM_EFFECTS];
190

    
191
    for( int i=0; i<NUM_EFFECTS; i++)
192
      {
193
      names[i] = types[i].name();
194
      }
195

    
196
    return names;
197
    }
198

    
199
///////////////////////////////////////////////////////////////////////////////////////////////////
200

    
201
  @SuppressWarnings("unused")
202
  public static ScrambleEffect create(int ordinal) throws InstantiationException, IllegalAccessException
203
    {
204
    return types[ordinal].effect.newInstance();
205
    }
206

    
207
///////////////////////////////////////////////////////////////////////////////////////////////////
208

    
209
  public void onActionFinished(final long effectID)
210
    {
211
    addNewScramble();
212
    }
213

    
214
///////////////////////////////////////////////////////////////////////////////////////////////////
215

    
216
  private void effectFinishedAction(final long effectID)
217
    {
218
    mEffectReturned++;
219
    effectFinishedPlugin(effectID);
220

    
221
    if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
222
      {
223
      disassignEffects();
224

    
225
      mPluginReady = true;
226
      if( mRotReady ) mPre.effectFinished(FAKE_EFFECT_ID);
227
      }
228
    }
229

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

    
232
  public void effectFinished(final long effectID)
233
    {
234
    for(int i=0; i<mCubeEffectNumber; i++)
235
      {
236
      long id = mCubeEffects[i].getID();
237

    
238
      if( effectID == id )
239
        {
240
        effectFinishedAction(effectID);
241
        return;
242
        }
243
      }
244

    
245
    for(int i=0; i<mNodeEffectNumber; i++)
246
      {
247
      long id = mNodeEffects[i].getID();
248

    
249
      if( effectID == id )
250
        {
251
        effectFinishedAction(effectID);
252
        return;
253
        }
254
      }
255
    }
256

    
257
///////////////////////////////////////////////////////////////////////////////////////////////////
258

    
259
  @SuppressWarnings("unused")
260
  public long start(int duration, ObjectPreRender pre)
261
    {
262
    mObject     = pre.getObject();
263
    mObjectNode = pre.getObjectNode();
264
    mPre        = pre;
265

    
266
    // NOT mController.solve() !! This would be a very subtle bug. We need to do this immediately,
267
    // because here we are already inside the mController.preRender() function (doing 'scrambleObjectNow')
268
    // and doing a delayed 'solve()' here would mean we'd be sometimes first doing the first rotation,
269
    // and only after it - the solve.
270
    mObject.solve();
271

    
272
    mBasicAngle = mObject.getBasicAngles();
273

    
274
    int numScrambles = pre.getNumScrambles();
275
    mScrambles = new int[numScrambles][3];
276
    int dura = (int)(duration*Math.pow(numScrambles,0.66f));
277
    createBaseEffects(dura,numScrambles);
278
    createEffects    (dura,numScrambles);
279

    
280
    if( mCubeEffectNumber==0 && mNodeEffectNumber==0 )
281
      {
282
      throw new RuntimeException("Cube and Node Plugin Effects not created!");
283
      }
284

    
285
    assignEffects();
286

    
287
    return FAKE_EFFECT_ID;
288
    }
289

    
290
///////////////////////////////////////////////////////////////////////////////////////////////////
291

    
292
  @SuppressWarnings("unused")
293
  public static void enableEffects()
294
    {
295
    Method method;
296

    
297
    for(Type type: Type.values())
298
      {
299
      try
300
        {
301
        method = type.effect.getDeclaredMethod("enable"); // enable not public, thus getDeclaredMethod
302
        }
303
      catch(NoSuchMethodException ex)
304
        {
305
        android.util.Log.e("ScrambleEffect", type.effect.getSimpleName()+": exception getting method: "+ex.getMessage());
306
        method = null;
307
        }
308

    
309
      try
310
        {
311
        if( method!=null ) method.invoke(null);
312
        }
313
      catch(Exception ex)
314
        {
315
        android.util.Log.e("ScrambleEffect", type.effect.getSimpleName()+": exception invoking method: "+ex.getMessage());
316
        }
317
      }
318
    }
319
}
(1-1/3)