2019-04-01に更新

エイプリルフールはじめました

リリースしてからはじめてのエイプリールフールだったのでちょっと遊んでみました。ふわふわと飛んでいるのはくりえいとくんです。

元々

Crieit

という文字が顔に見えたのでそれをそのまま絵にしてみたらおばけになった、という感じです。クリックすると色々喋ります。

特筆することも無いので動き回らせているプログラムでも貼っておきます。

おばけクラス

move()で動かし、getX()getY()で表示するための位置を取得しているだけのよくあるクラスです。

Goast.ts

const ymax = 50
const width = 100

export default class Ghost {
  id: number
  private x = 0
  private y = 0
  private basey = 0
  private ax = 0
  private angle = 0

  constructor() {
    this.id = Date.now()

    if (Math.round(Math.random()) === 0) {
      this.x = -width
      this.ax = Math.floor(Math.random() * 2 + 2)
    } else {
      this.x = window.innerWidth
      this.ax = -Math.floor(Math.random() * 2 + 2)
    }

    this.basey = Math.floor(Math.random() * window.innerHeight)
    this.calculateY()
  }

  calculateY() {
    this.y = this.basey + Math.sin(this.angle) * ymax
  }

  move() {
    this.x += this.ax
    this.angle += Math.PI / 50
    if (this.angle >= Math.PI * 2) {
      this.angle -= Math.PI * 2
    }
    this.calculateY()
  }

  finished() {
    if (this.ax < 0 && this.x < -width) {
      return true
    }
    if (this.ax > 0 && this.x > window.innerWidth) {
      return true
    }
    return false
  }

  getX() {
    return this.x
  }

  getY() {
    return Math.floor(this.y)
  }

  getAx() {
    return this.ax
  }
}

おばけたちの管理コンポーネント

これも特に特筆することのない単なるゲームループ的なコンポーネントです。おばけを管理して画面からはみ出したら削除したりしています。

<template>
  <div>
    <AprilfoolGhost v-for="ghost in ghosts" :key="ghost.id" :ghost="ghost"></AprilfoolGhost>
  </div>
</template>

<script lang="ts">
import { Vue, Component, Prop } from 'vue-property-decorator'
import Aprilfool from './Aprilfool.vue'
import AprilfoolGhost from './AprilfoolGhost.vue'
import Ghost from './Ghost'

@Component({
  components: { AprilfoolGhost }
})
export default class AprilfoolGhosts extends Aprilfool {
  ghosts: Ghost[] = []

  mounted() {
    if (!this.isAprilfool()) {
      return
    }
    setInterval(() => {
      if (this.ghosts.length < 10) {
        this.ghosts.push(new Ghost())
      }
    }, 5000)
    setInterval(() => {
      this.moveAll()
    }, 41)
  }

  moveAll() {
    const ghosts: Ghost[] = []
    this.ghosts.forEach((ghost, index) => {
      ghost.move()
      if (!ghost.finished()) {
        ghosts.push(ghost)
      }
    })
    this.ghosts = ghosts
  }
}
</script>

おばけコンポーネント

もう動きはおばけクラス、管理は前述のコンポーネントで行われているので、ここでは表示したりクリックイベントを処理したりするだけです。これで一通り完了です。面倒だったので表示はfixedにしてスクロールは考慮しないようにしています。

<template>
  <div>
    <a @click.prevent="showMessage()" :style="getStyle()">
      <img src="/img/aprilfool/crieit.png" :class="getClass()">
    </a>
    <div :style="getFukidashiStyle()" class="fukidashi">
      <div class="d-flex justify-content-center align-items-center">
        <div v-html="message"></div>
      </div>
    </div>
  </div>
</template>

<script lang="ts">
import { Vue, Component, Prop } from 'vue-property-decorator'
import Ghost from './Ghost'

const messages = [
  'Happy Halloween!',
  'Trick or Treat??',
  :
  :
]

@Component
export default class AprilfoolGhost extends Vue {
  @Prop(Object) ghost: Ghost

  isMessageShown = false
  message = ''

  getStyle() {
    return {
      left: `${this.ghost.getX()}px`,
      top: `${this.ghost.getY()}px`
    }
  }

  getClass() {
    return {
      reverse: this.ghost.getAx() < 0
    }
  }

  getFukidashiStyle() {
    return {
      left: this.ghost.getX() - 200 + 'px',
      top: this.ghost.getY() - 200 + 'px',
      opacity: this.isMessageShown ? 1 : 0
    }
  }

  showMessage() {
    if (this.isMessageShown) {
      return
    }
    this.message = messages[Math.floor(Math.random() * messages.length)]
    this.isMessageShown = true
    setTimeout(() => {
      this.isMessageShown = false
    }, 5000)
  }
}
</script>

<style scoped>
div > * {
  display: block;
  position: fixed;
  opacity: 0.8;
}

.reverse {
  transform: scale(-1, 1);
}

.fukidashi {
  background: url(/img/aprilfool/fukidashi.png);
  width: 274px;
  height: 200px;
  opacity: 0;
  transition-duration: 0.2s;
}

.fukidashi > div {
  margin-left: 40px;
  margin-top: 20px;
  width: 200px;
  height: 100px;
  font-size: 1.8rem;
}
</style>

まとめ

さあ、みなさんも新元号のことは忘れてエイプリールフールやりましょう。今からでも間に合います!!!!!(?)


だら@Crieit開発者

Crieitの開発者です。 主にLAMPで開発しているWebエンジニアです(在宅)。大体10年程。 記事でわかりにくいところがあればDMで質問していただくか、案件発注してください。 業務依頼、同業種の方からのコンタクトなどお気軽にご連絡ください。 業務経験有:PHP, MySQL, Laravel5, CakePHP3, JavaScript, RoR 趣味:Elixir, Phoenix, Node, Nuxt, Express, Vue等色々

Crieitは個人で開発中です。 興味がある方は是非記事の投稿をお願いします! どんな軽い内容でも嬉しいです。
なぜCrieitを作ろうと思ったか

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください!

ボードとは?

関連記事

コメント