Laden...

Starfield-Flyby-Animation

Erstellt von KainPlan vor 14 Jahren Letzter Beitrag vor 14 Jahren 6.003 Views
K
KainPlan Themenstarter:in
133 Beiträge seit 2009
vor 14 Jahren
Starfield-Flyby-Animation

Beschreibung:

Bestimmt nicht das erste und erstrecht nicht das letzte ^^.
Ist eigentlich alles recht selbsterklärend. Wenn fragen auftreten immer her damit. Have Phun.


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Windows.Forms;

namespace DrawingExt
{
    /// <summary>
    /// The starfield class generates dots that emulates a starfield on flyby.
    /// </summary>
    public class Starfield
    {
        #region Publix
        public float AdditionalAngle { get; set; }
        /// <summary>
        /// The direction in which you want the stars to flyby.
        /// </summary>
        public float ScrollDirection
        {
            get { return _scrollDirection; }
            set { setScrollDir(value); }
        }
        /// <summary>
        /// The starfield class generates dots that emulates a starfield on flyby.
        /// </summary>
        /// <param name="ColorPalette"> Array of colors that are given to the stars.</param>
        /// <param name="Bounds">Bounds of the starfield. Stars only drawn inside this rectangle.</param>
        /// <param name="UpdateInterval">Interval in milliseconds to update the entire starlayer.</param>
        /// <param name="ScrollDirection">The direction in which you want the stars to flyby.</param>
        public Starfield(Color[] ColorPalette, Rectangle Bounds, int UpdateInterval, float ScrollDirection)
        {
            _objects = new List<StarfieldObject>();

            _outputBounds = Bounds;

            _colorPalette = ColorPalette;

            _scrollDirection = ScrollDirection;

            _updateInvoker = new Timer();
            _updateInvoker.Interval = UpdateInterval;
            _updateInvoker.Tick += new EventHandler(updateInvoker);

            _initStarfield();
        }
        /// <summary>
        /// Brings updating to a complete halt.
        /// </summary>
        public void Pause()
        {
            _updateInvoker.Enabled = false;
        }
        /// <summary>
        /// Begins updating.
        /// </summary>
        public void Start()
        {
            _updateInvoker.Enabled = true;
        }
        /// <summary>
        /// Draw all the stars to the desired devicecontext.
        /// </summary>
        /// <param name="dc"> Devicecontext where the stars are to be drawn at. </param>
        public void Draw(Graphics dc)
        {
            _scrollDirection += AdditionalAngle;
            dc.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            dc.TranslateTransform(-(_outputBounds.Width / 2), -(_outputBounds.Height / 2));
            dc.RotateTransform(_scrollDirection, System.Drawing.Drawing2D.MatrixOrder.Append);
            dc.TranslateTransform(_outputBounds.Width / 2, _outputBounds.Height / 2,
                System.Drawing.Drawing2D.MatrixOrder.Append);
            foreach (StarfieldObject obj in _objects) obj.Draw(dc);
            dc.ResetTransform();
        }
        /// <summary>
        /// Add a new StarfieldObject to the handling query.
        /// </summary>
        /// <param name="obj">StarfieldObject to add.</param>
        public void AddObject(StarfieldObject obj)
        {
            _objects.Add(obj);
        }
        #endregion

        #region Privates
        private Timer _updateInvoker;
        private Color[] _colorPalette;
        // = new Color[] { Color.White, Color.WhiteSmoke, 
        // Color.Snow, Color.Silver, Color.Gray, Color.LightGray, Color.DarkGray, };
        private List<StarfieldObject> _objects;
        private Rectangle _bounds;
        private Rectangle _outputBounds;
        private float _scrollDirection;
        private PointF _poc;
        private Point _poMoveDir;
        private int _pocLenght;
        private int _lenOfLife;
        private void setScrollDir(float scrollDirection)
        {
            _scrollDirection = scrollDirection;
        }
        private void _initStarfield()
        {
            // Satz des Pythagoras um ein Quadrat zu erschaffen in das _outputBounds egal in welchem drehungswinkel
            // 100% hinein passt.
            int bSide = (int)Math.Sqrt(Math.Pow(_outputBounds.Width, 2) + Math.Pow(_outputBounds.Height, 2));

            _bounds = new Rectangle(-((bSide - _outputBounds.Width) / 2), -((bSide - _outputBounds.Height) / 2),
                bSide, bSide);

            _pocLenght = _bounds.Height;
            _poc = new Point(_bounds.Left, -1);
            _lenOfLife = _bounds.Width;
            _poMoveDir = new Point(1, 0);

            // Scrollt Sterne ein...
            for (int i = 0; i < _lenOfLife; i++)
            {
                updateInvoker(null, null);
            }
        }
        private PointF getRndPoc()
        {
            PointF p = _poc;
            float rndpoc = ((float)Star.Random.Next(_bounds.Top, _bounds.Bottom));

            if (p.X == -1)
                p.X = rndpoc;
            else if (p.Y == -1)
                p.Y = rndpoc;

            return p;
        }
        private Star[] generateStars()
        {
            Star[] stars = new Star[Star.Random.Next(1, 4)];

            for (int i = 0; i < stars.Length; i++)
            {
                float speed = ((float)Star.Random.Next(50, 350) / 100);
                stars[i] = new Star(_colorPalette, new PointF(speed, speed),
                    getRndPoc());
            }

            return stars;
        }
        private void updateInvoker(object sender, EventArgs e)
        {
            lock (_objects)
            {
                _objects.AddRange(generateStars());

                List<StarfieldObject> remIxs = new List<StarfieldObject>();
                for (int i = 0; i < _objects.Count; i++)
                {
                    StarfieldObject obj = _objects[i];
                    obj.Update(_poMoveDir);
                    if (obj.OutOf(_bounds))
                        remIxs.Add(obj);
                }

                foreach (StarfieldObject obj in remIxs) _objects.Remove(obj);
                GC.Collect();
            }

            if (e != null) OnUpdated();
        }
        #endregion

