Project

General

Profile

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

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

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.main.DistortedScreen;
28
import org.distorted.library.message.EffectListener;
29

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

    
36
///////////////////////////////////////////////////////////////////////////////////////////////////
37

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

    
46
    final Class<? extends ScrambleEffect> effect;
47

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

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

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

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

    
69

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

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

    
87
///////////////////////////////////////////////////////////////////////////////////////////////////
88

    
89
  ScrambleEffect()
90
    {
91
    mRnd = new Random( System.currentTimeMillis() );
92
    mScrambles = new int[ObjectType.MAX_SCRAMBLE][3];
93
    }
94

    
95
///////////////////////////////////////////////////////////////////////////////////////////////////
96

    
97
  abstract void createEffects(int duration, int numScrambles);
98
  abstract void effectFinishedPlugin(final long effectID);
99

    
100
///////////////////////////////////////////////////////////////////////////////////////////////////
101

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

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

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

    
120
    mRotReady    = false;
121
    mPluginReady = false;
122

    
123
    addNewScramble();
124
    }
125

    
126
///////////////////////////////////////////////////////////////////////////////////////////////////
127

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

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

    
147
///////////////////////////////////////////////////////////////////////////////////////////////////
148

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

    
157
    DistortedEffects nodeEffects = mObject.getEffects();
158

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

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

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

    
175
    DistortedEffects nodeEffects = mObject.getEffects();
176

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

    
183
///////////////////////////////////////////////////////////////////////////////////////////////////
184
// PUBLIC API
185
///////////////////////////////////////////////////////////////////////////////////////////////////
186

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

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

    
197
    return names;
198
    }
199

    
200
///////////////////////////////////////////////////////////////////////////////////////////////////
201

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

    
208
///////////////////////////////////////////////////////////////////////////////////////////////////
209

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

    
215
///////////////////////////////////////////////////////////////////////////////////////////////////
216

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

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

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

    
231
///////////////////////////////////////////////////////////////////////////////////////////////////
232

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

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

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

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

    
258
///////////////////////////////////////////////////////////////////////////////////////////////////
259

    
260
  @SuppressWarnings("unused")
261
  public long start(int duration, DistortedScreen screen, ObjectPreRender pre)
262
    {
263
    mObject= pre.getObject();
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.getBasicAngle();
273

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

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

    
284
    assignEffects();
285

    
286
    return FAKE_EFFECT_ID;
287
    }
288

    
289
///////////////////////////////////////////////////////////////////////////////////////////////////
290

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

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

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