2015年9月2日水曜日

d3.jsでチャートを作る ラインチャートとバーチャートを2つのy軸上に描画する

d3.js周りを調査して、簡易なチャートをいくつか作ったので後々のためにまとめておく。今回は2つのy軸上にラインチャートとバーチャートをプロットする。

他のチャートはこちら
d3.jsでチャートを作る ツールチップ
d3.jsでチャートを作る パイチャート



JSFiddleに動作するサンプルをあげてあるので詳細はそちらを参考にしてもらいたいが、簡単に解説しておく。なおd3.jsはdata, enterの仕組みが理解できていないと一見しても意味不明なコードになるのでチュートリアル的なものをどこかで一読されることをお勧めする。

JSFiddleはこちら

データを用意する。
var data = [
      { name:'Branch A', sales: 5400, forecast: 7000 },
      { name:'Branch B', sales: 2800, forecast: 4500 },
      { name:'Branch C', sales: 3600, forecast: 3300 },
      { name:'Branch D', sales: 1700, forecast: 4700 },
      { name:'Branch E', sales: 2200, forecast: 5500 }
  ];

svg要素を用意する。
var margin = { top: 50, right: 100, bottom: 40, left: 40 }
      , width = 800 - margin.left - margin.right
      , height = 300 - margin.top - margin.bottom
      , svg = d3.select('#item-container').append('div').append('svg')
                  .attr('width', width + margin.left + margin.right)
                  .attr('height', height + margin.top + margin.bottom)
                  .append('g')
                  .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

X軸。ここでscaleにはordinal()を使用している。他に線形のlinear()と時系列用のtime()が使用できる。
// x軸は文字列なのでordinalにするのとrangeRoundPointsでちょうど良い場所を取得する
  var x = d3.scale.ordinal()
              .domain(data.map(function (d) { return d.name; }))
              .rangeRoundPoints([0, width], 0.5);
  var xAxis = d3.svg.axis().scale(x)
                  .orient('bottom');
  svg.append('g')
      .attr('class', 'x axis')
      .attr('transform', 'translate(0, ' + height + ')')
      .call(xAxis);

   // x軸のTickの文字を斜めにする
   svg.selectAll(".x text")
        .attr("transform", function (d) {
            return "translate(" + this.getBBox().height * -2 + "," + this.getBBox().height + ")rotate(-45)";
        });

一つ目のY軸。domain()に0から売り上げと予想の最大値を指定している。またnice()でよさげにtickを調整してもらう。range()がheightから0になっているのはSVGの(0, 0)は左上をさすため。
// 一つ目のy軸。売り上げと予想から最大値を取得する
  var y = d3.scale.linear().nice()
              .domain([0, d3.max(data, function (d) { return Math.max(d.sales, d.forecast); })])
              .range([height, 0]);
  var yAxis = d3.svg.axis().scale(y)
              .orient('left')
              .ticks(5);
  var gy = svg.append('g')
      .attr('class', 'y axis')
      .call(yAxis);
  // テキストを表示する
  gy.append('text')
      .attr('transform', 'rotate(-90)')
      .attr('y', 16)
      .style('text-anchor', 'end')
      .text('万円');

二つ目のY軸。右端にtransform.translateで移動する。また横線を引くためにd3が追加してくれたtickのg要素があるのでそこに横線用のline要素を追加して描画している。
// 二つ目のy軸。売り上げと予想の割合を表示する
  var y2 = d3.scale.linear().nice()
              .domain([0, 150])
              .range([height, 0]);
  var yAxis2 = d3.svg.axis().scale(y2)
              .orient('right');
  var gy2 = svg.append('g')
      .attr('transform', 'translate(' + width + ',0)')
      .attr('class', 'y2 axis')
      .call(yAxis2);
  // 横線を描画する
  gy2.selectAll('g').filter(function(d) { return d; })
      .append('line')
      .attr('x1', -width)
      .attr('x2', 0)
      .classed('minor', true);
  // テキストを表示する
  gy2.append('text')
      .attr('transform', 'rotate(-90)')
      .attr('y', -10)
      .style('text-anchor', 'end')
      .text('%');

