Министерство образования и науки Российской Федерации Федеральное агентство по образованию Государственное образовательное учреждение высшего профессионального образования САМАРСКИЙ ГОСУДАРСТВЕННЫЙ АЭРОКОСМИЧЕСКИЙ УНИВЕРСИТЕТ
имени академика С.П. КОРОЛЕВА
НАЦИОНАЛЬНЫЙ ИССЛЕДОВАТЕЛЬСКИЙ УНИВЕРСИТЕТ
Пояснительная записка к курсовой работе на тему
Гитарный симулятор по дисциплине «Методы программирования» Выполнил: Гольцев Ф. А.
Группа: 6311
Проверил: Журавлев Д.Ю.
Дата:
Оценка:
Самара 2012
РЕФЕРАТ Пояснительная записка 19 с, 6 рисунков, 3 источника. ПРОГРАММИРОВАНИЕ, ГИТАРНЫЙ СИМУЛЯТОР, ANDROID.
Объектом исследования является популярная мобильная платформа Android, и ее использование для разработки игр.
Цель работы – освоение мобильной платформы Android и разработка приложения “Гитарный симулятор”.
В результате работы разработано мобильное приложение, имитирующее игру на музыкальном инструменте.
СОДЕРЖАНИЕ
ВВЕДЕНИЕ 5
1.ЗАДАНИЕ 6
2.МАТЕМАТИЧЕСКАЯ ПОСТАНОВКА ЗАДАЧИ 7
3.СТРУКТУРА ПРОГРАММЫ 9
4.ТЕКСТ ПРОГРАММЫ 10
5 ОПИСАНИЕ ПРОГРАММЫ 16
6 РЕЗУЛЬТАТЫ ВЫПОЛНЕНИЯ ПРОГРАММЫ 17
ЗАКЛЮЧЕНИЕ 19
СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ 20
ВВЕДЕНИЕ
В наше время смартфоны стали незаменимым инструментом для доступа в Интернет. Уже сейчас число пользователей Android превысило в России число пользователей iPhone. А если посмотреть на темпы роста, то масштабы этой платформы станут еще более очевидными! Люди носят с собой смартфоны везде – в дороге, в ресторанах, на отдыхе или дома на диване. Раньше, чтобы узнать какую-то информацию, им необходим был компьютер – теперь они пользуются мобильным устройством. В Android-маркете уже более 250 000 программ, и каждый день это число растет.
Разработка такого приложения как гитарный симулятор поможет людям интереснее проводить свой досуг и окунет их в чудесный мир музыки.
ЗАДАНИЕ Реализовать приложение имитирующее игру на 6-струнной гитаре. Гитара представлена частью грифа с нанесенными на него ладами и шестью струнами.
Приложение должно отзываться на прикосновения пользователя к экрану мобильного телефона. Звучащая нота должна соответствовать ноте на грифе, к которой прикоснулся пользователь. Должна быть реализована поддержка двухточечного мультитача и адекватная реакция на скольжения пальцев по экрану устройства.
МАТЕМАТИЧЕСКАЯ ПОСТАНОВКА ЗАДАЧИ
Программа должна отрисовывать в реальном времени часть гитарного грифа с нужным количеством ладов, меток и струн. На отрисованном грифе размечаются активные тач-зоны и к ним привязываются звуки, соответствующие ноте на данном участке грифа. Ноты хранятся в специальной матрице Note, которая содержит 6 столбцов и 24 строки.
Так как отображение грифа динамическое, то для разметки тач-зон используется значение разрешения экрана устройства, которое по вертикали делится на количество отображаемых ладов, а по горизонтали на количество струн.

Рисунок 1 – Гриф и расположение нот на нём Для ориентирования по грифу в программе предусмотрена отрисовка меток, которые позволяют относительно точно установить, какая часть грифа отображена в данный момент времени.

