sprite copy functionality
This commit is contained in:
parent
b46b5a907d
commit
1f52458057
|
@ -12,28 +12,28 @@
|
||||||
|
|
||||||
#define AVATAR_ROTATION_DIFF 300
|
#define AVATAR_ROTATION_DIFF 300
|
||||||
#define MAX_AMOUNT_OF_BULLETS 40
|
#define MAX_AMOUNT_OF_BULLETS 40
|
||||||
|
#define BULLET_COOLDOWN_START 20
|
||||||
|
|
||||||
FoodScene::FoodScene(const std::shared_ptr<GBAEngine> &engine) : Scene(engine) {}
|
FoodScene::FoodScene(const std::shared_ptr<GBAEngine> &engine) : Scene(engine), bulletCooldown(BULLET_COOLDOWN_START) {}
|
||||||
|
|
||||||
std::vector<Background *> FoodScene::backgrounds() {
|
std::vector<Background *> FoodScene::backgrounds() {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Sprite *> FoodScene::sprites() {
|
std::vector<Sprite *> FoodScene::sprites() {
|
||||||
std::vector<Sprite*> sprites = {
|
std::vector<Sprite*> sprites;
|
||||||
avatar.get() // order is important for affine transformations because of updateSpritesInScene()
|
// TODO order is important for affine transformations because of affinity - those always last!
|
||||||
};
|
// some kind of affine bug depending on the order of sprites added in OAM
|
||||||
for(auto& b : bullets) {
|
for(auto& b : bullets) {
|
||||||
if(!b->isOffScreen()) {
|
sprites.push_back(b.get());
|
||||||
sprites.push_back(b.get());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
sprites.push_back(someBullet.get());
|
||||||
|
sprites.push_back(avatar.get());
|
||||||
|
|
||||||
return sprites;
|
return sprites;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FoodScene::removeBulletsOffScreen() {
|
void FoodScene::removeBulletsOffScreen() {
|
||||||
// TODO crashes after this
|
|
||||||
bullets.erase(
|
bullets.erase(
|
||||||
std::remove_if(bullets.begin(), bullets.end(), [](std::unique_ptr<Sprite> &s) { return s->isOffScreen(); }),
|
std::remove_if(bullets.begin(), bullets.end(), [](std::unique_ptr<Sprite> &s) { return s->isOffScreen(); }),
|
||||||
bullets.end());
|
bullets.end());
|
||||||
|
@ -41,35 +41,46 @@ void FoodScene::removeBulletsOffScreen() {
|
||||||
|
|
||||||
void FoodScene::tick(u16 keys) {
|
void FoodScene::tick(u16 keys) {
|
||||||
avatar->animateToFrame(0);
|
avatar->animateToFrame(0);
|
||||||
|
bool bulletAdded, allowedToShoot;
|
||||||
|
|
||||||
//removeBulletsOffScreen();
|
if(bulletCooldown > 0) {
|
||||||
|
bulletCooldown--;
|
||||||
|
} else if(bulletCooldown == 0) {
|
||||||
|
allowedToShoot = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeBulletsOffScreen();
|
||||||
TextStream::instance().setText(std::to_string(bullets.size()) + std::string(" bullets"), 1, 1);
|
TextStream::instance().setText(std::to_string(bullets.size()) + std::string(" bullets"), 1, 1);
|
||||||
|
TextStream::instance().setText(std::to_string(bulletCooldown) + std::string(" cooldown"), 2, 1);
|
||||||
|
|
||||||
if(keys & KEY_LEFT) {
|
if(keys & KEY_LEFT) {
|
||||||
avatarRotation -= AVATAR_ROTATION_DIFF;
|
avatarRotation -= AVATAR_ROTATION_DIFF;
|
||||||
} else if(keys & KEY_RIGHT) {
|
} else if(keys & KEY_RIGHT) {
|
||||||
avatarRotation += AVATAR_ROTATION_DIFF;
|
avatarRotation += AVATAR_ROTATION_DIFF;
|
||||||
}
|
}
|
||||||
if(keys & KEY_A) {
|
if((keys & KEY_A) && allowedToShoot) {
|
||||||
if(bullets.size() < MAX_AMOUNT_OF_BULLETS) {
|
avatar->animateToFrame(1);
|
||||||
avatar->animateToFrame(1);
|
|
||||||
bullets.push_back(createBullet());
|
|
||||||
|
|
||||||
engine->updateSpritesInScene();
|
if(bullets.size() < MAX_AMOUNT_OF_BULLETS) {
|
||||||
//addSprite(bullets.at(bullets.size() - 1).get());
|
bulletCooldown = BULLET_COOLDOWN_START;
|
||||||
|
bullets.push_back(createBullet());
|
||||||
|
bulletAdded = true;
|
||||||
|
|
||||||
|
auto &b = bullets.at(bullets.size() - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
avatar->rotate(avatarRotation);
|
avatar->rotate(avatarRotation);
|
||||||
|
|
||||||
|
if(bulletAdded) {
|
||||||
|
engine->updateSpritesInScene();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Sprite> FoodScene::createBullet() {
|
std::unique_ptr<Sprite> FoodScene::createBullet() {
|
||||||
// TODO shared bullet data tiles
|
return spriteBuilder->withVelocity(1, 1)
|
||||||
return this->spriteBuilder->withData(bullet_data, sizeof(bullet_data))
|
|
||||||
.withSize(SIZE_16_16)
|
|
||||||
.withVelocity(1, 1)
|
|
||||||
.withLocation(avatar->getX(), avatar->getY())
|
.withLocation(avatar->getX(), avatar->getY())
|
||||||
.buildPtr();
|
.buildWithDataOf(*someBullet.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FoodScene::load() {
|
void FoodScene::load() {
|
||||||
|
@ -88,4 +99,8 @@ void FoodScene::load() {
|
||||||
avatar->stopAnimating();
|
avatar->stopAnimating();
|
||||||
avatarRotation = 0;
|
avatarRotation = 0;
|
||||||
|
|
||||||
|
someBullet = spriteBuilder->withData(bullet_data, sizeof(bullet_data))
|
||||||
|
.withSize(SIZE_16_16)
|
||||||
|
.withLocation(GBA_SCREEN_WIDTH + 20, GBA_SCREEN_HEIGHT + 20)
|
||||||
|
.buildPtr();
|
||||||
}
|
}
|
|
@ -13,8 +13,10 @@
|
||||||
class FoodScene : public Scene {
|
class FoodScene : public Scene {
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<AffineSprite> avatar;
|
std::unique_ptr<AffineSprite> avatar;
|
||||||
|
std::unique_ptr<Sprite> someBullet;
|
||||||
std::vector<std::unique_ptr<Sprite>> bullets;
|
std::vector<std::unique_ptr<Sprite>> bullets;
|
||||||
int avatarRotation;
|
int avatarRotation;
|
||||||
|
u32 bulletCooldown;
|
||||||
|
|
||||||
std::unique_ptr<SpriteBuilder<Sprite>> spriteBuilder;
|
std::unique_ptr<SpriteBuilder<Sprite>> spriteBuilder;
|
||||||
std::unique_ptr<Sprite> createBullet();
|
std::unique_ptr<Sprite> createBullet();
|
||||||
|
|
|
@ -25,8 +25,8 @@ public:
|
||||||
void setAffineIndex(int index) { this->affIndex = index; }
|
void setAffineIndex(int index) { this->affIndex = index; }
|
||||||
void identity();
|
void identity();
|
||||||
void rotate(u16 alpha);
|
void rotate(u16 alpha);
|
||||||
AffineSprite(const void* imgData, int imgSize, int xC, int yC, SpriteSize spriteSize) : Sprite(imgData, imgSize, xC, yC, spriteSize), affIndex(0) {
|
explicit AffineSprite(const AffineSprite& other);
|
||||||
}
|
explicit AffineSprite(const void* imgData, int imgSize, int xC, int yC, SpriteSize spriteSize);
|
||||||
|
|
||||||
friend class SpriteManager;
|
friend class SpriteManager;
|
||||||
};
|
};
|
||||||
|
|
|
@ -47,11 +47,12 @@ private:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const void *data;
|
const void *data;
|
||||||
int x, y, priority, dx, dy;
|
u32 x, y, priority, dx, dy;
|
||||||
int w, h, size_bits, shape_bits;
|
u32 w, h, size_bits, shape_bits;
|
||||||
bool stayWithinBounds;
|
bool stayWithinBounds;
|
||||||
int imageSize, tileIndex;
|
u32 imageSize, tileIndex;
|
||||||
int animationDelay, amountOfFrames, currentFrame, animationCounter;
|
SpriteSize spriteSize;
|
||||||
|
u32 animationDelay, amountOfFrames, currentFrame, animationCounter;
|
||||||
bool animating;
|
bool animating;
|
||||||
|
|
||||||
std::unique_ptr<OBJ_ATTR> oam;
|
std::unique_ptr<OBJ_ATTR> oam;
|
||||||
|
@ -61,6 +62,7 @@ protected:
|
||||||
void setAttributesBasedOnSize(SpriteSize size);
|
void setAttributesBasedOnSize(SpriteSize size);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
explicit Sprite(const Sprite& other);
|
||||||
explicit Sprite(const void *imageData, int imageSize, int x, int y, SpriteSize size);
|
explicit Sprite(const void *imageData, int imageSize, int x, int y, SpriteSize size);
|
||||||
virtual ~Sprite() {}
|
virtual ~Sprite() {}
|
||||||
|
|
||||||
|
@ -85,13 +87,14 @@ public:
|
||||||
void flipVertically(bool flip);
|
void flipVertically(bool flip);
|
||||||
void flipHorizontally(bool flip);
|
void flipHorizontally(bool flip);
|
||||||
|
|
||||||
int getDx() { return dx; }
|
u32 getTileIndex() { return tileIndex; }
|
||||||
int getDy() { return dy; }
|
u32 getDx() { return dx; }
|
||||||
int getX() { return x; }
|
u32 getDy() { return dy; }
|
||||||
int getHeight() { return h; }
|
u32 getX() { return x; }
|
||||||
int getWidth() { return w; }
|
u32 getHeight() { return h; }
|
||||||
int getY() { return y; }
|
u32 getWidth() { return w; }
|
||||||
int getCurrentFrame() { return currentFrame; }
|
u32 getY() { return y; }
|
||||||
|
u32 getCurrentFrame() { return currentFrame; }
|
||||||
bool isOffScreen();
|
bool isOffScreen();
|
||||||
|
|
||||||
friend class SpriteManager;
|
friend class SpriteManager;
|
||||||
|
|
|
@ -9,13 +9,14 @@
|
||||||
|
|
||||||
template<typename T> class SpriteBuilder {
|
template<typename T> class SpriteBuilder {
|
||||||
private:
|
private:
|
||||||
int imageSize;
|
u32 imageSize;
|
||||||
bool stayWithinBounds;
|
bool stayWithinBounds;
|
||||||
const void *imageData;
|
const void *imageData;
|
||||||
int x, y, dx, dy;
|
u32 x, y, dx, dy;
|
||||||
int numberOfFrames, animationDelay;
|
u32 numberOfFrames, animationDelay;
|
||||||
SpriteSize size;
|
SpriteSize size;
|
||||||
|
|
||||||
|
void setProperties(T* sprite);
|
||||||
void reset() {
|
void reset() {
|
||||||
imageSize = x = y = dx = dy = numberOfFrames = animationDelay = 0;
|
imageSize = x = y = dx = dy = numberOfFrames = animationDelay = 0;
|
||||||
imageData = nullptr;
|
imageData = nullptr;
|
||||||
|
@ -40,7 +41,7 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpriteBuilder& withLocation(int x, int y) {
|
SpriteBuilder& withLocation(u32 x, u32 y) {
|
||||||
this->x = x;
|
this->x = x;
|
||||||
this->y = y;
|
this->y = y;
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -56,27 +57,38 @@ public:
|
||||||
}
|
}
|
||||||
T build();
|
T build();
|
||||||
std::unique_ptr<T> buildPtr();
|
std::unique_ptr<T> buildPtr();
|
||||||
|
std::unique_ptr<T> buildWithDataOf(const Sprite &other);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T> std::unique_ptr<T> SpriteBuilder<T>::buildPtr() {
|
template<typename T> std::unique_ptr<T> SpriteBuilder<T>::buildWithDataOf(const Sprite &other) {
|
||||||
auto s = new T(this->imageData, this->imageSize, this->x, this->y, this->size);
|
auto s = new T(other);
|
||||||
|
s->moveTo(this->x, this->y);
|
||||||
|
setProperties(s);
|
||||||
|
|
||||||
|
reset();
|
||||||
|
return std::unique_ptr<T>(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> void SpriteBuilder<T>::setProperties(T* s) {
|
||||||
s->setVelocity(this->dx, this->dy);
|
s->setVelocity(this->dx, this->dy);
|
||||||
if(this->numberOfFrames > 0) {
|
if(this->numberOfFrames > 0) {
|
||||||
s->makeAnimated(this->numberOfFrames, this->animationDelay);
|
s->makeAnimated(this->numberOfFrames, this->animationDelay);
|
||||||
}
|
}
|
||||||
s->setStayWithinBounds(stayWithinBounds);
|
s->setStayWithinBounds(stayWithinBounds);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> std::unique_ptr<T> SpriteBuilder<T>::buildPtr() {
|
||||||
|
auto s = new T(this->imageData, this->imageSize, this->x, this->y, this->size);
|
||||||
|
setProperties(s);
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
return std::unique_ptr<T>(s);
|
return std::unique_ptr<T>(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> T SpriteBuilder<T>::build() {
|
template<typename T> T SpriteBuilder<T>::build() {
|
||||||
T s(this->imageData, this->imageSize, this->x, this->y, this->size);
|
T s(this->imageData, this->imageSize, this->x, this->y, this->size);
|
||||||
s.setVelocity(this->dx, this->dy);
|
setProperties(&s);
|
||||||
if(this->numberOfFrames > 0) {
|
|
||||||
s.makeAnimated(this->numberOfFrames, this->animationDelay);
|
|
||||||
}
|
|
||||||
s.setStayWithinBounds(stayWithinBounds);
|
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
return s;
|
return s;
|
||||||
|
|
|
@ -12,6 +12,14 @@ void AffineSprite::identity() {
|
||||||
obj_aff_identity(this->affine.get());
|
obj_aff_identity(this->affine.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AffineSprite::AffineSprite(const AffineSprite &other) : Sprite(other), affIndex(other.affIndex) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
AffineSprite::AffineSprite(const void *imgData, int imgSize, int xC, int yC, SpriteSize spriteSize) : Sprite(imgData, imgSize, xC, yC, spriteSize), affIndex(0) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void AffineSprite::rotate(u16 alpha) {
|
void AffineSprite::rotate(u16 alpha) {
|
||||||
obj_aff_rotate(this->affine.get(), alpha);
|
obj_aff_rotate(this->affine.get(), alpha);
|
||||||
}
|
}
|
||||||
|
@ -48,7 +56,6 @@ void AffineSprite::buildOam(int tileIndex) {
|
||||||
rebuildOamAttr1ForAffineIndex();
|
rebuildOamAttr1ForAffineIndex();
|
||||||
|
|
||||||
if(!affine) {
|
if(!affine) {
|
||||||
TextStream::instance() << "building";
|
|
||||||
this->affine = std::unique_ptr<OBJ_AFFINE>(new OBJ_AFFINE());
|
this->affine = std::unique_ptr<OBJ_AFFINE>(new OBJ_AFFINE());
|
||||||
identity();
|
identity();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,12 @@
|
||||||
#include <libgba-sprite-engine/sprites/sprite.h>
|
#include <libgba-sprite-engine/sprites/sprite.h>
|
||||||
#include <libgba-sprite-engine/gba_engine.h>
|
#include <libgba-sprite-engine/gba_engine.h>
|
||||||
|
|
||||||
|
Sprite::Sprite(const Sprite &other) : Sprite(nullptr, 0, other.x, other.y, other.spriteSize) {
|
||||||
|
tileIndex = other.tileIndex;
|
||||||
|
}
|
||||||
|
|
||||||
Sprite::Sprite(const void *imageData, int imageSize, int x, int y, SpriteSize size)
|
Sprite::Sprite(const void *imageData, int imageSize, int x, int y, SpriteSize size)
|
||||||
: x(x), y(y), data(imageData), imageSize(imageSize),
|
: x(x), y(y), data(imageData), imageSize(imageSize), spriteSize(size),
|
||||||
animationDelay(0), amountOfFrames(0), currentFrame(0), animationCounter(0) {
|
animationDelay(0), amountOfFrames(0), currentFrame(0), animationCounter(0) {
|
||||||
setAttributesBasedOnSize(size);
|
setAttributesBasedOnSize(size);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +21,9 @@ Sprite::Sprite(const void *imageData, int imageSize, int x, int y, SpriteSize si
|
||||||
void Sprite::moveTo(int x, int y) {
|
void Sprite::moveTo(int x, int y) {
|
||||||
this->x = x;
|
this->x = x;
|
||||||
this->y = y;
|
this->y = y;
|
||||||
syncOam();
|
if(oam) {
|
||||||
|
syncOam();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sprite::isOffScreen() {
|
bool Sprite::isOffScreen() {
|
||||||
|
@ -125,19 +131,19 @@ void Sprite::buildOam(int tileIndex) {
|
||||||
|
|
||||||
if(!oam) {
|
if(!oam) {
|
||||||
this->oam = std::unique_ptr<OBJ_ATTR>(new OBJ_ATTR());
|
this->oam = std::unique_ptr<OBJ_ATTR>(new OBJ_ATTR());
|
||||||
}
|
|
||||||
|
|
||||||
this->oam->attr0 = ATTR0_Y(this->y) |
|
this->oam->attr0 = ATTR0_Y(this->y) |
|
||||||
ATTR0_MODE(0) |
|
ATTR0_MODE(0) |
|
||||||
(GFX_MODE << 10) |
|
(GFX_MODE << 10) |
|
||||||
(MOSAIC_MODE << 12) |
|
(MOSAIC_MODE << 12) |
|
||||||
(COLOR_MODE_256 << 13) |
|
(COLOR_MODE_256 << 13) |
|
||||||
(this->shape_bits << 14);
|
(this->shape_bits << 14);
|
||||||
this->oam->attr1 = this->x |
|
this->oam->attr1 = this->x |
|
||||||
(AFFINE_FLAG_NONE_SET_YET << 9) |
|
(AFFINE_FLAG_NONE_SET_YET << 9) |
|
||||||
(HORIZONTAL_FLIP_FLAG << 12) |
|
(HORIZONTAL_FLIP_FLAG << 12) |
|
||||||
(VERTICAL_FLIP_FLAG << 13) |
|
(VERTICAL_FLIP_FLAG << 13) |
|
||||||
(this->size_bits << 14);
|
(this->size_bits << 14);
|
||||||
|
}
|
||||||
|
|
||||||
this->oam->attr2 = ATTR2_ID(tileIndex) |
|
this->oam->attr2 = ATTR2_ID(tileIndex) |
|
||||||
ATTR2_PRIO(priority) |
|
ATTR2_PRIO(priority) |
|
||||||
|
|
|
@ -72,10 +72,15 @@ void SpriteManager::copyOverSpriteOAMToVRAM() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpriteManager::copyOverImageDataToVRAM(Sprite *sprite) {
|
void SpriteManager::copyOverImageDataToVRAM(Sprite *sprite) {
|
||||||
const auto allocated = Allocator::allocateObjectTiles(sprite->imageSize);
|
if(!sprite->data && sprite->imageSize == 0) {
|
||||||
dma3_cpy(allocated.pointer(), sprite->data, allocated.size);
|
// assume it's copied over from another sprite
|
||||||
|
sprite->buildOam(sprite->tileIndex);
|
||||||
|
} else {
|
||||||
|
const auto allocated = Allocator::allocateObjectTiles(sprite->imageSize);
|
||||||
|
dma3_cpy(allocated.pointer(), sprite->data, allocated.size);
|
||||||
|
|
||||||
sprite->buildOam(allocated.getTileLocation());
|
sprite->buildOam(allocated.getTileLocation());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpriteManager::copyOverImageDataToVRAM() {
|
void SpriteManager::copyOverImageDataToVRAM() {
|
||||||
|
|
Loading…
Reference in New Issue