ラインチャート。二つ目のY軸で高さを算出している。
// ラインチャート。売り上げと予想の割合を表示する
  var linePlaceHolder = svg.append('g');
  var percentLine = d3.svg.line()
              .x(function (d) { return x(d.name); })
              .y(function (d) { return y2((d.sales / d.forecast) * 100); });
  linePlaceHolder.append("path")
                  .datum(data)
                  .attr("class", "line percent")
                  .attr("d", percentLine);

バーチャート。一つ目のY軸で高さを算出している。またX軸のscaleでrangeRoundPoints()を指定しているおかげでちょうど良い感じの座標が取得できている。ここらへんは色々いじってためしてもらいたい。
// バーチャート。売り上げと予想を表示する
  // bars
  var bar = svg.selectAll('.bar')
      .data(data)
      .enter()
      .append('g')
      .attr('class', 'bar')
      .attr('transform', function(d) { return 'translate(' + (x.rangeBand() / 2 + x(d.name)) + ',0)'; });

  // 売り上げ
  bar.append('rect')
      .attr('class', 'sales')
      .attr('x', -10)
      .attr('y', function (d) { return y(d.sales); })
      .attr('height', function (d) { return height - y(d.sales); })
      .attr('width', 10);

  // 予想
  bar.append('rect')
      .attr('class', 'forecast')
      .attr('y', function (d) { return y(d.forecast); })
      .attr('height', function (d) { return height - y(d.forecast); })
      .attr('width', 10);

2015年3月12日木曜日

libgdxで2つ目のゲームを作ったので宣伝

スマホ用のゲームを作りました。

・作ったゲーム
スーパーホッケー

Get it on Google Play


・感想(ゲーム開発全般)
昨年中にこのゲームはリリースする予定だったのが、やる気の低下やらDragon Age Inquisitionやら、さらに延期したMy締め切りである一月中という目標も低下したやる気ではかなわず、結局Android版ができたのは二月末。毎月簡単なゲームをポンポンリリースしていこうかと思っていたけど、いやー、大変すわ、これは。おもにやる気の部分で。結局このゲーム用に凝ったものを作る気持ちが出てこなかったのでスーパーバレーボールから画像を流用しまくってお茶を濁すことに。なんだろ、多分これ作っても見返りほとんど無いしなぁ、って思いがゲーム作りたいって気持ちより強くなっちゃってやる気がでてこなかったんだろうな。次回はもっと新しいことにチャレンジしよう。じゃないと面白くないね。

・感想(libgdx周り)
libgdxでの開発は大分なれた。次回はfontやらsoundあたりをしっかりと組み込んでみようかな、と思案中。

2015年2月19日木曜日

.NETプログラム実行時にDLLの参照エラーになったときようのツール

実行時にDLLが見つからずにエラーになるのはままあることで原因を特定するのはさほど難しくないけれど面倒な作業である。とくにライブラリで参照しているDLLと呼び出し元のプロジェクトで参照しているDLLに差が出ることは、Nugetでパッケージを取得することが増えた昨今はよく起こる。

ということが今の職場でよく起きてそれを調べる用のツールを作ったので公開する。

Missing Reference Finder
https://github.com/yooontheearth/missing-reference-finder



使い方はいたって簡単。Pathにbin等のフォルダを指定してcheckボタンを押下するだけ。指定のフォルダかGACにないものはMISSING扱いになる。

2014年9月28日日曜日

libgdxでスマホ用のゲームを作っての感想

今年に入ってからの仕事で調べた物を社内のWikiにまとめるという作業がとても多いのでこちらのブログに書くモチベーションがまったくあがらず放置しまくっていたけれど久しぶりに仕事とは離れたネタができたので更新。

前々から何らかのゲームを作りたいなとAndroid用にAndEngineをいじくってみたりHtml5用にEaselJSで遊んでみたりしてみたけどどうにもしっくりこない。そんなこんなで月日は流れたけれど今年の夏に一念発起して二ヶ月に一本ぐらいのペースでゲームをリリースしていこうと決めた。

