теперь научим нашего игрока стрелять. Для этого надо описать класс пули. Какие должны быть данные у пули? Как она должна обновляться? Все это нужно описать в структуре класса и его методах. Кроме самой пули еще нужны впсышки от выстрелов. По хорошему надо бы реализацию классов и их описание писать в разных .cpp и .h файлах, но мне влом. Тем более они будут сильно завязаны как друг на друге, так и на игроке (глобальная переменная, не забыли?

)
кроме того, нужны будут глобальные переменные для спрайта вспышки выстрела и его текстуры, и текстуры пули.
Пишем:
Billboard *bspark;
Texture *bsparktex;
Texture *btex;
class Bullet
{
Entity *ent;
float l;
public:
Bullet();
~Bullet();
void Update();
};
class Flash
{
Entity *ent;
float l;
public:
Flash(Entity *asent);
~Flash();
void Update();
};
все пули и все вспышки надо хранить в списках. Списки std::list. Естественно храниться в списках будут не сами объекты а указатели на них.
typedef std::list<Bullet*> TBList;
TBList blist;
typedef std::list<Flash*> TFList;
TFList flist;
чтобы каждый раз не писать длинную муть вроде std::list<Bullet*> можно переопределить тип — командой typedef. У нее первое выражение это старое имя типа, а второе — новое.
Конструктор Bullet:
Bullet::Bullet()
{
ent = new Entity(bb);
ent->Blend(BM_ADD);
ent->Position(player);
ent->Rotate(player);
ent->Move(2);
ent->BindTex(btex);
ent->Scale(0.5f);
l = 1000.0f;
Flash *f = new Flash(ent);
blist.push_back(this);
}
как видите, создаем квад, ставим его в позицию игрока, сдвигаем на 2 еденицы вперед (Если у Move только один параметр — это значит смещение по Z в object-space), прикрепляем текстуру, настраиваем блендинг на аддиативный и размеры поменьще. Задаем время жизни в миллисекундах.
Кроме того, на месте пули создаем вспышку. И собственно добавляем созданный экземпляр в список. this – это указатель на текущий (создаваемый объект).
Деструктор пули:
Bullet::~Bullet()
{
delete ent;
blist.remove(this);
}
ну, тут ничего сложного — просто удаляем ентити и выкидываем из списка удаляемый экземпляр.
Функция обновления пули (она должна иметь именно такой формат):
void Bullet::Update()
{
ent->Move(0.08f * dt);
l -= dt;
if(l<0)
delete this;
}
двигаем вперед пулю (с учетом dt). Сокращаем время жизни. Не забывайте, что dt это вреся кадра в миллисекундах (пусть и дробное). Если пуля изжила свою секунду — она уничтожается.
Конструктор Flash:
Flash::Flash(Entity *asent)
{
ent = new Entity(bspark);
ent->Blend(BM_ADD);
ent->Position(asent);
ent->BindTex(bsparktex);
ent->Animate(0.0f,8.0f,7.0f / 500.0f);
flist.push_back(this);
l = 500;
}
тут все тоже самое. Стоит только остановиться на методе — Animate. Он собственно задает границу анимации (начальный и конечный кадр). Третий параметр — скорость анимации.
Деструктор Flash аналогичен деструктору Bullet.
Метод обновления даже проще:
void Flash::Update()
{
l-=dt;
if(l<0)
delete this;
}
далее, загрузка / создание ресурсов:
bspark = new Billboard(1.0f);
bspark->AnimLenght(8);
bspark->SetSmoothAnim(1);
bsparktex = new Texture("media/bflash.jpg");
btex = new Texture("media/bullet.jpg");
создаем биллбоард (он был выбран вместо квада так как его можно анимировать). Задаем ему длинну анимации в кадрах. Так как в текстуре 8 кадров то и тут пишем 8. SetSmoothAnim(1) – включает линейную интерполяцию между кадрами.
Ну и грузим две текстуры. Ничего сложного
до главного цикла объявили переменную float – fire.
if(MouseDown(1))
{
if(fire<1)
{
Bullet *b = new Bullet();
fire = 100;
}
}
fire = max_(0,fire-dt);
misc::update_this<TBList>(blist);
misc::update_this<TFList>(flist);
AnimUpdate(dt);
первый фрагмент (там где MouseDown(1)) – это стрельба.
Если ствол остыл (fire<1) то можно стрелять.
Поэтому создаем новую пулю, не волнуйтесь, она не засрет память, даже если мы и теряем ее указатель, так как в списке она осталась, и будет корректо почищена.
Ствол остывает - fire = max_(0,fire-dt);
следующие две строчки очень интересны. Они запускают обновление элементов в списке. Он отличается от std::for_each тем, что в нем элементы во время обновления могут удалить сами себя. А в for_each теряется итератор.
AnimUpdate – обновляет все анимированные объекты. Параметр — это twin.
Исходник:

