Игра танки тормозит при появлении 6 и более врагов - C#
Формулировка задачи:
как то писал курсач -"танки". c# знал плохо, ооп вообще не понимал. сейчас стал кое что понимать решил повторить попытку. столкнулся с тем, что при появлении >= 6 врагов игра начинает тормозить. делаю все на WinForm. контролы танков - PictureBox'ы.
как избавиться от торможения? может что то сделать по другому?
class _Bullet { public PictureBox Box { get; set; } public _Orientation Or; public int Velocity { get; set; } public bool IsRunning { get; set; } int maxWidth, maxHeight; public _Bullet(int maxWidth, int maxHeight) { Box = new PictureBox() { Location = new Point(-10, -10), Size = new Size(6, 6), Image = x3004.Properties.Resources.bulletImage }; Velocity = 2; this.maxWidth = maxWidth; this.maxHeight = maxHeight; } /// <summary> /// подготовка пули к выстрелу(вычисляем начальное положение и направление) /// </summary> /// <param name="pictureBox"> picBox героя, который производит выстрел</param> /// <param name="orientation"> направление движения героя </param> public void Shoot(PictureBox pictureBox, _Orientation orientation) { switch (orientation) { case _Orientation.Up: { Box.Location = new Point(pictureBox.Left + pictureBox.Width / 2 - Box.Width / 2, pictureBox.Top - Box.Height / 2); break; } case _Orientation.Down: { Box.Location = new Point(pictureBox.Left + pictureBox.Width / 2 - Box.Width / 2, pictureBox.Bottom - Box.Height / 2); break; } case _Orientation.Left: { Box.Location = new Point(pictureBox.Left - Box.Width / 2, pictureBox.Top + pictureBox.Height / 2 - Box.Height / 2); break; } case _Orientation.Right: { Box.Location = new Point(pictureBox.Right - Box.Width / 2, pictureBox.Top + pictureBox.Height / 2 - Box.Height / 2); break; } } Or = orientation; IsRunning = true; } /// <summary> /// сброс параметров пули(остановка пули) /// </summary> public void Reset() { IsRunning = false; Box.Location = new Point(-10, -10); } /// <summary> /// обновляем параметры /// </summary> /// <param name="timeInterval"> интервал обновлений </param> /// <param name="blocks"> список препятствий </param> /// <param name="panel"> панель </param> public void Update(int timeInterval, ref List<_Block> blocks, ref Panel panel) { int dx = 0, dy = 0; if (IsRunning) { if (Or == _Orientation.Up) dy = -Velocity * timeInterval; else if (Or == _Orientation.Down) dy = Velocity * timeInterval; else if (Or == _Orientation.Left) dx = -Velocity * timeInterval; else if (Or == _Orientation.Right) dx = Velocity * timeInterval; } Rectangle boxRect = new Rectangle(Box.Location, Box.Size); boxRect.Offset(dx, dy); if (boxRect.Left > 0 && boxRect.Right < maxWidth && boxRect.Top > 0 && boxRect.Bottom < maxHeight) { Box.Location = boxRect.Location; } else Reset(); for (int i = 0; i < blocks.Count; i++) { if (RectIntersect(new Rectangle(blocks[i].Box.Location, blocks[i].Box.Size), boxRect)) { panel.Controls.Remove(blocks[i].Box); blocks.RemoveAt(i); Reset(); } } } /// <summary> /// проверка на пересечение 2х прямоугольников /// </summary> /// <param name="rect1"> прямоугольник 1 </param> /// <param name="rect2"> прямоугольник 2 </param> /// <returns></returns> bool RectIntersect(Rectangle rect1, Rectangle rect2) { bool intersect = false; if (rect1.Left >= rect2.Left && rect1.Left <= rect2.Right && rect1.Top >= rect2.Top && rect1.Top <= rect2.Bottom || rect1.Left >= rect2.Left && rect1.Left <= rect2.Right && rect1.Bottom >= rect2.Top && rect1.Bottom <= rect2.Bottom || rect1.Right >= rect2.Left && rect1.Right <= rect2.Right && rect1.Top >= rect2.Top && rect1.Top <= rect2.Bottom || rect1.Right >= rect2.Left && rect1.Right <= rect2.Right && rect1.Bottom >= rect2.Top && rect1.Bottom <= rect2.Bottom) intersect = true; return intersect; } }
class _Hero { public PictureBox Box { get; set; } public _Orientation Or; public int Velocity { get; set; } public bool IsRunning { get; set; } public _Bullet Bullet { get; set; } int maxWidth, maxHeight; /// <summary> /// конструктор /// </summary> /// <param name="startPosition"> стартовая позиция танка </param> /// <param name="maxWidth"> ширина поля, по которому танк может перемещаться </param> /// <param name="maxHeight"> высота поля, по которому танк может перемещаться </param> public _Hero(Point startPosition, int maxWidth, int maxHeight) { Box = new PictureBox() { Location = startPosition, Size = new Size(32, 32) }; Velocity = 1; Or = _Orientation.Up; Bullet = new _Bullet(maxWidth, maxHeight); this.maxWidth = maxWidth; this.maxHeight = maxHeight; } /// <summary> /// обновляем параметры /// </summary> /// <param name="timeInterval"> интервал обновлений(интервал таймера) </param> /// <param name="blocks"> список препятствий </param> /// <param name="panel"> панель(игровое поле) </param> public void Update(int timeInterval,ref List<_Block> blocks, ref Panel panel) { int dx = 0, dy = 0; if (IsRunning) { if (Or == _Orientation.Up) dy = -Velocity * timeInterval; else if (Or == _Orientation.Down) dy = Velocity * timeInterval; else if (Or == _Orientation.Left) dx = -Velocity * timeInterval; else if (Or == _Orientation.Right) dx = Velocity * timeInterval; } bool intersect=false; Rectangle boxRect = new Rectangle(Box.Location, Box.Size); boxRect.Offset(dx, dy); Box.Image = Rotation(); foreach (_Block block in blocks) { Rectangle rect = new Rectangle(block.Box.Location, block.Box.Size); if (RectIntersect(rect, boxRect)) intersect = true; } if (boxRect.Left > 0 && boxRect.Right < maxWidth && boxRect.Top > 0 && boxRect.Bottom < maxHeight && !intersect) { Box.Location = boxRect.Location; } Bullet.Update(timeInterval,ref blocks, ref panel); } /// <summary> /// старт выстрела /// </summary> public void StartShoot() { Bullet.Shoot(Box, Or); } /// <summary> /// поворот изображения танка /// </summary> /// <returns> возвращает текущее изображение танка </returns> Image Rotation() { Image temp = x3004.Properties.Resources.heroImage; switch (Or) { case _Orientation.Up: break; case _Orientation.Down: temp.RotateFlip(RotateFlipType.Rotate180FlipNone); break; case _Orientation.Left: temp.RotateFlip(RotateFlipType.Rotate270FlipNone); break; case _Orientation.Right: temp.RotateFlip(RotateFlipType.Rotate90FlipNone); break; } return temp; } /// <summary> /// проверяет, пересекаются ли 2 прямоугольника /// </summary> /// <param name="rect1"> 1 прямоугольник </param> /// <param name="rect2"> 2 прямоугольник </param> /// <returns> true - пересекаются, false - не пересекаются </returns> bool RectIntersect(Rectangle rect1, Rectangle rect2) { bool intersect = false; if (rect1.Left >= rect2.Left && rect1.Left <= rect2.Right && rect1.Top >= rect2.Top && rect1.Top <= rect2.Bottom || rect1.Left >= rect2.Left && rect1.Left <= rect2.Right && rect1.Bottom >= rect2.Top && rect1.Bottom <= rect2.Bottom || rect1.Right >= rect2.Left && rect1.Right <= rect2.Right && rect1.Top >= rect2.Top && rect1.Top <= rect2.Bottom || rect1.Right >= rect2.Left && rect1.Right <= rect2.Right && rect1.Bottom >= rect2.Top && rect1.Bottom <= rect2.Bottom) intersect = true; return intersect; } }
class _Enemy { public PictureBox Box { get; set; } public _Orientation Or; public int Velocity { get; set; } int maxWidth, maxHeight; public _Bullet Bullet { get; set; } /// <summary> /// конструктор /// </summary> /// <param name="startPosition"> стартовая позиция врага </param> /// <param name="maxWidth"> на поля, по которому танк может перемещаться </param> /// <param name="maxHeight"> высота поля, по которому танк может перемещаться </param> public _Enemy(Point startPosition, int maxWidth, int maxHeight) { Box = new PictureBox() { Location = startPosition, Size = new Size(32, 32) }; Velocity = 1; NewOrientation(); Bullet = new _Bullet(maxWidth, maxHeight); this.maxWidth = maxWidth; this.maxHeight = maxHeight; } /// <summary> /// изменение направлерия движения врага /// </summary> void NewOrientation() { Random rnd = new Random(); switch (rnd.Next(7)) { case 0: Or = _Orientation.Down; break; case 1: Or = _Orientation.Up; break; case 2: Or = _Orientation.Down; break; case 3: Or = _Orientation.Left; break; case 4: Or = _Orientation.Down; break; case 5: Or = _Orientation.Right; break; case 6: Or = _Orientation.Down; break; } } int timeForNewOr; int timeForShoot; /// <summary> /// обновляем параметры /// </summary> /// <param name="timeInterval"> интервал обновления </param> /// <param name="blocks"> список препятствий </param> /// <param name="panel"> панель </param> public void Update(int timeInterval, ref List<_Block> blocks, ref Panel panel) { int dx = 0, dy = 0; if (Or == _Orientation.Up) dy = -Velocity * timeInterval; else if (Or == _Orientation.Down) dy = Velocity * timeInterval; else if (Or == _Orientation.Left) dx = -Velocity * timeInterval; else if (Or == _Orientation.Right) dx = Velocity * timeInterval; bool intersect = false; Rectangle boxRect = new Rectangle(Box.Location, Box.Size); boxRect.Offset(dx, dy); Box.Image = Rotation(); foreach (_Block block in blocks) { Rectangle rect = new Rectangle(block.Box.Location, block.Box.Size); if (RectIntersect(rect, boxRect)) intersect = true; } if (boxRect.Left > 0 && boxRect.Right < maxWidth && boxRect.Top > 0 && boxRect.Bottom < maxHeight && !intersect) { Box.Location = boxRect.Location; } timeForShoot++; if (timeForShoot > maxWidth / Bullet.Velocity) { timeForShoot = 0; Bullet.Reset(); StartShoot(); } Bullet.Update(timeInterval, ref blocks, ref panel); timeForNewOr++; if (timeForNewOr == 100) { timeForNewOr = 0; NewOrientation(); } } /// <summary> /// старт выстрела /// </summary> public void StartShoot() { Bullet.Shoot(Box, Or); } /// <summary> /// поворот изображения героя /// </summary> /// <returns> возвращает текущее изображение героя </returns> Image Rotation() { Image temp = x3004.Properties.Resources.heroImage; switch (Or) { case _Orientation.Up: break; case _Orientation.Down: temp.RotateFlip(RotateFlipType.Rotate180FlipNone); break; case _Orientation.Left: temp.RotateFlip(RotateFlipType.Rotate270FlipNone); break; case _Orientation.Right: temp.RotateFlip(RotateFlipType.Rotate90FlipNone); break; } return temp; } /// <summary> /// проверка прямоугольников на пересечение /// </summary> /// <param name="rect1"> 1 прямоугольник </param> /// <param name="rect2"> 2 прямоугольник </param> /// <returns> true - пересекаются, false - не пересекаются </returns> bool RectIntersect(Rectangle rect1, Rectangle rect2) { bool intersect = false; if (rect1.Left >= rect2.Left && rect1.Left <= rect2.Right && rect1.Top >= rect2.Top && rect1.Top <= rect2.Bottom || rect1.Left >= rect2.Left && rect1.Left <= rect2.Right && rect1.Bottom >= rect2.Top && rect1.Bottom <= rect2.Bottom || rect1.Right >= rect2.Left && rect1.Right <= rect2.Right && rect1.Top >= rect2.Top && rect1.Top <= rect2.Bottom || rect1.Right >= rect2.Left && rect1.Right <= rect2.Right && rect1.Bottom >= rect2.Top && rect1.Bottom <= rect2.Bottom) intersect = true; return intersect; } }
/// <summary> /// тип препятствия /// </summary> enum _BlockType { Brick, Concrete } class _Block { public PictureBox Box { get; set; } //препятствие public _BlockType BlockType { get; set; } //тип препятствия /// <summary> /// конструктор /// </summary> /// <param name="location"> положение препятствия </param> /// <param name="blockType"> тип препятствия </param> public _Block(Point location, _BlockType blockType) { Box = new PictureBox() { Location = location, Size = new Size(16, 16) }; switch (blockType) { case _BlockType.Brick: Box.Image = x3004.Properties.Resources.brickImage; break; } } }
enum _Orientation { Up, Down, Left, Right } public partial class Form1 : Form { Button startButton, exitButton; static Panel panel; Timer timer; _Hero player1; List<_Enemy> enemys; List<_Block> blocks; int currentLevel; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { ClientSize = new System.Drawing.Size(650,490); panel = new Panel() { Location = new Point(5, 5), Size = new Size(ClientSize.Width - 10, ClientSize.Height - 10) }; Controls.Add(panel); int x = panel.Width / 2 - 50, y = panel.Height / 2 - 30; startButton = new Button() { Location = new Point(x, y), Size = new Size(100, 25), Text = "start" }; startButton.Click += new EventHandler(startButton_Click); y += 40; exitButton = new Button() { Location = new Point(x, y), Size = startButton.Size, Text = "exit" }; exitButton.Click += new EventHandler(exitButton_Click); panel.Controls.AddRange(new Control[] { startButton, exitButton }); startRects = new Rectangle[3] { new Rectangle(5, 5, 32, 32), new Rectangle(panel.Width / 2 - 16, 5, 32, 32), new Rectangle(panel.Width - 37, 5, 32, 32) }; timer = new Timer(); timer.Interval = 1; timer.Tick += new EventHandler(Update); } void exitButton_Click(object sender, EventArgs e) { Application.Exit(); } void startButton_Click(object sender, EventArgs e) { startButton.Enabled= startButton.Visible= exitButton.Enabled=exitButton.Visible=false; player1 = new _Hero(new Point(panel.Width / 2 - 16, panel.Height - 40), panel.Width, panel.Height); panel.Controls.AddRange(new Control[] { player1.Box, player1.Bullet.Box }); enemys = new List<_Enemy>(); _Enemy enemy = new _Enemy(new Point(5, 5), panel.Width, panel.Height); enemys.Add(enemy); panel.Controls.AddRange(new Control[] { enemy.Box, enemy.Bullet.Box }); currentLevel = 1; CreateLevel(currentLevel); timer.Start(); } /// <summary> /// загрузка уровня /// </summary> /// <param name="currentLevel"> загружаемый уровень </param> private void CreateLevel(int currentLevel) { int x = 0, y = 0; blocks = new List<_Block>(); string filePath = @"levels/level" + currentLevel.ToString() + ".txt"; string[] text = File.ReadAllLines(filePath); foreach (string s in text) { foreach (char c in s) { if (c == 'X') blocks.Add(new _Block(new Point(x, y), _BlockType.Brick)); x += 16; } x = 0; y += 16; } foreach (_Block block in blocks) { panel.Controls.Add(block.Box); } } int timeForNewEnemy; public void Update(object sender, EventArgs e) { player1.Update(timer.Interval, ref blocks, ref panel); foreach (_Enemy enemy in enemys) { enemy.Update(timer.Interval, ref blocks, ref panel); } timeForNewEnemy++; if (timeForNewEnemy == 100) { timeForNewEnemy = 0; _Enemy enemy = new _Enemy(EnemyStartPoint(), panel.Width, panel.Height); enemys.Add(enemy); panel.Controls.AddRange(new Control[] { enemy.Box, enemy.Bullet.Box }); currentStartPoint++; if (currentStartPoint == 3) currentStartPoint = 0; } } protected override void OnKeyDown(KeyEventArgs e) { switch (e.KeyCode) { case Keys.Up: { StartRun(player1, _Orientation.Up); break; } case Keys.Down: { StartRun(player1, _Orientation.Down); break; } case Keys.Left: { StartRun(player1, _Orientation.Left); break; } case Keys.Right: { StartRun(player1, _Orientation.Right); break; } case Keys.M: { if (!player1.Bullet.IsRunning) player1.StartShoot(); break; } } base.OnKeyDown(e); } protected override void OnKeyUp(KeyEventArgs e) { switch (e.KeyCode) { case Keys.Up: case Keys.Down: case Keys.Left: case Keys.Right: { player1.IsRunning = false; break; } } base.OnKeyUp(e); } /// <summary> /// старт движения игрока /// </summary> /// <param name="player"> игрок </param> /// <param name="orientation"> направление </param> void StartRun(_Hero player, _Orientation orientation) { player.IsRunning = true; player.Or = orientation; } int currentStartPoint; Rectangle[] startRects; /// <summary> /// выбор стартовой позиции врага /// </summary> /// <returns> возвращает стартовую позицию врага </returns> Point EnemyStartPoint() { bool intersect = false; do { intersect = false; foreach (_Enemy enemy in enemys) { if (RectIntersect(new Rectangle(enemy.Box.Location, enemy.Box.Size), startRects[currentStartPoint])) intersect = true; } if (intersect) currentStartPoint++; if (currentStartPoint == 3) currentStartPoint = 0; } while (intersect != false); return startRects[currentStartPoint].Location; } /// <summary> /// проверка прямоугольников на пересечение /// </summary> /// <param name="rect1"></param> /// <param name="rect2"></param> /// <returns></returns> bool RectIntersect(Rectangle rect1, Rectangle rect2) { bool intersect = false; if (rect1.Left >= rect2.Left && rect1.Left <= rect2.Right && rect1.Top >= rect2.Top && rect1.Top <= rect2.Bottom || rect1.Left >= rect2.Left && rect1.Left <= rect2.Right && rect1.Bottom >= rect2.Top && rect1.Bottom <= rect2.Bottom || rect1.Right >= rect2.Left && rect1.Right <= rect2.Right && rect1.Top >= rect2.Top && rect1.Top <= rect2.Bottom || rect1.Right >= rect2.Left && rect1.Right <= rect2.Right && rect1.Bottom >= rect2.Top && rect1.Bottom <= rect2.Bottom) intersect = true; return intersect; } }
Решение задачи: «Игра танки тормозит при появлении 6 и более врагов»
textual
Листинг программы
public void CreateLevel(int level) { blocks = new List<_Block>(); string levelFilePath = @"levels/level" + level + ".txt"; string[] fileStr = File.ReadAllLines(levelFilePath); int x=0,y=0; foreach (string s in fileStr) { foreach (char c in s) { if (c=='X') { _Block block = new _Block(new Point(x, y), _BlockType.Brick); blocks.Add(block); } x += 16; } x = 0; y += 16; } blocks.Add(new _Block(panel.Width, panel.Height)); }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д