で、八月の頭からゲーム開発を余暇を使ってしてきたんだけど先ほどつつがなく一本目のリリース(2014/11/06につつがなくApp Storeへのリリースも完了)が終わったので宣伝やら何やらも兼ねて楽しかったり大変だったりしたことをまとめたのが以下。今回は主に開発環境周りで。

・作ったゲーム
宣伝です。

Get it on Google Play



余談:「バレーボール ゲーム」で調べたらあんまり出てこなかったので油断して「Slime Volleyball」って名前にして作ってたらまんま同名の10万回ぐらいダウンロードされてるタイトルがあって内容も似てたのでとりあえず「Super Volleyball」にしてお茶を濁す。


・フレームワーク
libgdx
AndEngineとかEaselJSをいじってみて思ったんだけど同じ製品をAndroid用、Html用、iOS用とか作り分けるのはやっぱりめんどい。他プラットフォーム用に製品を作るのはロジック部分とかほぼほぼ転用できるので開発は思いのほか楽なんだけどそれでもメンテナンスを考えるとめちゃめんどい。リソースが自分ひとりで開発からグラフィック、リリースとかまで全部やるのにこれはかなりの重労働になるのでうまいこと他プラットフォーム用のコードを生成してくれるフレームワークがないかなぁと思っていて見つけたのがこれ。

Unityも考えたけどlibgdxはフリーだし必要そうな機能も満たしてたのでこちらへ。javaで開発できるのもいいね。C#でもできるっぽいけどC++とか今更触りたくないよ。

・libgdxの感想
さくさく開発できた。libgdxはビルドをGradleに任せてるんだけどそのお陰か私のメインIDEであるIntelliJ Ideaでのセットアップもすぐに完了し即コーディングに入れたのはベリーグッド。グッジョブだ。Box2dとかも初期設定で参照するようにできるし簡単だった。ただねGradleのことが良く分かってなかった(今現在もポワポワしてる)ので何らかのサードパーティのライブラリを追加するのは結構骨が折れたしこれからも骨が折れそう。

・コーディング周りの感想
scene2dという形でScreen、Actor、Actionとか画面の要素をうまいことまとめて使えるようにしてくれてるけどまだ自分の中でしっくりきてないしまだまだこなれてない。それなので模索しながら開発しつつ今現在もまだモヤモヤしたまま。けれど可能性は十分あると感じた。やっぱController的なレイヤーをしっかりと作ってView的な要素ともっと明確にわけたほうがスコアとか画面のステートとかがごちゃごちゃせずにすっきりするだろうなという感じ。

・フォント
これは今もってどうしたほうが良いのか謎。今回みたいにほとんどテキスト表示するものが無いものはあんまりこだわる必要もなくデフォルトのを使えばよいかなぁと思った。ちょっと凝った部分は画像を文字として使うことになるし。多言語化とか考えたら文字を画像にするのとかご法度だろうけど。

・ツール類
Texture Packerの存在を途中まで認識しておらず最初のころは自前で複数の画像を一枚の画像につめてその画像内の座標を指定して表示用に抜き取ったりという狂気の沙汰を続けていたのだけれどTexture Packerさんにご足労いただいてからはその自死一歩手前から引き返すことができた。とても便利。

さらにPhysics Body Editorなるめちゃんこ優秀なツールもあるのでBox2dを使う方は目を通されるとよいかと。

あとは2D Particle Editorとかもある。未使用なのでまだいまいち把握していないけれどエフェクトを派手にするためにも次のゲームでは使ってみようと考えている。

・マネタイズ
libgdxを選んだ理由にAdMobとかとの統合のチュートリアルがちゃんとあるというのも大きなウェートを占める。少し苦労したけれど無事にAdMobを実装し広告が出せるようになった。いずれはiOS版も出そうとは考えているけれどそっちはまだあまり調べていないので少し謎だけど一応問題なくできそう。

