Игра танки тормозит при появлении 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));
}