        #region Events
        /// <summary>
        /// Occurs whenever the starfield is updated.
        /// </summary>
        public event StarfieldUpdated Updated;
        /// <summary>
        /// Occurs whenever the starfield is updated.
        /// </summary>
        protected virtual void OnUpdated()
        {
            if (Updated != null)
            {
                Control target = Updated.Target as Control;
                if (target != null && target.InvokeRequired)
                    target.Invoke(Updated, new object[] { this });
                else
                    Updated(this);
            }
        }
        #endregion
    }
    /// <summary>
    /// Occurs whenever the starfield is updated.
    /// </summary>
    public delegate void StarfieldUpdated(Starfield sf);

    /// <summary>
    /// A generic point object in space.
    /// </summary>
    public class StarfieldObject
    {
        /// <summary>
        /// Generate random numbers.
        /// </summary>
        public static Random Random = new Random();
        /// <summary>
        /// The actual position of this object.
        /// </summary>
        public PointF Position { get; set; }
        /// <summary>
        /// The PoC point of creation is the point where this object has been created.
        /// </summary>
        public PointF PointOfCreation { get; private set; }
        /// <summary>
        /// The speed of this object.
        /// </summary>
        public PointF Speed { get; set; }
        /// <summary>
        /// Create a new object instance.
        /// </summary>
        /// <param name="speed">Speed of the object.</param>
        /// <param name="poc">PoC - Point of Creation. </param>
        public StarfieldObject(PointF speed, PointF poc)
        {
            Speed = speed;
            PointOfCreation = poc;
            Position = poc;
        }
        /// <summary>
        /// Override this method to draw the starfield object.
        /// </summary>
        /// <param name="dc"></param>
        public virtual void Draw(Graphics dc)
        {
            string ex = string.Format("Drawing for {0} is not handled.", 
                this.GetType().FullName);
            throw new Exception(ex);
        }
        /// <summary>
        /// Updates this object in the given direction.
        /// </summary>
        /// <param name="dir">The direction in witch the object should be fly.</param>
        public virtual void Update(PointF dir)
        {
            PointF pos = Position;

            dir.X = dir.X > 1 ? 1 : dir.X < -1 ? -1 : dir.X;
            dir.Y = dir.Y > 1 ? 1 : dir.Y < -1 ? -1 : dir.Y;

            pos.X += Speed.X * dir.X;
            pos.Y += Speed.Y * dir.Y;

            Position = pos;
        }
        /// <summary>
        /// Checks if the object is outside of the given bounds.
        /// </summary>
        /// <param name="bounds">The bounds to check.</param>
        /// <returns>True if the object is outside.</returns>
        public virtual bool OutOf(RectangleF bounds)
        {
            return !bounds.Contains(Position);
            /*
            if (bounds.Left > Position.X) return true;
            else if (bounds.Top > Position.Y) return true;
            else if (bounds.Right < Position.X) return true;
            else if (bounds.Bottom < Position.Y) return true;

            return false;
            */
        }
        /// <summary>
        /// Same as Update() but you probably want to assing a new speed also.
        /// </summary>
        /// <param name="dir">The direction in witch the object should be fly.</param>
        /// <param name="newSpeed">The new speed.</param>
        public virtual void Update(Point dir, PointF newSpeed)
        {
            Speed = newSpeed;
            Update(dir);
        }
 
    }
    /// <summary>
    /// Supplies information about speed, position and color for each star.
    /// </summary>
    class Star : StarfieldObject
    {
        /// <summary>
        /// The color of this star.
        /// </summary>
        public Color Color { get; set; }
        /// <summary>
        /// Create a new star instance.
        /// </summary>
        /// <param name="clPalette">The palette where the star picks a random color.</param>
        /// <param name="speed">Speed of the star.</param>
        /// <param name="poc">PoC - Point of Creation. </param>
        public Star(Color[] clPalette, PointF speed, PointF poc)
            : base(speed, poc)
        {
            int clIdx = Star.Random.Next(0, clPalette.Length - 1);
            Color = clPalette[clIdx];
        }
        /// <summary>
        /// Draws this star on the given devicecontext.
        /// </summary>
        /// <param name="dc">Devicecontext to draw on.</param>
        public override void Draw(Graphics dc)
        {
            dc.FillRectangle(new SolidBrush(Color), Position.X, Position.Y, 1, 1);
        }
    }
}


Schlagwörter: Sternenfeld, Starfield, Generator, Pixel, Drawing

5.299 Beiträge seit 2008
vor 14 Jahren

hmm. hab kein Plan 😉, wie man damit was zu sehen bekommt - machste'n Sample-Upload?

Der frühe Apfel fängt den Wurm.

K
KainPlan Themenstarter:in
133 Beiträge seit 2009
vor 14 Jahren

Klar mach ich hatte in letzter Zeit etwas weniger von dieser.

830 Beiträge seit 2005
vor 14 Jahren

Hallo KainPlan,

finde die Animation ziemlich gelungen, wenn ich auch nicht weiß für was ich das brauchen könnte.

Gruss
Friedel

Ohne Ziel ist auch der Weg egal.

2.921 Beiträge seit 2005
vor 14 Jahren

@KainPlan

ein ähnliches Thema gibt's auch hier:

Schnelle GDI(+) Grafik - wie? [Parallax Scrolling]

vll. findest Du da noch Anregungen

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.