・グラフィック
Ink Scapeを使用。グラフィックの勉強をちゃんとしたこともないしPhotoShopで適当に画像をいじったりとかしかしたことなかったけれどInk Scapeは優秀なのでネットに転がってるチュートリアルを参考にいくつかサンプルを作ったりしてたら大分慣れてきてほぼほぼ満足いくキャラとか背景とかが作れた。まだ隠された機能がたくさんあるようなので精進あるのみ。非常に使いやすいのでお勧め。フリーだし。

・サウンド
なし。スマホゲームでサウンドはいらんかなと思ったのでばっさりと。サウンドやらBGMの作り方とかまったくの門外漢なので。今後も予定無し。

・iOS
Androidアプリは今までもいくつか作ったことがあったので勝手が分かってたけどiOSのほうは全然分からないので現在勉強中。アイコンとかでさえどっから手をつければよいのかがまったく分からん。iAdを組み込むならなおさら。
下記に追記。


まとめ
専門学校以来10数年ぶりのゲーム作成で面白かった。libgdxはさくさく作れるので良い。動作テストもDesktopのプロジェクトを含めておけばPCですぐに確認できるし。これがAndroidのEmulatorだけだったら遅すぎて発狂すると思う。



追記 2014/11/07
App Reviewが昨日承認されて晴れてApp Storeにリリースできた。iOSアプリを作ったことがなかったのに加えてlibgdxでiOS版をリリースするチュートリアルがEclipseメインで書かれているものが多くIntellij ideaを使ってのリリースはかなり大変だった。またAppleのチュートリアルもXCodeを使って開発することを想定してのものなので、libgdx+intelij ideaというiOSアプリ開発環境的に邪道感満載の環境で手動設定するべき値がどれなのかを調べるのには骨が折れた。iAdのほうがマネタイズ的にAdMobよりも断然おいしいという比較記事を読んでいたのでiAdを組み込みたかったのだけれどそこにたどり着くまでにかなり試行錯誤を繰り返しすぎて発狂しそうだったのでそこはすっぱりとあきらめてrobovm-ios-bindings/admobでさくりと実装した。それとApp Reviewはなんやかんやとやっぱり時間を食う。それでもSubmitしてから一週間ということを考えれば早いほうなのかな、と。

いずれAdMobの組み込み方とか、iOS版のリリース方法とかまとめたいと考えているけれどとりあえず年内にもう一本簡単なゲームをリリースしたいのでそれが終わってから気が向いたら書くかも。

2014年4月10日木曜日

html5のcanvasにレーダーチャートを描画する

レーダーチャートの話が仕事中に出て自前で作るかどこかのコンポーネントを購入するかという話になり結局購入することになったのだけれども、デモ用にちゃちゃっとレーダーチャートを実装したのがあるので公開しておく。

デモはこちら

実装周り
// Knockoutjs周りは省略

var canvas = document.getElementById("canvas")
 , c = canvas.getContext("2d");
function drawRader(){
 var points = viewModel.points()
    , eachRad = (Math.PI*2) / points.length
 , i
 , accumRad = Math.PI/2
 , radius = 150
 , center = 200
 , sin
 , cos
    , endOfAxisPt
 , firstPt
 , prevPt
 , currentPt;
 c.clearRect(0,0,400,400);
 for(i = 0; i < points.length; i ++){
  c.strokeStyle = "#ffa500";
  c.beginPath();
  sin = Math.sin(accumRad);
  cos = Math.cos(accumRad);
        endOfAxisPt = {
            x: center + (cos * radius),  
            y: center - (sin * radius)
        };
  accumRad += eachRad;
  c.moveTo(center, center);
  c.lineTo(endOfAxisPt.x, endOfAxisPt.y);
  c.stroke();
        
        c.fillStyle = "#00A0E9";
        c.fillText(points[i].text(),
                   endOfAxisPt.x - 10, 
                   endOfAxisPt.y - (sin * 20));
  
  c.strokeStyle = "#00A0E9";
  c.beginPath();
  currentPt = { 
    x: center + (cos * (radius * points[i].ratio())), 
    y: center - (sin * (radius * points[i].ratio())) 
   };
  if(prevPt){   
   c.moveTo(prevPt.x, prevPt.y);
   c.lineTo(currentPt.x, currentPt.y);
  }
  else
   firstPt = currentPt;
  prevPt = currentPt;  
  c.stroke();
 } 
  
 c.beginPath();
 c.moveTo(prevPt.x, prevPt.y);
 c.lineTo(firstPt.x, firstPt.y);
 c.stroke();
}
drawRader();
drawRader()の冒頭でviewModel.points()と取得しているのはKnockoutjs用のViewModelが内部的に保持しているObservableArrayだ(Knockoutjsを知らない人は配列のようなものと考えてもらって構わない)。描画の処理は単純で配列のアイテム数で360度を割ってその角度ごとに軸線を描画し、前後の軸線上の点と点を結んでいくだけ。