#define SIGEL_USE_ONLY
#define SIGEL_DEVIL
#define SIGEL_SOUND
#include <sigel/ISigel.h>
Surface *bb = 0;
Entity *player = 0;
float dt = 0;
Billboard *bspark;
Texture *bsparktex;
Texture *btex;
class Bullet
{
Entity *ent;
float l;
public:
Bullet();
~Bullet();
void Update();
};
class Flash
{
Entity *ent;
float l;
public:
Flash(Entity *asent);
~Flash();
void Update();
};
typedef std::list<Bullet*> TBList;
TBList blist;
typedef std::list<Flash*> TFList;
TFList flist;
Bullet::Bullet()
{
ent = new Entity(bb);
ent->Blend(BM_ADD);
ent->Position(player);
ent->Rotate(player);
ent->MoveY(0,2);
ent->BindTex(btex);
ent->Scale(0.5f);
l = 1000.0f;
Flash *f = new Flash(ent);
blist.push_back(this);
}
Bullet::~Bullet()
{
delete ent;
blist.remove(this);
}
void Bullet::Update()
{
ent->Move(0.08f * dt);
l -= dt;
if(l<0)
delete this;
}
Flash::Flash(Entity *asent)
{
ent = new Entity(bspark);
ent->Blend(BM_ADD);
ent->Position(asent);
ent->BindTex(bsparktex);
ent->Animate(0.0f,8.0f,7.0f / 500.0f);
flist.push_back(this);
l = 500;
}
Flash::~Flash()
{
delete ent;
flist.remove(this);
}
void Flash::Update()
{
l-=dt;
if(l<0)
delete this;
}
sGAME
{
debug::startlog();
Init();
AppTitle("_ISh2");
Image *cur = new Image("media/cur.jpg");
Camera *eye = new Camera();
Entity *cam = new Entity(EC_PIVOT);
eye->BindEntity(cam);
cam->Rotate(-90.0f,0,0); //поворачиваем камеру вниз. Игра то с видом сверху.
bb = new Surface();
bb->MakeQuad(2.0f);
player = new Entity(bb);
player->Blend(BM_ALPHA);
Texture *playerdiffus[19];
for(int i=0;i<19;++i)
{
char buff[80];
sprintf_s(buff,80,"media/solider/%d.png",i+1);
playerdiffus[i] = new Texture(buff);
}
Surface *sfloor = new Surface();
sfloor->MakeQuad(64.0f,16.0f);
Entity *efloor = new Entity(sfloor);
Texture *fdiffus = new Texture("media/Fieldstone.png",TF_MIPMAP | TF_ANISOTROPIC);
efloor->BindTex(fdiffus);
bspark = new Billboard(1.0f);
bspark->AnimLenght(8);
bspark->SetSmoothAnim(1);
bsparktex = new Texture("media/bflash.jpg");
btex = new Texture("media/bullet.jpg");
VWait(0);
TFont *fnt = new TFont("tahoma.txt");
player -> Position(32.0f,0.5f,32.0f); //ставим игрока на середину. (чуть выше земли).
int move = 0;
float frame = 0;
player->BindTex(playerdiffus[(int)frame]);
HidePointer();
float fire = 0;
while(!KeyDown(VK_ESCAPE))
{
dt = GetFrameTime();
//3d
move = 0;
Vector2D mdir(0,0);
if(KeyDown('W'))
{
move = 1;
mdir.y -= 1;
}
if(KeyDown('S'))
{
move = 1;
mdir.y += 1;
}
if(KeyDown('A'))
{
move = 1;
mdir.x -= 1;
}
if(KeyDown('D'))
{
move = 1;
mdir.x += 1;
}
if(move)
{
if(mdir.length()>0.1f)
mdir.normalize();
mdir *= (dt*0.01f);
player->Translate(mdir.x,0,mdir.y);
frame += dt * 0.03f;
if(frame>18.0f)
frame -= 18.0f;
player->BindTex(playerdiffus[(int)frame]);
}
float a = atan2f((float)((ScreenWidth()/2)-MouseX()),(float)((ScreenHeight()/2)-MouseY()));
player->RotateY(a*57.1f);
cam->Position(player);
cam->PositionY(24.0f);
if(MouseDown(1))
{
if(fire<1)
{
Bullet *b = new Bullet();
fire = 100;
}
}
fire = max_(0,fire-dt);
misc::update_this<TBList>(blist);
misc::update_this<TFList>(flist);
AnimUpdate(dt);
Render();
//2d
fnt->Text(GetFPS(),10,10);
Blend(BM_ADD);
cur->Draw(MouseX()-16,MouseY()-16);
Blend(BM_ALPHA);
Flip();
}
ShowPointer();
DeInit();
debug::endlog();
};
часть скриншота:
