アフィリエイト広告を利用しています

広告

この広告は30日以上更新がないブログに表示されております。
新規記事の投稿を行うことで、非表示にすることが可能です。
posted by fanblog

ネットワーク対戦型ゲームその4-1

すっごく久しぶりに更新です(^-^;)

前回はTCPのサンプルをのせてみたので今回はUDPのサンプルでもw

UDPは以前記述したように
通信速度は速いが信憑性に欠けるものです。
そしてUDPには大きな特徴として
マルチキャストという手法があります。

マルチキャストとは一言でいえば複数の対象に
一度に送信することです。
イメージとしてはメールの一斉送信ですね。

個人的には通信方式について
TCPは電話
UDPはメールのように例えてます。

TCPは通信中常に相手と接続しているので、片方が切断してしまえば
もう片方も切断してしまいます。
すなわち、電話は片方が切ったらお互いに終了しますよね?
また、TCPの接続は1対1で行われます。
それ故に、サーバが複数のクライアントと通信する場合は
マルチスレッドを用いなければなりません。
基本的に電話は1対1です。
もし、自分がA君B君二人と同時に話したければ電話が2台必要です。

これに対してUDPは一方的に送りつけて終わりなので
相手の状態にかかわらず送信はできます。
すなわち、電源が切れてる相手にもメールは送れるのと一緒ですね笑
また、冒頭で述べたようにマルチキャストが使えます。
マルチキャストは一度の送信処理で複数の相手に送ることができる便利な手法です。
メールの一斉送信も一度の送信で済みますよね?

このように、速度や信憑性を考えないで例えてみましたw

雑なプログラムで恐縮ですが前回のようにサンプルを載せてみたいと思います。
動作内容はTCPとUDPの比較がしやすいようにまったく同じにしてあります。
また、図を描くのがめんどいから
プログラムの説明をしやすいようにコメントを異常に書いてみましたww

ソースはサーバとクライアントの通信部分のみ変更しました。
MainFrameとMainPanelは使い回しでお願いします(^-^;)

まずはサーバから



import java.io.IOException;
import java.net.*;
import java.util.ArrayList;
import java.util.List;

//UDPサーバのメインクラス
//UDP通信として複数のクライアントへ一度に送信するマルチキャストを実装する
//TCPは複数のクライアントへ送信する場合はクライアント数だけ送信処理を繰り返す必要があった
//だがマルチキャストなら、プログラムの処理は一度のみで
//あとはネットワーク内で勝手にすべてのクライアントへ送ってくれる
//ただしマルチキャストで送信できる相手はマルチキャストアドレスと呼ばれるアドレスに属しているプログラムである

public class MainServer {

//通信待機ポート
//クライアントからの通信を受け付ける

public final static int PORT = 50000;

//リスト
//UDPではTCPのようにソケットでのクライアントの区別が付けられない
//なぜならTCPでは新しいプログラムを立ち上げるたびに、新しいソケットが作られていたが
//UDPでは送信したらそれでおしまいなので、ソケットをリストにしても意味がない
//なので送信元のIPアドレスを格納するようにした
//また同一PCから複数のプログラムを立ち上げても上記の理由ですべて送信元は一緒とみなされてしまう

private static List IPaddress = new ArrayList();

//マルチキャスト送信用アドレス
//このアドレスに属しているクライアントへは
//一回でデータを送信することができる

private final static String castIP = "224.1.1.1";

//パケットの寿命 同一LANなら1
//パケットがどこまで届くか、ということらしい
//詳しくはわからないが同一LANで接続するならば1でよいw

private final static int TimeToLive = 1;

//マルチキャストIPとマルチキャストポートをまとめておく
private static InetSocketAddress inetSocketAddress;

//通信待機処理
private void start(){

//受信用バイト配列
byte[] buf = new byte[1024];

try{
//UDPではサーバ、クライアントともにDatagramSocketを使用する
//ここではマルチキャストを利用するのでDatagramSocketのサブクラスであるMulticastSocketを使う

MulticastSocket soc = new MulticastSocket(PORT);

//マルチキャスト用にまとめておく
inetSocketAddress = new InetSocketAddress(castIP, PORT);

//パケット寿命を適応する
soc.setTimeToLive(TimeToLive);

while(true){
try{

//UDPでデータを受け取るにはパケットを受信する
//そのためにDatagramPacketオブジェクトを生成する

DatagramPacket recvPacket = new DatagramPacket(buf, 1024);

//受信待機
//データを受信するまでこの行で停止
//データを受信すればrecvPacketに受け渡される

soc.receive(recvPacket);

//もし、受信したデータの送信元がリストになければ追加しておく
if(IPaddress.indexOf(recvPacket.getAddress()) < 0){
IPaddress.add(recvPacket.getAddress());
}

//受信したデータの送信元が何番目に接続したクライアントか取得する
int number = IPaddress.indexOf(recvPacket.getAddress());

//受信データを文字列化する
//recvPacket.getData()でバイト配列を取得できる
//recvPacket.getLength()で受信データの長さを取得できる

String receiveData = new String(recvPacket.getData(), 0, recvPacket.getLength());

//マルチキャストする文字列を作成する
String sendData = number + ":" + receiveData;

//通信用に文字列をバイトデータ化しておく
byte[] b = sendData.getBytes();

//UDPでは受信も送信もパケットをしようして行う
//なので送信用にパケットを作成する
//引数1にはバイト配列を
//2にはその長さを
//そして3には送信先のIPアドレスとポート番号をまとめたInetSocketAddressオブジェクトを指定する
//この場合ではマルチキャスト用のInetSocketを指定しているが、
//1対1であれば相手のIPとポートを指定してやればよい

DatagramPacket sendPacket= new DatagramPacket(b, b.length, inetSocketAddress);

//そしてソケットのsend()メソッドでパケットを送信する
soc.send(sendPacket);

}catch (SocketException e){
e.printStackTrace();

}catch (IOException e){
e.printStackTrace();
}
}

}catch (IOException e){
e.printStackTrace();
}
}

//メインメソッド
public static void main(String[] args){
MainServer server = new MainServer();
server.start();
}
}


ネットワーク対戦型ゲームその3-2

続いてクライアントのプログラムです。

まずはクライアントのメインクラスから



import javax.swing.*;
import java.awt.*;

//ウインドウの原型を生成するクラス
//およびクライアントプログラムのメインクラス
public class MainFrame extends JFrame{

  //コンストラクタ
  public MainFrame(){
    //ウインドウのタイトルセット
    setTitle("TCPClientSample");

    //MainPanelのオブジェクト生成
    MainPanel panel = new MainPanel();

    //MainPanelをウインドウへ適応
    Container contentPane = getContentPane();
    contentPane.add(panel);

    //ウインドウの大きさをMainPanelの大きさにリサイズ
    pack();
  }

  public static void main(String[] args) {
    //自身のオブジェクト生成
    MainFrame frame = new MainFrame();

    //閉じるボタンの終了処理の実装
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    //必要な記述
    frame.setVisible(true);

    //ウインドウのサイズを変更可能かどうか
    frame.setResizable(false);

  }
}



次にパネルの設定クラスです。



import java.awt.*;
import java.awt.event.*;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.image.*;
import java.io.*;

//ウインドウの詳細設定を行うクラス
//MouseListenerインターフェースを実装することで
//マウスによるイベントを取得することができる
public class MainPanel extends JPanel implements MouseMotionListener{
  private final static int WIDTH = 960;
  private final static int HEIGHT = 540;

  //接続可能なクライアント最大数分配列を用意する
  public int[] x = new int[10];
  public int[] y = new int[10];

  //接続しているクライアントの数を格納する
  public int clientNum = 0;

  //色配列
  private Color[] color = new Color[10];

  ClientThread client;

  public MainPanel(){
    //パネルのサイズ設定
    setPreferredSize(new Dimension(WIDTH, HEIGHT));

    //レイアウトは使用しないのでnull
    setLayout(null);

    //マウスイベントを取得できるようにする
    addMouseMotionListener(this);

    //ClientThreadオブジェクトの生成
    client = new ClientThread(this);
    client.start();

    //color配列の初期化
    color[0] = Color.RED;
    color[1] = Color.BLUE;
    color[2] = Color.YELLOW;
    color[3] = Color.GREEN;
    color[4] = Color.PINK;
    color[5] = Color.GRAY;
    color[6] = Color.MAGENTA;
    color[7] = Color.ORANGE;
    color[8] = Color.CYAN;
    color[9] = Color.BLACK;
  }