Рисунок 2 – Гриф и расположение на нём меток
Так же стоит обратить внимание на технические ограничения музыкального инструмента, в частности на невозможность одновременного звучания нот, находящихся на одной струне.
СТРУКТУРА ПРОГРАММЫ
Программа состоит из таких частей, как:
Классы реализующие методы работы с графикой.
Ресурсы использующиеся в процессе выполнения программы(графика и звуки).
Класс, который отрисовывает гриф и привязывает звуковые файлы к определенным зонам экрана.
Обработчик нажатий на экран.

Рисунок 3 – Схема работы программы.
ТЕКСТ ПРОГРАММЫ public class MainScreen extends Activity implements OnTouchListener {
mSurfaceView mainview;
mScene scene;
mSimpleSprite sprites[] = new mSimpleSprite[24];
mSimpleSprite label;
mSimpleSprite label2;
MediaPlayer mp;
int ms[][] = new int[20][20];
int stream[]={0,0,0,0,0,0};
int f1=0,f2=12;
int rezX=480, rezY=800;
int x;
int y;
int temp=0;
boolean letst;
SoundPool soundpool[] = new SoundPool[6];
String note[][] = {
{"E2", "A2" ,"D2", "G3", "B3", "E4"},
{"F2", "A#2","D#2","G#3","C3", "F4"},
{"F#2","B2", "E3", "A3", "C#3","F#4"},
{"G2", "C2", "F3", "A#3","D3", "G4"},
{"G#2","C#2","F#3","B3", "D#3","G#4"},
{"A2", "D2", "G3", "C3", "E4", "A4"},
{"A#2","D#2","G#3","C#3","F4", "A#4"},
{"B2", "E3", "A3", "D3", "F#4","B4"},
{"C2", "F3", "A#3","D#3","G4", "C4"},
{"C#2","F#3","B3", "E4", "G#4","C#4"},
{"D2", "G3", "C3", "F4", "A4", "D4"},
{"D#2","G#3","C#3","F#4","A#4","D#4"},
{"E3", "A3", "D3", "G4", "B4", "E5"},
{"F3", "A#3","D#3","G#4","C4", "F5"},
{"F#3","B3", "E4", "A4", "C#4","F#5"},
{"G3", "C3", "F4", "A#4","D4", "G5"},
{"G#3","C#3","F#4","B4", "D#4","G#5"},
{"A3", "D3", "G4", "C4", "E5", "A5"},
{"A#3","D#3","G#4","C#4","F5", "A#5"},
{"B3", "E4", "A4", "D4", "F#5","B5"},
{"C3", "F4", "A#4","D#4","G5", "C5"},
{"C#3","F#4","B4", "E5", "G#5","C#5"},
{"D3", "G4", "C4", "F5", "A5", "D5"},
{"D#3","G#4","C#4","F#5","A#5","D#5"},
{"E4", "A4", "D4", "G5", "B5", "E6"}};
/////
FrameLayout MainLayer;
FrameLayout fl;
///
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Начальные настройки движка
mSettings.AutoScale = true;
mSettings.setDefaultRes(480, 800);
mSettings.Init(this, this.getWindowManager().getDefaultDisplay(), 20);
mSettings.setSound(true);
// // Создаем новую сцену
scene = new mScene(480, 800, 2);
// // Устанавливаем в сцене текущим слоем первый слой (нумерация слоев с нуля)
scene.setCurLay(1);
// Загружем в цикле все спрайты и добавляем их на сцену
int drin=(int) (rezY/f2-5);
for (int i = 0; i < f2-f1; i++) {
sprites[i] = new mSimpleSprite("fret1.jpg",
this.getAssets());
if((i==3)||(i==5)||(i==7)||(i==9)||(i==15)||(i==17))
{
label= new mSimpleSprite("label.png", this.getAssets());
scene.addItem(label);
label.setX(rezX/2);
label.setY(drin-(rezY/(f2*2))-10);
}
if(i==12){
label= new mSimpleSprite("label.png", this.getAssets());
label2= new mSimpleSprite("label.png", this.getAssets());
scene.addItem(label);
label.setX(rezX/2+50);
label.setY(drin-(rezY/(f2*2))-10);
scene.addItem(label2);
label.setX(rezX/2-50);
label.setY(drin-(rezY/(f2*2))-10);
}
scene.addItem(sprites[i]);
sprites[i].setX(0);
sprites[i].setY(drin);
drin+=rezY/f2;
}
// Обновляем сцену
// Устанвливаем текущим слоем нулевой
scene.setCurLay(0);
// На него добавляем фоновую картинку
scene.addItem(new mSimpleSprite("neck1.jpg", this.getAssets()));
// Инициализируем поверхность
mainview = new mSurfaceView(this, scene);
this.setContentView(this.mainview);
mainview.setOnTouchListener(this);
soundpool[0] = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
AssetManager assetmanager = getAssets();
AssetFileDescriptor desc;
for(int i=0;i<=16;i++)
{
for(int j=0;j<6;j++)
{
try {
desc = assetmanager.openFd("s/" + note[i][j] + ".ogg");
ms[i][j] = soundpool[/*j*/0].load(desc,1);
Log.d("ff","ms"+ i + j +"eq" +ms[i][j] +".mp3 LOADED");
Log.d("ff","sound "+note[i][j]+".mp3 LOADED");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
} @Override
public void onStart(){
super.onStart();
} // идентификаторы для пунктов меню
private static final int IDM_FRET6 = 101;
private static final int IDM_FRET12 = 104;
private static final int IDM_EXIT = 102;
private static final int IDM_LETST = 103;
//Создание меню
public boolean onCreateOptionsMenu(Menu menu)
{
// добавляем пункты меню
MenuItem ls;
ls=menu.add(0, IDM_LETST,0,"Let strings");
menu.add(Menu.NONE, IDM_FRET6, Menu.NONE, "6-Frets");
menu.add(Menu.NONE, IDM_FRET12, Menu.NONE, "12-Frets");
menu.add(Menu.NONE, IDM_EXIT, Menu.NONE, "Exit");
ls.setCheckable(true);
ls.setChecked(true);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId()) {
case IDM_FRET6:
f2=6;
refresh();
break;
case IDM_FRET12:
f2=12;
refresh();
break;
case IDM_LETST:
letst=!letst;
break;
case IDM_EXIT:
quit();
break;
default:
return false;
}
return true;
}
public void refresh()
{ scene.setCurLay(1);
scene.clear();
//
// Загружем в цикле все спрайты и добавляем их на сцену
int drin=(int) (rezY/f2-5);
for (int i = 0; i < f2-f1; i++) {
sprites[i] = new mSimpleSprite("fret1.jpg",
this.getAssets());
scene.addItem(sprites[i]);
if((i==3)||(i==5)||(i==7)||(i==9)||(i==15)||(i==17))
{
label= new mSimpleSprite("label.png", this.getAssets());
scene.addItem(label);
label.setX(rezX/2);
label.setY(drin-(rezY/(f2*2))-10);
}
if(i==12){
label= new mSimpleSprite("label.png", this.getAssets());
label2= new mSimpleSprite("label.png", this.getAssets());
scene.addItem(label);
label.setX(rezX/2+50);
label.setY(drin-(rezY/(f2*2))-10);
scene.addItem(label2);
label.setX(rezX/2-50);
label.setY(drin-(rezY/(f2*2))-10);
}
sprites[i].setX(0);
sprites[i].setY(drin);
drin+=rezY/f2;
}
}
private void quit(){
finish();
} //Переводит экранные координаты в номер струны
public int scrXToGame(int x) {
x = x/(rezX/6);
return x;
}
//Переводит экранные координаты в номер лада
public int scrYToGame(int y) {
y = y / (rezY/f2);
return y;
} //Проигрывает ноту
public int play(int ID, int x)
{
soundpool[0].play(ID,1, 1, 1, 0, 1);
return soundpool[0].play(ID,1, 1, 1, 0, 1);
}
//Останавливает проигрывание
public void stop(int streamID, int x)
{
soundpool[0].stop(streamID);
}
// Обрабатываем нажатие на экран
@Override
public boolean onTouch(View v, MotionEvent evt) {
int Action = evt.getAction();
if(Action==MotionEvent.ACTION_DOWN)
{
y =(scrYToGame((int) evt.getY(0))+f1);
x = scrXToGame((int) evt.getX(0));
stop(stream[x],x);
stream[x] = play(ms[y][x],x);
temp=ms[y][x];
Log.d("touch1","playsound "+note[y][x]);
}else
if(Action==MotionEvent.ACTION_UP&&letst)
{
y =(scrYToGame((int) evt.getY(0))+f1);
x = scrXToGame((int) evt.getX(0));
stop(stream[x],x);
Log.d("touch1","stopsound "+note[y][x]);
}else
if (Action==MotionEvent.ACTION_MOVE)
{
y =(scrYToGame((int) evt.getY(0))+f1);
x = scrXToGame((int) evt.getX(0));
if(temp!=ms[y][x]) {
stream[x] = play(ms[y][x],x);
temp=ms[y][x];}
Log.d("touch","playsound "+note[y][x]);
}
if(Action==MotionEvent.ACTION_POINTER_2_DOWN)
{
y =(scrYToGame((int) evt.getY(1))+f1);
x = scrXToGame((int) evt.getX(1));
stop(stream[x],x);
stream[x] = play(ms[y][x],x);
temp=ms[y][x];
Log.d("touch2","playsound "+note[y][x]);
}else
if(Action==MotionEvent.ACTION_POINTER_2_UP&&letst)
{
y =(scrYToGame((int) evt.getY(1))+f1);
x = scrXToGame((int) evt.getX(1));
stop(stream[x],x);
Log.d("touch2","stopsound "+note[y][x]);
}
return true;
}}
return true;
}}
5 ОПИСАНИЕ ПРОГРАММЫ Задача решена с использованием среды программирования Eclipse SDK и Android SDK.
При запуске приложения появляется часть грифа, отображающая 12 ладов, прикосновение к струне на определенном ладу вызывает воспроизведение соответствующей ноты. Функция “Let String” заставляет ноты быстрее затухать при отпускании пальца, так же в меню можно выбрать количество отображаемых ладов (шесть или двенадцать).
6 РЕЗУЛЬТАТЫ ВЫПОЛНЕНИЯ ПРОГРАММЫ
Внешний вид программы представлен на Рисунке 4.

Рисунок 4 – Внешний вид рабочего окна программы
Меню, которое можно вызвать с помощью стандартной кнопки телефона (Рисунок 5):

Рисунок 5 – Внешний вид первоначального результата

Рисунок 6 – 6-ладовый режим
ЗАКЛЮЧЕНИЕ
В рамках курсовой работы было разработано игровое приложение для системы Android. Данное приложение написано на языке программирования Java. В результате проделанной работы были получены базовые знания о структуре системы и изучены основы программирования на языке Java с использованием Android SDK. Приложение получилось вполне жизнеспособным и обладает функционалом на уровне подобных приложений, имеющихся в Google Play.
СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ Книги
Аккуртатов Е. Е. Самоучитель Java [Текст] / Аккуртатов Е. Е. - М.: Вильямс, 2005. – 250 с.
С. Хашими, С. Коматинени, Д. Маклин - Разработка приложений для Android. – СПб.: Питер, 2011. – 736 с.
Ноутон П., Шилдт Г. Java 2 - Наиболее полное руководство [Текст] / Г. Шилдт. –, 2007. – 700 с.
|