2014年1月4日土曜日

html5のcanvasに描画した曲線をヒットテストする

昨年はWPFを使ってGUIをグリグリ動かすアプリ開発にどっぷりはまっていたので今回は久しぶりにJavaScriptをいじりたくなり表題のものをガリガリ作った。

デモはこちら
githubはこちら(デモと差は皆無)

赤い四角が始点と終点だ。オレンジの四角が制御点になる。すべてdraggableなので任意に動かしてもらいたい。線上の点は曲線を直線に分割している点だ。曲線をクリックすると緑色になる。

曲線描画 on canvas
html5のcanvas上で曲線を描画するのは至極簡単だ。context.bezierCurveToまたはcontext.quadraticCurveToを呼び出せば良い。前者は制御点が2つのcubic bezierで後者は名称そのままの制御点1つのquadratic bezierだ。今回のデモではcubic bezierのほうを使用している。

曲線ヒットテスト on canvas
しかしあたり判定になると手段が提供されていないので自前でやる必要がある。以下任意のクリックした点が曲線上に位置しているかを計算する方法である。

1、曲線上の任意の点の接線の傾きを計算し曲線上の近傍点の接線の傾きと比較する
2、1の差が許容範囲内ならば2点は直線に近いと判断する
3、1の差が許容範囲外ならば2点間は曲がっているので2点間の中央で分割し再度1の判定を再帰的に行う
4、1~3までを繰り返し曲線を点で分割する
5、4で得られた点群とクリックされた点が直線上に位置するかを計算する
6、5で直線上に存在すれば曲線がクリックされたとする
7、5で直線上に存在しないならば曲線はクリックされていないとする

上記の計算に必要なものを解説していく。

曲線上の任意の点の計算方法
Cubic bezier curveの式を使うと簡単に任意の点を取得できる。Cubic bezier curveの式は以下。
b(t) = p0*(1-t)^3 + p1*3t(1-t)^2 + p2*3(1-t)t^2 + p3*t^3
p0は始点、p3が終点、p1、p2はそれぞれ制御点の1と2だ。これに時間であるtを0~1の間で指定すると曲線上の任意の点が取得できる。

曲線上の任意の点の接線の傾きの計算方法
これもCubic bezier curveの式の導関数を使えば簡単に計算できる。式は以下。
b'(t) = 3(1-t)^2(p1-p0) + 6(1-t)t(p2-p1) + 3t^2(p3-p2)
p0~p3とtの説明は前述したものと同じだ。

上2つの式はWikipediaを見てもらったほうが分かりやすいと思う。

任意の点が2点間の線上に存在するかの計算方法
任意の点Pが線AB上に存在するならば距離AB=距離AP+距離PBが成り立つ。

コード解説
ここから実際にいくつかコードを見ていこう。

