LovyanGFX で画面描画(3):スプライト描画

# スプライト

古のホビーPCやレトロゲーム機などでおなじみだったスプライト機能。
本来はハードウェアで高速描画をするものでしたが、扱いやすさから同様の機能をソフトウェアで実現したものも多くあります。

https://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%97%E3%83%A9%E3%82%A4%E3%83%88_(%E6%98%A0%E5%83%8F%E6%8A%80%E8%A1%93)


LovyanGFX もドライバでスプライト機能が実現されています。ゲーム機のスプライトとは異なり、スプライト描画命令でスプライトに指定された画像をオブジェクト内に上書き描画するという概念です。これを活用することで、簡単に楽しい描画をすることができます。


# サンプルコード


```
    
#define LGFX_USE_V1
#include <LovyanGFX.hpp>
#include <LGFX_AUTODETECT.hpp>

LGFX display ( 128, 64 , 5 );
static LGFX_Sprite sprite(&display);

void setup()
{
  display.init();
  sprite.createSprite( 16,16);
  sprite.fillRect(0,0,15,15,TFT_WHITE);
  sprite.pushSprite(0, 0);
}

void loop()
{
}


```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/c6ebf0f2-f955-df55-7b9c-3e2a4809beb7.png)


16x16 のスプライトを表示してみました。一番簡単に、白い豆腐が表示されています。うーん、もうちょっと楽しくしたい・・・

# アニメーション

プログラムを以下のように変更します。
 
```
#define LGFX_USE_V1
#include <LovyanGFX.hpp>
#include <LGFX_AUTODETECT.hpp>

LGFX display ( 128,64,5 );
static LGFX_Sprite sprite(&display);

void setup()
{
  display.init();
  sprite.createSprite(17,17);
  sprite.fillCircle(8,8,8,TFT_RED);
  sprite.fillRect(2,6,13,5,TFT_WHITE);
}

void loop()
{
  for(int i=0; i<128; i++){
    display.clear();
    display.fillRect(5,5,25,25,display.color888(127,127,127));
    sprite.pushSprite(i,0,0);
    SDL_Delay(50);
  }
}


```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/420bc603-161f-ae06-911c-afcc348a6e36.png)

標識マークが移動していきます。

` pushSprite(i,0,0); ` のように、第3引数があるとそのパレット色を抜いて描画します。


# スプライトの回転、拡大縮小

以下で r 角度に回転、 xscale,yscale で拡縮したものを x, y 座標に描画するようになります。

```
  sprite.pushRotateZoom(x,y,r,xscale,yscale);
```

回転軸は以下のように指定します。

```
  sprite.setPivot(sprite.width()/2.0, sprite.height()/2.0);
```

# 複雑なスプライト

```
LGFX display ( 128,64,5 );
static LGFX_Sprite sprite(&display);
static LGFX_Sprite sprite2(&sprite);
void setup()
{
  display.init();
  sprite.createSprite(65, 65);
  sprite2.createSprite(16, 3);
  sprite.fillCircle(32,32,32,TFT_WHITE);
  sprite2.fillRect(0,0,16,2,TFT_RED);
  sprite2.pushSprite(24,31,0);
  sprite.pushSprite(0,0,0);
}
```
のようにすると、sprite 中に sprite2 を使って描画できます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/133b41a5-1769-acaa-664c-b94faf1aaf92.png)

もちろん、sprite3,sprite4 なども親子関係でどんどん建て増しできます。


sprite2 を回転して複数回 sprite に描画してみました。

```
#define LGFX_USE_V1
#include <LovyanGFX.hpp>
#include <LGFX_AUTODETECT.hpp>

LGFX display ( 320,200,2 );
static LGFX_Sprite sprite(&display);
static LGFX_Sprite sprite2(&sprite);
void setup()
{
  display.init();
  sprite.createSprite(256, 256);
  sprite2.createSprite(30, 5);
  sprite.fillCircle(128,128,128,TFT_WHITE);
  sprite2.drawGradientLine(0,0,30,0,sprite.color888(227,227,164),sprite.color888(227,227,227));
  sprite2.drawGradientLine(0,1,30,1,sprite.color888(220,220,164),sprite.color888(220,220,220));
  sprite2.drawGradientLine(0,2,30,2,sprite.color888(210,210,164),sprite.color888(210,210,210));
  sprite2.drawGradientLine(0,2,30,3,sprite.color888(200,200,164),sprite.color888(200,200,200));
  sprite2.drawGradientLine(0,2,30,4,sprite.color888(190,190,164),sprite.color888(190,190,190));
  sprite2.setPivot(128, 2);
  for ( int i=0; i < 12; i++){
    sprite2.pushRotateZoom(128,128,360/12*i,1.0,1.0,0);
  }
}
void loop()
{
  for(int i=0; i<320; i++){
    display.clear();
    display.fillRect(50,50,250,250,display.color888(127,127,127));
    sprite.pushRotateZoom(i,128,i,0.5,0.5,0);
    SDL_Delay(50);
  }
}
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/459098b3-148a-898d-a41c-cef3d96c9956.png)


時計なんかが簡単に描けそうですね!