ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 30.11.2023
Просмотров: 72
Скачиваний: 2
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
| ДЕПАРТАМЕНТ ОБРАЗОВАНИЯ ИВАНОВСКОЙ ОБЛАСТИ Областное государственное бюджетное профессиональное образовательное учреждение «Ивановский промышленно-экономический колледж» | |||||||
| | |||||||
| | |||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | | ||||||
| | |||||||
| | |||||||
| | |||||||
| | |||||||
| | |||||||
| КУРСОВОЙ ПРОЕКТ | |||||||
| | |||||||
| Разработка игрового приложения «Контра» | |||||||
| | |||||||
| ИвПЭК. 09.02.03. | |||||||
| | |||||||
| | |||||||
| | |||||||
| | |||||||
| | |||||||
| | Специальность: | 09.02.03 Программирование в компьютерных системах, базовая подготовка | |||||
| | |||||||
| | |||||||
| | |||||||
| | |||||||
| | |||||||
| Руководитель курсового проекта | | А.С. Иродов | |||||
| Выполнил обучающийся группы 402 | | В.К. Сухарев | |||||
| | | | |||||
| | |||||||
| | |||||||
| Курсовой проект выполнен и защищен с оценкой__________________________________ | |||||||
| | |||||||
| «___» ________________ 2020 г. | |||||||
| | | ||||||
| | | | |||||
| | | | |||||
| | Иваново 2020 | | |||||
Содержание
Введение 3
1.Пояснительная записка 4
2.Технико-рабочий проект 6
3. Рабочая документация 8
Заключение 17
Список используемой литературы 18
Приложение А. Фрагмент кода 19
Введение
Использование ООП позволяет обойти ряд сложных проблем в программировании с минимальными потерями, сводя необходимую модификацию программы к её расширению и дополнению. Систематическое применение объектно-ориентированного подхода позволяет разрабатывать достаточно хорошо структурированные, надежные в эксплуатации, просто модифицируемые программные системы. Элементы объектно-ориентированного программирования получили своё развитие, и в настоящее время ООП принадлежит к числу ведущих технологий программирования.Целью выполнения курсового проекта является детальное проектирование и программная реализация противоборства, в котором в соответствии с вариантом задания реализуются процессы создания и взаимодействия объектов.Программа написана на языке программирования C# и дополнительном ПО «Monogame»-
Пояснительная записка
-
Цель работы
-
Техническое задание
-
Введение
-
Основания для разработки
-
Назначение разработки
-
Ограничения, условия функционирования и выполнения
-
Требования к программной документации
-
Стадии и этапы разработки.
-
Составление классов, объектов, задач; -
Проектирование связей между объектами; -
Разработка готового решения; -
Оптимизация продукта; -
Разработка документации.
-
Порядок приема и контроля
-
Технико-рабочий проект
-
Построение иерархии классов
-
Обоснование выбора средств разработки
Поскольку язык принадлежит компании майкрософт, то применяется практически во всех продуктах, которые были разработаны или куплены.
Плюсы C#:
-
поддержка майкрософтом. В отличии от Java, которой не пошел на пользу переход в собственность Oracle, C# хорошо развивается благодаря усилиям Microsoft; -
в последнее время много совершенствуется. Так как C# был создан позже, чем Java и другие языки, то требовалось очень много доработать. Также это касается популяризации и бесплатности - было обещано открыть исходный код, а инструменты (Visual Studio, Xamarin) стали бесплатными для частных лиц и небольших компаний; -
много синтаксического сахара. Синтаксический сахар - это такие конструкции, которые созданы для облегчения написания и понимания кода (особенно если это код другого программиста) и не играют роли при компиляции; -
средний порог вхождения. Синтаксис похожий на C, С++ или Java облегчает переход для других программистов. Для новичков это также один из самых перспективных языков для изучения; -
Xamarin. Благодаря покупке Xamarin на C# теперь можно писать под Android и iOS. Это, несомненно, большой плюс, так как их собственная мобильная ОС (Windows Phone) не завоевала большой популярности; -
добавлено функциональное программирование (F#); -
большое сообщество программистов; -
много вакансий на должность C# программиста в любом регионе.
-
Моделирование с использованием UML-диаграмм
-
Рабочая документация
using System.Threading.Tasks;using Contra.Models;using Contra.Managers;using Contra.Sprites;namespace Contra.Sprites{public enum CollisionTypes{None,Full,Top,}public class Sprite : Component, ICloneable{protected Dictionary
protected AnimationManager _animationManager;
protected float _layer { get; set; }
protected Vector2 _origin { get; set; }
protected Vector2 _position { get; set; }
protected float _rotation { get; set; }
protected float _scale { get; set; }
public Vector2 Direction;
protected Texture2D _texture;
public Vector2 _velocity;
public List
public CollisionTypes CollisionType { get; set; }
public Color Colour { get; set; }
public bool IsRemoved { get; set; }
public float Layer
{
get { return _layer; }
set
{
_layer = value;
if (_animationManager != null)
_animationManager.Layer = _layer;
}
}
public Vector2 Origin
{
get { return _origin; }
set
{
_origin = value;
if (_animationManager != null)
_animationManager.Origin = _origin;
}
}
public Vector2 Position
{
get
{
return _position;
}
set
{
_position = value;
if (_animationManager != null)
_animationManager.Position = _position;
}
}
public Rectangle Rectangle
{
get
{
if (_texture != null)
{
return new Rectangle((int)Position.X - (int)Origin.X, (int)Position.Y - (int)Origin.Y, _texture.Width, _texture.Height);
}
if (_animationManager != null)
{
var animation = _animations.FirstOrDefault().Value;
return new Rectangle((int)Position.X - (int)Origin.X, (int)Position.Y - (int)Origin.Y, animation.FrameWidth, animation.FrameHeight);
}
throw new Exception("Unknown sprite");
}
}
public Vector2 Centre
{
get
{
return new Vector2(Rectangle.X + Origin.X, Rectangle.Y + Origin.Y);
}
}
public float Rotation
{
get { return _rotation; }
set
{
_rotation = value;
if (_animationManager != null)
_animationManager.Rotation = value;
}
}
public readonly Color[] TextureData;
public Matrix Transform
{
get
{
return Matrix.CreateTranslation(new Vector3(-Origin, 0)) *
Matrix.CreateRotationZ(_rotation) *
Matrix.CreateTranslation(new Vector3(Position, 0));
}
}
public Sprite Parent;
///
/// The area of the sprite that could "potentially" be collided with
///
public Rectangle CollisionArea
{
get
{
return new Rectangle(Rectangle.X, Rectangle.Y, MathHelper.Max(Rectangle.Width, Rectangle.Height), MathHelper.Max(Rectangle.Width, Rectangle.Height));
}
}
public Sprite(Texture2D texture)
{
_texture = texture;
Children = new List
Origin = new Vector2(_texture.Width / 2, _texture.Height / 2);
CollisionType = CollisionTypes.None;
Colour = Color.White;
TextureData = new Color[_texture.Width * _texture.Height];
_texture.GetData(TextureData);
}
public Sprite(Dictionary
{
_texture = null;
Children = new List
Colour = Color.White;
TextureData = null;
_animations = animations;
var animation = _animations.FirstOrDefault().Value;
_animationManager = new AnimationManager(animation);
Origin = new Vector2(animation.FrameWidth / 2, animation.FrameHeight / 2);
}
public override void Update(GameTime gameTime)
{
}
public virtual void ApplyPhysics(GameTime gameTime)
{
}
public override void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
if (_texture != null)
spriteBatch.Draw(_texture, Position, null, Colour, _rotation, Origin, 1f, SpriteEffects.None, Layer);
else if (_animationManager != null)
_animationManager.Draw(spriteBatch);
}
public bool Intersects(Sprite sprite)
{
if (this.TextureData == null)
return false;
if (sprite.TextureData == null)
return false;
var transformAToB = this.Transform * Matrix.Invert(sprite.Transform);
var stepX = Vector2.TransformNormal(Vector2.UnitX, transformAToB);
var stepY = Vector2.TransformNormal(Vector2.UnitY, transformAToB);
var yPosInB = Vector2.Transform(Vector2.Zero, transformAToB);
for (int yA = 0; yA < this.Rectangle.Height; yA++)
{
var posInB = yPosInB;
for (int xA = 0; xA < this.Rectangle.Width; xA++)
{
var xB = (int)Math.Round(posInB.X);
var yB = (int)Math.Round(posInB.Y);
if (0 <= xB && xB < sprite.Rectangle.Width &&
0 <= yB && yB < sprite.Rectangle.Height)
{
var colourA = this.TextureData[xA + yA * this.Rectangle.Width];
var colourB = sprite.TextureData[xB + yB * sprite.Rectangle.Width];
if (colourA.A != 0 && colourB.A != 0)
{
return true;
}
}
posInB += stepX;
}
yPosInB += stepY;
}
return false;
}
public virtual void OnCollides(Sprite sprite)
{
}
public object Clone()
{
var sprite = this.MemberwiseClone() as Sprite;
if (_animations != null)
{
sprite._animations = this._animations.ToDictionary(c => c.Key, v => v.Value.Clone() as Animation);
sprite._animationManager = sprite._animationManager.Clone() as AnimationManager;
}
return sprite;
}
public bool WillIntersect(Sprite sprite)
{
return this.WillIntersectBottom(sprite) ||
this.WillIntersectLeft(sprite) ||
this.WillIntersectRight(sprite) ||
this.WillIntersectTop(sprite);
}
public bool WillIntersectLeft(Sprite sprite)
{
return this.Rectangle.Right + this._velocity.X >= sprite.Rectangle.Left &&
this.Rectangle.Left + this._velocity.X < sprite.Rectangle.Left &&
this.Rectangle.Top /*+ this._velocity.Y */< sprite.Rectangle.Bottom &&
this.Rectangle.Bottom/* + this._velocity.Y*/ > sprite.Rectangle.Top;
}
public bool WillIntersectRight(Sprite sprite)
{
return this.Rectangle.Left + this._velocity.X <= sprite.Rectangle.Right &&
this.Rectangle.Right > sprite.Rectangle.Right &&
this.Rectangle.Top /*+ this._velocity.Y */< sprite.Rectangle.Bottom &&
this.Rectangle.Bottom/* + this._velocity.Y*/ > sprite.Rectangle.Top;
}
public bool WillIntersectTop(Sprite sprite)
{
return this.Rectangle.Bottom + this._velocity.Y >= sprite.Rectangle.Top &&
this.Rectangle.Top < sprite.Rectangle.Top &&
this.Rectangle.Right/* + this._velocity.X*/ > sprite.Rectangle.Left &&
this.Rectangle.Left /*+ this._velocity.Y */< sprite.Rectangle.Right;
}
public bool WillIntersectBottom(Sprite sprite)
{
return this.Rectangle.Top + this._velocity.Y <= sprite.Rectangle.Bottom &&
this.Rectangle.Bottom > sprite.Rectangle.Bottom &&
this.Rectangle.Right/* + this._velocity.X*/ > sprite.Rectangle.Left &&
this.Rectangle.Left /*+ this._velocity.Y */< sprite.Rectangle.Right;
}
}
}
Код обработки логики для врагов:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
namespace Contra.Sprites
{
public class Enemy : Body
{
private float _timer;
public bool fire;
public float ShootingTimer = 1.75f;
public Enemy(Texture2D texture)
: base(texture)
{
Speed = 2f;
}
public override void Update(GameTime gameTime)
{
Direction = new Vector2((float)Math.Cos(_rotation), (float)Math.Sin(_rotation));
_timer += (float)gameTime.ElapsedGameTime.TotalSeconds;
if (_timer >= ShootingTimer)
{
Shoot2(Direction,-5f);
_timer = 0;
}
Position += new Vector2(-Speed, 0);
// if the enemy is off the left side of the screen
if (Position.X < -_texture.Width)
IsRemoved = false;
ApplyPhysics(gameTime);
}
public override void OnCollide(Sprite sprite)
{
// If we crash into a player that is still alive
if (sprite is Player && !((Player)sprite).IsDead)
{
((Player)sprite).Score.Value++;
// We want to remove the ship completely
IsRemoved = true;
}
// If we hit a bullet that belongs to a player
if (sprite is Bullet && ((Bullet)sprite).Parent is Player)
{
Health--;
if (Health <= 0)
{
IsRemoved = true;
((Player)sprite.Parent).Score.Value++;
}
}
}
}
}
3.2 Руководство пользователя
После запуска приложения вас встречает главное меню:
Рисунок 3 – Главное меню приложения
По центру приложения расположены главные кнопки управления. Необходимые для смены состояний игры.
Рисунок 4 – Экран Игры
На нем отображены: игрок(и), база, блоки, враги
Рисунок 5 – Экран результатов
Чтобы закончить работу с приложением можно закрыть главное окно.
Заключение
В ходе курсового проекта было разработано игровое приложение «Контра». В трех разделах пояснительной записки описано проектирование и разработка приложения.
Приложение выполнено с помощью среды разработки Visual Studio и дополнительного ПО «Monogame» и протестировано согласно приведенной программе проведения испытаний.
Цели, поставленные перед разработкой курсового проекта достигнуты
Список используемой литературы
-
Албахари, Джозеф C# 3.0. Справочник / Джозеф Албахари, Бен Албахари. - М.: БХВ-Петербург, 2013. - 944 c. -
Бишоп, Дж. C# в кратком изложении / Дж. Бишоп, Н. Хорспул. - М.: Бином. Лаборатория знаний, 2013. - 472 c. -
Вагнер, Билл С# Эффективное программирование / Билл Вагнер. - М.: ЛОРИ, 2013. - 320 c. -
Банк, В.С. Информационные технологии в экономике / В.С. Банк, В.С. Зверевю – М.: Финансы и статистика, 2013. – 547 с. -
Докучаев, А.А. Средства информатики в офисе торговой фирмы. Средства компьютерных коммуникаций. / А.А. Докучаев, С.А. Мошенский, О.В. Назаров – СПб.: ТЭИ, 2006. – 320 с. -
Клименко, С.В. Internet: среда обитания информационного общества. / С.В. Клименко, В.Ф. Уразметов – М.: РЦ ФТИ, 2005. -
Климова, Р.Н. Информатика торговой фирмы / Учебное пособие. Для студентов всех специальностей всех форм обучения. / Р.Н. Климова, М.В. Сорокина, И.А. Хахаев, С.А. Мошенский – СПб.: ТЭИ, 2008. – 320 с. -
Monogame Introduction (руководство пользования) Monogame team. https://docs.monogame.net/
Приложение А. Фрагмент кода
-
using System; -
using System.Collections.Generic; -
using System.Linq; -
using System.Text; -
using System.Threading.Tasks; -
using Microsoft.Xna.Framework; -
using Microsoft.Xna.Framework.Content; -
using Microsoft.Xna.Framework.Graphics; -
using Contra.Sprites; -
using Microsoft.Xna.Framework.Input; -
using Contra.Managers; -
using System.Reflection; -
using Contra.States; -
using Contra.Models; -
using System.Reflection.Metadata; -
-
namespace Contra.status -
{ -
public class GameState : State -
{ -
private EnemyManager _enemyManager; -
-
private BlockManager _blockManager; -
-
private SpriteFont _font; -
-
private List
_players; -
-
private ScoreManager _scoreManager; -
-
private List_sprites;
private Camera _camera;
private Texture2D _map;
public int PlayerCount;
public bool Spawn;
public int Lindex = 0;
public int ind;
public GameState(Game1 game, ContentManager content)
: base(game, content)
{
}
public override void LoadContent()
{
var playerTexture = _content.Load("player1");
var bulletTexture = _content.Load("bullet");
_map = _content.Load("Map");
_font = _content.Load("text2");
_scoreManager = ScoreManager.Load();
_camera = new Camera();
var texture = _content.Load("trava");
_sprites = new List()
{
//new Sprite(_content.Load("Map"))
//{
// Layer = 0.0f,
// Position = new Vector2(0,0),
// CollisionType = CollisionTypes.None,
//},
};
var bulletPrefab = new Bullet(bulletTexture)
{
};
if (PlayerCount >= 1)
{
_sprites.Add(new Player(playerTexture)
{
index = 0,
Position = new Vector2(122, 275),
Layer = 0.3f,
Bullet = bulletPrefab,
Input = new Input()
{
Up = Keys.W,
Down = Keys.S,
Left = Keys.A,
Right = Keys.D,
Jump = Keys.Space,
Shoot = Keys.F,
},
Health = 4,
Score = new Score()
{
PlayerName = "Player 1",
Value = 0,
},
});
}
if (PlayerCount >= 2)
{
ind = 1;
_sprites.Add(new Player(playerTexture)
{
index= 1,
Colour = Color.Green,
Position = new Vector2(172, 275),
Layer = 0.4f,
Bullet = bulletPrefab,
Input = new Input()
{
Up = Keys.Up,
Down = Keys.Down,
Left = Keys.Left,
Right = Keys.Right,
Jump = Keys.RightShift,
Shoot = Keys.Enter,
},
Health = 4,
Score = new Score()
{
PlayerName = "Player 2",
Value = 0,
},
});
}
_players = _sprites.Where(c => c is Player).Select(c => (Player)c).ToList();
_enemyManager = new EnemyManager(_content)
{
Bullet = bulletPrefab,
};
_blockManager = new BlockManager(_content)
{
};
}
public override void Update(GameTime gameTime)
{
if (Keyboard.GetState().IsKeyDown(Keys.Escape))
_game.ChangeState(new MenuState(_game, _content));
foreach (var sprite in _sprites)
sprite.Update(gameTime);
if (ind > 0)
if (_players[0].IsDead)
Lindex = 1;
_enemyManager.Update(gameTime);
if (_enemyManager.CanAdd && _sprites.Where(c => c is Enemy).Count() < _enemyManager.MaxEnemies)
{
_sprites.Add(_enemyManager.GetEnemy());
}
_blockManager.Update(gameTime);
if (Spawn)
{
int c = 0;
for(int x = 137; x < 11000; x +=94)
{
for(int y = 0; y < 700; y +=1)
{
//c = 1;
//if (x >= 2299 && x < 2779 && y == 311)
//{
// _sprites.Add(_blockManager.GetBlock(x, y, c));
//}
c = 0;
if (x >= 4038 && x < 5542 && y == 223 || x >= 6012 && x < 6482 && y == 223
|| x >= 137 && x < 4226 && y == 321 || x >= 5448 && x < 6106 && y == 321 || x >= 6576 && x < 6764 && y == 321
|| x >= 6952 && x < 7140 && y == 321 || x >= 7422 && x < 7798 && y == 321
|| x>= 513 && x <795 && y == 415 || x >= 1265 && x < 1453 && y == 415 || x >= 4696 && x < 5354 && y == 415
|| x >= 6388 && x < 6670 && y == 415 || x >= 6858 && x < 7046 && y == 415 || x >= 7234 && x < 7422 && y == 415
|| x >= 7798 && x < 7892 && y == 415
|| x >= 1923 && x < 2205 && y == 458 || x >= 4414 && x < 4602 && y == 458 || x >= 6200 && x < 6294 && y == 458
|| x >= 7516 && x < 7798 && y == 458
|| x >= 795 && x < 889 && y == 509 || x >= 1077 && x < 1171 && y == 509 || x >= 5636 && x < 5824 && y == 509
|| x >= 5918 && x < 6106 && y == 509 || x >= 7892 && x < 7986 && y == 509
|| x >= 889 && x < 1077 && y == 600 || x >= 1829 && x < 2017 && y == 600 || x >= 4132 && x < 4414 && y == 600
|| x >= 5072 && x < 5636 && y == 600 || x >= 7422 && x < 8174 && y == 600 )
{
_sprites.Add(_blockManager.GetBlock(x,y,c));
}
}
}
Spawn= false;
}
CheckCollision(gameTime);
}
public void CheckCollision(GameTime gameTime)
{
var collidableSprites = _sprites.Where(c => c is ICollidable);
foreach (var spriteA in collidableSprites)
{
foreach (var spriteB in collidableSprites)
{
// Don't do anything if they're the same sprite!
if (spriteA == spriteB)
continue;
if (spriteA.WillIntersect(spriteB))
//if (spriteA.Rectangle.Intersects(spriteB.Rectangle))
spriteA.OnCollides(spriteB);
}
}
}
public override void PostUpdate(GameTime gameTime)
{
var collidableSprites = _sprites.Where(c => c is ICollidable);
foreach (var spriteA in collidableSprites)
{
foreach (var spriteB in collidableSprites)
{
// Don't do anything if they're the same sprite!
if (spriteA == spriteB)
continue;
if (!spriteA.CollisionArea.Intersects(spriteB.CollisionArea))
continue;
if (spriteA.Intersects(spriteB))
((ICollidable)spriteA).OnCollide(spriteB);
}
}
// Add the children sprites to the list of sprites (ie bullets)
int spriteCount = _sprites.Count;
for (int i = 0; i < spriteCount; i++)
{
var sprite = _sprites[i];
foreach (var child in sprite.Children)
_sprites.Add(child);
sprite.Children = new List();
}
for (int i = 0; i < _sprites.Count; i++)
{
if (_sprites[i].IsRemoved)
{
_sprites.RemoveAt(i);
i--;
}
}
// If all the players are dead, we save the scores, and return to the highscore state
if (_players.All(c => c.IsDead))
{
foreach (var player in _players)
_scoreManager.Add(player.Score);
ScoreManager.Save(_scoreManager);
_game.ChangeState(new HighscoresState(_game, _content));
}
}
public override void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
float playerX = MathHelper.Clamp(_players[Lindex].Position.X, 300, 10000);
float offsetX = 300 - playerX;
Matrix transform;
//back
transform = Matrix.CreateTranslation(offsetX, 0, 0);
spriteBatch.Begin(transformMatrix: transform);
spriteBatch.Draw(_map, Vector2.Zero, Color.White);
spriteBatch.End();
//block
//transform = Matrix.CreateTranslation(offsetX * 0.6f, 0, 0);
//spriteBatch.Begin();
// spriteBatch.Draw(_map, Vector2.Zero, Color.White);
//spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.FrontToBack, transformMatrix: transform);
foreach (var sprite in _sprites)
sprite.Draw(gameTime, spriteBatch);
spriteBatch.End();
spriteBatch.Begin();
float x = 10f;
foreach (var player in _players)
{
spriteBatch.DrawString(_font, "Player: " + player.Score.PlayerName, new Vector2(x, 10f), Color.White);
spriteBatch.DrawString(_font, "Health: " + player.Health, new Vector2(x, 30f), Color.White);
spriteBatch.DrawString(_font, "Score: " + player.Score.Value, new Vector2(x, 50f), Color.White);
spriteBatch.DrawString(_font, Convert.ToString(player.Position), new Vector2(x, 120), Color.White);
x += 150;
}
spriteBatch.End();
}
}
}