  //描画メソッド
  public void paintScreen(){

    Graphics2D g2 = (Graphics2D) this.getGraphics();

    //グラフィックオブジェクトに白色を設定する
    g2.setColor(Color.WHITE);

    //背景を白で初期化
    g2.fillRect(0, 0, getWidth(), getHeight());

    for(int i=0; i<clientNum; i++){

      //色をセットする
      g2.setColor(color[i]);

      //塗りつぶした円を描画する
      g2.fillOval(x[i]-10, y[i]-10, 20, 20);
    }

  }

  //マウスでドラッグしたときに呼ばれる
  @Override
  public void mouseDragged(MouseEvent e) {

  }

  //マウスがウインドウ内で移動しているときに呼ばれる
  @Override
  public void mouseMoved(MouseEvent e) {
    //サーバに送る文字列を作成する
    //マウスのX座標,マウスのY座標E として送る
    //具体的には
    //156,189E のようになる こうすれば一回の送信で二つの情報を送ることができる
    //また文字列がつながってしまっても
    //156,189E124,389E123, のようにEが区切りとして働くので見分けが付けやすい
    String sendData = e.getX() + "," + e.getY() + "E";
    client.send(sendData);
  }
}




最後にサーバとの通信処理クラスです



import java.net.*;
import java.io.*;

//サーバと通信するクラス
public class ClientThread extends Thread{

  //サーバのIPアドレスまたは同一LAN内ならばホスト名
  private final static String IP = "localhost";

  //サーバのポート番号
  private final static int PORT = 60000;

  //MainPanelのオブジェクト
  public MainPanel panel;

  //ソケット
  private Socket socket;

  //各ストリーム
  private InputStream in;
  private OutputStream out;

  //コンストラクタ
  public ClientThread(MainPanel panel){
    this.panel = panel;
  }

  //スレッド処理
  public void run(){
    try{
      //サーバへ接続
      connect(IP, PORT);

    }catch (Exception e){
      e.printStackTrace();
    }
  }

  //接続かつ受信
  public void connect(String ip,int port) {
    int size;
    String str;
    byte[] w=new byte[1024];

    try {
      //ソケット接続
      socket = new Socket(ip,port);

      in = socket.getInputStream();
      out = socket.getOutputStream();

      //受信ループ
      while (socket!=null && socket.isConnected()) {

        //データの受信
        size = in.read(w);

        if (size <= 0) continue;

        str = new String(w, 0, size, "UTF-8");

        int clientNumber = Integer.parseInt(str.substring(0, str.indexOf(':')));

        //クライアントと接続できた時に もっとも大きなクライアントナンバー+1が今接続している数なので
        //MainPanelのclientNumへ反映する
        if(panel.clientNum < clientNumber+1){
          panel.clientNum = clientNumber+1;
        }

        //サーバから送られてきた各クライアントの座標をMainPanelのx, y配列にセットする
        panel.x[clientNumber] = Integer.parseInt(str.substring(str.indexOf(':')+1, str.indexOf(',')));
        panel.y[clientNumber] = Integer.parseInt(str.substring(str.indexOf(',')+1, str.indexOf('E')));

        //そして再描画する
        panel.paintScreen();

      }
    } catch (Exception e) {
      e.printStackTrace();
      disconnect();
    }
  }