まずは曲線上の任意の点を取得するコード。pointsは始点、制御点1、制御点2、終点の配列だ。
function b0(t) { return Math.pow(1 - t, 3); };
function b1(t) { return t * Math.pow(1 - t, 2) * 3; };
function b2(t) { return (1 - t) * Math.pow(t, 2) * 3; };
function b3(t) { return Math.pow(t, 3); };
function getPointOnBezier(points, t){
 var x = points[0].x * b0(t) + points[1].x * b1(t) + points[2].x * b2(t) + points[3].x * b3(t)
  , y = points[0].y * b0(t) + points[1].y * b1(t) + points[2].y * b2(t) + points[3].y * b3(t);
 return new Point(x, y);
};

ついで曲線上の任意の点の接線の傾きを取得するコード。ここもpointsは始点、制御点1、制御点2、終点の配列だ。
function bd0(t) { return 3 * Math.pow(1-t, 2); };
function bd1(t) { return 6 * (1-t) * t; };
function bd2(t) { return 3 * Math.pow(t, 2); };
function getSlopeOfTangentLine(points, t){
 var x = bd0(t) * (points[1].x-points[0].x) + bd1(t) * (points[2].x-points[1].x) + bd2(t) * (points[3].x-points[2].x)
  , y = bd0(t) * (points[1].y-points[0].y) + bd1(t) * (points[2].y-points[1].y) + bd2(t) * (points[3].y-points[2].y);
 return y/x;
};

曲線を直線に分割していくコード。mDiffやdDiffのしきい値をどこに設定するかで分割する大きさが変わってくるので上手いこと調整してもらいたい。
function calculateDividingPoints(){
 var points = []
  , bi = bezierInfo
  , i;
 for(i = 0.1; i <= 1.0; i += 0.1){
  divideCurveRecursively(bi, points, i-0.1, i); 
 }
 points.push(bi.points[bi.points.length-1]);
 bi.dividingPoints = points;
};
function divideCurveRecursively(bi, points, t1, t2){
 var prevD = getSlopeOfTangentLine(bi.points, t1)
  , currentD = getSlopeOfTangentLine(bi.points, t2)
  , dDiff = Math.abs(Math.abs(prevD)-Math.abs(currentD))
  , mDiff = t2-t1
  , middleT = t1 + mDiff / 2;
  
 if(mDiff > 0.05 && (sign(prevD) !== sign(currentD) || dDiff > 0.2)){
  divideCurveRecursively(bi, points, t1, middleT);
  divideCurveRecursively(bi, points, middleT, t2);
 }
 else
  points.push(getPointOnBezier(bi.points, t1));
};

任意の点が2点間の線上に存在するかをチェックするコード。これも許容値を変更することで当たり判定を厳しくしたりゆるくしたりできるので上手いこと調整してもらいたい。
function onStraightLine(pt){
 var bi = bezierInfo
  , i;
 for(i = 1; i < bi.dividingPoints.length; i ++){
  var p1 = bi.dividingPoints[i-1]
   , p2 = bi.dividingPoints[i]
   , trueDistance = calculateDistance(p1, p2)
   , testDistance1 = calculateDistance(p1, pt)
   , testDistance2 = calculateDistance(pt, p2);
  if(Math.abs(trueDistance - (testDistance1 + testDistance2)) < 0.2)
   return true;
 } 
 return false;
};

ざーっと解説してきたけれどCubic Bezierの公式さえ分かっていればさほど難しくないと思う。フレームワークから提供される曲線のあたり判定などは多量の曲線が存在する場合にボトルネックになったりもするので自前で計算できるよう公式を理解しておいても損はないだろう。処理実行の最適化などはまったく考慮していないので使用メモリだったり処理時間などを勘案して計算処理をキャッシュするなどは実際のコードベースでは行ったほうがよいと思われる。

2013年8月8日木曜日

UbuntuにGitをセットアップしてWindowsから接続する

自前のGitサーバが欲しくなり設定したのでその方法をまとめる。今回の環境は以下。

・Gitサーバ
Ubuntu 12.04.2 LTS

・Windowsクライアント
Windows 7 64bit


Ubuntu認証用のSSHキーを用意する
WindowsでSSHキーを用意するにはPuTTYgenを使ったりする方法もあるけれど、git bashからもさくりと作れるので今回はそちらで。git bashをまだインストールしていない場合はGit for Windowsをインストールしよう。

