Hatena::Groupjavascript

JavaScriptで遊ぶよ

 | 

2009-07-15

ラングトンの蟻をcanvasでやってみる

05:14

リンク先のデモがおもしろかったので、 canvas を使ってやってみた。

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>Langton's ant</title>
<script type="text/xaml" id="xaml"><?xml version="1.0"?>
  <Canvas xmlns="http://schemas.microsoft.com/client/2007"></Canvas></script>
<script type="text/javascript" src="http://uupaa-js-spinoff.googlecode.com/svn/trunk/uupaa-excanvas.js/uupaa-excanvas.js"></script>

<script>
function $(id){return document.getElementById(id);};
var WORLD_SIZE = 100;
var CELL_SIZE = 3;

function Ant(world,x,y,vx,vy,ageDisp){
  this.world = world;
  this.ageDisp = ageDisp || {};
  this.age = 0;
  this.x = x;
  this.y = y;
  this.vx = vx;
  this.vy = vy;
}
Ant.prototype.move = function(){
  this.x += this.vx;
  this.y += this.vy;
  this.ageDisp.innerHTML = ++this.age;
  if (this.x < 0 || this.x >= WORLD_SIZE || this.y < 0 || this.y >= WORLD_SIZE) {
    return this.die();
  }
  if (this.world[this.x][this.y].getAndToggleColor()) {
    var tmp = this.vx;
    this.vx = this.vy;
    this.vy = -tmp;
  } else {
    var tmp = this.vx;
    this.vx = -this.vy;
    this.vy = tmp;
  }

  var self = this;
  setTimeout(function(){self.move()},0);
}
Ant.prototype.die = function(){
  alert('Langton\'s ant is dead.');
}

function Cell(ctx,x,y){
  this.color = false;
  this.ctx = ctx;
  this.x = x;
  this.y = y;
}
Cell.prototype.getAndToggleColor = function(){
  this.color = !this.color;
  if (this.color) {
    this.ctx.fillRect(this.x,this.y,CELL_SIZE,CELL_SIZE);
  } else {
    this.ctx.clearRect(this.x,this.y,CELL_SIZE,CELL_SIZE);
  }
  return !this.color;
}

window.onload = function(){
uuCanvas.ready(function() {
  var canvas = $('canvas');
  canvas.height = CELL_SIZE*WORLD_SIZE;
  canvas.width = CELL_SIZE*WORLD_SIZE;
  canvas.style.cssText = 'border:1px solid #999;'
  var ctx = canvas.getContext('2d');

  var world = [];
  for(var x=0; x<WORLD_SIZE; x++){
    world[x] = [];
    for (var y=0; y<WORLD_SIZE; y++){
      world[x].push(new Cell(ctx, x*CELL_SIZE, y*CELL_SIZE));
    }
  }
  var lang_ant = new Ant(world,60,40,0,-1,$('step'));

  var run = $('run');
  run.disabled = false;
  run.onclick = function(){lang_ant.move(); this.disabled = true;};
})
}

</script>
</head>
<body>
<p><input type="button" value="run" id="run" disabled="disabled"> <span id="step"></span>
 <input type="button" value="stop &amp; refresh" onclick="location.reload();"></p>
<canvas id="canvas"></canvas>
  • 2色なので clearRect と fillRect でいい。色指定もなし。
  • 元のコードは setInterval(..,5) でやっているが、こちらは setTimeout(..,0) を連続して呼んでいる。
    • ブラウザ上での実行速度は、描画速度よりも setTimeout が呼ばれるまでの速さに多分に影響を受けるかもしれない。(未確認)
  • id:uupaa さんの uupaa-excanvas.js を一応ロードしてあるので、もしかしたら IE でも動くかも。(動いたら教えてください)

コメントいただいたところなどを修正。

SongmuSongmu2009/07/16 11:33ソース元の作者です。Canvasでも(の方が)全然高速に動きますね。すばらしい!いろいろ勉強になります。

IEでも動いてます!しかも高速。ただ残念ながらボックスのheightが短く表示されてしまっています。これはライブラリの問題ですかね。でもこのuupaa-excanvas.jsはIEでもCanvasが高速に動くので凄い。

ちなみに元のプログラムでcanvasを使わなかったのはcanvasの知識があまりなく、canvasがこんなに高速に動くとは思ってなかったのと、divを並べればスタイルシートを切り替えて、表示の切り替え(罫線を引くとか)なんかも出来るかなと考えていたからだったりします。

edvakfedvakf2009/07/17 00:46もしかしたら style を弄るんじゃなくて class を付けたり外したりするだけだったらよかったのかも。試してませんけど。

IE で canvas の高さが変ということですが、
canvas.height = CELL_SIZE*WORLD_SIZE;
canvas.width = CELL_SIZE*WORLD_SIZE;
のあたりが問題なのかな。HTML 部分に書いたらよかったのかもしれませんね。

hnakamur5hnakamur52009/07/17 04:26おもしろいサンプルありがとうございます。div版と見比べるとどうも動きが違うと思ったらclearRectとfillRectが逆になってますね。あとdieを呼ぶ条件判定とageのインクリメントの順序も逆です。これで完全に同じ動きになりましたよ。

edvakfedvakf2009/07/17 05:07ちゃんと作ってないのがバレバレですね。
修正しときました。

トラックバック - http://javascript.g.hatena.ne.jp/edvakf/20090715
 |