Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Osnovy_razrabotki_prilozheny_besprovodnykh_ustr...docx
Скачиваний:
1
Добавлен:
01.04.2025
Размер:
784.07 Кб
Скачать

Лабораторная работа №9. Игра "Загони шар в лузу"

Задание

Создать игру "Загони шар в лузу" для Windows Phone 7 с использованием акселерометра (шар меняет направление и скорость при наклоне телефона) и возможностью сохранения наилучшего времени в изолированном хранилище.

Освоение

  • акселерометр

  • работа с потоками

  • изолированное хранилище

Описание

Создадим новый проект Silverlight for Windows Phone – Windows Phone Application.

Откроем файл разметки главной страницы MainPage.xaml. Разместим элемент Canvas, в котором будут находиться два эллипса (элемент управления Ellipse). В зависимости от положения телефона будем менять свойства Canvas.Left и Canvas.Top. Добавим также текстовый блок для вывода времени игры и 3 кнопки: новая игра, просмотр рекорда и сброс рекорда.

<!--ContentPanel - place additional content here-->

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">

<StackPanel>

<Canvas Name="cnvMain" Height="700" Width="450" Background="White">

<Ellipse Name="ellBall" Height="30" Width="30" Canvas.Left="50" Canvas.Top="200" Canvas.ZIndex="2"

Stroke="Black" StrokeThickness="1" VerticalAlignment="Top" Fill="Red" />

<Ellipse Name="ellHole" Height="50" Width="50" Canvas.Left="200" Canvas.Top="50" Canvas.ZIndex="1"

Stroke="Black" StrokeThickness="1" VerticalAlignment="Top" Fill="Black" />

</Canvas>

<StackPanel Orientation="Horizontal">

<TextBlock Name="lblTime" Text="00:00" FontSize="26" VerticalAlignment="Center" />

<Button Name="btnNewGame" Content="Новая" Click="btnNewGame_Click" />

<Button Name="btnRecord" Content="Рекорд" Click="btnRecord_Click" />

<Button Name="btnResetRecord" Content="Сброс" Click="btnResetRecord_Click" />

</StackPanel>

</StackPanel>

</Grid>

Добавим константы для определения радиусов шарика и лузы:

private const double BALL_RAD = 15d;

private const double HOLE_RAD = 20d;

В конструкторе класса проинициализируем размеры элепсов:

ellBall.Width = BALL_RAD * 2d;

ellBall.Height = BALL_RAD * 2d;

ellHole.Width = HOLE_RAD * 2d;

ellHole.Height = HOLE_RAD * 2d;

Для работы с акселерометром добавим в код директиву:

using Microsoft.Devices.Sensors;

Создадим глобальную переменную акселерометра:

private Accelerometer myAccel;

В конструкторе класса страницы проинициализируем акселерометр и подпишемся на событие изменения положения телефона:

myAccel = new Accelerometer();

myAccel.ReadingChanged += new EventHandler<AccelerometerReadingEventArgs>(myAccel_ReadingChanged);

Для изменения скорости шарика определим глобальную константу и переменные в классе:

private const double KOEFF_ACCEL = 20d;

private double nSpeedUpZ, nSpeedUpX;

private bool bGameStopped;

При изменении положения телефона будем менять координаты шарика. Поскольку из отдельного потока нельзя напрямую работать с элементами управления, будем пользоваться диспетчерами. После изменения координат будем проверять игру на победу (попадание центра шарика в лузу).

void myAccel_ReadingChanged(object sender, AccelerometerReadingEventArgs e)

{

if (myAccel.IsDataValid && !bGameStopped)

{

nSpeedUpZ = e.Z * KOEFF_ACCEL;

nSpeedUpX = e.X * KOEFF_ACCEL;

if (e.Z < 0)

{

Dispatcher.BeginInvoke(() => HandleUp());

}

else

{

Dispatcher.BeginInvoke(() => HandleDown());

}

if (e.X < 0)

{

Dispatcher.BeginInvoke(() => HandleLeft());

}

else

{

Dispatcher.BeginInvoke(() => HandleRight());

}

Dispatcher.BeginInvoke(() => WinChecking());

}

}

private void HandleUp()

{

if ((double)ellBall.GetValue(Canvas.TopProperty) > 0d)

{

ellBall.SetValue(Canvas.TopProperty, (double)ellBall.GetValue(Canvas.TopProperty) + nSpeedUpZ);

}

}

private void HandleDown()

{

if ((double)ellBall.GetValue(Canvas.TopProperty) < (cnvMain.Height - ellBall.Height))

{

ellBall.SetValue(Canvas.TopProperty, (double)ellBall.GetValue(Canvas.TopProperty) + nSpeedUpZ);

}

}

private void HandleLeft()

{

if ((double)ellBall.GetValue(Canvas.LeftProperty) > 0d)

{

ellBall.SetValue(Canvas.LeftProperty, (double)ellBall.GetValue(Canvas.LeftProperty) + nSpeedUpX);

}

}

private void HandleRight()

