Jypeli  5
The simple game programming library
Meter.cs
Siirry tämän tiedoston dokumentaatioon.
1 #region MIT License
2 /*
3  * Copyright (c) 2009 University of Jyväskylä, Department of Mathematical
4  * Information Technology.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #endregion
25 
26 /*
27  * Authors: Tero Jäntti, Tomi Karppinen, Janne Nikkanen.
28  */
29 
30 using System;
31 using System.Collections.Generic;
32 
33 namespace Jypeli
34 {
38  public enum TriggerDirection
39  {
43  Up,
44 
48  Down,
49 
54  };
55 
60  public abstract class Meter
61  {
65  public abstract double RelativeValue { get; set; }
66 
67  internal abstract double GetValue();
68  internal abstract double GetMinValue();
69  internal abstract double GetMaxValue();
70 
77  public Meter<T> OfType<T>() where T : struct, IComparable<T>, IEquatable<T>
78  {
79  Type meterType = this.GetType();
80  Type[] genargs = meterType.GetGenericArguments();
81 
82  if ( genargs.Length < 1 ) throw new ArgumentException( "This meter is not typed" );
83  if ( genargs[0] != typeof( T ) ) throw new ArgumentException( String.Format( "This meter measures {0}, not {1}", genargs[0].Name, typeof( T ).Name ) );
84 
85  return (Meter<T>)this;
86  }
87  }
88 
93  [Save]
94  public abstract class Meter<ValueType> : Meter where ValueType : struct, IComparable<ValueType>, IEquatable<ValueType>
95  {
96  private struct Trigger
97  {
98  public ValueType value;
99  public TriggerDirection direction;
100  public Action method;
101 
102  public Trigger(ValueType value, TriggerDirection direction, Action method)
103  {
104  this.value = value;
105  this.direction = direction;
106  this.method = method;
107  }
108  }
109 
110  private bool valueSet;
111 
112  private ValueType val;
113  private ValueType minval;
114  private ValueType maxval;
115  private ValueType defval;
116 
117  private List<Trigger> triggers;
118 
122  [Save]
123  public ValueType Value
124  {
125  get { return val; }
126  set
127  {
128  if ( value.Equals( val ) )
129  return;
130 
131  ValueType oldval = val;
132  valueSet = true;
133 
134  if (value.CompareTo(minval) < 0) value = minval;
135  if (value.CompareTo(maxval) > 0) value = maxval;
136 
137  val = value;
138  OnChange(oldval, value);
139  CheckLimits( oldval, value );
140  CheckTriggers(oldval, value);
141  }
142  }
143 
147  public ValueType DefaultValue
148  {
149  get { return defval; }
150  set
151  {
152  defval = clampValue( value, minval, maxval );
153  if ( !valueSet ) Value = value;
154  }
155  }
156 
161  public ValueType MinValue
162  {
163  get { return minval; }
164  set { minval = value; updateBounds(); }
165  }
166 
171  public ValueType MaxValue
172  {
173  get { return maxval; }
174  set { maxval = value; updateBounds(); }
175  }
176 
177  #region Events
178 
182  public delegate void ChangeHandler( ValueType oldValue, ValueType newValue );
183 
187  public event ChangeHandler Changed;
188 
192  public event Action LowerLimit;
193 
197  public event Action UpperLimit;
198 
199 
200  private void OnChange( ValueType oldValue, ValueType newValue )
201  {
202  if ( Changed != null )
203  Changed( oldValue, newValue );
204  }
205 
206  private void CheckLimits( ValueType oldValue, ValueType newValue )
207  {
208  if ( LowerLimit != null && newValue.CompareTo(minval) <= 0 && oldValue.CompareTo(minval) > 0 )
209  {
210  LowerLimit();
211  return;
212  }
213 
214  if ( UpperLimit != null && newValue.CompareTo(maxval) >= 0 && oldValue.CompareTo(maxval) < 0 )
215  {
216  UpperLimit();
217  return;
218  }
219  }
220 
221  private void CheckTriggers( ValueType oldValue, ValueType newValue )
222  {
223  if ( triggers == null ) return;
224 
225  foreach ( Trigger t in triggers )
226  {
227  if ( t.direction != TriggerDirection.Down && oldValue.CompareTo( t.value ) < 0 && newValue.CompareTo( t.value ) >= 0 )
228  t.method();
229 
230  else if ( t.direction != TriggerDirection.Up && oldValue.CompareTo( t.value ) > 0 && newValue.CompareTo( t.value ) <= 0 )
231  t.method();
232  }
233  }
234 
235  #endregion
236 
243  public Meter( ValueType defaultVal, ValueType minVal, ValueType maxVal )
244  {
245  minval = minVal;
246  maxval = maxVal;
247  defval = defaultVal;
248  val = defaultVal;
249  updateBounds();
250  }
251 
256  public Meter( Meter<ValueType> src )
257  {
258  minval = src.minval;
259  maxval = src.maxval;
260  defval = src.defval;
261  val = src.val;
262  updateBounds();
263  }
264 
268  public void Reset()
269  {
270  Value = DefaultValue;
271  }
272 
278  public void SetValue( ValueType value )
279  {
280  Value = value;
281  }
282 
289  public void AddTrigger( ValueType value, TriggerDirection direction, Action method )
290  {
291  if ( triggers == null ) triggers = new List<Trigger>();
292  triggers.Add( new Trigger( value, direction, method ) );
293  }
294 
301  public void AddTrigger( ValueType value, TriggerDirection direction, Action<ValueType> method )
302  {
303  AddTrigger( value, direction, delegate() { method( this.Value ); } );
304  }
305 
310  public void RemoveTriggers( ValueType value )
311  {
312  if ( triggers == null ) return;
313  triggers.RemoveAll( t => t.value.Equals( value ) );
314  }
315 
320  public void RemoveTriggers( Action method )
321  {
322  if ( triggers == null ) return;
323  triggers.RemoveAll( t => t.method == method );
324  }
325 
329  public void ClearTriggers()
330  {
331  if ( triggers == null ) return;
332  triggers.Clear();
333  }
334 
335  private static ValueType clampValue( ValueType v, ValueType min, ValueType max )
336  {
337  if (min.CompareTo(max) > 0)
338  {
339  // Maximum is less than minimum, don't clamp
340  return v;
341  }
342 
343  if ( v.CompareTo( min ) < 0 )
344  return min;
345 
346  if ( v.CompareTo( max ) > 0 )
347  return max;
348 
349  return v;
350  }
351 
352  private static void clampValue( ref ValueType v, ValueType min, ValueType max )
353  {
354  if ( min.CompareTo( max ) > 0 )
355  {
356  // Maximum is less than minimum, don't clamp
357  return;
358  }
359 
360  if ( v.CompareTo( min ) < 0 )
361  v = min;
362 
363  else if ( v.CompareTo( max ) > 0 )
364  v = max;
365  }
366 
367  private void updateBounds()
368  {
369  clampValue( ref val, minval, maxval );
370  clampValue( ref defval, minval, maxval );
371  }
372 
376  public override String ToString()
377  {
378  return Value.ToString();
379  }
380  }
381 
382 
387  public class IntMeter : Meter<int>
388  {
389  private List<Operation> operations = new List<Operation>();
390 
391  public override double RelativeValue
392  {
393  get { return ( Value - MinValue ) / (double)( MaxValue - MinValue ); }
394  set { Value = (int)( MinValue + value * ( MaxValue - MinValue ) ); }
395  }
396 
397  public IntMeter( int defaultValue )
398  : base( defaultValue, 0, int.MaxValue )
399  {
400  }
401 
402  public IntMeter(int defaultValue,int minValue, int MaxValue)
403  : base(defaultValue, minValue,MaxValue)
404  {
405  }
406 
412  public static implicit operator int( IntMeter m )
413  {
414  return m.Value;
415  }
416 
422  public static implicit operator double( IntMeter m )
423  {
424  return (double)m.Value;
425  }
426 
432  public void AddValue( int change )
433  {
434  Value += change;
435  }
436 
442  public void MultiplyValue( int multiplier )
443  {
444  Value *= multiplier;
445  }
446 
452  public void MultiplyValue( double multiplier )
453  {
454  Value = (int)Math.Round( Value * multiplier );
455  }
456 
464  public Operation AddOverTime( int change, double seconds, Action onComplete )
465  {
466  Operation op = AddOverTime( change, seconds );
467  op.Finished += onComplete;
468  return op;
469  }
470 
477  public Operation AddOverTime( int change, double seconds )
478  {
479  Operation op = new IntMeterAddOperation( this, change, seconds );
480  op.Finished += delegate { operations.Remove( op ); };
481  op.Stopped += delegate { operations.Remove( op ); };
482  operations.Add( op );
483  return op;
484  }
485 
489  public void Stop()
490  {
491  while ( operations.Count > 0 )
492  operations[0].Stop();
493  }
494 
495  internal override double GetValue()
496  {
497  return Value;
498  }
499 
500  internal override double GetMinValue()
501  {
502  return MinValue;
503  }
504 
505  internal override double GetMaxValue()
506  {
507  return MaxValue;
508  }
509  }
510 
515  public class DoubleMeter : Meter<double>
516  {
517  private List<Operation> operations = new List<Operation>();
518 
519  public override double RelativeValue
520  {
521  get { return ( Value - MinValue ) / ( MaxValue - MinValue ); }
522  set { Value = MinValue + value * ( MaxValue - MinValue ); }
523  }
524 
525  public DoubleMeter( double defaultValue )
526  : base( defaultValue, 0.0, double.MaxValue )
527  {
528  }
529 
530  public DoubleMeter(double defaultValue,double minValue, double maxValue)
531  : base(defaultValue,minValue, maxValue)
532  {
533  }
534 
540  public static implicit operator double( DoubleMeter m )
541  {
542  return m.Value;
543  }
544 
550  public void AddValue( double change )
551  {
552  Value += change;
553  }
554 
560  public void MultiplyValue( double multiplier )
561  {
562  Value *= multiplier;
563  }
564 
572  public Operation AddOverTime( double change, double seconds, Action onComplete )
573  {
574  Operation op = AddOverTime( change, seconds );
575  op.Finished += onComplete;
576  return op;
577  }
578 
585  public Operation AddOverTime( double change, double seconds )
586  {
587  Operation op = new DoubleMeterAddOperation( this, change, seconds );
588  op.Finished += delegate { operations.Remove( op ); };
589  op.Stopped += delegate { operations.Remove( op ); };
590  operations.Add( op );
591  return op;
592  }
593 
597  public void Stop()
598  {
599  while ( operations.Count > 0 )
600  operations[0].Stop();
601  }
602 
603  internal override double GetValue()
604  {
605  return Value;
606  }
607 
608  internal override double GetMinValue()
609  {
610  return MinValue;
611  }
612 
613  internal override double GetMaxValue()
614  {
615  return MaxValue;
616  }
617  }
618 }
void Stop()
Pysäyttää AddOverTime-metodilla tehtävät lisäykset mittariin.
Definition: Meter.cs:489
void AddTrigger(ValueType value, TriggerDirection direction, Action< ValueType > method)
Lisää mittarille rajan, jonka yli mentäessä laukaistaan aliohjelma.
Definition: Meter.cs:301
Nappi on ylhäällä.
Operation AddOverTime(int change, double seconds)
Lisää tietyn summan mittariin tasaisesti tietyn ajan sisällä.
Definition: Meter.cs:477
void MultiplyValue(double multiplier)
Kertoo mittarin arvon jollakin. Sama kuin Value-ominaisuuden kertominen, mutta helpompi käyttää tapah...
Definition: Meter.cs:452
abstract double RelativeValue
Mittarin suhteellinen arvo (minimi 0, maksimi 1)
Definition: Meter.cs:65
IntMeter(int defaultValue, int minValue, int MaxValue)
Definition: Meter.cs:402
Nappi on alhaalla.
Operation AddOverTime(double change, double seconds)
Lisää tietyn summan mittariin tasaisesti tietyn ajan sisällä.
Definition: Meter.cs:585
ChangeHandler Changed
Tapahtuu, kun mittarin arvo muuttuu.
Definition: Meter.cs:187
void ClearTriggers()
Poistaa kaikki raja-arvotapahtumat.
Definition: Meter.cs:329
Action Stopped
Tapahtuu kun tehtävä pysäytetään Stop-metodilla.
Definition: Operation.cs:32
Action LowerLimit
Tapahtuu, kun mittari saavuttaa pienimmän sallitun arvonsa.
Definition: Meter.cs:192
Meter(ValueType defaultVal, ValueType minVal, ValueType maxVal)
Luo uuden mittarin.
Definition: Meter.cs:243
Käynnissä oleva tehtävä
Definition: Operation.cs:11
void RemoveTriggers(Action method)
Poistaa kaikki raja-arvotapahtumat, jotka kutsuvat tiettyä aliohjelmaa.
Definition: Meter.cs:320
Mittari, joka mittaa double-tyyppisiä arvoja. Sidottavissa näyttöihin, kuten ValueDisplay ja BarGauge...
Definition: Meter.cs:515
void Stop()
Pysäyttää AddOverTime-metodilla tehtävät lisäykset mittariin.
Definition: Meter.cs:597
DoubleMeter(double defaultValue, double minValue, double maxValue)
Definition: Meter.cs:530
DoubleMeter(double defaultValue)
Definition: Meter.cs:525
Tehtävä mittarin arvon kasvattamiselle.
Action UpperLimit
Tapahtuu, kun mittari saavuttaa suurimman sallitun arvonsa.
Definition: Meter.cs:197
Mittari, joka mittaa int-tyyppisiä arvoja. Sidottavissa näyttöihin, kuten ValueDisplay ja BarGauge...
Definition: Meter.cs:387
void RemoveTriggers(ValueType value)
Poistaa kaikki tietylle arvolle asetetut raja-arvotapahtumat.
Definition: Meter.cs:310
Tehtävä mittarin arvon kasvattamiselle.
override String ToString()
Palauttaa mittarin arvon merkkijonona.
Definition: Meter.cs:376
void AddTrigger(ValueType value, TriggerDirection direction, Action method)
Lisää mittarille rajan, jonka yli mentäessä laukaistaan aliohjelma.
Definition: Meter.cs:289
void AddValue(int change)
Lisää jotain mittarin arvoon. Sama kuin Value-ominaisuuteen lisääminen, mutta helpompi käyttää tapaht...
Definition: Meter.cs:432
Meter(Meter< ValueType > src)
Luo uuden mittarin kopiona parametrina annetusta.
Definition: Meter.cs:256
IntMeter(int defaultValue)
Definition: Meter.cs:397
void AddValue(double change)
Lisää jotain mittarin arvoon. Sama kuin Value-ominaisuuteen lisääminen, mutta helpompi käyttää tapaht...
Definition: Meter.cs:550
TriggerDirection
Suunta mittarin muutokselle.
Definition: Meter.cs:38
Operation AddOverTime(double change, double seconds, Action onComplete)
Lisää tietyn summan mittariin tasaisesti tietyn ajan sisällä.
Definition: Meter.cs:572
void MultiplyValue(double multiplier)
Kertoo mittarin arvon jollakin. Sama kuin Value-ominaisuuden kertominen, mutta helpompi käyttää tapah...
Definition: Meter.cs:560
void SetValue(ValueType value)
Asettaa mittarille arvon. Sama kuin Value-ominaisuuteen sijoitus, mutta helpompi käyttää tapahtumakäs...
Definition: Meter.cs:278
Action Finished
Tapahtuu kun tehtävä valmistuu. Ei tapahdu, jos tehtävä keskeytetään Stop-aliohjelmalla.
Definition: Operation.cs:27
Mittari, joka mittaa erityyppisiä arvoja. Sidottavissa näyttöihin, kuten ValueDisplay ja BarGauge...
Definition: Meter.cs:60
Operation AddOverTime(int change, double seconds, Action onComplete)
Lisää tietyn summan mittariin tasaisesti tietyn ajan sisällä.
Definition: Meter.cs:464
void MultiplyValue(int multiplier)
Kertoo mittarin arvon jollakin. Sama kuin Value-ominaisuuden kertominen, mutta helpompi käyttää tapah...
Definition: Meter.cs:442
void Reset()
Palauttaa mittarin arvon oletusarvoonsa.
Definition: Meter.cs:268