  //送信
  public void send(String message){
    byte[] b = message.getBytes();

    try {
      if(out != null){
      out.write(b);
      out.flush();
      }

    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  //切断
  public void disconnect() {
    try {
      socket.close();
      socket=null;
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}




ネットワーク処理はイメージがしにくいのでプログラムを作りにくいですが
ネットには先人たちの豊富な知識がありますので
たくさんサンプルを読んでみるといいですね〜^^

ネットワーク対戦型ゲームその3-1

前回TCPについてお話したので、今回はそのサンプルプログラムを〜
2回にわけて載せてみます。

プログラムを載せる時にうまくいかなかったのでもしかしたら
不備があるかもしれません(汗
そのときはご指摘お願いします。

このサンプルでは、サーバに接続しているクライアントすべてのウインドウ内のマウスの位置を
各クライアントウインドウに色を分けて表示するものです。

まずはサーバプログラムですが、マルチアクセプトのために
ネットで調べたものを参考にさせてもらいました。

まずはサーバのメインクラス



import java.io.IOException;
import java.net.*;

//サーバを起動し、接続要求に応答するクラス
//接続完了後はMainServerThreadへ処理を譲渡する
public class MainServer {
 
  //サーバスタートメソッド
  //引数にポート番号を指定
  public void start(int port){

    //サーバソケットの作成
    //サーバソケットは接続待機用のソケット
    ServerSocket server;

    //接続数を制限する場合は指定
    int acceptCount = 0;

    try{

      //ポート番号を指定してサーバを作成
      server = new ServerSocket(port);
      System.out.println("Server Start!\n" + "This server name is " +
        InetAddress.getLocalHost().getHostName() + "\n" +
        "And port is " + port);

      //仮に接続制限を10としてサーバを作成する
      while(acceptCount < 10){

        try{
          //TCP通信で用いるソケットの作成
          //ひとまずnullで初期化をしておく
          Socket socket = null;

          //サーバソケットによる待機
          //接続相手が現れれば先ほど生成したsocketへ受け渡す
          socket = server.accept();

          //受け取ったソケットを引数にMainServerThreadのオブジェクトを生成する
          new MainServerThread(socket).start();

          //クライアントとの接続が完了すればカウントしていく
          acceptCount++;

        }catch (IOException e){
          e.printStackTrace();
        }
      }

    }catch (IOException e){
      System.err.println(e);
    }
  }

  //サーバのメインメソッドである
  public static void main(String[] args) {
    //自身のオブジェクトを生成
    MainServer server = new MainServer();
    
    //serverオブジェクトのstartメソッドを引数60000をしていして起動
    server.start(60000);
  }
}


続いてサーバの通信スレッドクラス
このクラスで各クライアントとの通信をマルチスレッドで処理します



import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

//各クライアントと通信を行うクラス
public class MainServerThread extends Thread{
  //リストとして各クライアントとの通信処理を行っているオブジェクトを格納する
  private static List<MainServerThread> threads = new ArrayList<MainServerThread>();
 
  private Socket socket;

  //何番目に接続したかを記録する
  private int number = 0;

  //コンストラクタ
  public MainServerThread(Socket socket){
    this.socket = socket;

    //クライアントとの通信を開始するのでリストに自身を追加してやる
    threads.add(this);

    //リストのindexOf()メソッドを使用することで引数の要素が何番目に含まれるか取得する
    number = threads.indexOf(this);
  }

  //スレッド処理
  public void run(){
    InputStream in = null;
    String message;
    int size;
    byte[] w = new byte[10240];

    try{
      //ストリームの生成
      in = socket.getInputStream();

      //受信ループ
      while(true){
        try{
          //クライアントからの受信待ち
          if(size <= 0) throw new IOException();

          //受け取ったバイトデータを文字列へ変換
          message = new String(w, 0, size, "UTF-8");

          //全てのクライアントへ送信する
          //受け取ったデータの前にクライアント識別ナンバーを付与する
          this.sendMessageAll(number + ":" + message);

        }catch (IOException e){
          e.printStackTrace();
        }
      }

    }catch (IOException e){
      e.printStackTrace();
    }
  }

  //全員にメッセージ送信
  public void sendMessageAll(String message) {
    MainServerThread thread;

    //リストに含まれている要素の数だけ繰り返す
    for (int i=0;i<threads.size();i++) {

      //リストからオブジェクトを取り出す
      thread=(MainServerThread)threads.get(i);

      //threadが存在して入れば処理を行う
      if (thread.isAlive())
      //そのスレッドのsendMessageメソッドを使用する
      //すなわち呼び出し元である自分から見れば
      //サーバを仲介して別のクライアントへデータを送信している
      thread.sendMessage(this, message);
    }
  }

  //メッセージ送信
  public void sendMessage(MainServerThread talker,String message){
    try {
      //ソケットから書き込み用のストリームを受け取る
      OutputStream out = socket.getOutputStream();
      byte[] w = message.getBytes("UTF8");
      out.write(w);
      out.flush();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

画像編集ソフト P Edit

課題というのはどうしてこう、溜まっていくんでしょうね〜?

どうもお久しぶりです笑

課題に追われる日々の合間を見つけてデータ整理をしていたら
数か月前に作ったプログラムが出てきたのでちょこっとアップロードw

名前はP Edit
ジャンルは画像編集ソフトです

P Edit
こちらからダウンロードしてください^^

特徴はやはりJavaというところでしょうか。
JavaがインストールされているPCであれば
ファイルを解凍してダブルクリックするだけで起動できます。
アンインストールもファイルを削除するだけで終了です。

機能面は
個人的に画像編集でのわずらわしい経験をもとに実装しました。

具体的には
トリミングを(10,10)から始めたいのにマウスだと1ドットの調整が難しい!!
というのを改善するために
P Editはマウス、座標どちらでもトリミング範囲を指定できるようにしました。

他には色変換で
モノトーン、ネガポジ、セピア、二値化
挑戦としてペールトーンなんてのも作ってみました。

ただ、学生が作ったものなので有名なフリーソフトには及ばないですww

もしよければ使ってみてください。
感想もいただけたらとてもうれしいです。

詳しい説明はReadMeにいろいろと書いてますので参照してください^^

Javaは少しでも使えるようになったらとても楽しくなります♪
もし興味があれば始めてみませんか?(って言えるほどの技術は持ってないんですけどw)

以下にJavaを学ぶ上でとても頼りになった書籍を紹介させてもらいます^^








ネットワーク対戦型ゲームその2

お久しぶりです^^

AndroidでのUDP hole punchingについて書く前に
TCP、UDPについてもう少し詳しく書いていこうかと思います。

TCPもUDPも通信にはソケットというものを使用します。

ソケットとはIPアドレスとポート番号をひとまとめにしたものだと言えます。
ポート番号を使用する利点としては、同一IPアドレスでもポート番号を変えることで
同時に複数の通信を行うことができることです。
例えば、もしIPアドレスのみであれば
ブラウザでネットに接続している間はSkypeは使えない、と言った問題が発生するのです。

それ故にTCPでもUDPでもソケットを使用しないと通信がおこなえないのです。

それではTCP、UDPの通信方法を見ていきましょうか。

TCPではまず、受信側(サーバ)が受信を監視するポート番号を指定して待機します。
ここでは10000番にしておきましょう。
Javaでは次の用に書きます。
ServerSocket server = new ServerSocket(10000);
これでサーバを作成し、
Socket S_socket = server.accept();
これで監視をして待機します。

サーバとクライアントのプログラムは別々に書きます。

送信側(クライアント)はサーバのIPアドレスとポート番号を指定して接続します。
Socket C_socket = new Socket(サーバのIPアドレス , 10000);
これでserver.accept()関数によってサーバと接続することができます。
接続するだけであればこれで完了です。

接続している間はサーバ側のS_socketとクライアント側のC_socketは繋がっている状態と言えます。
相手からデータを受信する場合はInputStreamを使用します。
InputStream in = S_socket.getInputStream();(サーバからクライアントへ送信の場合)
InputStream in = C_socket.getInputStream();(クライアントからサーバへ送信の場合)
どちらの場合でも
byte[] rb = new byte[10240];
int size = in.read(rb);
String receive = new String(rb, 0, size, "UTF-8");

これでOKです。

受信データはbyte型なので受信用にbyte配列を作成します。
次にin.read(rb);で受信待ちをします。
データを受信した場合はbyte配列rbにデータを格納して、その大きさをsizeに代入します。
そしてbyteデータをString型に変換します。
Stringのコンストラクタは(byte配列 , 変換開始位置指定 , 変換する文字数指定 , 文字コード);
となります。
なのでここではbyte配列の最初からsizeの数だけ文字をUTF-8でString型に変換する、となります。

相手にデータを送信する場合はOutputStreamを使います。
OutputStream out = S_socket.getOutputStream();(もしくはC_socket.getOutputStream();)
byte[] sb = "送信したい文字列".getBytes("UTF8");
out.write(sb);

送信したい文字列をbyte配列に格納したあと、out.write(sb);で書き込みます。
これを受信側がin.read(rb);によって読み取るのです。
これだけで簡単な文字列のやり取りができます。

これをマルチスレッドで処理することで繰り返しやり取りすることができます。
すなわちチャットプログラムになるのです。


文章で説明するのは苦手なので図も載せておきます笑



かなり自己解釈が多いので詳しく知りたい方は検索して調べてみることをお勧めします(^_^;)

次回はUDPについて書いてみます。

ネットワーク対戦型ゲームその1

今大学の講義でネットワーク対戦型ゲーム制作の課題が進行中なので完成までちょいちょい書いていこうかと思います(^o^)

対戦ゲームと言ってもたくさんあるのですが
1対1のアクションゲームを制作していこうかと思ってます^^
しかもこの課題はコンテストがあるのでAndroidも可能ならば使用したいと思います(^_^;)
そして優勝をもぎ取る!!←

ゲームというと派手なアクションなどを夢見るのは当然ですがまずは基盤づくりをww
ネットワークでの対戦ということで当然ネットワーク処理が必要です。

ネットワーク通信の種類としてTCPとUDPが代表的なものです。
これらの違いとしては
TCP:データの送受信が成功したか確認しながら通信するので速度が遅い、その代り信頼性が高い
UDP:データを一方的に送りつけるので速度は早いが届いているかの確認がないので信頼性が低い
この2つについては調べればかなりの情報が手に入ると思います。

パッと見だとUDPよりTCPの方が良さそうですが使用する環境によって優劣が変わってきます。

たとえばチャットプログラムのように確実に相手にコメントを届けないといけなく、それほど高速な通信を必要としない場合であればTCPの方が適しています。
それに対してアクションゲームのようにプレイヤー情報が常に変化する場合は速度が重要になってきます。

何を作りたいかで通信方式を選ぶ必要があるわけですね。

ここで、自分の場合はUDPで決定じゃん、と言いたいところなのですが
これがまた環境を考慮するとそうでもありません。
それは今回のネットワーク対戦型ゲームは同一LAN内のPC同士で通信を行うということです。
同一LAN内であればTCPとUDPの速度の差はそれほど大きくはなりません。
プログラムによっては差をなくすことも可能かもしれません。
それ故にこのアクションゲームではTCPを使用したいと思います。

実装済みの通信形態としては複数のプレイヤーをマッチングする必要があるので
マッチング専用のサーバを構築しました。
まず、すべてのプレイヤーはサーバに接続し、プレイヤー情報を送信します。
次にサーバから他のプレイヤー情報を取得します。
そして対戦したい相手を選んだあとはサーバからそれぞれのIPアドレスを取得します。



そしてどちらかをサーバに見立てて
新たに対戦者間での直通通信を構築します。



こうすることでサーバを経由するタイムラグを排除できます。

実際にはプレイヤー間では2つのTCP通信を結んでいます。
上の図のような繋がりが2組あるわけです。

一つはコマンドを送信するラインです。
攻撃ボタンが押されたら攻撃開始の指示を送信する、といった具合に
任意のタイミングで送受信するための通信ラインです。

もう一つは座標を常時送受信するためのラインです。
座標は常に変化するので任意のタイミングではワープしているように見えてしまうからです。

ここにブログタイトルのCよりJavaが好き の理由があったりします笑
Javaではこれらの通信処理をマルチスレッディングによって簡単に実装することができるのですがCではちと厳しい(今の自分には無理だけど上級者の方なら可能なのでしょうw)

以上のように同一LAN内のPCならば簡単にできるのですが
自分はAndroidを投入したいのでAndroid用に別の方法も考えねばなりません。
正直ここが一番苦しかったww

AndroidではUDP通信を使用しました。
そして実機で3Gによる通信をするのでUDP hole punchingという技法を導入して通信を確立することに成功しました。

ただ、説明が難しいので
また暇があればAndroidの通信について書いてみます。w

ここまで読んでいただきありがとうございます!

はじめに

初投稿です^^

大学ではC言語を習っているのでJavaを個人的に独学してきました。
友人がブログを書いていたので真似をしてブログを書いてみますw

当分は大学の半年間課題であるゲーム制作についてのプログラムを載せていこうかな〜と
ただ、今はAndroidにはまっているので時折Androidを入れながら(^_^;)

また、プログラミングは学習している最中なので間違っているところは指摘してもらえるととても助かります♪

多くの方に読んでもらえるようなブログになるよう頑張ります!
<< 前へ    
×

この広告は30日以上新しい記事の更新がないブログに表示されております。