Для имитации неба, дождя, дороги и других различных объектов на заднем фоне, можно использовать со всех сторон зацикленные текстуры(loopable texture).
Ниже приведена реализация использования зацикленных текстур в качестве фона, который непрерывно двигаются снизу вверх. При комбинирование нескольких таких фонов, можно добиться интересных parallax-эффектов.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | //зацикленный фон class LoopableBackground { //зацикленная текстура private readonly Texture2D _texture; //начальные точки всех кусков private readonly List<Vector2> _startPoints; //скорость пикселей в секнду private readonly float _speed; //пределы начальных точек по Y private readonly float _minY; private readonly float _maxY; //накопленное смещение private float _keepOffset; //видимое смещение private const float VisibleOffset = 0.5f; public LoopableBackground(Texture2D texture, int screenWidth, int screenHeight, float speed) { _texture = texture; _speed = speed; _keepOffset = 0; _startPoints = new List<Vector2>(); //нижний предел _minY = -texture.Height; //создаем фрагменты по все высоте экрана var y = _minY; while (y <= screenHeight) { //создаем фрагменты по все ширине экрана var x = 0; while (x <= screenWidth) { _startPoints.Add(new Vector2(x, y)); x += texture.Width; } y += texture.Height; } //верхний предел _maxY = y; } public void Update(GameTime gameTime) { var elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds; _keepOffset += _speed * elapsed; //ждем пока смещение не будет видимым if (_keepOffset < VisibleOffset) return; //смещаем все начальные точки на константу for (var i = 0; i < _startPoints.Count; i++) { _startPoints[i] = new Vector2(_startPoints[i].X, _startPoints[i].Y + VisibleOffset); //если оказались за передлом, то делаем перенос if (_startPoints[i].Y >= _maxY) { _startPoints[i] = new Vector2(_startPoints[i].X, _startPoints[i].Y - (_maxY - _minY)); } } _keepOffset = 0; } public void Draw(SpriteBatch spriteBatch) { //отрисовка фрагментов foreach (var startPoint in _startPoints) { spriteBatch.Draw(_texture, startPoint, Color.White); } } } |
//зацикленный фон class LoopableBackground { //зацикленная текстура private readonly Texture2D _texture; //начальные точки всех кусков private readonly List<Vector2> _startPoints; //скорость пикселей в секнду private readonly float _speed; //пределы начальных точек по Y private readonly float _minY; private readonly float _maxY; //накопленное смещение private float _keepOffset; //видимое смещение private const float VisibleOffset = 0.5f; public LoopableBackground(Texture2D texture, int screenWidth, int screenHeight, float speed) { _texture = texture; _speed = speed; _keepOffset = 0; _startPoints = new List<Vector2>(); //нижний предел _minY = -texture.Height; //создаем фрагменты по все высоте экрана var y = _minY; while (y <= screenHeight) { //создаем фрагменты по все ширине экрана var x = 0; while (x <= screenWidth) { _startPoints.Add(new Vector2(x, y)); x += texture.Width; } y += texture.Height; } //верхний предел _maxY = y; } public void Update(GameTime gameTime) { var elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds; _keepOffset += _speed * elapsed; //ждем пока смещение не будет видимым if (_keepOffset < VisibleOffset) return; //смещаем все начальные точки на константу for (var i = 0; i < _startPoints.Count; i++) { _startPoints[i] = new Vector2(_startPoints[i].X, _startPoints[i].Y + VisibleOffset); //если оказались за передлом, то делаем перенос if (_startPoints[i].Y >= _maxY) { _startPoints[i] = new Vector2(_startPoints[i].X, _startPoints[i].Y - (_maxY - _minY)); } } _keepOffset = 0; } public void Draw(SpriteBatch spriteBatch) { //отрисовка фрагментов foreach (var startPoint in _startPoints) { spriteBatch.Draw(_texture, startPoint, Color.White); } } }
Пример (необходим MonoGame 3.0)