|
Быть может кто-то из Вас знает игру Sims, к какому жанру она относиться? Жизненная симуляция, ролевая игра, там можно и дома строить..... |
Опубликован: 10.04.2009 | Доступ: свободный | Студентов: 3253 / 244 | Оценка: 4.49 / 4.39 | Длительность: 17:21:00
Темы: Компьютерная графика, Программирование, Игры
Специальности: Программист
Самостоятельная работа 12:
Сетевые игры
Теперь рассмотрим код главного класса нашей игры. В листинге 16.3. вы можете найти код класса Game1. Именно он реализует сетевую функциональность для нашей игры. При разработке этого класса мы пользовались справочными материалами Microsoft.
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
namespace P12_1
{
public class Game1 : Microsoft.Xna.Framework.Game
{
//Для управления графическим устройством
GraphicsDeviceManager graphics;
//Для вывода изображений
SpriteBatch spriteBatch;
//Для объекта-мяча
Ball b;
//Для обработки состояния клавиатуры
KeyboardState Kb;
//Для сетевой сессии
NetworkSession networkSession;
//Для записи и чтения пакетов данных
PacketWriter packetWriter;
PacketReader packetReader;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
//Добавляем новый GamerServiceComponent
Components.Add(new GamerServicesComponent(this));
}
protected override void Initialize()
{
//Объекты для записи и чтения данных созданы
//с конструкторами по умолчанию
packetWriter = new PacketWriter();
packetReader = new PacketReader();
base.Initialize();
}
/// <summary>
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
//Создадим новый мяч
b = new Ball(Content, this);
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
//Состояние клавиатуры
Kb = Keyboard.GetState();
//Если сетевая сессия не создана
if (networkSession == null)
{
//Если окно приложения активно
if (IsActive)
{
//Если ни один игрок не вошел в систему
if (Gamer.SignedInGamers.Count == 0)
{
//Если окно регистрации не видно - отобразить его
if (!Guide.IsVisible)
Guide.ShowSignIn(2, false);
}
else
//Если пользователь вошел в систему
//Запустить процедуру, которая сначала пытается
//найти существующую сетевую сессию
//если не находит - создает новую
TryToJoinOrCreate();
}
}
else
//Если сетевая сессия создана
//Перейти к процедуре обработки сессии
WorkWithSession();
base.Update(gameTime);
}
//Процедура, которая пытается подключиться к существующей сессии
//или создать новую
void TryToJoinOrCreate()
{
//Выводим сообщение в заголовок окна
this.Window.Title = "Ищу доступную сессию";
//Начинаем поиск новой сессии типа SystemLink - такая сессия
//позволяет создавать игры для автономных, не подключенных к Интернету,
//локальных сетей
using (AvailableNetworkSessionCollection availNetSessions =
NetworkSession.Find(NetworkSessionType.SystemLink,
2, null))
{
//Если ни одной сессии нет
if (availNetSessions.Count == 0)
{
this.Window.Title = "Сессия не найдена - создаю новую сессию";
//Создаем новую сессию
networkSession = NetworkSession.Create(NetworkSessionType.SystemLink,
1, 2);
//Подключаем обработчики событий
JoinEventhandlers();
this.Window.Title = "Сессия создана";
}
//Иначе, если сессия найдена
else
{
this.Window.Title = "Сессия найдена, присоединяюсь";
//Присоединяемся к ней и так же подключаем обработчики
networkSession = NetworkSession.Join(availNetSessions[0]);
JoinEventhandlers();
}
}
}
//Подключение обработчиков событий
void JoinEventhandlers()
{
//Объект типа NetworkSession имеет множество событий
//В частности, они используются для того, чтобы показать, что к игре присоединился новый пользователь
//что игра начата, закончен. Здесь мы подключили два события
//Одно из них происходит, когда к игре присоединяется новый игрок, подключим соответствующий обработчик
networkSession.GamerJoined += new EventHandler<GamerJoinedEventArgs>(networkSession_GamerJoined);
//Второе происходит после закрытия сессии
networkSession.SessionEnded += new EventHandler<NetworkSessionEndedEventArgs>(networkSession_SessionEnded);
}
//Обработчик события, происходящего при присоединении нового игрока
void networkSession_GamerJoined(object sender, GamerJoinedEventArgs e)
{
//Получим номер игрока
int plNumber = networkSession.AllGamers.IndexOf(e.Gamer);
//Запишем в поле Tag игрока, которое имеет тип Object, то есть - способно
//принимать любые объекты, новый объект Bat. Номер игрока, который мы передали
//объекту, используется для его установки. В нашей игре могут участвовать лишь два игрока
//поэтому номер 0 используется для установки биты в левой части экрана, а номер 1 -
//в правой. Игрок, создавший сессию, занимает левую часть экрана
e.Gamer.Tag = new Bat(plNumber, Content, this);
}
//Обработчик события, происходящего при закрытии сессии
void networkSession_SessionEnded(object sender, NetworkSessionEndedEventArgs e)
{
//уничтожим сессию
networkSession.Dispose();
networkSession = null;
}
//Процедура обработки событий в течение сессии
void WorkWithSession()
{
//Вызвать процедуру, вычисляющую новое положение игрового объекта
//для локального игрока - в нашем случае это один игрок с номером 0
//и записывающей данные в сетевой поток
CalcAndWrite(networkSession.LocalGamers[0]);
//Обновить состояние сессии
networkSession.Update();
//Если сессия оказалась уничтоженной - выйти из процедуры
if (networkSession == null) return;
//Прочесть сетевые данные и модифицировать состояние объектов
ReadAndImplement(networkSession.LocalGamers[0]);
}
//Вычисления и передача данных в сеть
void CalcAndWrite(LocalNetworkGamer gamer)
{
//Рассматривать объект, записанный в Tag текущего игрока
//как биту - Bat
Bat bat = gamer.Tag as Bat;
//Модифицировать координаты в соответствии с клавиатурными командами
//Клавиша вверх перемещает биту вверх
if (Kb.IsKeyDown(Keys.Up))
{
bat.sprPosition.Y -= 3;
}
//Клавиша вниз - вниз
if (Kb.IsKeyDown(Keys.Down))
{
bat.sprPosition.Y += 3;
}
//Записать положение биты в сеть
packetWriter.Write(bat.sprPosition);
//Если текущий игрок - хост, то есть он создал
//сетевую сессию, на него возложим обязанности
//вычисления позиции мяча и обработки столкновений
if (gamer.IsHost)
{
//Если к игре подключено 2 пользователя
//То есть она началась
if (networkSession.AllGamers.Count == 2)
{
//Изменить позицию мяча в соответствии с его
//скоростью
b.sprPosition += b.sprSpeed;
//Если вышли за пределы верхней части игрового окна
if (b.sprPosition.Y < b.scrBounds.Y)
{
//Вернуть объект и инвертировать скорость по Y
b.sprPosition.Y = b.scrBounds.Y;
b.sprSpeed.Y *= -1;
}
//Если пересекли нижнюю границу окна
//Вернуть объект и инвертировать скорость по Y
if (b.sprPosition.Y + b.sprRectangle.Height > b.scrBounds.Height)
{
b.sprPosition.Y = b.scrBounds.Height - b.sprRectangle.Height;
b.sprSpeed.Y *= -1;
}
//Получить биту для игрока №0 - она расположена слева
//Берем этот объект из списка всех игроков
bat = networkSession.AllGamers[0].Tag as Bat;
//Если есть столкновение с битой
if (b.sprPosition.X + b.sprRectangle.Width > bat.sprPosition.X &&
b.sprPosition.X < bat.sprPosition.X + bat.sprRectangle.Width &&
b.sprPosition.Y + b.sprRectangle.Height > bat.sprPosition.Y &&
b.sprPosition.Y < bat.sprPosition.Y + bat.sprRectangle.Height)
{
//Вернем мяч и инвертируем скорость по X
b.sprPosition.X = bat.sprRectangle.Width;
b.sprSpeed.X *= -1;
}
//Получим биту для игрока №1 - она расположена справа
bat = networkSession.AllGamers[1].Tag as Bat;
//Если есть столкновение с ней
if (b.sprPosition.X + b.sprRectangle.Width > bat.sprPosition.X &&
b.sprPosition.X < bat.sprPosition.X + bat.sprRectangle.Width &&
b.sprPosition.Y + b.sprRectangle.Height > bat.sprPosition.Y &&
b.sprPosition.Y < bat.sprPosition.Y + bat.sprRectangle.Height)
{
//Вернем мяч и инвертируем скорость по X
b.sprPosition.X = b.scrBounds.Width - bat.sprRectangle.Width - b.sprRectangle.Width;
b.sprSpeed.X *= -1;
}
}
//Запишем позицию мяча в сетевой поток
packetWriter.Write(b.sprPosition);
}
//Отправим данные другим игрокам
gamer.SendData(packetWriter, SendDataOptions.InOrder);
}
//Процедура чтения и применения данных от других объектов
void ReadAndImplement(LocalNetworkGamer gamer)
{
//До тех пор, пока есть данные для чтения
while (gamer.IsDataAvailable)
{
//Новый объект sender типа NetworkGamer
//Он бует использован для хранения ссылки на объект
//который отправил данные
NetworkGamer sender;
// Прочесть данные
gamer.ReceiveData(packetReader, out sender);
//Если данные отправлены не локальным игроком - то есть -
//пришли к нам от одного из сетевых игроков (в нашем случае возможно наличие лишь одного
//такого игрока
if (!sender.IsLocal)
{
//Получить объект bat из поля Tag игрока, отправившего данные
Bat bat = sender.Tag as Bat;
//Записать прочитанные данные в качестве позиции этого объекта
bat.sprPosition = packetReader.ReadVector2();
//Если отправитель данных - хост - дополнительно установить
//позицию мяча, прочитав данные из потока
//Таким образом хост всегда пишет в поток два фрагмента данных
//и если другой объект читает данные хоста - он так же
//воспринимает два фрагмента
if (sender.IsHost) b.sprPosition = packetReader.ReadVector2();
}
}
}
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
//Начало вывода спрайтов
spriteBatch.Begin();
//Если создана сетевая сессия и количество игроков равно 2
//То есть - выполнены условия для начала игры
if (networkSession!=null && networkSession .AllGamers .Count==2)
{
//Для каждого игрока из всех игроков, имеющих отношение к данной сессии
foreach (NetworkGamer gamer in networkSession.AllGamers)
{
//Получить объект bat для текущего игрока
Bat bat = gamer.Tag as Bat;
//Вывести объект bat
bat.Draw(spriteBatch);
//Вывести мяч
b.Draw(spriteBatch);
}
}
//Завершить вывод объектов
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Листинг
16.3.
Код класса Game1
На рис. 16.4. вы можете видеть экран выбора игрока. Мы зарегистрировались как Player1.
На рис. 16.5 вы можете видеть игровой экран после подключения программы к уже созданной сессии.

