お知らせ

  • 超科学戦隊オレ一人

WPFを触ってみる

noimage

WPFを触ってみる

まいどヾ(´・∀・`)オレです。 どうも昨今の世間的には、 Windows Formsはもうアカン、 これからはWPFだ、いやいやUWPだと開発手法が移ろいでいるそうです。 ですので、WPFとやらを触ってみることにしました。 そもそもの発端は、 Formsで作ったアプリを、いまどきのディスプレイで表示すると、 レイアウトが崩れたり、見た目が汚くなったり、ぼんやりしたりして困ってたのです。 ↓こんな感じで低DPI環境では普通に見えるアプリですが… ↓このとおり、高DPI環境(カスタムスケーリング)だと、ジャギジャギ&ぼんやり。 その点、WPFは、大丈夫らしいぞと。 しかも、WPFは、かっちょええ画面を作れるらしいぞと。 しかも、WPFは、かっちょええ画面を作れるらしいぞと。 ただし、従来の感覚で開発できないらしいぞと。 四の五の言わずに作ってみたのがこちら。 ↓ 簡単スクリーンショット『キャプちゃん』 ・アクティブウィンドウとデスクトップのスクリーンショットをとるだけのしょうもないツールです。 ・ダウンロードしてすぐ使えます。 ・もちろん無料ですのでお好きにどうぞ。ただし自己判断でお願いします。 ■開発言語 C# .NET 4.5 ■参考にしたサイトさま http://d.hatena.ne.jp/sensepicker/20091025/1256439647 https://www.ipentec.com/document/document.aspx?page=wpf-wndproc-capture ■ソースコードはこちら(改変はご自由に) プロジェクト一式   と、いうわけで、 ふぅむ、WPFで作ると確かに高DPIでも低DPIでも乱れずに表示されました。 低DPI環境 高DPI環境 ちなみに、Windows Formsで作った場合、 肝心のスクショキャプチャ機能もめちゃくちゃな結果になった。 ↓ どこ撮影しとんスカ。 Window Forms、もう終わりなんやろか。

  • 超科学戦隊オレ一人

【Android】OpenGLでテクスチャ表示したかっただけなんや

noimage

【Android】OpenGLでテクスチャ表示したかっただけなんや

まいど。ゴミ社員のKです。 ぐえっへっへへ(o´・∀・)y~ やめてー。 ガベージコレクトせんといてー。 要らん子やけどここに居たいんやー。 k = null; System.gc(); ぎゃぁああああああ! ■どうしても避けて通りたかった3Dプログラミング。 ”ワイのゲームはファミコン風ドット絵やから3Dなんか要らんズー” ”3Dってあれやろ、ハリウッドの。そんなんワイのゲームに要らんズー” ”つか、3Dってダサくね?HAHAHAHA・・・” ・・・なぞというカッチョわりぃ言い訳をして、3Dの勉強から逃げてきましたが、 このたび、3Dプログラミング(OpenGL ES)に手を染める運びとなりました。 逃げてた理由=それは難しいからです。 (行列演算・・・?うっ頭が・・・) やろうと思った理由は簡単です。 オレのAndroidゲーム、もっとたくさんのキャラをもっと速く動かしたい。そんだけ。 そのためには、ゲームフレーム中の描画処理のコストを下げる… というか、強力な描画機構を使うのがよかろうと。 なお、Androidアプリの描画の仕組みは、 View、SurfaceView、GLSurfaceViewと3種類あり、 左ほど作るのが簡単だけど遅くて、右ほど難しいけどパワフルで高速化が見込めるぜ…と、よく聞く。 一番右のGLSurfaceViewというやつがOpenGL ESで3Dプログラミングできるやつです。 ちなみに、前回紹介した2Dゲーム「忍者盛り」は、真ん中のやつ(SurfaceView)で実装しています。 今回の話は、これをGLSurfaceView(つまりOpenGL ES)に置き換えたらどうなんねんハゲコラ!泣かしたろか!というコスモが起源です。 ワンポイントアドバイス(ゝω・) ”忍者盛り”をGoogle検索すると、勝手に”忍者めし”に変換してくれるぞ!それチガウンヤケドナ…(2015年10月現在) ■板ポリゴンにテクスチャを表示 さて、3Dをどのように2Dゲームに転用するかというと、 それは当然、厚みをもたない四角い板(板ポリゴン)に、画像を貼りつけて表示するのがセオリーだろうと。 ははーん。板に絵をぶちまけるだけでヨゴザンスね?ニヤニヤ? ということで、”オレは板ポリに絵(テクスチャ)貼っちゃる、それは簡単だ”と思いました。 ところが!これがもう・・・それはそれは苦難の道でしたとさ・・・。 例えるならば、固形の吐しゃ物を、老廃物と一緒に自由自在に体内からいつでも放出できる感じです。 これを嘔吐コントロール(Auto Control)と言います。 まず、何から手を付けていいかわからんのです! 正直な話、ネットに転がってるサンプルを見ても、何をしているのかいっこもワカラン。 頂点配列?深度テスト?ビューポート? フーム、ワカリマセンネ(o´・∀・)シゲシゲ?ワカリマセンヨ。 「ええから、ポリ公にオレの絵貼っつける方法、はよ。」 まぁ、やっぱり自分はゴミカスやったということです。 その事実を認めたくないがために、ただひたすらにやりました。 ■―かくして1週間。 板ポリ助に貼った絵を簡単に操る仕組みを作ったドン!キター! 以下のコードのMySpriteというクラスがそれです。 こいつに絵を(リソースIDを)与えて、draw●●メソッドを呼べば、移動・反転・拡大・回転!自由に描画できるドン。 MyRendererのonDrawFrameメソッドを見れば、簡単に描画できることが分かると思います。 「忍者盛り」もスプライト単位でクラス化していたので、簡単に置き換えができるドン。 天才やー。ワイ、ゴミカスやとおもたら天才やったんやー。 うん知ってた(´・∀・`)マァナ。オレってこう見えてけっこうナイスな男子なんよね。実際。 罪深いオレでまったく申し訳ないと思っているね。ここだけの話。マジで。 というわけでサモハンinチャンプル(サンプル) ↓MainActivity.java [java collapse="true"]</pre> package com.syscube.openglsample; import android.app.Activity; import android.os.Bundle; /** * アクティビティ * * @author イケメンのオレ * */ public class MainActivity extends Activity { /** * 生成 */ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // GLSurfaceViewを設定します setContentView(new MyGLView(this)); } } <pre>[/java] ↓MyGLView.java [java collapse="true"]</pre> package com.syscube.openglsample; import android.app.Activity; import android.opengl.GLSurfaceView; /** * GLSurfaceView * * @author ワイ * * これを使うとOpenGL(ES)で3Dプログラミング結果を描画できます * */ public class MyGLView extends GLSurfaceView { /** * コンストラクタ */ public MyGLView(Activity activity) { super(activity); this.getHolder().addCallback(this); // レンダラ―をセット this.setRenderer(new MyRenderer(activity.getApplicationContext())); } } <pre>[/java] ↓MyRenderer.java [java collapse="true"]</pre> package com.syscube.openglsample; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.content.Context; import android.opengl.GLSurfaceView.Renderer; /** * レンダラ― * * @author 拙者 * * このクラスがアプリケーションの実質の描画担当者になります。 * 何もしなくても勝手にonDrawFrameメソッドが呼ばれます。 * 描画したいものをonDrawFrameメソッドに指定すればよいです。 */ public class MyRenderer implements Renderer { /** * アプリケーションの幅(pixel) */ private static final int APP_SIZE_W = 480; /** * アプリケーションの高さ(pixel) */ private static final int APP_SIZE_H = 800; /** * アプリケーションコンテキスト */ private final Context context; /** * 板ポリで実現したスプライト(キャラクター) */ private MySprite ninja = new MySprite(); /** * コンストラクタ * @param context:アプリケーションコンテキスト */ public MyRenderer(Context context) { this.context = context; } /** * 生成(初期化) */ @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // 画面のクリア時の色の指定 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // 黒 //gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // 白 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ちょっぴり高速化対策(効果の程は知らないがたぶんそれなりに) //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ディザ使いません(デフォルトでOFFになってると思うけど念のため) gl.glDisable(GL10.GL_DITHER); // ポリゴンの面に陰影をつけません gl.glShadeModel(GL10.GL_FLAT); // ポリゴンの輪郭がジャギジャギしてもかまいません gl.glHint(GL10.GL_POINT_SMOOTH_HINT, GL10.GL_FASTEST); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // スプライト用のビットマップ(キャラクター画像)をロードします //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ this.ninja.load(gl, this.context.getResources(), R.drawable.ninja); } /** * 向き変更 * このメソッド内でアプリケーションの描画スクリーンを設定する */ @Override public void onSurfaceChanged(GL10 gl, int w, int h) { //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ビューポート(表示領域)の指定 // // 【引数の説明】 // 開始X座標, 開始Y座標, 幅, 高 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gl.glViewport(0, 0, w, h); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // プロジェクターに投影するような感じにする //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // プロジェクションモードに設定 gl.glMatrixMode(GL10.GL_PROJECTION); // スクリーン座標を初期化 gl.glLoadIdentity(); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ビューポート内の座標系を左上(0, 0)に設定 // こうしないと左下が(0, 0)になってややこしくなる // // 【引数の説明】 // 左X, 右X, 下Y, 上Y, 手前Z, 奥Z // 2Dゲームなので手前Zと奥Zは気にしなくてよい //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gl.glOrthof(0.0f, APP_SIZE_W, APP_SIZE_H, 0.0f, -1.0f, 1.0f); } /** * 描画 * これは毎フレーム勝手に呼び出されます(メインループに相当する) */ @Override public void onDrawFrame(GL10 gl) { //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // キャラクターをお好きなように描画します //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // x=0, y=0の座標に普通に描画 this.ninja.draw(gl, 0, 0); // x=0, y=64の座標にデブッチョ(横幅2倍)に描画 this.ninja.drawEx(gl, 0, 64, 2, 1); // x=64, y=64の座標に左右反転に描画 this.ninja.drawTurnLR(gl, 64, 128); // x=200, y=200の座標に40度傾けて描画 this.ninja.drawRota(gl, 200, 200, 40); } } <pre>[/java] ↓MySprite.java [java collapse="true"]</pre> package com.syscube.openglsample; import javax.microedition.khronos.opengles.GL10; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.opengl.GLUtils; import android.util.Log; /** * スプライトクラス * * @author 忍者マン * * ビットマップ(つまり画像)を、矩形の板ポリゴンにテクスチャとして貼りつけるクラスです。 * loadメソッドを呼んで初期化しておけば、いつでもdraw●●メソッドで自由に描画できます。 * ビットマップは、タテヨコが必ず2の2乗の正方形でなければいけません。 * */ public class MySprite { /** * テクスチャID */ private Integer textureID = null; /** * 板ポリゴン(矩形) */ private MyPorigon porigon = null; /** * リソースのビットマップをロードしてテクスチャ登録します * * @param gl:GL10 * @param res:コンテキストリソース * @param id:ビットマップのリソースID * @return true:成功 */ public boolean load(GL10 gl, Resources res, int id) { //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ビットマップをメモリにロード //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Bitmap bitmap = BitmapFactory.decodeResource(res, id); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ビットマップのイレギュラーチェック //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ロード正常チェック if(bitmap == null) { Log.e("Error!", "ビットマップロードに失敗ですドン!"); } // サイズが2の2乗の正方形かどうかチェック if(this.isNumberPowerOfTwo(bitmap.getWidth()) == false || this.isNumberPowerOfTwo(bitmap.getHeight()) == false) { Log.e("Error!", "ビットマップが2の2乗の正方形じゃないですドン!"); } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // 板ポリゴンを生成 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ this.porigon = new MyPorigon(bitmap.getWidth(), bitmap.getHeight()); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ビットマップをテクスチャとして登録 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ this.registTexture(gl, bitmap); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ビットマップをメモリから破棄 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // 上でテクスチャ登録してるのでもう要らない if(bitmap != null) { bitmap.recycle(); bitmap = null; } // いまのうちにガベージコレクト System.gc(); return true; } /** * 数値が2の乗数かどうかを返します * @param n:数値 * @return true:2の乗数 */ private boolean isNumberPowerOfTwo(int n) { return (n & (n - 1)) == 0; } /** * ビットマップをテクスチャとして登録します * @param gl:GL10 * @param bitmap:ビットマップ */ private void registTexture(GL10 gl, Bitmap bitmap) { //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // 使用可能なテクスチャ識別番号を取得 // テクスチャ識別番号はOpenGLが管理しているので // プログラマはOpenGLに問合わせて空き番号をもらいます // glGenTexturesが問合せメソッド //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ int[] textures = new int[1]; gl.glGenTextures(1, textures, 0); // テクスチャ管理番号の保存 this.textureID = textures[0]; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // テクスチャ識別番号とビットマップの紐付 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // まず今回のテクスチャ管理番号をバインドする gl.glBindTexture(GL10.GL_TEXTURE_2D, this.textureID); // そのバインドした状態でビットマップを与えることで紐づく GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // テクスチャを拡大・縮小する方法の指定 // // 【引数の説明】 // GL_TEXTURE_2D(固定), 拡大時の指定 or 縮小時の指定, 伸縮方法 // // 拡大時の指定 or 縮小時の指定は、 // GL_TEXTURE_MAG_FILTERで拡大時の指定 // GL_TEXTURE_MIN_FILTERで縮小時の指定 // // 伸縮方法は、 // GL_NEARESTは軽いけど見た目が荒くなる // GL_LINEARは重いけど見た目が滑らかになる //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST); gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_NEAREST); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // テクスチャの繰り返し方法の指定 // // 【引数の説明】 // GL_TEXTURE_2D(固定), X方向の指定 or Y方向の指定, 繰り返し方法 // // X方向の指定 or Y方向の指定は、 // GL_TEXTURE_WRAP_S:X方向の指定 // GL_TEXTURE_WRAP_T:Y方向の指定 // // 繰り返し方法は、 // GL_REPEAT:繰り返しする // GL_CLAMP:繰り返ししない(OpenGL ESでは使えないみたい) //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT); gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT); } /** * 描画します * @param gl:GL10 * @param posX:X座標 * @param posY:Y座標 */ public void draw(GL10 gl, float posX, float posY) { // マトリックスを設定 this.porigon.setMatrix(gl, posX, posY, 1.0f, 1.0f, 0.0f, false, false); // テクスチャを描画 this.porigon.draw(gl, this.textureID); } /** * 左右反転描画します * @param gl:GL10 * @param posX:X座標 * @param posY:Y座標 */ public void drawTurnLR(GL10 gl, float posX, float posY) { // マトリックスを設定 this.porigon.setMatrix(gl, posX, posY, 1.0f, 1.0f, 0.0f, true, false); // テクスチャを描画 this.porigon.draw(gl, this.textureID); } /** * 上下反転描画します * @param gl:GL10 * @param posX:X座標 * @param posY:Y座標 */ public void drawTurnTB(GL10 gl, float posX, float posY) { // マトリックスを設定 this.porigon.setMatrix(gl, posX, posY, 1.0f, 1.0f, 0.0f, false, true); // テクスチャを描画 this.porigon.draw(gl, this.textureID); } /** * 拡大縮小描画します * @param gl:GL10 * @param posX:X座標 * @param posY:Y座標 * @param exRateX:X方向拡大縮小率(1.0で等倍) * @param exRateY:Y方向拡大縮小率(1.0で等倍) */ public void drawEx(GL10 gl, float posX, float posY, float exRateX, float exRateY) { // マトリックスを設定 this.porigon.setMatrix(gl, posX, posY, exRateX, exRateY, 0.0f, false, false); // テクスチャを描画 this.porigon.draw(gl, this.textureID); } /** * 回転描画します * @param gl:GL10 * @param posX:X座標 * @param posY:Y座標 * @param degree:角度(0~360) */ public void drawRota(GL10 gl, float posX, float posY, float degree) { // マトリックスを設定 this.porigon.setMatrix(gl, posX, posY, 1.0f, 1.0f, degree, false, false); // テクスチャを描画 this.porigon.draw(gl, this.textureID); } } <pre>[/java] ↓MyPorigon.java [java collapse="true"]</pre> package com.syscube.openglsample; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import javax.microedition.khronos.opengles.GL10; /** * (矩形)板ポリゴン * * @author オレがガンダムだ * */ public class MyPorigon { /** * マトリックスのクラス * マトリックスと名付けてますが、単に、座標とか諸々をまとめた構造体みたいなものです */ private class Graph2DMatrix { /** * X座標 */ public float posX = 0.0f; /** * Y座標 */ public float posY = 0.0f; /** * 拡大・縮小率X(1.0で等倍) */ public float exRateX = 1.0f; /** * 拡大・縮小率Y(1.0で等倍) */ public float exRateY = 1.0f; /** * 角度 */ public float degree = 0.0f; /** * 設定します * @param sizeW:画像1コマ分のサイズ(幅)px * @param sizeH:画像1コマ分のサイズ(高)px * @param posX:X座標(左) * @param posY:Y座標(上) * @param exRateX:拡大・縮小率X * @param exRateY:拡大・縮小率Y * @param degree:角度 * @param isLRReverse:trueで左右反転 * @param isTBReverse:trueで上下反転 */ public void set(int sizeW, int sizeH, float posX, float posY, float exRateX, float exRateY, float degree, boolean isLRReverse, boolean isTBReverse) { this.posX = posX; this.posY = posY; this.exRateX = exRateX; this.exRateY = exRateY; this.degree = degree; // 左右反転するときのみ if(isLRReverse) { // 拡大・縮小率を負にすると反転する this.exRateX *= -1.0f; // 左右反転に伴ってサイズ(幅)の分だけ移動させる(そうしないと左に寄ってしまう) this.posX += sizeW; } // 上下反転するときのみ if(isTBReverse) { // 拡大・縮小率を負にすると反転する this.exRateY *= -1.0f; // 左右反転に伴ってサイズ(高)の分だけ移動させる(そうしないと上に寄ってしまう) this.posY += sizeH; } } } /** * マトリックスのインスタンス */ private Graph2DMatrix matrix = new Graph2DMatrix(); /** * UV配列オブジェクト(U:ヨコ、V:タテとする左上原点の画像切り出し範囲。画像全体をサイズW=1.0f、サイズH=1.0fとして表現される) */ private FloatBuffer uvArray = null; /** * 頂点配列オブジェクト */ private FloatBuffer vertexArray = null; /** * サイズ(幅) */ private final int sizeW; /** * サイズ(高) */ private final int sizeH; /** * 半分のサイズ(幅) */ private final int halfSizeW; /** * 半分のサイズ(高) */ private final int halfSizeH; /** * コンストラクタ * @param sizeW:テクスチャの幅(pixel) * @param sizeH:テクスチャの高さ(pixel) */ public MyPorigon(int sizeW, int sizeH) { this.sizeW = sizeW; this.sizeH = sizeH; // 半分のサイズを設定 this.halfSizeW = this.sizeW / 2; this.halfSizeH = this.sizeH / 2; // UV配列オブジェクトを生成する this.uvArray = this.createUVArray(); // 頂点配列オブジェクトを生成 this.vertexArray = this.createVertexArray(); } /** * マトリックスを設定します * @param gl:GL10 * @param posX:X座標 * @param posY:Y座標 * @param exRateX:X方向拡大縮小率(1.0で等倍) * @param exRateY:Y方向拡大縮小率(1.0で等倍) * @param degree:角度(0~360) * @param isLRReverse:左右反転するかどうか * @param isTBReverse:上下反転するかどうか */ public void setMatrix(GL10 gl, float posX, float posY, float exRateX, float exRateY, float degree, boolean isLRReverse, boolean isTBReverse) { this.matrix.set(this.sizeW, this.sizeH, posX, posY, exRateX, exRateY, degree, isLRReverse, isTBReverse); } /** * 描画します * @param gl:GL10 * @param textureID:テクスチャID(nullでテクスチャ無し) */ public void draw(GL10 gl, Integer textureID) { //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // 頂点配列を有効にする //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ブレンドを有効にする //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gl.glEnable(GL10.GL_BLEND); gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // 色と透明度の指定 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // まっ白 gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // 最後の引数を0.0f~1.0fの範囲で透明度を表せます if(textureID != null) { //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // テクスチャ、テクスチャ座標配列を有効にする //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gl.glEnable(GL10.GL_TEXTURE_2D); gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // テクスチャ画像の指定 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // テクスチャの指定 gl.glBindTexture(GL10.GL_TEXTURE_2D, textureID); // 0番テクスチャを有効化(この板ポリゴンにテクスチャを重ねて貼る場合に0~Nで指定するが今回は0しかない) gl.glActiveTexture(GL10.GL_TEXTURE0); // 0はデフォルトで有効のためこの行はコメントアウトしてもかまわない //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // UV配列オブジェクトの指定(テクスチャのどの部分を切出して描画するか) //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, this.uvArray); } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // 頂点配列オブジェクトの指定 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gl.glVertexPointer(3, GL10.GL_FLOAT, 0, this.vertexArray); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // マトリックスの有効化 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // マトリックス有効化 gl.glPushMatrix(); // まず移動(実際は最後に移動が適用される) gl.glTranslatef(this.matrix.posX, this.matrix.posY, 0.0f); // 次に回転 if(this.matrix.degree > 0 || this.matrix.degree < 0) { // 画像中心点で回転させるために移動が必要 gl.glTranslatef(this.halfSizeW * this.matrix.exRateX, this.halfSizeH * this.matrix.exRateY, 0.0f); // 回転させる gl.glRotatef(this.matrix.degree, 0.0f, 0.0f, 1.0f); // 移動を元に戻す gl.glTranslatef(-this.halfSizeW * this.matrix.exRateX, -this.halfSizeH * this.matrix.exRateY, 0.0f); } // 最後に拡大・縮小 gl.glScalef(this.matrix.exRateX, this.matrix.exRateY, 1.0f); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // 描画 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // マトリックスの無効化 // これをしないと全ての描画オブジェクトに影響してしまいます //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // マトリックス無効化 gl.glPopMatrix(); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // 頂点配列、テクスチャ座標配列を無効にする //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // テクスチャ、テクスチャ座標配列を無効にする //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gl.glDisable(GL10.GL_TEXTURE_2D); gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ブレンドを無効にする //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gl.glDisable(GL10.GL_BLEND); } /** * UV配列オブジェクトを生成します * @return UV配列オブジェクト */ private FloatBuffer createUVArray() { // float配列で定義 float[] uv = { 0.0f, 0.0f, // 左上 0.0f, 1.0f, // 左下 1.0f, 0.0f, // 右上 1.0f, 1.0f, // 右下 }; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // 画像全体を幅1.0、高さ1.0として扱われる // 切出し範囲のWidth/Heightを0.0~1.0の間で指定することができる // 今回は画像切り出しなしなので、1.0までを(全体を)指定をする //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // FloatBufferに変換して返す return this.getFloatBufferFromFloatArray(uv); } /** * 頂点配列オブジェクトを生成します */ private FloatBuffer createVertexArray() { float left = 0.0f; float top = 0.0f; float right = left + this.sizeW; float bottom = top + this.sizeH; //頂点バッファの生成 float[] vertexs = { // x, y, z left, top, 0.0f, // 頂点0 left, bottom, 0.0f, // 頂点1 right, top, 0.0f, // 頂点2 right, bottom, 0.0f, // 頂点3 }; // FloatBufferに変換して返す return this.getFloatBufferFromFloatArray(vertexs); } /** * float配列をFloatBufferに変換します * @param fa:float配列 * @return 変換後のFloatBuffer */ public FloatBuffer getFloatBufferFromFloatArray(float[] fa) { // このやり方はAndroidDocで紹介されているため通例(と思われる) FloatBuffer fb = ByteBuffer.allocateDirect(fa.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); fb.put(fa).position(0); return fb; } }[/java] なげぇよ。なげーんだよ! しかし、それがAndroid!OpenGL ES! 実行結果は↓こんなん。好きな位置に、好きな大きさで、好きな角度で絵を表示できてます。 ちなみに使った画像は↓これ。忍者盛りの赤丸くん(64px*64px) resフォルダ直下に、drawable-nodpiというフォルダを作って、そこに入れるのですよ。 そういえば、このサンプルは、頂点配列を毎フレームGPUに転送しているよ。 なので、もっと高速化したい場合は頂点バッファで、あらかじめGPUに転送しておくとよいかもよ。 床井先生のサイトがかなり参考になった。OpenGLについては全部ここに書かれとる。 和歌山大学・床井先生のサイト(ゼミのサイトっぽい) ちなみに、ちょっとだけ、自分のゲームを板ポリに置き換えてみたのですが、その良さはまだいっこもわかりません。 むしろ、なんか遅くなってる気がす・・・ゲフン! たぶん、こういうゲームだとOpenGLの恩恵をそれほど受けられないのか、ワイのプログラムがゴミ過ぎるかのいずれかだろうと思います。 まとめると、ゴミ野郎はゴミ野郎らしく、毎日4時間睡眠で頑張れってことです。 ニキビが出来てもかまわねぇオレカッケェ(深刻)。

  • 超科学戦隊オレ一人

Androidゲーム作ったドン

noimage

Androidゲーム作ったドン

まいど仮面の忍者、Kです(o´・∀・)y~ ガラケー依存症です。 何かよほどのことでもない限り、永遠にスマホに切り替えられん…と思っていましたが、 いよいよスマホ男子として生まれ変わるかもしれません。 そんなことになったら、うっかりLINEしたり、うっかりコンカツしたりしてしまいそうですね。 うっかりダメ、絶対。 ↓きっかけはこれ。Androidゲームを作ってみたわけです。(紹介動画) https://www.youtube.com/watch?v=DmpN0MkM0mE&feature=youtu.be 中二病で8bit風な忍者ゲー「忍者盛り-Ninja Mori-」 これ、Androidアプリはどうやって作るのかを勉強するために作ったものです。 動画では録画の都合上、30FPSで動かしてますが、 リリース版は、フレームレートを選択できるように機能追加しているのでもっとぬるぬる動かせます。 グラフィックは自作です。 サウンドはフリー素材です(そのうち気が向いたら自作して差し替えるかもしれません)。 特にフレームワークとかゲームエンジンは利用してません。 生Java、というか生Activity、というか生SurfaceView。とにかく直接いじらないと気が済まない性分です。 作ってみた感想としては、メモリの節約が主になりよるわと。 あんまり大きい画像使ったりするとアウト。量もちょっぴりしか使えない感じ。 なので、なるべくキャッシングして使いまわすようにして、スプライトは色数も控えめにしました。 (生pngとか使ったら即アウトな気配がプンスカ) まぁ、画像よりも音声ファイルが容量食いまくるので、 シーンごとに必要な音声をロード・リリースするようにして、品質もかなり落としました。 (もともと8bit風なサウンドなので、まったく耳に違和感ないと思います) mp3は、酒の肴にもならんウンコ形式クンなので、素直にoggです。 あと、スマホ=しょせん電話。なので、演算処理にモチャモチャ時間をかけさせたらアキマヘン。 このゲームでは、日本刀がチャキンチャキンするチャンバラが売り(?)なのですが、 諸々の衝突判定を、2Dとはいえ、あんまり複雑なプログラムにすることは許されませんでした。 なので、アルゴリズムは足し算と引き算だけで済ませています。 もちろん見た目に違和感なくてゲームプレイを損なわないギリギリを狙うように調整はしてます。 とにかく、スマホゲームは命がけで節約することです。 節約できるプログラミングを命がけで考えることが大事。 20年くらい前のゲームデザイナーやプログラマーも、こうやって命がけで節約にあけくれたはず。 ・・・という、感傷にひたりましたよ、という日記です。 つまり、オレ=かっけぇ!ドヤ!ということです。 フフフ…(o´・∀・)ニンニン…。 ※このゲームは、Google Playストアで無料ゲームとして配信されます(まもなく)

  • 超科学戦隊オレ一人

DXライブラリでデスクトップマスコットを作ろう 第4回

noimage

DXライブラリでデスクトップマスコットを作ろう 第4回

まいどどうも(o´・∀・)o 久々に連載再開します。 前回までで、 ・ウィンドウを作ることと、 ・ウィンドウに絵を表示すること ができました。 ちなみに、この連載での最終的な成果物は↓これです。 (紫色のチビ忍者が、パソコンの画面の中でシュタタタタ…と、勝手に動くのを想像してください。)               (1)デスクトップマスコットの仕組み さて、この連載でのデスクトップマスコットは、 いったいどういうからくりで動くものなのかというと… ・透明なウィンドウ(目に見えないウィンドウ)に、 ・マスコットキャラの絵を表示して、 ・その絵を動かす これだけです。シンプルですね。 順に説明しますよ。 まず、透明なウィンドウ。 これは、DXライブラリにその機能があります。便利ですなぁ。 (具体的なやり方は、この回のおしまいにお見せしますよ。) 次に、マスコットキャラの絵を表示する。 これはもうできますね。 DxLib::LoadGraph()して、DxLib::DrawGraph()するのでしたね。 最後、絵を動かす。 さあ、これです。絵を動かすことがこの連載の本質であり、その第一歩が、この第4回なのです。 (2)絵を動かす仕組み まずは、以下をご覧あれ(GIFアニメです)。 さて、この絵はどうやって動いている(ように見える)のでしょうか。 もちろんパラパラ漫画と同じ原理です。 高速に絵を切り替えてるだけです。 (ここでは3枚のパターンの絵をいい感じにパラパラさせてます) デスクトップマスコットも同じです。 つまり、高速に絵を切り替えるということを、プログラムでやればいいのです。 (3)メインループという考え方 パラパラ漫画は、たくさんの紙に、それぞれの瞬間の絵を描きますね。 ところが、デスクトップマスコットは、ウィンドウというひとつの紙しかありません。 ではどうするかというと、 ひとつの紙に、絵を出したら、すぐにその絵を消して、次の絵をだす…といったことをすればよいのです。 描画 ⇒ クリア ⇒ 描画 ⇒ クリア…。 というイメージですね。 実際には、どのタイミングでどの絵を、どの位置に出すべきなのかといった、 演算(計算)をする必要もあるので、 演算 ⇒ 描画 ⇒ クリア ⇒ 演算 ⇒ 描画 ⇒ クリア…。 があるべき姿となります。 疑似コードで表すと、こうなります。 [cpp] int WINAPI WinMain( /*省略*/ ) { // 無限ループ処理 while( /*省略*/ ) { // 演算 Update() ; // 描画 Draw() ; // ウィンドウの中を全部クリア Clear() ; } // プログラム終了 return 0 ; } [/cpp] Clear()は、ウィンドウの中を全て空っぽにします。 一部分だけを消す、といったことはしません。 つまり、毎回、ウィンドウの中を全部描きなおすのです。 こういう無限ループのことを、メインループとかゲームループとか言いますが、 デスクトップマスコットのプログラムというのは、 このメインループの中のUpdate()とDraw()の中身を作ることに他なりません。 自分だけのロジックを、メインループの中にひたすらプログラミングしてゆく…。 この感覚は、イベントドリヴンなWindowフォームアプリや、 Post/Getがトリガーとなるブラウザアプリの開発しかやったことが無い人には、 なかなか刺激的な体験になると思います。 (4)ついでにダブルバッファリング さて、メインループの中で描いたり消したりを繰り返すことで、ある問題が起こります。 メインループというのは、1秒間に何十回という超高速なペースで繰り返されるものですが、 実際にやると、チカチカと点滅して見えてしまうのです。人間の眼は優秀です。 ではどうするかというと、 見えない紙に先に下書きして、見せたいタイミングになったら、見える紙に複写する。 こういう手法を取ります。 これをダブルバッファリングと呼びます。 この連載の中では、 見えない紙のことをウラ画面と呼びます。 見える紙のことをオモテ画面と呼びます。 描画とクリアを繰り返すのはウラ画面で行い、描画後の瞬間だけ、オモテ画面に反映するのです。 疑似コードで表すと、↓こうなります。 [cpp] int WINAPI WinMain( /*省略*/ ) { // 無限ループ処理 while( /*省略*/ ) { // 演算 Update() ; // ウラ画面に描画 DrawUra() ; // オモテ画面に複写 CopyOmote() ; // ウラ画面の中を全部クリア ClearUra() ; } // プログラム終了 return 0 ; } [/cpp] こうすることで、オモテ画面には常に絵が見えている状態になり、チカチカしなくなるのです。 (5)今回の成果コード 色んなパターンの絵を切り替える、ということはさておきで、 先ほどまでの疑似コードをちゃんとコーディングするとこうなります。 ウィンドウの透明化の方法も書いておきますよ。 [cpp] #include <DxLib.h> // DXライブラリを使います //************************************************************** // 定数宣言 //************************************************************** // 描画スクリーン(ウラ・オモテ画面)のサイズ static const int SCREEN_SIZE_W = 200 ; // 幅px static const int SCREEN_SIZE_H = 200 ; // 高px //************************************************************** // WinMain関数(プログラムはここから実行されます) //************************************************************** int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // 1.DXライブラリの使用前の準備 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ウィンドウを透明に設定します DxLib::ChangeWindowMode( TRUE ) ; // ウィンドウモードにします DxLib::SetGraphMode( SCREEN_SIZE_W, SCREEN_SIZE_H, 32 ) ; // 描画スクリーンのサイズを指定します DxLib::SetWindowStyleMode( 2 ) ; // ウィンドウのスタイルを枠無しにします DxLib::SetUseBackBufferTransColorFlag( TRUE ) ; // ウィンドウを透明にします //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // 2.DXライブラリの初期処理(ウィンドウを生成します) //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //------------------------------------ // 2-1.ウィンドウの生成 //------------------------------------ if( DxLib::DxLib_Init() != 0 ) { // 失敗したら直ちに終了します return -1 ; } //------------------------------------ // 2-2.画像を描画する画面の設定 //------------------------------------ // オモテ画面を作ってハンドルを得ます ※ウラ画面はDXライブラリが最初から用意しています const int omoteHandle = DxLib::MakeRGB8ColorSoftImage( SCREEN_SIZE_W, SCREEN_SIZE_H ) ; // ウラ画面(みえない画面)に描画するように設定しておきます DxLib::SetDrawScreen( DX_SCREEN_BACK ) ; //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // 3.デスクトップマスコットの初期処理 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // マスコットの画像をメモリにロードしてハンドルを得ます const int graphHandle = DxLib::LoadGraph( "GRAPH/TEST_GRAPH.png", TRUE ) ; //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // 4.メインループ //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Windowsからのメッセージ処理を行いながら永遠にループします while( DxLib::ProcessMessage() == 0 ) { // 演算 // まだやることないでゴザル(o´・∀・) // ウラ画面(見えない画面)に描画 DxLib::DrawGraph( 0, 0, graphHandle, TRUE ) ; // ウラ画面(見えない画面)の内容をオモテ画面(見える画面)に複写します DxLib::GetDrawScreenSoftImage( 0, 0, SCREEN_SIZE_W, SCREEN_SIZE_H, omoteHandle ) ; // オモテ画面(見える画面)の内容をウインドウに反映します DxLib::UpdateLayerdWindowForSoftImage( omoteHandle ) ; // ウラ画面(見えない画面)の中を全部クリアします DxLib::ClearDrawScreen() ; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // 5.デスクトップマスコットの終了処理 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // マスコットの画像データをメモリから解放します DxLib::DeleteGraph( graphHandle ) ; // オモテ画面の領域をメモリから解放します ※ウラ画面はDXライブラリが勝手に破棄してくれます DxLib::DeleteGraph( omoteHandle ) ; //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // 6.DXライブラリの終了処理 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ウィンドウを破棄してDXライブラリが確保したメモリ領域などをすべて解放します DxLib::DxLib_End() ; // プログラム終了します return 0 ; } [/cpp] 知らない関数ばっかり出てると思いますが、関数を覚える必要はないです。 大事なのは何をやってるのかわかる、ということです。 全部日本語でコメント書いてるからわかるでしょう。 ちょっとだけ解説すると、ウラ画面とオモテ画面をどちらも200*200というサイズで作っています。 そして、ループで、ウラ⇒オモテに転写してウィンドウ内の表示を更新しています。 転写するためにはウラとオモテがぴったり同じサイズでなければなりません。 実行すると↓こうなります。 前回の絵を流用してるので(一枚しかないので)、パラパラしているようには見えませんが、 実際には目にもとまらぬ速度でパラパラしているのです。         次回へ続くドンヾ(´・∀・`)

  • 超科学戦隊オレ一人

DXライブラリでデスクトップマスコットを作ろう 第3回

noimage

DXライブラリでデスクトップマスコットを作ろう 第3回

まいどどうも(o´・∀・)o みなさん、デスクトップマスコット作ってますか。 え?まだ? そいつぁいけねぇや。そりゃいけねぇや。 さて、前回までで、準備は整いましたね。 ちょっとだけ演習してみましょうか。 ようやく楽しいプログラミングですよ。 今回は絵を出しましょう。 こういう趣味プログラミングというのは結局のところ、 やはり、自分の絵が画面に出ること、それが一番の面白みであると思います。 (1)まず、画像を置くための「GRAPH」フォルダを作りますよ Main.cppが作成されている階層と同じところに「GRAPH」というフォルダ作ります。 (例:C:\VCProject\MyMascot\MyMascot\GRAPH) ↓こんな感じです。 ※場所を間違えないようにしてください。Main.cppがある場所です。 (2)次は、絵「TEST_GRAPH.png」を描きますよ ルールは以下の通りです。 ・どんなツールで描いてもよい ・キャンバスの大きさや形はなんでもよい ・どんな絵を描いてもよい ・真っ黒は使わない(RGBがいずれも0のカラーは使わない) ・画像形式はpngにする(jpgやgifを使わない) ・アニメーションpngは使わない ・ファイル名は「TEST_GRAPH.png」にする ↓こんな感じです。 保存先は、さっきのGRAPHフォルダです。 (例:C:\VCProject\MyMascot\MyMascot\GRAPH\TEST_GRAPH.png) (3)それでは、絵を表示するプログラムを書いてみますよ Main.cppを以下のように変更します。 [cpp] #include <DxLib.h> // DXライブラリを使います // WinMain関数(プログラムはここから実行されます) int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { // ウィンドウモードにしておく DxLib::ChangeWindowMode( TRUE ) ; // これをしないとフルスクリーンモードになります // DXライブラリの初期処理(ウィンドウが生成されます) // これはDXライブラリでお約束の処理です if( DxLib::DxLib_Init() != 0 ) { // 失敗したら直ちに終了します return -1 ; } // 画像をメモリにロードする  ↓パス区切りは「円円」でもスラッシュでもいい const int graphHandle = DxLib::LoadGraph( "GRAPH/TEST_GRAPH.png" ) ; // メモリの画像データをウィンドウに描画する DxLib::DrawGraph( 0, 0, graphHandle, TRUE ) ; // ( x, y ) = ( 0, 0 )の座標に表示します // キーボードでなんらかのキーが押されるまでここでずっと待機 DxLib::WaitKey() ; // DXライブラリの終了処理 DxLib::DxLib_End() ; // これはDXライブラリでお約束の処理です // プログラム終了します return 0 ; } [/cpp] 前回のプログラム内で「ウィンドウの中央に白い箱を表示する」と書いている部分を 画像のロードと表示に変えているだけです。 そんで、デバッグ実行ボタンを押して・・・ ウィンドウ内に絵が表示されたらOKです。 ※絵が表示されなかったらパスが間違っています。 ※もしくは、第2回から見直してください。 (4)DXライブラリの関数について補足しておきますよ この記事内で出現する「DxLib::●●」は、すべてDXライブラリの関数です。 「DxLib::」を省略してもかまいません。 自分はC++らしさを強調するために名前空間を省略していないだけです。 (5)DXライブラリのハンドルについて説明しておきますよ ↓これについてですが、 const int graphHandle = DxLib::LoadGraph( "GRAPH\\test.png" ) ; LoadGraph関数は、相対パス(または絶対パス)指定で、 画像ファイルをメモリにロードして、戻り値としてハンドルを返してくれます。 DXライブラリではこうやって、画像データや音声データなどを、ハンドルというもので扱います。 ハンドルはint型です。 ロードの成功や失敗の確認は、このハンドルの値を確認すればわかります。 だいたいの関数が、-1なら失敗を表し、それ以外は成功を表します。 ハンドルの値は、関数を呼び出すごとに変わります。 自動連番のようなもので、DXライブラリ内で重複することはありません。 たまに勘違いする人がいるので一応書いておきますが、 画像データそのものが、ハンドルというint型変数に格納されるのではありません。 画像データそのものは、パソコンの、どこか知らないメモリ領域に展開されます。 ハンドルは、そのメモリ領域につける名札のようなものです。 例えば、絵を表示するときは、名札で指示するわけです。 今後、記事内では、DXライブラリの関数については、重要な部分以外は説明しません。 ソース内のコメントを見れば分かるように書くつもりですし、 分からない関数があれば、公式サイトのリファレンスをご覧いただくのが一番よいです。 http://homepage2.nifty.com/natupaji/DxLib/dxfunc.html (公式サイトで公開されていない隠し関数については、なるべく本記事内で補完します) (6)透過色について少しだけ説明しておきますよ DXライブラリでは初期設定では、RGB値が0の完全な黒は透過色として扱われます。 つまり、その色は目に見えなくなるってことです。 いまは、ウィンドウの背景が黒なので、 絵の中の黒色が、見えてるのか見えてないのかさえ区別できないのですが、 これから作るマスコットはウィンドウの背景を見えなくしてゆきます。 そうすると、きっと、「あれぇ?黒い色が勝手に消えるんだけど・・・?」ってなると思います。 なので、とりあえず、完全な黒の使用を控えておいてください。 画像を透過したい場合、一番簡単なのは、画像ファイル側であらかじめ透過設定しておくことです。 GimpやPhotoshopなど、透過レイヤーが使えるツールで絵を描くのがよいです。 (いまどきの人は、透過と言ってもピンとこなくて、透過レイヤーとか透明部分と言った方がわかりやすいスね) 例えば、画像の背景の余白部分が気になる場合は、 ↓こんな風にツールでくり抜いて透明にしてしまいましょう 余白をくりぬいて透明にしておけば↓こんな風になります。 今回はここまでです。 つか、展開おせぇな(o´・∀・)y~ なるべく初心者向けに書いてるもんで、許してくれ。 あまつさえ、WordPressで文章タイプするのがヘタクソでまことにスマンと思っています。 (まかせとけ、じきに使い方を覚えます。オレはすぐに学習する。そういうやつです。絶対に)

  • 超科学戦隊オレ一人

DXライブラリでデスクトップマスコットを作ろう 第2回

noimage

DXライブラリでデスクトップマスコットを作ろう 第2回

まいど(o´・∀・)o 第2回です。 (第1回はこちら) 今回は、DXライブラリを使えるようにプロジェクトを作りますよ。 今回の内容は、公式サイト(↓)に全て書かれてますし、 知ってる人は読まなくていいです。はい。 http://homepage2.nifty.com/natupaji/DxLib/use/dxuse_vc2010.html なお、この連載ではプロジェクト名を「MyMascot」として記載してゆきます。 (1)まずは、DXライブラリを開発パソコンに設置しますよ。  ダウンロードしたやつを解凍して・・・ (※ダウンロード先は第1回に書いています)    解凍したやつをCドライブ直下に置きます。   (2)次にVisual C++ 2010 Expressで空のプロジェクトを作りますよ。  ↓こんな感じです。   プロジェクト名は「MyMascot」としますよ。 (3)次はプログラムソースファイルを作りますよ。  ↓こんな感じです。      ソースファイル名は「Main」としますよ。   (4)次にDXライブラリを使えるようにしますよ。  ↓こんな感じです。        「追加のインクルードディレクトリ」と 「追加のライブラリディレクトリ」には、 いずれも(1)で配置したDXライブラリのフォルダの中の 「プロジェクトに追加すべきファイル_VS用」というやつを指定します。       (5)最後にDXライブラリが使えるか実験しますよ。 Main.cppに以下のようにプログラムコードをタイプします。  ※ただの実験なので、コードの意味はわからなくてもいいです。 [cpp] #include &lt;DxLib.h&gt; // DXライブラリを使います // WinMain関数(プログラムはここから実行されます) int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { // ウィンドウモードにしておく DxLib::ChangeWindowMode( TRUE ) ; // DXライブラリの初期処理(ウィンドウが生成されます) if( DxLib::DxLib_Init() != 0 ) { // 失敗したら直ちに終了します return -1 ; } // ウィンドウの中央に白い箱を表示する DxLib::DrawBox( 310, 230, 330, 250, DxLib::GetColor( 255, 255, 255 ), TRUE ) ; // キーボードでなんらかのキーが押されるまでここでずっと待機 DxLib::WaitKey() ; // DXライブラリの終了処理 DxLib::DxLib_End() ; // プログラム終了します return 0 ; } [/cpp] ↓こんな画面が出たらOKです。DXライブラリが使えている証拠です。  おお、なんということだ勇者よ。  プロジェクト作成手順のスクリーンショットを貼りつけるだけで第2回が終わるとは。  ということで次回に続け、者ども。

  • 超科学戦隊オレ一人

DXライブラリでデスクトップマスコットを作ろう 第1回

noimage

DXライブラリでデスクトップマスコットを作ろう 第1回

ちょっと前に、Windows用のデスクトップマスコットを作ったので、 その備忘録として、作り方を書き残しておきますよ(o´・∀・)o ↓こんなん(社内向けとか、プライベート向けとかいくつか作ったです) これから数回に分けて、作り方を書くので暇な人は真似すればいいでしょう。 ※連載は不定期です。 あなたの描いたマスコットキャラが、友達のパソコンでちょこまか動く、 そう考えるとクリエイティブを感じませんか? (考えるな、感じろ) (1)対象読者  ・ポインタとかクラスが(なんちゃってでもいいので)わかる人  ・クリエイティブしたい人 ※なるべく初心者向けに書くと思います (2)使う物(無料です。いずれも公式サイトからダウンロードできます)  ・Visual C++ 2010 Express  http://www.visualstudio.com/downloads/download-visual-studio-vs  ・DXライブラリ  http://homepage2.nifty.com/natupaji/DxLib/dxdload.html (3)DXライブラリについて少し  DirectX(絵を出す、音を鳴らすetc)と  Win32API(ウィンドウを作る、ウィンドウを制御するetc)を、  うまいことラップ(包み隠す)してくれているライブラリです。  C言語ベースで関数呼び出しするだけで、おおよそ欲しい機能を実現できます。  これを使うことで、分厚い書籍を読んだり、MSDNのくどいリファレンスを追いかけたり、  どう考えても楽しくない「作業」からオサラバできるってわけです。  リリースされて10年余り経っており、いまでもサポートが続いているので嬉しく安心です。  DXライブラリを利用した成果物は、WindowsOSでなければ動きませんが、  勉強がてらに創意工夫する工程をたしなむにはうってつけでしょう。 (4)開発言語について  DXライブラリは、C、C#、C++のいずれかを選べますが、ここではC++を扱います。  なので、   ・メモリ管理を自前でやる   ・オブジェクト指向で   ・.NetFrameworkなしで  たぶん脳みその鍛錬になりますよ。ちょっとくらいは。  .Netフォームアプリ開発や、JavaのWebアプリ開発に見受けられる、  いたれりつくせりなプログラミングでは物足らん人におすすめです。  この連載は、そういう人向けに書きます。  「オレ様ってば、ちょっとクリエイティブしてぇわマジデ」な人向け。 ということで第1回は終わり。次回に続けゴマ。 ⇒第2回はこちら

  • 超科学戦隊オレ一人

JavaでByRef

noimage

JavaでByRef

JavaでByRef ByRef・・・つまり参照渡し。 要は、あるメソッドに対し、パラメータとして渡しつつも、 その値を変更したいって場合の話よ(o´・∀・)y~ Javaにはこれがない。 結論からいうと、配列とかコレクション型を使うと、これに似たことができるって話よ。 下の方にサンプルを載せておきます。 .NETばっかりやってると、 あまりにも至れり尽くせりなので、「ほえ~」てな気分で、 なーも考えないでポコポコ作ってしまえる場面がいくつかあって、 そのひとつが、ByRefだと思ふ。 久しぶりにJava触って、ByRefしたいときがあったので、それをメモる。 そういえば、JavaにはByRefなんてねーわ!ちゅう話です。 そうです。ByRefなんて、そもそも、普通の、プリミティブな言語には、ねーのです。 .NET Framework様は、お便利なので、ByRefがあるのです。そーいうことです。 そもそも、そんなお便利なものがあること自体、どうか、と思い始めた。 つまり、ある関数に対し、渡したはずのパラメータの値を、関数自身が変えやがるってことです。 よう考えたら、これは、恐ろしいことです。 たとえば、こういうことです。 親が、アホの息子に、1000円札を渡して、お使いに行かせたら、 アホの息子は5万円のレアなトレカを買ってきたよ。むろん、支払いは親のカードでな! くらいの恐ろしさです。 わかるな(o´・∀・)y~ でも、まぁ、それが必要なときもあるわけよ。 JavaでByRefしたいときもあるわけよ。 配列の要素に対しては、ByRef的な動きが実現できる。 以下、サンポォ(sample) ---------------------------------------------------------- /** * 親の金を、親に黙って勝手に使ったりしない一般的なガキのプログラム */ publis static void main(String[] args) { // プリミティブなint型変数i     int i=0; // ガキに渡す前     System.out.println(“金=” + i); // NotByRefというガキに、iという小遣いを渡してみる     NotByRef(i); // ガキは小遣いを変更していない件     System.out.println(“金=” + i); } // パラメータiを勝手に変更しそうでしない一般的なガキ private static void NotByRef(int i) { // iを変更してみるものの…実はこれは呼び出し元では変更されない     i += 1; } ---------------------------------------------------------- ---------------------------------------------------------- /** * 親の金を勝手に変更しくさるクソガキのサンプルプログラム */ publis static void main(String[] args) { // 配列変数i     int[] i = new int[1]; // iの0番目を0円で初期化     i[0] = 0; // ガキに渡す前     System.out.println(“金=” + i[0]); // メソッドByRefというクソガキに、iという小遣いを渡してみる     ByRef(i); // ガキによって小遣いが変更されている件     System.out.println(“金=” + i[0]); } // パラメータiを勝手に変更するクソガキ private static void ByRef(int[] i) { // 親にもろた金を自在に操る     i[0] += 1; } ---------------------------------------------------------- というわけで、配列とかを渡してやると、ガキはこの内容を変更しまくり(o´・∀・)y~ へー。 まったくどうでもええわ。 オレがやりたいのは、こんな作業ではないので、 こんなことを改めて知ったところで、まったくモチベーションはあがらんよ。 そうだ、会社を興そう。 以上。

  • 超科学戦隊オレ一人

キューブくん立体化計画 その2【完成したお】

noimage

キューブくん立体化計画 その2【完成したお】

まいどヾ(´・∀・`) Kです。 いつぞやから始動していた、 キューブくん立体化計画、その後、完成しました。 というわけで、ここに晒します。うほっ!イイネ!(o´・∀・)y~ このフィギュアストラップは、 原型はオレ様のオリジナル(手作り)ですが、それを某製作所様に複製&着色をお願いして、 大量生産してもらいました。 本日、それが納品された次第です。 段ボール箱にいっぱいぎっしり詰め込まれた無数のキューブくん達を見るというのは、圧巻でした。 なかなかの良い出来やと思います。 以下、原型製作中の頃のお写真。 実にチマイ作業でした(o´・∀・)y~ そういえば、脚が折れたこともありました。 慌ててアロンアルファで接着しました。 そして今に至る!ドーン! これで、オリジナルのフィギュアを大量につくるという、ささやかな夢が叶いました。 次は、どの夢を叶えさせてくれるんですか、社長。オウコラ!(o´・∀・)y~ 終わり。

  • 超科学戦隊オレ一人

Javaでソケット通信(ジャバソケ)

noimage

Javaでソケット通信(ジャバソケ)

ソケット? ソケット通信? ハ?ナンスカソリャ(o´・∀・)y~ たぶん、恐らく、普通のIT戦士ならば知っていること。 ぼかぁ、なんちゃってエンジニアなので、知りませんでした。 でも、ソケット通信するプログラムを作らにゃならんことになりました。 そこで、今回えんやこらしたいきさつを、ここにメモります。 ソケット通信とは何か。 何かしらのデータを、何かしらの仕組みでやりとりすることらしい。 ふぅん。それってパケット通信とどう違うの?ヨクワカラナイネ。 えんやこらしたあげくに、僕は以下のように理解しました。 引きこもりニートが、毎日、母親に夕飯を部屋まで届けてもらうケースを考えます。 すると、以下のような手続きが想定できますね。 (1)お母さんは、ニートの部屋のドアをコンコンする。 (2)ニートが、「なんの用じゃババア!」と返事する。 (3)お母さんは、「夕飯持ってきた、ここ置いとくで」と言う。 (4)ニートが、「わかった」と返事する。 これを、ソケット通信で例えると、以下のようになります。 ニート・・・ソケットA 夕飯・・・データ お母さん・・・ソケットB ふむふむ。 データを持ってくる人がいて、 データを受け取る人がいて、 コンコン→なんの用じゃ→置いとくで→わかった。という流れがある。 ほほぅ。べりぃイージーれすねぃ(o´・∀・)y~ で、こういうやりとりを、プログラムではどうするかっちゅうと、 Javaでは簡単にでけますた。 今回作る必要があったのは、受け取る側。 つまり、引きこもりニートを作りました。 以下、サンポォソース(サンプルソース) /** * ええ年こいて働きにも出んと、毎日部屋に引きこもって、 * 夕食はお母さんに部屋まで届けてもらっているニートのプログラム * めんどくさいのでエラー処理は省いています。ニートはめんどくさがりです。 * * @author KaZ */ public class Neet { // ニートの本体     public static void main(String[] args) { // ニートはポートを開きます(ニートポート5000番)         ServerSocket neetSocket = new ServerSocket(5000); // 働きにも出んとコンコンされるのをただただ待ち続けます while(true) { // お母さんにコンコンされます             Socket mamaSocket = serverSocket.accept(); // メシを受け取る準備をします(モノもらうときだけは一丁前に動きます)             InputStream inStream = mamaSocket.getInputStream(); byte[] meshi = new byte[ 100 ];    // 100バイト分の受け取り皿を用意 // メシを受け取ります(中身はともかく、くれるもんはもらう主義です)             inStream.read(meshi, 0, 100); // 受け取ったので閉じます             inStream.close(); // もちろんお母さんはもう不要なので追い出します             mamaSocket.close();    // 入ってくんな!でていけババア! // ほくほくしながらメシをのぞいてみます             String meshiNoNakami[] = new String(meshi);    // 中身を文字列にしてみる // メシの中身を文字列で出力             System.out.println(meshiNoNakami); } } } きゃっほう!ニートの生活ってイージー!イージー!(o´・∀・)y~ しかし、驚くべきことに、 このプログラムはうまく動かない場合があるのです。 それは、お母さんが、なかなかメシを渡さないイジワルババアの場合です。 例えるならば、じらすかのようにオカズ、一皿ずつ渡されるとき。 そうです。お母さんは、 必ずしも、一回の手続きでメシを全品くれるとは限らないのです。 だから、以下の一行をループ処理に書き換えます。 // メシを受け取ります(中身はともかく、くれるもんはもらう主義です) inStream.read(meshi, 0, 100); ↓↓↓↓↓↓↓↓↓ // 一時的な変数をご用意 int ima_moratta_sara = 0;    // たった今受け取った皿の数 int imamadeno_sara = 0;        // 今まで受け取った皿の数 // メシが全品そろうまで、受け取り続ける while(メシが全品そろわない限り)    // ここの条件はお好みで { // たった今受け取った皿の数を覚えておきます ima_moratta_sara = inStream.read(meshi, imamadeno_sara, 100 - imamadeno_sara); // 今まで受け取った皿の数に加算します     imamadeno_sara += ima_moratta_sara } これで、ニートは腹いっぱいメシを食えるちゅうことですね(o´・∀・)y~ おわり。

1 2