インストールできたら「Git Bash」があるのでそちらを叩いて起動する。初期作業位置はc:\Users\your nameかc:\Users\your name\Documentsなどになっているはずである。さっそくSSHキーを下記のコマンドから生成する。
※your nameは自分のユーザ名で置き換えてもらいたい。

$ ssh-keygen

そうすると以下の内容が出力されるので順々に必要な項目をタイプする。
Generating public/private rsa key pair.
Enter file in which to save the key (/c/users/your name/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Vera vera vera vera ....

/c/users/your name/.ssh/id_rsaの場所はgit sshから参照されるので名前と場所を変更しないように。エンターキーでpassphraseの入力に移ろう。passphraseは入力しなくてもかまわないがセキュリティの観点から入力するのが望ましい。

さて、c:\Users\your name\.sshを参照するとid_rsaとid_rsa.pubができているはずだ。とりあえずWindowsのセットアップはここまでにしてGitサーバをたてる。


Gitサーバをたてる
サーバセットアップまでは以下をそのまま参考してもらいたい。
4.4 Git on the Server - Setting Up the Server

一応手順を訳すとこうなる。

1、サーバにGitをインストールする
$ apt-get install git

2、'git'ユーザを作り、そのユーザ用の.sshディレクトリを作る
$ sudo adduser git
$ su git
$ cd
$ mkdir .ssh

3、Windowsで作ったid_rsa.pubを/home/git/に持ってくる
コピーするなりFTPで渡すなりしてもらいたい。

4、(サーバに複数ユーザいる場合は他のユーザのホームディレクトリに作らないように注意!)gitユーザのhomeの.sshにauthorized_keysファイルを作る
$ cat id_rsa.pub >> /home/git/.ssh/authorized_keys

.sshとauthorized_keysの権限は以下のようにしておく必要があるので注意してほしい。
$ chmod 700 .ssh
$ chmod 600 .ssh/authorized_keys

authorized_keysを作った後はid_rsa.pubは不要なので削除する
$ rm id_rsa.pub

ちなみに複数ユーザを追加する場合はユーザ分のid_rsa.pubをどんどんauthorized_keysに追加していくだけでよい。

この時点でWindowsからgitサーバにSSHでログインできるはずなので、Windowsに戻ってGit Bashから以下のコマンドを試してもらいたい。
$ ssh git@your domain.com
※your domain.comは自分のドメイン名に変更してもらいたい。

ここでPermission deniedされる場合はSSHのキーがへぼっている可能性があるのでキー作成からやり直して再度authorized_keysにpublic key(id_rsa.pub)を追加してもらいたい。

5、Git用の作業ディレクトリを作る
それぞれのリポジトリ用に空のディレクトリを用意する必要がある。git initを--bareオプションで行う。
$ cd /opt/git
$ mkdir project.git
$ cd project.git
$ git --bare init
必要に応じてどんどんディレクトリを増やしていこう。

project.gitのオーナーがgitになっていることを確認しよう。もしもなっていない場合は以下コマンドで変更しておこう。
$ chown -R git:git project.git

いざcommit
さてこれで準備がととのったので再度WindowsにもどりGit Bashから下記のコマンドを実行してみよう。
$ cd myproject
$ git init
$ git add .
$ git commit -m 'initial commit'
$ git remote add origin git@your domain.com:/opt/git/project.git
$ git push origin master

これで他の端末にcloneすることもできるようになったので、他の端末から下記のコマンドを実行してみよう。
$ git clone git@your domain.com:/opt/git/project.git
$ cd project
$ vim README
$ git commit -am 'fix for the README file'
$ git push origin master


まとめ
SSH周りにはまるとアホみたいに時間がかかるけれど、それさえなければ一時間もかからずにGitサーバを用意してリポジトリをどんどん追加できるはずだ。SSH周りの認証がうまくいかない場合は下手に色々といじくるよりも手順を最初からやり直したほうが早いことが往々にしてあるのでそれを試してみるとよいだろう。