Используя механизмы анимации, реализованные в предыдущей статье, создадим небольшой пользовательский интерфейс, для управления настройками типичного Android-приложения. Для начала, нам понадобятся кнопки. Кнопки должны реагировать на нажатие, выполняя простую анимацию:
Button.h:
#ifndef _BUTTON_H_
#define _BUTTON_H_
#include "AnimatedSprite.h"
#include "AbstractSpriteOwner.h"
enum EButtonMessage {
ebmDown = 0x0100,
ebmUp = 0x0101,
ebmOutUp = 0x0111,
ebmPressed = 0x0102
};
class Button: public AnimatedSprite {
protected:
AnimateMessage* msgDown;
AnimateMessage* msgUp;
int message;
AbstractSpriteOwner* receiver;
void configure();
public:
Button(ISpriteOwner* scene, const char* res, int x, int y,
#define _BUTTON_H_
#include "AnimatedSprite.h"
#include "AbstractSpriteOwner.h"
enum EButtonMessage {
ebmDown = 0x0100,
ebmUp = 0x0101,
ebmOutUp = 0x0111,
ebmPressed = 0x0102
};
class Button: public AnimatedSprite {
protected:
AnimateMessage* msgDown;
AnimateMessage* msgUp;
int message;
AbstractSpriteOwner* receiver;
void configure();
public:
Button(ISpriteOwner* scene, const char* res, int x, int y,
int zOrder = 0, int loc = elNothing);
Button(ISpriteOwner* scene, int x, int y, int zOrder = 0);
virtual bool isValidMessage(int msg);
virtual bool sendMessage(int msg, uint64 timestamp = 0, void* data = NULL);
virtual void doMessage(int msg, void* data = NULL, uint64 timestamp = 0);
virtual bool isPausable() const {return false;}
void addReceiver(int m, AbstractSpriteOwner* r);
};
#endif // _BUTTON_H_
Button(ISpriteOwner* scene, int x, int y, int zOrder = 0);
virtual bool isValidMessage(int msg);
virtual bool sendMessage(int msg, uint64 timestamp = 0, void* data = NULL);
virtual void doMessage(int msg, void* data = NULL, uint64 timestamp = 0);
virtual bool isPausable() const {return false;}
void addReceiver(int m, AbstractSpriteOwner* r);
};
#endif // _BUTTON_H_
Button.cpp:
#include "Button.h"
#include "Desktop.h"
#include "MoveAction.h"
#include "SendMessageAction.h"
#include "SoundAction.h"
Button::Button(ISpriteOwner* scene, const char* res, int x, int y,
#include "Desktop.h"
#include "MoveAction.h"
#include "SendMessageAction.h"
#include "SoundAction.h"
Button::Button(ISpriteOwner* scene, const char* res, int x, int y,
int zOrder, int loc): AnimatedSprite(scene, res, x, y, zOrder, loc),
receiver(NULL) {
Button::configure();
}
Button::Button(ISpriteOwner* scene, int x, int y, int zOrder):
Button::configure();
}
Button::Button(ISpriteOwner* scene, int x, int y, int zOrder):
AnimatedSprite(scene, x, y, zOrder),
receiver(NULL) {
Button::configure();
}
void Button::configure() {
msgDown = new AnimateMessage();
msgDown->addAction(new MoveAction(this, 0, 50, 10, 10));
msgDown->addAction(new SoundAction(this, 50, "menubutton"));
addMessageRule(ebmDown, msgDown);
msgUp = new AnimateMessage();
msgUp->addAction(new MoveAction(this, 100, 150, 0, 0));
addMessageRule(ebmOutUp, msgUp);
msgUp = new AnimateMessage();
msgUp->addAction(new MoveAction(this, 100, 150, 0, 0));
msgUp->addAction(new SendMessageAction(this, 100, ebmPressed));
msgUp->addAction(new SendMessageAction(this, 110, emtInit));
addMessageRule(ebmUp, msgUp);
}
bool Button::isValidMessage(int msg) {
switch (msg) {
case emtTouchDown:
case emtTouchUp:
case ebmDown:
case ebmUp:
case ebmOutUp:
case ebmPressed: return true;
default: return AnimatedSprite::isValidMessage(msg);
}
}
void Button::doMessage(int msg, void* data, uint64 timestamp) {
if (msg == ebmPressed) {
if (receiver != NULL) {
receiver->sendMessage(message, 0, (IObject*)this);
}
return;
}
AnimatedSprite::doMessage(msg, data, timestamp);
}
bool Button::sendMessage(int msg, uint64 timestamp, void* data) {
if ((msg & emtTouchEvent) != 0) {
switch (msg & emtTouchMask) {
case emtTouchDown:
sendMessage(ebmDown, desktop.getCurrentTimestamp());
break;
case emtTouchUp:
sendMessage(ebmUp, desktop.getCurrentTimestamp());
break;
case emtTouchOutUp:
sendMessage(ebmOutUp, desktop.getCurrentTimestamp());
break;
}
return true;
}
return AnimatedSprite::sendMessage(msg, timestamp, data);
}
void Button::addReceiver(int m, AbstractSpriteOwner* r) {
message = m;
receiver = r;
}
Button::configure();
}
void Button::configure() {
msgDown = new AnimateMessage();
msgDown->addAction(new MoveAction(this, 0, 50, 10, 10));
msgDown->addAction(new SoundAction(this, 50, "menubutton"));
addMessageRule(ebmDown, msgDown);
msgUp = new AnimateMessage();
msgUp->addAction(new MoveAction(this, 100, 150, 0, 0));
addMessageRule(ebmOutUp, msgUp);
msgUp = new AnimateMessage();
msgUp->addAction(new MoveAction(this, 100, 150, 0, 0));
msgUp->addAction(new SendMessageAction(this, 100, ebmPressed));
msgUp->addAction(new SendMessageAction(this, 110, emtInit));
addMessageRule(ebmUp, msgUp);
}
bool Button::isValidMessage(int msg) {
switch (msg) {
case emtTouchDown:
case emtTouchUp:
case ebmDown:
case ebmUp:
case ebmOutUp:
case ebmPressed: return true;
default: return AnimatedSprite::isValidMessage(msg);
}
}
void Button::doMessage(int msg, void* data, uint64 timestamp) {
if (msg == ebmPressed) {
if (receiver != NULL) {
receiver->sendMessage(message, 0, (IObject*)this);
}
return;
}
AnimatedSprite::doMessage(msg, data, timestamp);
}
bool Button::sendMessage(int msg, uint64 timestamp, void* data) {
if ((msg & emtTouchEvent) != 0) {
switch (msg & emtTouchMask) {
case emtTouchDown:
sendMessage(ebmDown, desktop.getCurrentTimestamp());
break;
case emtTouchUp:
sendMessage(ebmUp, desktop.getCurrentTimestamp());
break;
case emtTouchOutUp:
sendMessage(ebmOutUp, desktop.getCurrentTimestamp());
break;
}
return true;
}
return AnimatedSprite::sendMessage(msg, timestamp, data);
}
void Button::addReceiver(int m, AbstractSpriteOwner* r) {
message = m;
receiver = r;
}
В методе sendMessage мы обрабатываем коды событий Touchpad, формируя внутренние события, с которыми работает кнопка. В configure с этими событиями связывается анимация, при нажатии, кнопка перемещается на 10 единиц вниз и вправо, при отпускании, возвращается на место. В случае, если при отпускании точка касания не ушла с кнопки, формируется событие ebmPressed, с которым мы можем связать произвольный обработчик. Реализацию SoundAction мы рассмотрим чуть позже.
Помимо обычных кнопок, нам понадобятся кнопки-переключатели, с изменяемой картинкой. Поскольку эта кнопка также должна анимироваться при нажатии, унаследуем ее от Button:
SwitchButton.h:
#ifndef _SWITCHBUTTON_H_
#define _SWITCHBUTTON_H_
#include "Button.h"
class SwitchButton: public Button {
protected:
void configure();
public:
SwitchButton(ISpriteOwner* scene, int x, int y, int zOrder = 0);
virtual bool sendMessage(int msg, uint64 timestamp = 0, void* data = NULL);
};
#endif // _SWITCHBUTTON_H_
#define _SWITCHBUTTON_H_
#include "Button.h"
class SwitchButton: public Button {
protected:
void configure();
public:
SwitchButton(ISpriteOwner* scene, int x, int y, int zOrder = 0);
virtual bool sendMessage(int msg, uint64 timestamp = 0, void* data = NULL);
};
#endif // _SWITCHBUTTON_H_
SwitchButton.cpp:
#include "SwitchButton.h"
#include "Desktop.h"
#include "MoveAction.h"
#include "SendMessageAction.h"
#include "SoundAction.h"
SwitchButton::SwitchButton(ISpriteOwner* scene, int x, int y, int zOrder):
#include "Desktop.h"
#include "MoveAction.h"
#include "SendMessageAction.h"
#include "SoundAction.h"
SwitchButton::SwitchButton(ISpriteOwner* scene, int x, int y, int zOrder):
Button(scene, x, y, zOrder) {
SwitchButton::configure();
}
void SwitchButton::configure() {
msgUp->addAction(new SendMessageAction(this, 50, emtSwitch));
}
bool SwitchButton::sendMessage(int msg, uint64 timestamp, void* data) {
if (msg == emtSwitch) {
doMessage(msg, 0, timestamp);
if (receiver != NULL) {
receiver->sendMessage(message, 0, (IObject*)this);
}
return true;
}
return Button::sendMessage(msg, timestamp, data);
}
SwitchButton::configure();
}
void SwitchButton::configure() {
msgUp->addAction(new SendMessageAction(this, 50, emtSwitch));
}
bool SwitchButton::sendMessage(int msg, uint64 timestamp, void* data) {
if (msg == emtSwitch) {
doMessage(msg, 0, timestamp);
if (receiver != NULL) {
receiver->sendMessage(message, 0, (IObject*)this);
}
return true;
}
return Button::sendMessage(msg, timestamp, data);
}
Мы просто добавляем в анимацию отпускания кнопки формирование события emtSwitch, переключающее изображение для любого AnimatedSprite.
В анимации Button мы использовали ранее неописанный нами SoundAction, который будет вызывать проигрывание звука нажимающейся кнопки. Рассмотрим его реализацию:
SoundAction.h:
#ifndef _SOUNDACTION_H_
#define _SOUNDACTION_H_
#include <string>
#include "IwSound.h"
#include "AnimateAction.h"
#include "Locale.h"
using namespace std;
class SoundAction: public AnimateAction {
private:
string res;
int loc;
bool checkSound();
protected:
virtual void doAction(int timeDelta);
public:
SoundAction(AbstractScreenObject* sprite, uint64 timeDelta, const char* r,
#define _SOUNDACTION_H_
#include <string>
#include "IwSound.h"
#include "AnimateAction.h"
#include "Locale.h"
using namespace std;
class SoundAction: public AnimateAction {
private:
string res;
int loc;
bool checkSound();
protected:
virtual void doAction(int timeDelta);
public:
SoundAction(AbstractScreenObject* sprite, uint64 timeDelta, const char* r,
int loc = elSound);
};
#endif // _SOUNDACTION_H_
};
#endif // _SOUNDACTION_H_
SoundAction.cpp:
#include "SoundAction.h"
#include "Desktop.h"
SoundAction::SoundAction(AbstractScreenObject* sprite, uint64 timeDelta,
const char* r, int loc): AnimateAction(sprite, timeDelta, timeDelta)
, res(r), loc(loc) {
}
void SoundAction::doAction(int timeDelta) {
CIwResGroup* resGroup;
const char* groupName = Locale::getGroupName(loc);
if (checkSound() &&(groupName != NULL)) {
resGroup = IwGetResManager()->GetGroupNamed(groupName);
CIwSoundSpec* SoundSpec = (CIwSoundSpec*)resGroup->GetResNamed(res.c_str(),
#include "Desktop.h"
SoundAction::SoundAction(AbstractScreenObject* sprite, uint64 timeDelta,
const char* r, int loc): AnimateAction(sprite, timeDelta, timeDelta)
, res(r), loc(loc) {
}
void SoundAction::doAction(int timeDelta) {
CIwResGroup* resGroup;
const char* groupName = Locale::getGroupName(loc);
if (checkSound() &&(groupName != NULL)) {
resGroup = IwGetResManager()->GetGroupNamed(groupName);
CIwSoundSpec* SoundSpec = (CIwSoundSpec*)resGroup->GetResNamed(res.c_str(),
IW_SOUND_RESTYPE_SPEC);
CIwSoundInst* SoundInstance = SoundSpec->Play();
}
}
bool SoundAction::checkSound() {
IObject* o = (IObject*)desktop.getName("soundon");
if (o != NULL) {
return (o->getState() != 0);
}
return false;
}
CIwSoundInst* SoundInstance = SoundSpec->Play();
}
}
bool SoundAction::checkSound() {
IObject* o = (IObject*)desktop.getName("soundon");
if (o != NULL) {
return (o->getState() != 0);
}
return false;
}
Этот пример показывает, как легко мы можем расширять список действий, выполняемых при анимации.
В методе checkSound проверяется состояние объекта с именем "soundon", для определения того, должен ли проигрываться звуковой эффект. Этот объект представляет собой SwitchButton с состояниями 0 и 1. который мы реализуем в нашем интерфейсе. Для того, чтобы искать объекты пользовательского интерфейса по имени, потребуется внести в код некоторые дополнения:
Desktop.h:
#ifndef _DESKTOP_H_
#define _DESKTOP_H_
#include <set>
#include <map>
#define _DESKTOP_H_
#include <set>
#include <map>
. . .
class Desktop {
private:
private:
. . .
map<string, void*> names;
public:
Desktop(): touches(), names(), currentScene(NULL) {}
map<string, void*> names;
public:
Desktop(): touches(), names(), currentScene(NULL) {}
. . .
void setName(string name, void* o);
void* getName(string name);
void setName(string name, void* o);
void* getName(string name);
typedef map<string, void*>::iterator NIter;
typedef pair<string, void*> NPair;
};
extern Desktop desktop;
#endif // _DESKTOP_H_
Desktop.cpp:
#include "Desktop.h"
#include "Iw2D.h"
#include "TouchPad.h"
Desktop desktop;
#include "Iw2D.h"
#include "TouchPad.h"
Desktop desktop;
. . .
void Desktop::release() {
. . .
names.clear();
}
names.clear();
}
void Desktop::setName(string name, void* o) {
NIter p = names.find(name);
if (p != names.end()) {
names.erase(p);
}
names.insert(NPair(name, o));
}
void* Desktop::getName(string name) {
NIter p = names.find(name);
if (p == names.end()) {
return NULL;
}
return p->second;
}
...
AbstractScreenObject.h:
#define _ABSTRACTSCREENOBJECT_H_
#include <string>
#include "Iw2D.h"
#include "IScreenObject.h"
using namespace std;
class AbstractScreenObject: public IScreenObject {
public:
. . .
void setName(string name);
static IObject* getName(string name);
};
#endif // _ABSTRACTSCREENOBJECT_H_
AbstractScreenObject.cpp:
#include "AbstractScreenObject.h"
#include "Desktop.h"
#include "Desktop.h"
...
void AbstractScreenObject::setName(string name) {desktop.setName(name, (IObject*)this);
}
IObject* AbstractScreenObject::getName(string name) {
return (IObject*)desktop.getName(name);
}
Следует отметить, что в Desktop::release мы должны освобождать всю явно или неявно выделенную динамическую память, в противном случае, мы получим следующую ошибку при завершении приложения:
Теперь все готово для разработки пользовательского интерфейса. Переносим код создания сцены из Main.cpp в новый класс Intro:
Main.cpp:
#include "Main.h"
...
#include "Intro.h"
#include "Intro.h"
...
int main() {
init(); {
Intro intro;
desktop.setScene(&intro);
...
init(); {
Intro intro;
desktop.setScene(&intro);
...
}
release();
return 0;
}
release();
return 0;
}
Intro.h:
#ifndef _INTRO_H_
#define _INTRO_H_
#include "Scene.h"
#include "CompositeSprite.h"
enum EIntroMessage {
eimPlay = 0x100,
eimSettings = 0x101,
eimBack = 0x102,
eimCheckMusic = 0x103
};
enum EIntroStatus {
eisMain = 0,
eisSettings = 1
};
class Intro: public Scene {
private:
Sprite* background;
CompositeSprite* title;
CompositeSprite* menu;
CompositeSprite* settings;
int state;
void checkMusic();
protected:
virtual bool doKeyMessage(int msg, s3eKey key);
virtual int getState() {return state;}
void setState(int s) {state = s;}
public:
Intro();
virtual bool init();
virtual bool sendMessage(int msg, uint64 timestamp = 0, void* data = NULL);
};
extern Intro* introScene;
#endif // _INTRO_H_
#define _INTRO_H_
#include "Scene.h"
#include "CompositeSprite.h"
enum EIntroMessage {
eimPlay = 0x100,
eimSettings = 0x101,
eimBack = 0x102,
eimCheckMusic = 0x103
};
enum EIntroStatus {
eisMain = 0,
eisSettings = 1
};
class Intro: public Scene {
private:
Sprite* background;
CompositeSprite* title;
CompositeSprite* menu;
CompositeSprite* settings;
int state;
void checkMusic();
protected:
virtual bool doKeyMessage(int msg, s3eKey key);
virtual int getState() {return state;}
void setState(int s) {state = s;}
public:
Intro();
virtual bool init();
virtual bool sendMessage(int msg, uint64 timestamp = 0, void* data = NULL);
};
extern Intro* introScene;
#endif // _INTRO_H_
Intro.cpp:
#include "Intro.h"
#include "Background.h"
#include "IntroTitle.h"
#include "IntroMenu.h"
#include "IntroSound.h"
#include "Desktop.h"
Intro* introScene = NULL;
Intro::Intro(): state(eisMain) {
introScene = this;
}
bool Intro::init() {
if (!Scene::init()) return false;
regKey(s3eKeyBack);
regKey(s3eKeyAbsBSK);
#if defined IW_DEBUG
regKey(s3eKeyLSK);
#endif
background = new Background(this, "background.png", 1);
title = new IntroTitle(this, 2);
menu = new IntroMenu(this, 3);
settings = new IntroSound(this, 4);
settings->doMessage(emtHide);
checkMusic();
return true;
}
bool Intro::doKeyMessage(int msg, s3eKey key) {
if (msg == emtKeyPressed) {
switch (state) {
case eisSettings:
sendMessage(eimBack);
return true;
}
}
return false;
}
bool Intro::sendMessage(int msg, uint64 timestamp, void* data) {
switch (msg) {
case eimPlay:
// TODO:
return true;
case eimSettings:
background->setAlpha(IW_2D_ALPHA_HALF);
title->doMessage(emtHide);
menu->doMessage(emtHide);
settings->doMessage(emtShow);
setState(eisSettings);
return true;
case eimBack:
background->setAlpha(IW_2D_ALPHA_NONE);
title->doMessage(emtShow);
menu->doMessage(emtShow);
settings->doMessage(emtHide);
setState(eisMain);
return true;
case emtInit:
case eimCheckMusic:
checkMusic();
return true;
}
return false;
}
void Intro::checkMusic() {
bool f = false;
IObject* o = (IObject*)desktop.getName("musicon");
if (o == NULL) {
desktop.stopMusic();
return;
}
f = (o->getState() != 0);
if (f) {
desktop.startMusic("music.mp3");
} else {
desktop.stopMusic();
}
}
#include "Background.h"
#include "IntroTitle.h"
#include "IntroMenu.h"
#include "IntroSound.h"
#include "Desktop.h"
Intro* introScene = NULL;
Intro::Intro(): state(eisMain) {
introScene = this;
}
bool Intro::init() {
if (!Scene::init()) return false;
regKey(s3eKeyBack);
regKey(s3eKeyAbsBSK);
#if defined IW_DEBUG
regKey(s3eKeyLSK);
#endif
background = new Background(this, "background.png", 1);
title = new IntroTitle(this, 2);
menu = new IntroMenu(this, 3);
settings = new IntroSound(this, 4);
settings->doMessage(emtHide);
checkMusic();
return true;
}
bool Intro::doKeyMessage(int msg, s3eKey key) {
if (msg == emtKeyPressed) {
switch (state) {
case eisSettings:
sendMessage(eimBack);
return true;
}
}
return false;
}
bool Intro::sendMessage(int msg, uint64 timestamp, void* data) {
switch (msg) {
case eimPlay:
// TODO:
return true;
case eimSettings:
background->setAlpha(IW_2D_ALPHA_HALF);
title->doMessage(emtHide);
menu->doMessage(emtHide);
settings->doMessage(emtShow);
setState(eisSettings);
return true;
case eimBack:
background->setAlpha(IW_2D_ALPHA_NONE);
title->doMessage(emtShow);
menu->doMessage(emtShow);
settings->doMessage(emtHide);
setState(eisMain);
return true;
case emtInit:
case eimCheckMusic:
checkMusic();
return true;
}
return false;
}
void Intro::checkMusic() {
bool f = false;
IObject* o = (IObject*)desktop.getName("musicon");
if (o == NULL) {
desktop.stopMusic();
return;
}
f = (o->getState() != 0);
if (f) {
desktop.startMusic("music.mp3");
} else {
desktop.stopMusic();
}
}
Класс Intro представляет единственную в нашем приложении сцену, загружающую несколько CompositeSprite. В sendMessage определены обработчики событий.
IntroTitle.h:
#ifndef _INTROTITLE_H_
#define _INTROTITLE_H_
#include <string.h>
#include "CompositeSprite.h"
class IntroTitle: public CompositeSprite {
public:
IntroTitle(Scene* scene, int zOrder): CompositeSprite(scene, 0, 0, zOrder) {}
virtual bool init();
virtual void refresh();
};
#endif // _INTROTITLE_H_
#define _INTROTITLE_H_
#include <string.h>
#include "CompositeSprite.h"
class IntroTitle: public CompositeSprite {
public:
IntroTitle(Scene* scene, int zOrder): CompositeSprite(scene, 0, 0, zOrder) {}
virtual bool init();
virtual void refresh();
};
#endif // _INTROTITLE_H_
IntroTitle.cpp:
#include "IntroTitle.h"
#include "Sprite.h"
bool IntroTitle::init() {
if (!AbstractScreenObject::init()) return false;
// Sprite settings
setXY(122, 100);
// Sprite components
new Sprite(this, "sprite.png", 0, 0, 1);
return true;
}
void IntroTitle::refresh() {
CompositeSprite::refresh();
}
#include "Sprite.h"
bool IntroTitle::init() {
if (!AbstractScreenObject::init()) return false;
// Sprite settings
setXY(122, 100);
// Sprite components
new Sprite(this, "sprite.png", 0, 0, 1);
return true;
}
void IntroTitle::refresh() {
CompositeSprite::refresh();
}
Здесь, мы просто выводим надпись с названием игры. Можно было-бы вывести ее отдельным спрайтом, но на случай если к надписи придется что-то добавить, использован CompositeSprite.
IntroMenu.h:
#ifndef _INTROMENU_H_
#define _INTROMENU_H_
#include "CompositeSprite.h"
#include "Button.h"
class IntroMenu: public CompositeSprite {
private:
Scene* scene;
Button* firstButton;
Button* secondButton;
public:
IntroMenu(Scene* scene, int zOrder): CompositeSprite(scene, 0, 0, zOrder),
#define _INTROMENU_H_
#include "CompositeSprite.h"
#include "Button.h"
class IntroMenu: public CompositeSprite {
private:
Scene* scene;
Button* firstButton;
Button* secondButton;
public:
IntroMenu(Scene* scene, int zOrder): CompositeSprite(scene, 0, 0, zOrder),
scene(scene) {}
virtual bool init();
};
#endif // _INTROMENU_H_
virtual bool init();
};
#endif // _INTROMENU_H_
IntroMenu.cpp:
#include "IntroMenu.h"
#include "Locale.h"
#include "Intro.h"
#include "Desktop.h"
bool IntroMenu::init() {
if (!AbstractScreenObject::init()) return false;
setXY(297, 384);
firstButton = new Button(this, "play", 0, 0, 1,
#include "Locale.h"
#include "Intro.h"
#include "Desktop.h"
bool IntroMenu::init() {
if (!AbstractScreenObject::init()) return false;
setXY(297, 384);
firstButton = new Button(this, "play", 0, 0, 1,
Locale::getCurrentImageLocale());
firstButton->addReceiver(eimPlay, scene);
secondButton = new Button(this, "setup", 0, 157, 2,
firstButton->addReceiver(eimPlay, scene);
secondButton = new Button(this, "setup", 0, 157, 2,
Locale::getCurrentImageLocale());
secondButton->addReceiver(eimSettings, scene);
return true;
}
secondButton->addReceiver(eimSettings, scene);
return true;
}
В главном меню определяем две кнопки. Первая будет передавать в сцену событие eimPlay, на обработку которого пока ничего не повешено, вторая сформирует eimSettings, в обработчике которого главное меню делается невидимым и включается меню настроек.
IntroSound.h:
#ifndef _INTROSOUND_H_
#define _INTROSOUND_H_
#include "CompositeSprite.h"
class IntroSound: public CompositeSprite {
private:
Scene* scene;
public:
IntroSound(Scene* scene, int zOrder): CompositeSprite(scene, 0, 0, zOrder),
#define _INTROSOUND_H_
#include "CompositeSprite.h"
class IntroSound: public CompositeSprite {
private:
Scene* scene;
public:
IntroSound(Scene* scene, int zOrder): CompositeSprite(scene, 0, 0, zOrder),
scene(scene) {}
virtual bool init();
};
#endif // _INTROSOUND_H_
virtual bool init();
};
#endif // _INTROSOUND_H_
IntroSound.cpp:
#include "IntroSound.h"
#include "SwitchButton.h"
#include "Button.h"
#include "Intro.h"
#include "Locale.h"
bool IntroSound::init() {
if (!AbstractScreenObject::init()) return false;
setXY(346, 227);
SwitchButton* s = new SwitchButton(this, 0, 0, 1);
s->addImage("musicoff", 0, Locale::getCurrentImageLocale());
s->addImage("musicon", 1, Locale::getCurrentImageLocale());
s->setName("musicon");
s->setState(1);
s->addReceiver(eimCheckMusic, scene);
s = new SwitchButton(this, 0, 157, 2);
s->addImage("soundoff", 0, Locale::getCurrentImageLocale());
s->addImage("soundon", 1, Locale::getCurrentImageLocale());
s->setName("soundon");
s->setState(1);
Button* b = new Button(this, "back.png", -300, 350, 3,
#include "SwitchButton.h"
#include "Button.h"
#include "Intro.h"
#include "Locale.h"
bool IntroSound::init() {
if (!AbstractScreenObject::init()) return false;
setXY(346, 227);
SwitchButton* s = new SwitchButton(this, 0, 0, 1);
s->addImage("musicoff", 0, Locale::getCurrentImageLocale());
s->addImage("musicon", 1, Locale::getCurrentImageLocale());
s->setName("musicon");
s->setState(1);
s->addReceiver(eimCheckMusic, scene);
s = new SwitchButton(this, 0, 157, 2);
s->addImage("soundoff", 0, Locale::getCurrentImageLocale());
s->addImage("soundon", 1, Locale::getCurrentImageLocale());
s->setName("soundon");
s->setState(1);
Button* b = new Button(this, "back.png", -300, 350, 3,
Locale::getCommonImageLocale());
b->addReceiver(eimBack, scene);
return true;
}
b->addReceiver(eimBack, scene);
return true;
}
В этом меню, мы определяем кнопки "musicon" и "soundon" управляющие проигрыванием фоновой музыки и звуковых эффектов соответственно.
Теперь, все готово, чтобы запустить приложение. После запуска, видим следующую картинку:
Язык интерфейса определяется в Locale.cpp из настроек оборудования. Кнопки нажимаются и при нажатии на вторую кнопку, происходит переключение в меню настроек:
Здесь, при нажатии на кнопки, меняется надпись "вкл"/"выкл" (соответсвенно включается и выключается фоновая музыка и звуковые эффекты). При нажатии на стрелку, происходит переключение на главное меню.
Как обычно, исходный текст проекта можно скачать здесь.
Здравствуйте! Очень классный у вас фреймворк получился, правда матрицу и вектора пришлось поменять с "S" на "F". Хотелось бы с вами юолее предметно пообщаться по мармеладу))
ОтветитьУдалитьЯ рад, что вам пригодилось, но боюсь, что в последнее время я несколько отошел от разработки под Android :( Да и лицензия на Мармелад кончилась. Пообщаться я всегда за, если конечно что-то вспомню
Удалитьсейчас раздают бесплатные годичные лицензии, посмотрите на сайте! Если вам удобно пишите на ящик, если нет на ВКонтакте - astorreviola.
УдалитьБесплатные лицензии гляну, спасибо. Ящик в вашем профиле не нашел, а ВК не посещаю по религиозным соображениям (я вообще товарищ антисоциальный). Мне писать можно на glukkazan@gmail.com
Удалить