{

if ((double)ellBall.GetValue(Canvas.LeftProperty) < (cnvMain.Width - ellBall.Width))

{

ellBall.SetValue(Canvas.LeftProperty, (double)ellBall.GetValue(Canvas.LeftProperty) + nSpeedUpX);

}

}

private void WinChecking()

{

if (IsWin())

{

bGameStopped = true;

dTimer.Stop();

myAccel.Stop();

if (IsRecord())

{

nTimeRecord = nTime;

MessageBox.Show("Победа!" + Environment.NewLine + "Новый рекорд: " + FormatTime(nTimeRecord) + "!");

SaveToIsolatedStorage(nTimeRecord.ToString());

}

else

{

MessageBox.Show("Победа!");

}

}

}

private bool IsWin()

{

bool bRes = false;

if ((((double)ellBall.GetValue(Canvas.TopProperty) + BALL_RAD) >

((double)ellHole.GetValue(Canvas.TopProperty))) &&

(((double)ellBall.GetValue(Canvas.TopProperty) + BALL_RAD) <

((double)ellHole.GetValue(Canvas.TopProperty) + HOLE_RAD + HOLE_RAD)))

{

if ((((double)ellBall.GetValue(Canvas.LeftProperty) + BALL_RAD) >

((double)ellHole.GetValue(Canvas.LeftProperty))) &&

(((double)ellBall.GetValue(Canvas.LeftProperty) + BALL_RAD) <

((double)ellHole.GetValue(Canvas.LeftProperty) + HOLE_RAD + HOLE_RAD)))

{

bRes = true;

}

}

return bRes;

}

Введем в игру счетчик времени. Добавим константу и переменные:

private const int MAX_TIME = 3599; //59:59

private int nTimeRecord;

private int nTime;

System.Windows.Threading.DispatcherTimer dTimer;

В конструкторе класса объявим новый поток и подпишемся на событие срабатывания таймера (каждую секунду):

dTimer = new System.Windows.Threading.DispatcherTimer();

dTimer.Interval = new TimeSpan(0, 0, 0, 1, 0); //1 сек

dTimer.Tick += new EventHandler(Timer_Tick);

По событию будем увеличивать таймер и с помощью диспетчера менять время в текстовом блоке на странице. А в случае, если максимальное время достигнуто, останавливаем игру.

private void Timer_Tick(object sender, EventArgs e)

{

nTime++;

Dispatcher.BeginInvoke(() => ChangeTimerLabel());

if (IsLose())

{

Dispatcher.BeginInvoke(() => Lose());

}

}

private void ChangeTimerLabel()

{

lblTime.Text = FormatTime(nTime);

}

private string FormatTime(int time)

{

return String.Format("{0:00}", (int)(time / 60)) + ":" + String.Format("{0:00}", (time % 60));

}

private bool IsLose()

{

bool bRes = false;

if (nTime >= MAX_TIME)

{

bRes = true;

}

return bRes;

}

private void Lose()

{

bGameStopped = true;

dTimer.Stop();

myAccel.Stop();

MessageBox.Show("Скучно...");

}

В случае успешного попадания шарика в лузу, если достигнут рекорд по времени, сохраняем его в файле в изолированном хранилище:

private const string strIStorageName = "Wp7IUSLab12.txt";

При этому в конструкторе класса, в случае если файл с рекордом существует, будем загружать рекорд:

if (IsIsolatedStorageExist())

{

nTimeRecord = int.Parse(LoadFromIsolatedStorage());

}

else

{

nTimeRecord = MAX_TIME;

}

При нажатии на кнопку "Сброс" будем очищать хранилище:

Для работы с хранилищем определим директивы:

using System.IO.IsolatedStorage;

using System.IO;

Создадим функции сохранения рекорда в хранилище, загрузки, удаления и проверки файла на существование:

private void SaveToIsolatedStorage(string histText)

{

IsolatedStorageFile fileStorage = IsolatedStorageFile.GetUserStoreForApplication();

IsolatedStorageFileStream fileStream = fileStorage.CreateFile(strIStorageName);

StreamWriter sw = new StreamWriter(fileStream);

sw.Write(histText);

sw.Close();

fileStream.Close();

}

private string LoadFromIsolatedStorage()

{

IsolatedStorageFile fileStorage = IsolatedStorageFile.GetUserStoreForApplication();

IsolatedStorageFileStream fileStream = fileStorage.OpenFile(strIStorageName, System.IO.FileMode.Open);

StreamReader sr = new StreamReader(fileStream);

string strRes = sr.ReadToEnd();

sr.Close();

fileStream.Close();

return strRes;

}

private bool IsIsolatedStorageExist()

{

IsolatedStorageFile sileStorage = IsolatedStorageFile.GetUserStoreForApplication();

return sileStorage.FileExists(strIStorageName);

}

private void RemoveIsolatedStorage()

{

if (IsIsolatedStorageExist())

{

IsolatedStorageFile fileStorage = IsolatedStorageFile.GetUserStoreForApplication();

fileStorage.DeleteFile(strIStorageName);

}

}

Теперь можно скомпилировать приложение, запустить на эмуляторе или телефоне и проверить его функциональность.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]