[Processing]マップスクロールとかアニメーションとかやってみた

#ピクセル配列を使ってマップスクロールする
Processingで
・キャラクターのアニメーション
・物理シミュレーション（重力）
・マップスクロール（ピクセル配列）

###Qなぜピクセル配列でマップスクロールするのか
**A.マップ変更が楽だから**
int型の二重配列にマップ情報を入れてると、変更の面倒くささが面倒くさくて頭痛が痛くなるやつだからです（伝われ）
その面倒くささをなくすために、もっと面倒なことになりましたがね（ほんっと苦労した）

マップを変更したい場合は画像を変えればできます
（背景の色の変数にその画像の背景色の数値を入れるのを忘れないように）

###実行結果
![MoveMap.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542691/d8b2eac4-498b-2b60-1e76-f49de90572ba.gif)

###使用プログラム
拡張子本当は.pdeですけど、javaにした方が色ついて見やすいかなって

```MoveMap.java
/*
*実行画面をマウスクリックすると始まります
*背景の色と違う色を地面と認識させています
*/


//アニメーションの種類
enum animMode {idle, move, jump}

Player player;//プレイヤーコントローラー
PImage MAP;//地形情報
//背景の色をprintで表示した値
final int backColor = -12400902;
boolean up, right, left;//キー入力
boolean start = false;

void setup() {
  size(1000, 500);
  //fullScreen();
  frameRate(30);
  imageMode(CENTER);

  //マップの読み込み
  MAP = loadImage("MAP.png");
  MAP.loadPixels();
  //プレイヤー作成
  player = new Player(new Anim("Player", 10, 0.05f));
  player.setIdle(2);//待機状態の画像番号
  player.setJump(5, 0);//ジャンプ状態と降下状態の画像番号
}
void mousePressed(){start = true;}
void draw() {
  int left =(int)player.x- width/20;//表示するマップの左の座標
  int right=(int)player.x+ width/20;//表示するマップの右の座標
  int top = (int)player.y- height/100 * 7;//表示するマップの上の座標
  int bottom = (int)player.y+ height/100 * 3;//表示するマップの下の座標
  //println("x:"+left + "-"+right);
  //println("y:"+top + "-"+bottom);
  pushMatrix();
  translate(-joyo(player.x,10),-joyo(player.y,10));
  for (int i=top-1; i<bottom+1; i++) {
    int leng = i * MAP.width; //計算量を減らすためのキャッシュ
    for (int j=left-1; j<right+1; j++) {
      fill(MAP.pixels[leng+j]);   //ピクセル配列から色を取得
      rect((j-left)*10, (i-top)*10, 10, 10);  //色つきの四角を描画
    }
  }
  popMatrix();
  if(!start) return;
  
  player.update();
  fill(255, 0, 0);
  //Playerの現在位置の目印
  rect(width/2, height/10 * 7, 10, 10);
}
//アニメーションクラス
class Anim {
  int num = 0;//現在の配列番号
  float timer = 0;//タイマー値保持
  float time = 0;//タイマー差異
  PImage[] anim;//アニメーション配列

  Anim(String name, int num, float interval) {
    anim = new PImage[num];
    for (int i=0; i<num; i++)anim[i] = loadImage(name + i +".png");
    timer = interval;
    time = millis();
  }

  void draw() {
    image(anim[num], 0, 0);

    if (millis() < time) return;

    time = millis() + timer * 1000;
    if (++num >= anim.length)num = 0;
  }
} //class Anim end }

//プレイヤーコントローラー
class Player {
  //アニメーションモード
  animMode am = animMode.idle;
  //位置
  float x=0, y = 0;
  //重力値
  float rigid = 0;
  //X軸方向の向き（画像反転用）
  float scaleX = 1;
  //地面の高さ
  float ground = MAP.height;
  //使用画像（1枚絵）
  PImage jump;
  //各アニメーションの番号
  int idle, jumpUp, jumpDawn;
  //アニメーション（移動）
  Anim move;
  //移動速度
  float speed = 1f;
  //x方向の速度
  float veloX = 0;
  //地に足のついた
  boolean grounded = false;

  //移動アニメーションと初期位置
  Player(Anim a) {
    move = a;
    jump = a.anim[0];
    x = width/10;
    y = MAP.height/3;
  }

  void setIdle(int ima) {idle = ima;}
  void setJump(int up, int dawn) { 
    jumpUp = up;
    jumpDawn = dawn;
  }

  void update() {
    rigider();
    grounded = grounded();
    if (grounded) {//地に足のついた
      if ( ! input()) {
        am = animMode.idle;//入力なければ待機
        if (abs(veloX) > 0)veloX *= 0.6f;//減衰調整
      }
    } else {//空中
      am = animMode.jump;
      move.num = rigid < 0 ? jumpUp : jumpDawn;
      jump = move.anim[move.num];
    }
    if (canMove()) {
      x += veloX;
    } else {
      am = animMode.idle;
    }
    pushMatrix();
    translate(width/2,(height/10 * 7)-jump.height/2+10);
    scale(scaleX, 1);
    switch(am) {
    case idle:
      image(move.anim[move.num = idle], 0, 0);
      break;
    case move:
      move.draw();
      break;
    case jump:
      image(jump, 0, 0);
      break;
    default:
      break;
    }
    popMatrix();
  }//void update() end }

  //入力判定
  boolean input() {
    if (right) {
      player.am = animMode.move;
      player.scaleX += player.scaleX < 1 ? 0.25f : 0;
      veloX = speed;
    }
    if (left) {
      player.am = animMode.move;
      player.scaleX += player.scaleX > -1 ? -0.25f : 0;
      veloX = -speed;
    }
    if (up) {
      player.am = animMode.jump;
      player.jump(3);
    }
    return up || right || left;
  }
  //重力設定
  void rigider() {
    if (grounded)y = ground;//地面足が着いているなら地面の位置
    else y += rigid += 0.2f;//加速度をy方向の変化量に加える
  }
  //地に足のついた
  boolean grounded() {
    //println("y:"+y+"-"+rigid);
    for (int i=(int)y; i<y+rigid; i++) { //現在地から加速度分まで地面がないか探索
      if (MAP.pixels[(int)i*MAP.width + (int)x] != backColor) {
        ground = i-1;
        return true;
      }
    }
    return false;
  }
  //進行方向に移動可能かチェック
  boolean canMove() {
    if (MAP.pixels[(int)y*MAP.width+(int)x + (int)sign(scaleX)] == backColor)return true;
    else if (MAP.pixels[(int)(y-1)*MAP.width+(int)x + (int)sign(veloX)] == backColor) {
      y-=0.1f;
      return true;
    }
    return false;
  }
  //ジャンプ
  void jump(float force) {
    if (grounded) {
      rigid = -force;
      grounded = false;
    }
  }
}//class Player end }

//複数入力に対応
void keyPressed() {
  switch (keyCode){
    case UP:up = true;break;
    case RIGHT:right = true;break;
    case LEFT:left = true;break;
  }
}
void keyReleased() {
  switch (keyCode){
    case UP:up = false;break;
    case RIGHT:right = false;break;
    case LEFT:left = false;break;
  }
}

float sign(float a) {
  return a>0 ? 1 : -1;
}
int sign(int a) {
  return a>0 ? 1 : -1;
}

float joyo(float a,float b){
  a = a % b;
  return a == b ? 0 : a;
}
```
###使用画像
以下の画像があれば実行できます
プロジェクト直下　あるいは　dataフォルダの中に入れてください

MAP.png
![MAP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542691/d2719e43-5bf9-f073-cb45-86268ab4caa8.png)

Player0.png～Player9.png
[お手本にしたイラスト](https://illustkun.com/wild-boar)
![Player0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542691/4505fada-31e4-4560-8642-8485fa16f0c4.png)
![Player1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542691/7709f365-39ff-4310-b27d-6b36a049db4c.png)
![Player2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542691/0d4f8e75-11f4-4e05-97d5-7491144ff6a0.png)
![Player3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542691/daeff682-ab5b-9bdc-8ac0-bb72150443be.png)
![Player4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542691/7ebb952b-2216-a1d4-7aa8-1c16a0c30da0.png)
![Player5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542691/55ba671d-e29e-191e-7ef1-3d1fea950059.png)
![Player6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542691/33e96926-3dd0-6f9d-0677-411f3166ce35.png)
![Player7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542691/7a822046-2112-d8f6-b058-fe53506d57ed.png)
![Player8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542691/8cd9093b-0b88-6cc8-d512-ac280fc32fad.png)
![Player9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542691/ce369bbd-005b-5ede-6663-4de32ba94c11.png)