Jypeli  5
The simple game programming library
Surface.cs
Siirry tämän tiedoston dokumentaatioon.
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using Physics2DDotNet.Shapes;
6 
7 namespace Jypeli
8 {
12  public class Surface : PhysicsObject
13  {
14  double[] heights = null;
15  double scale = 1.0;
16 
17  #region Constructors
18 
32  public Surface( double width, double[] heights, double scale )
33  : this( width, heights, scale, CalculateShapeParams( width, heights ) )
34  {
35  }
36 
37  public Surface( double width, double[] heights, double scale, CollisionShapeParameters shapeParameters )
38  : base( width, CalculateHeight( heights, scale ), CreateRuggedShape( width, heights, scale ), shapeParameters )
39  {
40  InitializeRugged( heights, scale );
41  }
42 
48  public Surface( double width, double height )
49  : base( width, height, Shape.Rectangle )
50  {
51  InitializeFlat( height );
52  }
53 
54  public Surface( double width, double height, CollisionShapeParameters shapeParameters )
55  : base( width, height, Shape.Rectangle, shapeParameters )
56  {
57  InitializeFlat( height );
58  }
59 
60  private void InitializeFlat( double height )
61  {
62  this.heights = new double[1] { height };
63  this.scale = 1.0;
64 
65  this.Color = Color.ForestGreen;
66  this.TextureFillsShape = true;
67  MakeStatic();
68  }
69 
70  private void InitializeRugged( double[] heights, double scale )
71  {
72  this.heights = heights;
73  this.scale = scale;
74  this.Color = Color.ForestGreen;
75  this.TextureFillsShape = true;
76  MakeStatic();
77  }
78 
87  public Surface( double width, double min, double max, int points )
88  : this( width, RandomGen.NextDoubleArray( Math.Max( min, 1.0f ), max, points ), 1.0 )
89  {
90  }
91 
92  public Surface( double width, double min, double max, int points, CollisionShapeParameters shapeParameters )
93  : this( width, RandomGen.NextDoubleArray( Math.Max( min, 1.0f ), max, points ), 1.0, shapeParameters )
94  {
95  }
96 
106  public Surface( double width, double min, double max, int points, int maxchange )
107  : this( width, RandomGen.NextDoubleArray( Math.Max( min, 1.0f ), max, points, maxchange ), 1.0 )
108  {
109  }
110 
111  public Surface( double width, double min, double max, int points, int maxchange, CollisionShapeParameters shapeParameters )
112  : this( width, RandomGen.NextDoubleArray( Math.Max(min, 1.0f), max, points, maxchange ), 1.0, shapeParameters )
113  {
114  }
115 
116  #endregion
117 
118  #region Static private methods for constructors
119 
120  private static double CalculateHeight( double[] heights, double scale )
121  {
122  if ( heights.Length < 2 )
123  throw new Exception( "At least two Y-points needed in order to create ground" );
124  if ( heights.Min() < 1 )
125  throw new Exception( "The heights must be positive and at least 1" ); // JN: doesn't work well with 0 values (slow and memory usage problems)
126 
127  return heights.Max() * scale;
128  }
129 
130  private static Vector[] CalculateVertexes( double width, double[] heights, double scale )
131  {
132  int n = heights.Length;
133  double step = width / ( n - 1 );
134  double maxHeight = heights.Max() * scale;
135 
136  // Each point should be adjusted by this amount in order to get the center of the shape at (0, 0)
137  // This way, drawing a single texture on top of it covers the whole shape.
138  double halfHeight = maxHeight / 2;
139 
140  Vector[] vertexes = new Vector[n * 2];
141 
142  // Let's start from the bottom right corner and head clockwise from there.
143  Vector bottomRight = new Vector( width / 2, -halfHeight );
144 
145  // Bottom vertexes, right to left
146  for ( int i = 0; i < n; i++ )
147  {
148  vertexes[i] = new Vector( bottomRight.X - ( i * step ), bottomRight.Y );
149  }
150 
151  double left = -width / 2;
152 
153  // Top vertexes, left to right
154  for ( int i = 0; i < n; i++ )
155  {
156  vertexes[n + i] = new Vector( left + ( i * step ), heights[i] * scale - halfHeight );
157  }
158 
159  return vertexes;
160  }
161 
162  private static Polygon CreateRuggedShape( double width, double[] heights, double scale )
163  {
164  Vector[] vertexes = CalculateVertexes( width, heights, scale );
165  return CreateShape( width, heights, vertexes );
166  }
167 
168  private static Polygon CreateShape( double width, double[] heights, Vector[] vertexes )
169  {
170  int n = heights.Length;
171  double step = width / ( n - 1 );
172  IndexTriangle[] triangles = new IndexTriangle[( n - 1 ) * 2];
173  Int16[] outlineIndices = new Int16[n * 2];
174 
175  for ( int i = 0; i < n * 2; i++ )
176  outlineIndices[i] = (Int16)i;
177  for ( int i = 0; i < n - 1; i++ )
178  {
179  triangles[2 * i] = new IndexTriangle( i, 2 * n - i - 2, 2 * n - i - 1 );
180  triangles[2 * i + 1] = new IndexTriangle( i, i + 1, 2 * n - i - 2 );
181  }
182 
183  Vector[] outlineVertices = new Vector[outlineIndices.Length];
184  for ( int i = 0; i < outlineIndices.Length; i++ )
185  outlineVertices[i] = vertexes[outlineIndices[i]];
186 
187  return new Polygon( new ShapeCache( vertexes, triangles, outlineIndices ), false );
188  }
189 
190  private static double GetMinHeightDifference( double[] heights )
191  {
192  int n = heights.Length;
193  double minHeightDifference = double.PositiveInfinity;
194 
195  for ( int i = 0; i < n - 1; i++ )
196  {
197  double diff = Math.Abs( heights[i + 1] - heights[i] );
198  if ( diff > double.Epsilon && diff < minHeightDifference ) minHeightDifference = diff;
199  }
200 
201  return minHeightDifference;
202  }
203 
204  private static CollisionShapeParameters CalculateShapeParams( double width, double[] heights )
205  {
206  int n = heights.Length;
207  double step = width / ( n - 1 );
208 
210  parms.DistanceGridSpacing = Math.Max( step / 8, GetMinHeightDifference( heights ) / 2 );
211  parms.MaxVertexDistance = 20;
212  return parms;
213  }
214 
215  #endregion
216 
217  #region Factory methods
218 
226  public static Surface Create( Level level, Direction direction )
227  {
228  if ( direction == Direction.Left ) return CreateLeft( level );
229  if ( direction == Direction.Right ) return CreateRight( level );
230  if ( direction == Direction.Up ) return CreateTop( level );
231  if ( direction == Direction.Down ) return CreateBottom( level );
232 
233  return null;
234  }
235 
246  public static Surface Create( Level level, Direction direction, double min, double max, int points )
247  {
248  if ( direction == Direction.Left ) return CreateLeft( level, min, max, points );
249  if ( direction == Direction.Right ) return CreateRight( level, min, max, points );
250  if ( direction == Direction.Up ) return CreateTop( level, min, max, points );
251  if ( direction == Direction.Down ) return CreateBottom( level, min, max, points );
252 
253  return null;
254  }
255 
267  public static Surface Create( Level level, Direction direction, double min, double max, int points, int maxchange )
268  {
269  if ( direction == Direction.Left ) return CreateLeft( level, min, max, points, maxchange );
270  if ( direction == Direction.Right ) return CreateRight( level, min, max, points, maxchange );
271  if ( direction == Direction.Up ) return CreateTop( level, min, max, points, maxchange );
272  if ( direction == Direction.Down ) return CreateBottom( level, min, max, points, maxchange );
273 
274  return null;
275  }
276 
283  public static Surface CreateLeft( Level level )
284  {
285  double thickness = level.GetBorderThickness();
286  Surface ground = new Surface( level.Height, thickness );
287  ground.Angle = -Angle.RightAngle;
288  ground.Position = new Vector( level.Left - ( thickness / 2 ), level.Center.Y );
289  return ground;
290  }
291 
301  public static Surface CreateLeft( Level level, double min, double max, int points )
302  {
303  Surface ground = new Surface( level.Height + 2 * max, min, max, points );
304  ground.Angle = -Angle.RightAngle;
305  ground.Position = new Vector( level.Left - ( max / 2 ), level.Center.Y );
306  return ground;
307  }
308 
319  public static Surface CreateLeft( Level level, double min, double max, int points, int maxchange )
320  {
321  Surface ground = new Surface( level.Height + 2 * max, min, max, points, maxchange );
322  ground.Angle = -Angle.RightAngle;
323  ground.Position = new Vector( level.Left - ( max / 2 ), level.Center.Y );
324  return ground;
325  }
326 
333  public static Surface CreateRight( Level level )
334  {
335  double thickness = level.GetBorderThickness();
336  Surface ground = new Surface( level.Height, thickness );
337  ground.Angle = Angle.RightAngle;
338  ground.Position = new Vector( level.Right + ( thickness / 2 ), level.Center.Y );
339  return ground;
340  }
341 
351  public static Surface CreateRight( Level level, double min, double max, int points )
352  {
353  Surface ground = new Surface( level.Height + 2 * max, min, max, points );
354  ground.Angle = Angle.RightAngle;
355  ground.Position = new Vector( level.Right + ( max / 2 ), level.Center.Y );
356  return ground;
357  }
358 
369  public static Surface CreateRight( Level level, double min, double max, int points, int maxchange )
370  {
371  Surface ground = new Surface( level.Height + 2 * max, min, max, points, maxchange );
372  ground.Angle = Angle.RightAngle;
373  ground.Position = new Vector( level.Right + ( max / 2 ), level.Center.Y );
374  return ground;
375  }
376 
383  public static Surface CreateTop( Level level )
384  {
385  double thickness = level.GetBorderThickness();
386  Surface ground = new Surface( level.Width + ( 2 * thickness ), thickness );
387  ground.Angle = Angle.StraightAngle;
388  ground.Position = new Vector( level.Center.X, level.Top + ( thickness / 2 ) );
389  return ground;
390  }
391 
401  public static Surface CreateTop( Level level, double min, double max, int points )
402  {
403  Surface ground = new Surface( level.Width + 2 * max, min, max, points );
404  ground.Angle = Angle.StraightAngle;
405  ground.Position = new Vector( level.Center.X, level.Top + ( max / 2 ) );
406  return ground;
407  }
408 
419  public static Surface CreateTop( Level level, double min, double max, int points, int maxchange )
420  {
421  Surface ground = new Surface( level.Width + 2 * max, min, max, points, maxchange );
422  ground.Angle = Angle.StraightAngle;
423  ground.Position = new Vector( level.Center.X, level.Top + ( max / 2 ) );
424  return ground;
425  }
426 
433  public static Surface CreateBottom( Level level )
434  {
435  double thickness = level.GetBorderThickness();
436  Surface ground = new Surface( level.Width + ( 2 * thickness ), thickness );
437  ground.Position = new Vector( level.Center.X, level.Bottom - ( thickness / 2 ) );
438  return ground;
439  }
440 
450  public static Surface CreateBottom( Level level, double min, double max, int points )
451  {
452  Surface ground = new Surface( level.Width + 2 * max, min, max, points );
453  ground.Position = new Vector( level.Center.X, level.Bottom - ( max / 2 ) );
454  return ground;
455  }
456 
467  public static Surface CreateBottom( Level level, double min, double max, int points, int maxchange )
468  {
469  Surface ground = new Surface( level.Width + 2 * max, min, max, points, maxchange );
470  ground.Position = new Vector( level.Center.X, level.Bottom - ( max / 2 ) );
471  return ground;
472  }
473 
474  #endregion
475 
476  #region Public methods
477 
478  public double GetGroundHeight( double x )
479  {
480  if ( heights == null || x < Left || x > Right ) return Top;
481 
482  int n = heights.Length;
483  double step = Width / ( n - 1 );
484  double maxHeight = heights.Max() * scale;
485 
486  double indexX = ( Width / 2 + x ) / step;
487  int lowerIndex = (int)Math.Floor( indexX );
488  int upperIndex = (int)Math.Ceiling( indexX );
489 
490  if ( upperIndex >= n ) return Top; // DEBUG
491  if ( lowerIndex == upperIndex ) return Bottom + scale * heights[lowerIndex];
492 
493  double k = ( heights[upperIndex] - heights[lowerIndex] ) / step;
494  double relX = ( Width / 2 + x ) % step;
495 
496  return Bottom + heights[lowerIndex] + relX * k;
497  }
498 
499  public Vector GetGroundNormal( double x )
500  {
501  if ( heights == null || x < Left || x > Right ) return Vector.UnitY;
502 
503  int n = heights.Length;
504  double step = Width / ( n - 1 );
505  double maxHeight = heights.Max() * scale;
506 
507  double indexX = ( Width / 2 + x ) / step;
508  int lowerIndex = (int)Math.Floor( indexX );
509  int upperIndex = (int)Math.Ceiling( indexX );
510 
511  if ( upperIndex >= n ) return Vector.UnitY; // DEBUG
512  if ( lowerIndex == upperIndex )
513  {
514  return ( GetGroundNormal( x - step / 2 ) + GetGroundNormal( x + step / 2 ) ) / 2;
515  }
516 
517  double k = ( heights[upperIndex] - heights[lowerIndex] ) / step;
518  return Vector.FromLengthAndAngle( 1, Angle.ArcTan( k ) + Angle.RightAngle );
519  }
520 
521  #endregion
522  }
523 }
static Direction Down
Suunta alas.
Definition: Direction.cs:65
Kuvio.
Definition: Shapes.cs:48
void MakeStatic()
Tekee oliosta staattisen. Staattinen olio ei liiku muiden olioiden törmäyksistä, vaan ainoastaan muut...
Definition: Inertia.cs:179
Surface(double width, double[] heights, double scale, CollisionShapeParameters shapeParameters)
Definition: Surface.cs:37
Vector GetGroundNormal(double x)
Definition: Surface.cs:499
Surface(double width, double min, double max, int points, CollisionShapeParameters shapeParameters)
Definition: Surface.cs:92
static Surface CreateBottom(Level level)
Luo kentälle tasaisen alareunan. Ei lisää reunaa automaattisesti kenttään.
Definition: Surface.cs:433
double Right
Olion oikean reunan x-koordinaatti.
Suuntakulma (rajoitettu -180 ja 180 asteen välille) asteina ja radiaaneina. Tietoja kulmasta: http://...
Definition: Angle.cs:40
double Top
Kentän yläreunan y-koordinaatti.
Definition: Level.cs:160
static Direction Left
Suunta vasemmalle.
Definition: Direction.cs:70
Suorakulmio.
Definition: Shapes.cs:315
Surface(double width, double min, double max, int points, int maxchange)
Luo satunnaisen pinnan.
Definition: Surface.cs:106
Satunnaisgeneraattori. Luo satunnaisia arvoja, mm. lukuja, vektoreita sekä kulmia.
Definition: RandomGen.cs:39
static Surface Create(Level level, Direction direction)
Luo kentälle tasaisen reunan. Ei lisää reunaa automaattisesti kenttään.
Definition: Surface.cs:226
static Surface CreateRight(Level level)
Luo kentälle tasaisen oikean reunan. Ei lisää reunaa automaattisesti kenttään.
Definition: Surface.cs:333
static readonly Vector UnitY
Pystysuuntainen yksikkövektori (pituus 1, suunta ylös).
Definition: Vector.cs:71
Surface(double width, double[] heights, double scale)
Helppo tapa lisätä kenttään epätasainen pinta. Pinta kuvataan luettelemalla Y-koordinaatteja vasemmal...
Definition: Surface.cs:32
Peliolio, joka noudattaa fysiikkamoottorin määräämiä fysiikan lakeja. Voidaan kuitenkin myös laittaa ...
Definition: Coefficients.cs:36
static Surface CreateBottom(Level level, double min, double max, int points)
Luo kentälle epätasaisen alareunan. Ei lisää reunaa automaattisesti kenttään.
Definition: Surface.cs:450
Törmäyskuvion laatuun vaikuttavat parametrit.
override Angle Angle
Kulma, jossa olio on. Oliota voi pyörittää kulmaa vaihtamalla.
Definition: Dimensions.cs:80
bool TextureFillsShape
Jos true, kuva piirretään niin, ettei se mene olion muodon ääriviivojen yli. Toisin sanoen kuva piirr...
double Bottom
Olion alareunan y-koordinaatti.
Surface(double width, double height, CollisionShapeParameters shapeParameters)
Definition: Surface.cs:54
double Top
Olion yläreunan y-koordinaatti.
readonly Vector Center
Kentän keskipiste.
Definition: Level.cs:96
static readonly Angle RightAngle
Suora kulma (90 astetta).
Definition: Angle.cs:50
static readonly Angle StraightAngle
Oikokulma (180 astetta).
Definition: Angle.cs:55
static Surface CreateTop(Level level, double min, double max, int points)
Luo kentälle epätasaisen yläreunan. Ei lisää reunaa automaattisesti kenttään.
Definition: Surface.cs:401
Pelikenttä, johon voi lisätä olioita. Kentällä voi myös olla reunat ja taustaväri tai taustakuva...
Definition: Level.cs:78
Perussuunta tasossa.
Definition: Direction.cs:50
Sisältää valmiiksi lasketut kolmiot, joiden avulla piirtäminen on suoraviivaista. ...
Definition: Shapes.cs:577
static Surface CreateBottom(Level level, double min, double max, int points, int maxchange)
Luo kentälle epätasaisen alareunan. Ei lisää reunaa automaattisesti kenttään.
Definition: Surface.cs:467
double Y
Definition: Vector.cs:275
static Surface CreateTop(Level level, double min, double max, int points, int maxchange)
Luo kentälle epätasaisen yläreunan. Ei lisää reunaa automaattisesti kenttään.
Definition: Surface.cs:419
static Surface CreateRight(Level level, double min, double max, int points, int maxchange)
Luo kentälle epätasaisen oikean reunan. Ei lisää reunaa automaattisesti kenttään. ...
Definition: Surface.cs:369
Surface(double width, double min, double max, int points, int maxchange, CollisionShapeParameters shapeParameters)
Definition: Surface.cs:111
Tasainen tai epätasainen pinta.
Definition: Surface.cs:12
double Bottom
Kentän alareunan y-koordinaatti.
Definition: Level.cs:168
static Surface CreateLeft(Level level, double min, double max, int points, int maxchange)
Luo kentälle epätasaisen vasemman reunan. Ei lisää reunaa automaattisesti kenttään.
Definition: Surface.cs:319
static Surface CreateRight(Level level, double min, double max, int points)
Luo kentälle epätasaisen oikean reunan. Ei lisää reunaa automaattisesti kenttään. ...
Definition: Surface.cs:351
Surface(double width, double min, double max, int points)
Luo satunnaisen pinnan.
Definition: Surface.cs:87
double X
Definition: Vector.cs:274
static Surface CreateLeft(Level level)
Luo kentälle tasaisen vasemman reunan. Ei lisää reunaa automaattisesti kenttään.
Definition: Surface.cs:283
double Height
Kentän korkeus.
Definition: Level.cs:126
static Vector Max(params Vector[] vectors)
Palauttaa pisimmän vektorin.
Definition: Vector.cs:216
static Surface Create(Level level, Direction direction, double min, double max, int points)
Luo kentälle epätasaisen reunan. Ei lisää reunaa automaattisesti kenttään.
Definition: Surface.cs:246
Väri.
Definition: Color.cs:13
static Surface CreateTop(Level level)
Luo kentälle tasaisen yläreunan. Ei lisää reunaa automaattisesti kenttään.
Definition: Surface.cs:383
double Width
Kentän leveys.
Definition: Level.cs:117
override Vector Position
Olion paikka koordinaatistossa. Käsittää sekä X- että Y-koordinaatin.
Definition: Dimensions.cs:49
static Angle ArcTan(double d)
Palauttaa kulman joka vastaa d:n arcus-tangentti.
Definition: Angle.cs:479
static Surface Create(Level level, Direction direction, double min, double max, int points, int maxchange)
Luo kentälle epätasaisen reunan. Ei lisää reunaa automaattisesti kenttään.
Definition: Surface.cs:267
static Direction Right
Suunta oikealle.
Definition: Direction.cs:75
Monikulmio.
Definition: Shapes.cs:496
double Width
Olion leveys (X-suunnassa, leveimmässä kohdassa).
static Direction Up
Suunta ylös.
Definition: Direction.cs:60
double Right
Kentän oikean reunan x-koordinaatti.
Definition: Level.cs:152
2D-vektori.
Definition: Vector.cs:56
static Surface CreateLeft(Level level, double min, double max, int points)
Luo kentälle epätasaisen vasemman reunan. Ei lisää reunaa automaattisesti kenttään.
Definition: Surface.cs:301
Surface(double width, double height)
Luo tasaisen pinnan.
Definition: Surface.cs:48
static readonly Color ForestGreen
Metsänvihreä.
Definition: Color.cs:624
Muotojen määrityksessä käytettävä kolmio.
Definition: Shapes.cs:547
double GetGroundHeight(double x)
Definition: Surface.cs:478
double Left
Kentän vasemman reunan x-koordinaatti.
Definition: Level.cs:144