wslでelixir その173

# 概要
wsl(wsl2じゃない)で、elixirやってみた。
練習問題やってみた。

# 練習問題
Livebookの、kino.jsで、弾幕を動作させよ。

# 写真



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/52bcab7b-9135-4634-b406-44b2b5d4d544.png)

# サンプルコード

```
defmodule KinoHTML.Bullet do
  use Kino.JS
	def new(tag) do
		Kino.JS.new(__MODULE__, tag)
	end
	asset "main.js" do
		"""
    var danmaku0;
  var SC_W = 400;
  var SC_H = 400;

    export async function init(ctx, tag) {
    await ctx.importJS("https://cdn.rawgit.com/daishihmr/bulletml.js/master/build/bulletml.min.js")
    ctx.root.innerHTML = `
            <canvas id="canvas"></canvas>
			`;
  danmaku0 = bulletml.buildXML(tag);
  var scene = new Scene();
  var player = new Player().addTo(scene);
  var danmakuConfig = {
    target: player,
    createNewBullet: function(runner, spec) {
      var bullet = new Bullet(spec);
      bullet.x = runner.x;
      bullet.y = runner.y;
      runner.onVanish = function() {
        bullet.remove();
      };
      bullet.update = function() {
        runner.update();
        this.x = runner.x;
        this.y = runner.y;
        this.areaTest();
      };
      bullet.addTo(scene);
    }
  }; 
  var enemyXML = new Hex(40, 30, 15, "hsl(290, 60%, 80%)").addTo(scene);
  enemyXML.danmakuRunner = danmaku0.createRunner(danmakuConfig);
  enemyXML.update = function(frame) {
      this.x = SC_W * .5 - Math.cos(frame * 0.01) * SC_W * .4;
      this.y = SC_H * .3 - Math.sin(frame * 0.03) * SC_H * .2;
      this.danmakuRunner.x = this.x;
      this.danmakuRunner.y = this.y;
      this.danmakuRunner.update();
  };
  scene.start();
}
var keyboard = {
    up: false,
    down: false,
    left: false,
    right: false
  };
  Array.prototype.erase = function(obj) {
    var idx = this.indexOf(obj);
    if (idx !== -1) 
      this.splice(idx, 1);
  };
  CanvasRenderingContext2D.prototype.fillHex = function(w, h) {
    this.beginPath();
    this.moveTo(Math.sin(Math.PI / 3 * 0) * w * .5, Math.cos(Math.PI / 3 * 0) * h * .5);
    for (var i = 1; i < 6; i++) 
    {
      this.lineTo(Math.sin(Math.PI / 3 * i) * w * .5, Math.cos(Math.PI / 3 * i) * h * .5);
    }
    this.closePath();
    this.fill();
  };
  HTMLCanvasElement.prototype.fitWindow = function() {
    var resize = function() {
      var rateWidth = this.width / window.innerWidth;
      var rateHeight = this.height / window.innerHeight;
      var rate = this.height / this.width;
      if (rateWidth > rateHeight) 
      {
        this.style.width = innerWidth + "px";
        this.style.height = innerWidth * rate + "px";
      } 
      else 
      {
        this.style.width = innerHeight / rate + "px";
        this.style.height = innerHeight + "px";
      }
    }.bind(this);
    window.addEventListener("resize", resize, false);
    resize();
  };
  var Scene = function() {
    var canvas = document.getElementById('canvas');
    canvas.width = SC_W;
    canvas.height = SC_H;
    canvas.fitWindow();
    this.context = canvas.getContext("2d");
    this.context.textAlign = "right";
    this.context.textBaseline = "top";
    this.frame = 0;
    this.sceneObjects = [];
  };
  Scene.prototype.start = function() {
    var renderFrame = function() {
      this.context.fillStyle = "black";
      this.context.globalCompositeOperation = "source-over";
      this.context.fillRect(0, 0, SC_W, SC_H);
      this.context.globalCompositeOperation = "lighter";
      var copied = [].concat(this.sceneObjects);
      for (var i = 0, end = copied.length; i < end; i++) 
      {
        copied[i].update(this.frame);
        copied[i].draw(this.context);
      }
      this.context.fillStyle = "white";
      this.frame += 1;
      requestAnimationFrame(renderFrame);
    }.bind(this);
    renderFrame();
  };
  Scene.prototype.addChild = function(obj) {
    obj.parent = this;
    this.sceneObjects.push(obj);
  };
  Scene.prototype.removeChild = function(obj) {
    obj.parent = null;
    this.sceneObjects.erase(obj);
  };
var Hex = function(w, h, radius, color) {
    this.radius = radius;
    this.x = 0;
    this.y = 0;
    this.color = color || "hsl(0, 60%, 80%)";
    this.canvas = document.createElement("canvas");
    this.canvas.width = w * 2;
    this.canvas.height = h * 2;
    var context = this.canvas.getContext("2d");
    context.globalCompositeOperation = "lighter";
    context.fillStyle = this.color;
    context.translate(w, h);
    context.globalAlpha = 1.0;
    context.fillHex(w, h);
    this.parent = null;
  };
  Hex.prototype = {
    constructor: Hex,
    update: function() {
    },
    draw: function(context) {
      context.fillStyle = this.color;
      context.save();
      context.translate(this.x, this.y);
      context.drawImage(this.canvas, -this.canvas.width * .5, -this.canvas.height * .5);
      context.restore();
    },
    addTo: function(parent) {
      parent.addChild(this);
      return this;
    },
    remove: function() {
      if (this.parent) 
        this.parent.removeChild(this);
      return this;
    }
  };
  var Bullet = function(spec) {
    Hex.call(this, 8, 8, 2, spec.color);
  };
  Bullet.prototype = Object.create(Hex.prototype);
  Bullet.prototype.areaTest = function() {
    if (this.x < 0 || SC_W < this.x || this.y < 0 || SC_H < this.y) 
    {
      this.remove();
      return;
    }
  };
  var Player = function() {
    Hex.call(this, 10, 10, 5, "hsl(120, 60%, 80%)");
    this.x = SC_W * 0.5;
    this.y = SC_H * 0.9;
    this.speed = 1.5;
  };
  Player.prototype = Object.create(Hex.prototype);
  Player.prototype.update = function(frame) {
    if (keyboard.left) 
      this.x -= this.speed;
    else if (keyboard.right) 
      this.x += this.speed;
    if (keyboard.up) 
      this.y -= this.speed;
    else if (keyboard.down) 
      this.y += this.speed;
    this.x = Math.max(0, Math.min(this.x, SC_W));
    this.y = Math.max(0, Math.min(this.y, SC_H));
  };
    """
  end
end

KinoHTML.Bullet.new("""
<bulletml>
  <action label="top">
    <repeat>
      <times>200</times>
      <action>
        <fire>
          <direction type="sequence">23</direction>
          <bullet/>
        </fire>
        <wait>1</wait>
      </action>
    </repeat>
  </action>
</bulletml>
""")
```

以上。