Jypeli  5
The simple game programming library
__GameObject.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.IO;
32 using System.Collections.Generic;
33 using System.ComponentModel;
34 
35 #if !XBOX && !WINDOWS_PHONE
36 using System.Runtime.Serialization.Formatters.Binary;
37 #endif
38 
39 using Microsoft.Xna.Framework;
40 using Jypeli.Controls;
41 using System.Reflection;
42 
43 
44 namespace Jypeli
45 {
50 #if !XBOX && !WINDOWS_PHONE
51  [Serializable]
52 #endif
53  [Save]
54  public class GameObject : GameObjects.GameObjectBase, IGameObjectInternal
55  {
56  #region Fields
57 
58 #if !XBOX && !WINDOWS_PHONE
59  [NonSerialized]
60 #endif
61  private Color color = Color.White;
62  private Vector size;
63  private Shape shape;
64  private Vector textureWrapSize = new Vector( 1, 1 );
65 
66  internal List<IGameObject> childObjects = null;
67  private Queue<IGameObject> childObjectsToRemove = null;
68 
69  public List<Listener> AssociatedListeners { get; private set; }
70 
71  private bool textureFillsShape = false;
72  private bool isAddedToGame = false;
73 
74  protected Timer moveTimer = null;
75  protected Vector? moveTarget = null;
76  protected double moveSpeed;
77 
78  #endregion
79 
83  public IEnumerable<IGameObject> Objects
84  {
85  get { InitializeObjectLists(); return childObjects; }
86  }
87 
91  [Save] public bool IsVisible { get; set; }
92 
97  public override Vector Size
98  {
99  get { return size; }
100  set
101  {
102  if ( value.X < 0.0 || value.Y < 0.0 )
103  throw new ArgumentException( "The size must be positive." );
104 
105  // TODO: this doesn't work properly.
106 
107  Vector oldSize = size;
108  Vector newSize = value;
109  size = value;
110 
111  double xFactor = newSize.X / oldSize.X;
112  double yFactor = newSize.Y / oldSize.Y;
113  if (childObjects != null)
114  {
115  foreach (var o in childObjects)
116  {
117  Vector oldChildSize = o.Size;
118  o.Size = new Vector(oldChildSize.X * xFactor, oldChildSize.Y * yFactor);
119 
120  // Vector direction = o.Position.Normalize();
121  // double distance = o.Position.Magnitude;
122  Vector oldChildPosition = o.Position;
123  o.Position = new Vector(oldChildPosition.X * xFactor, oldChildPosition.Y * yFactor);
124  }
125  }
126  }
127  }
128 
133  public override Angle Angle { get; set; }
134 
138  public override Animation Animation { get; set; }
139 
144  public Vector TextureWrapSize
145  {
146  get { return textureWrapSize; }
147  set { textureWrapSize = value; }
148  }
149 
153  public Color Color
154  {
155  get { return color; }
156  set { color = value; }
157  }
158 
169  public bool TextureFillsShape
170  {
171  get { return textureFillsShape; }
172  set { textureFillsShape = value; }
173  }
174 
178  public virtual Shape Shape
179  {
180  get { return shape; }
181  set { shape = value; }
182  }
183 
187  internal string ShapeString
188  {
189  get { return Shape.GetType().Name; }
190  set { Shape = Shape.FromString( value ); }
191  }
192 
197  [Obsolete("Käytä Game.Instance ja IsAddedToGame")]
198  public Game Game
199  {
200  get { return isAddedToGame ? Game.Instance : null; }
201  }
202 
206  public bool IsAddedToGame
207  {
208  get { return isAddedToGame; }
209  set
210  {
211  isAddedToGame = value;
212  if ( childObjects != null )
213  {
214  foreach ( var o in childObjects )
215  o.IsAddedToGame = value;
216  }
217  }
218  }
219 
223  [Obsolete("Käytä mieluummin Arrived-tapahtumaa (ottaa parametriksi IGameObject pelkän GameObjectin sijaan)")]
224  public event Action<GameObject, Vector> ArrivedAt;
225 
230  [Obsolete( "Käytä mieluummin Arrived-tapahtumaa (ottaa parametriksi IGameObject pelkän GameObjectin sijaan)" )]
231  public void OnArrivedAt( Vector location )
232  {
233  if ( ArrivedAt != null )
234  ArrivedAt( this, location );
235  }
236 
237  #region Destroyable
238 
242  public override void Destroy()
243  {
244  this.MaximumLifetime = TimeSpan.Zero;
245 
246  if ( childObjects != null )
247  {
248  foreach ( GameObject child in childObjects )
249  {
250  child.Destroy();
251  }
252  }
253 
254  if ( AssociatedListeners != null )
255  {
256  foreach ( Listener listener in AssociatedListeners )
257  {
258  listener.Destroy();
259  }
260  }
261 
262  base.Destroy();
263  }
264 
265  #endregion
266 
272  public GameObject( double width, double height )
273  : this( width, height, Shape.Rectangle )
274  {
275  }
276 
282  public GameObject(Image image)
283  : this( image.Width, image.Height, Shape.Rectangle )
284  {
285  this.Image = image;
286  }
287 
294  public GameObject( double width, double height, Shape shape )
295  : base()
296  {
297  this.IsVisible = true;
298  this.size = new Vector( width, height );
299  this.shape = shape;
300  this.AssociatedListeners = new List<Listener>();
301  this.Arrived += delegate( IGameObject obj, Vector location ) { OnArrivedAt( location ); };
302  }
303 
304 #if !XBOX && !WINDOWS_PHONE
305  public object Clone()
312  {
313  MemoryStream ms = new MemoryStream();
314  BinaryFormatter bf = new BinaryFormatter();
315 
316  bf.Serialize( ms, this );
317  ms.Position = 0;
318 
319  object obj = bf.Deserialize( ms );
320  ms.Close();
321 
322  // Copy nonserializable data
323  ( (GameObject)obj ).Animation = new Animation( this.Animation );
324 
325  return obj;
326  }
327 #endif
328 
332  public bool IsInside(Vector point)
333  {
334  Vector p = this.AbsolutePosition;
335 
336  if ( AbsoluteAngle == Angle.Zero )
337  {
338  // A special (faster) case of the general case below
339  if ( point.X >= ( p.X - Width / 2 )
340  && point.X <= ( p.X + Width / 2 )
341  && point.Y >= ( p.Y - Height / 2 )
342  && point.Y <= ( p.Y + Height / 2 ) ) return true;
343  }
344  else
345  {
346  Vector unitX = Vector.FromLengthAndAngle( 1, this.AbsoluteAngle );
347  Vector unitY = unitX.LeftNormal;
348  double pX = p.ScalarProjection( unitX );
349  double pY = p.ScalarProjection( unitY );
350  double pointX = point.ScalarProjection( unitX );
351  double pointY = point.ScalarProjection( unitY );
352 
353  if ( pointX >= ( pX - Width / 2 )
354  && pointX <= ( pX + Width / 2 )
355  && pointY >= ( pY - Height / 2 )
356  && pointY <= ( pY + Height / 2 ) ) return true;
357  }
358 
359  if ( childObjects == null ) return false;
360 
361  for ( int i = 0; i < childObjects.Count; i++ )
362  {
363  if ( childObjects[i].IsInside( point ) ) return true;
364  }
365 
366  return false;
367  }
368 
376  public void Add( IGameObject childObject )
377  {
378  var childObjectInt = (IGameObjectInternal)childObject;
379 
380  InitializeObjectLists();
381 
382  if ( childObjects.Contains( childObject ) )
383  throw new ArgumentException( "The child object has already been added" );
384  if ( childObject is PhysicsObject )
385  throw new NotImplementedException( "Having a PhysicsObject as a child object is not supported." );
386 
387  childObjects.Add( childObject );
388  childObject.Parent = this;
389 
390  if ( IsAddedToGame )
391  {
392  childObject.IsAddedToGame = true;
393  childObjectInt.OnAddedToGame();
394  }
395  else
396  AddedToGame += childObjectInt.OnAddedToGame;
397 
398 
399  // Let's keep it simple and assume that child objects need updating,
400  // even if that is not the case.
401  if ( !IsUpdated )
402  IsUpdated = true;
403  }
404 
405  private void InitializeObjectLists()
406  {
407  if ( childObjects == null )
408  {
409  childObjects = new List<IGameObject>();
410  childObjectsToRemove = new Queue<IGameObject>();
411  }
412  }
413 
422  public void Remove( IGameObject childObject )
423  {
424  childObjectsToRemove.Enqueue( childObject );
425  }
426 
433  [EditorBrowsable( EditorBrowsableState.Never )]
434  public virtual void Update( Time time )
435  {
436  base.Update( time );
437 
438  if (childObjects != null)
439  {
440  foreach (GameObject child in childObjects)
441  {
442  child.Update(time);
443  if (child.IsDestroyed)
444  {
445  childObjectsToRemove.Enqueue(child);
446  }
447  }
448 
449  while (childObjectsToRemove.Count > 0)
450  {
451  IGameObject o = childObjectsToRemove.Dequeue();
452  childObjects.Remove(o);
453  this.AddedToGame -= ( (IGameObjectInternal)o ).OnAddedToGame;
454  o.IsAddedToGame = false;
455  }
456  }
457  }
458 
463  public void SetImage( StorageFile file )
464  {
465  this.Image = Image.FromStream( file.Stream );
466  }
467 
472  public virtual void Move( Vector movement )
473  {
474  Position += movement;
475  }
476 
487  public virtual void MoveTo( Vector location, double speed )
488  {
489  if ( moveTimer == null )
490  {
491  moveTimer = new Timer();
492  moveTimer.Timeout += MoveToTarget;
493  moveTimer.Interval = 0.01;
494  }
495  else if ( moveTimer.Enabled )
496  moveTimer.Stop();
497 
498  moveSpeed = speed;
499  moveTarget = location;
500  moveTimer.Start();
501  }
502 
503  protected virtual void MoveToTarget()
504  {
505  if ( !moveTarget.HasValue )
506  {
507  moveTimer.Stop();
508  return;
509  }
510 
511  Vector d = moveTarget.Value - Position;
512  double vt = moveSpeed * moveTimer.Interval;
513 
514  if ( d.Magnitude < vt )
515  {
516  Vector targetLoc = moveTarget.Value;
517  moveTimer.Stop();
518  Position = moveTarget.Value;
519  moveTarget = null;
520  OnArrived( targetLoc );
521  }
522  else
523  //Position += d.Normalize() * moveSpeed * sender.Interval;
524  Position += Vector.FromLengthAndAngle( vt, d.Angle );
525  }
526  }
527 }
double Interval
Aika sekunneissa, jonka välein TimeOut tapahtuu.
Definition: Timer.cs:99
Jypelin sisäiset metodit ja propertyt joihin käyttäjän ei tarvitse päästä käsiksi kuuluvat tähän luokkaan...
Definition: IGameObject.cs:84
bool IsAddedToGame
Onko olio lisätty peliin.
Kuvio.
Definition: Shapes.cs:48
double Magnitude
Vektorin pituus.
Definition: Vector.cs:281
Angle Angle
Kulma radiaaneina.
Definition: Vector.cs:308
void Stop()
Pysäyttää ajastimen ja nollaa sen tilan.
Definition: Timer.cs:255
Action Timeout
Tapahtuu väliajoin.
Definition: Timer.cs:46
bool IsVisible
Piirretäänkö oliota ruudulle.
Definition: __GameObject.cs:91
virtual void MoveToTarget()
GameObject(double width, double height)
Alustaa uuden peliolion.
object Clone()
Tekee oliosta kopion.
List< Listener > AssociatedListeners
Definition: __GameObject.cs:69
Suuntakulma (rajoitettu -180 ja 180 asteen välille) asteina ja radiaaneina. Tietoja kulmasta: http://...
Definition: Angle.cs:40
TimeSpan MaximumLifetime
Olion suurin mahdollinen elinaika. Kun Lifetime on suurempi kuin tämä, olio kuolee.
Angle AbsoluteAngle
Olion absoluuttinen kulma pelimaailmassa. Jos olio ei ole minkään toisen peliolion lapsiolio...
static Image FromStream(Stream stream)
Lataa kuvan tiedostovirrasta.
Definition: Image.cs:567
Suorakulmio.
Definition: Shapes.cs:315
bool IsInside(Vector point)
Onko piste p tämän olion sisäpuolella.
bool IsDestroyed
Onko olio tuhottu.
GameObject(Image image)
Alustaa uuden peliolion. Kappaleen koko ja ulkonäkö ladataan parametrina annetusta kuvasta...
bool Enabled
Ajastin päällä/pois päältä.
Definition: Timer.cs:78
void Remove(IGameObject childObject)
Poistaa lapsiolion. Jos haluat tuhota olion, kutsu mielummin olion Destroy-metodia.
override Vector Size
Olion koko pelimaailmassa. Kertoo olion äärirajat, ei muotoa.
Definition: __GameObject.cs:98
Peliolio, joka noudattaa fysiikkamoottorin määräämiä fysiikan lakeja. Voidaan kuitenkin myös laittaa ...
Definition: Coefficients.cs:36
IEnumerable< IGameObject > Objects
Olion lapsioliot. Ei voi muokata.
Definition: __GameObject.cs:84
static Game Instance
Definition: Game.cs:149
bool TextureFillsShape
Jos true, kuva piirretään niin, ettei se mene olion muodon ääriviivojen yli. Toisin sanoen kuva piirr...
Sisältää tiedon ajasta, joka on kulunut pelin alusta ja viime päivityksestä.
Definition: Time.cs:13
Kuva.
Definition: Image.cs:24
bool IsUpdated
Tarvitseeko olio päivittämistä. Kun perit oman luokkasi tästä luokasta, aseta tämä arvoon true...
override Animation Animation
Animaatio. Voi olla null, jolloin piirretään vain väri.
virtual void Move(Vector movement)
Siirtää oliota.
double ScalarProjection(Vector unitVector)
Definition: Vector.cs:169
double Y
Definition: Vector.cs:275
Peliluokka reaaliaikaisille peleille.
Definition: DebugScreen.cs:10
Vector LeftNormal
Vasen normaali.
Definition: Vector.cs:82
void Remove(IGameObject childObject)
static readonly Angle Zero
Nollakulma.
Definition: Angle.cs:45
Action< GameObject, Vector > ArrivedAt
Tapahtuu, kun on saavuttu haluttuun paikkaan (MoveTo-metodi)
double X
Definition: Vector.cs:274
IGameObject Parent
Definition: IGameObject.cs:17
Action AddedToGame
Tapahtuu, kun olio lisätään peliin.
void OnArrivedAt(Vector location)
Kutsutaan, kun on saavuttu haluttuun paikkaan (MoveTo-metodi)
Vector TextureWrapSize
Määrittää kuinka moneen kertaan kuva piirretään. Esimerkiksi (3.0, 2.0) piirtää kuvan 3 kertaa vaakas...
Ajastin, joka voidaan asettaa laukaisemaan tapahtumia tietyin väliajoin.
Definition: Timer.cs:39
Väri.
Definition: Color.cs:13
override void Destroy()
Tuhoaa olion. Tuhottu olio poistuu pelistä.
Yhteinen rajapinta kaikille peliolioille.
Definition: IGameObject.cs:14
Sarja kuvia, jotka vaihtuvat halutulla nopeudella. Yksi animaatio koostuu yhdestä tai useammasta kuva...
Definition: Animation.cs:56
GameObject(double width, double height, Shape shape)
Alustaa uuden peliolion.
void Add(IGameObject childObject)
Lisää annetun peliolion tämän olion lapseksi. Lapsiolio liikkuu tämän olion mukana, ja sen paikka ja koko ilmaistaan suhteessa tähän olioon.
void Start()
Käynnistää ajastimen.
Definition: Timer.cs:220
double Width
Olion leveys (X-suunnassa, leveimmässä kohdassa).
virtual void Update(Time time)
Peliolion päivitys. Tätä kutsutaan, kun IsUpdated-ominaisuuden arvoksi on asetettu true ja olio on li...
static Shape FromString(string shapeStr)
Luo muodon merkkijonosta, esim. "Circle"
Definition: Shapes.cs:146
2D-vektori.
Definition: Vector.cs:56
Pelialueella liikkuva olio. Käytä fysiikkapeleissä PhysicsObject-olioita.
Definition: __GameObject.cs:54
Vector AbsolutePosition
Olion absoluuttinen paikka pelimaailmassa. Jos olio ei ole minkään toisen peliolion lapsiolio...
static readonly Color White
Valkoinen.
Definition: Color.cs:894
virtual Vector Position
Olion paikka. Jos olio on jonkun toisen peliolion lapsi, paikka on suhteessa tämän vanhempaan (Parent...
void SetImage(StorageFile file)
Lataa kuvan tiedostosta ja asettaa sen oliolle.
virtual void MoveTo(Vector location, double speed)
Yrittää siirtyä annettuun paikkaan annetulla nopeudella. Laukaisee tapahtuman ArrivedAt, kun paikkaan on päästy.
double Height
Olion korkeus (Y-suunnassa, korkeimmassa kohdassa).