mmag

ハマったことメモなど

初回プッシュ以外でもプルリクをつくるリンクを表示する

remote: Resolving deltas: 100% (7/7), completed with 7 local objects.
remote:
remote: Create a pull request for 'baz' on GitHub by visiting:
remote:      https://github.com/foo/bar/pull/new/baz
remote:

このリンク。そのブランチを初めてプッシュしたときしか出してくれず不便なので、ググって.git/hooks/pre-pushに仕込んだ。

#!/bin/sh

branch=$(git rev-parse --abbrev-ref HEAD)
userRepo=$(git remote -v | grep fetch | awk '{print $2}' | grep "github.com" | cut -d':' -f2)

if [ -n "$userRepo" ]
then
  echo ""
  echo "Create PR at: https://github.com/$userRepo/compare/$branch?expand=1&labels=qux"
  echo ""
fi

よく使うラベルを指定することも可能。

細かくpackage.jsonでmainを指定しておくと便利

読んでなるほどと思ったのでメモ。言われてみれば確かにそう。

components
└── Button
    ├── Button.module.css
    └── Button.tsx

みたいな構造になっているときにButton.tsxをimportすると

import Button from '~/components/Button/Button'

と書かないといけない。index.tsにする手もあるけど全部index.tsになってしまう。そこで、ここにpackage.jsonを置いて

components
└── Button
    ├── Button.module.css
    ├── Button.tsx
    └── package.json
{
  main: "Button.tsx"
}

とすると

import Button from '~/components/Button'

でimportできる。

Phaser 3でコントローラーを使う

最近遊んでいたのでメモ。

PhaserにはScene Pluginという仕組みがあるようです。そこでthis.game.events.onupdate前にコールバックを仕込めるので、そこでコントローラー入力周りのお世話をしています。

// main.ts

import Phaser from 'phaser'
import { GamepadPlugin } from './plugins/gamepad'
import { GameScene } from './scenes/game'

new Phaser.Game({
  ...
  input: {
    gamepad: true,
  },
  scene: [GameScene],
  plugins: {
    scene: [
      {
        key: 'GamepadPlugin',
        plugin: GamepadPlugin,
        mapping: 'gamepad',
      },
    ],
  },
}
// plugins/gamepad.ts

type ControllerType = 'NintendoSwitchPro'
type Key = 'A' | 'B' | 'X' | 'Y' | 'L1' | 'L2' | 'R1' | 'R2' | 'UP' | 'DOWN' | 'LEFT' | 'RIGHT' | 'START' | 'SELECT'
type Button = {
  pressed: boolean
  justPressed: boolean
}

const mappings: Record<ControllerType, Record<Key, number>> = {
  NintendoSwitchPro: {
    A: 1,
    B: 0,
    X: 3,
    Y: 2,
    L1: 4,
    L2: 6,
    R1: 5,
    R2: 7,
    UP: 12,
    DOWN: 13,
    LEFT: 14,
    RIGHT: 15,
    START: 9,
    SELECT: 8,
  },
}

const button: Button = {
  pressed: false,
  justPressed: false,
}

export class GamepadPlugin extends Phaser.Plugins.ScenePlugin {
  private gamepad?: Phaser.Input.Gamepad.Gamepad
  private controllerType: ControllerType = 'NintendoSwitchPro'

  public readonly buttons: Record<Key, Button> = {
    A: { ...button },
    B: { ...button },
    X: { ...button },
    Y: { ...button },
    L1: { ...button },
    L2: { ...button },
    R1: { ...button },
    R2: { ...button },
    UP: { ...button },
    DOWN: { ...button },
    LEFT: { ...button },
    RIGHT: { ...button },
    START: { ...button },
    SELECT: { ...button },
  }

  constructor(scene: Phaser.Scene, pluginManager: Phaser.Plugins.PluginManager) {
    super(scene, pluginManager, 'GamepadPlugin')
  }

  boot() {
    this.game.events.on(Phaser.Core.Events.PRE_STEP, this.beforeUpdate, this)

    if (this.scene.input.gamepad.total === 0) {
      this.scene.input.gamepad.once('connected', (pad: Phaser.Input.Gamepad.Gamepad) => {
        this.gamepad = pad
        this.controllerType = this.detectController()
      })
    } else {
      this.gamepad = this.scene.input.gamepad.pad1
      this.controllerType = this.detectController()
    }
  }

  beforeUpdate() {
    if (this.gamepad) {
      const mapping = mappings[this.controllerType]

      Object.entries(mapping).forEach((entry) => {
        const button = entry[0] as Key
        const index = entry[1] as number

        const prevPressed = this.buttons[button].pressed
        const pressed = this.gamepad?.buttons[index].pressed ?? false

        this.buttons[button].justPressed = !prevPressed && pressed
        this.buttons[button].pressed = pressed
      })
    }
  }

  private detectController(): ControllerType {
    if (this.gamepad?.id.match(/Pro Controller/)) {
      return 'NintendoSwitchPro'
    } else {
      return 'NintendoSwitchPro' // fallback
    }
  }
}
// scenes/game.ts

import Phaser from 'phaser'
import { GamepadPlugin } from '../plugins/gamepad'

export class GameScene extends Phaser.Scene {
  private gamepad!: GamepadPlugin

  constructor() {
    super('GameScene')
  }

  preload() {}

  create() {}

  update(_time: number, delta: number) {
    if (this.gamepad.buttons.LEFT.pressed) {
      // 左
    } else if (this.gamepad.buttons.RIGHT.pressed) {
      // 右
    }
  }
}