HTML5:今日の運勢 ― 2013/11/09
当たるも八卦、当たらぬも八卦、
運勢占いの(ような)文章を、日替わりで表示します。
今日の運勢
・操作方法
テキストボックスに名前を入力して、「占う」ボタンを押してください。
※表示された文章の内容については一切の責任を持ちません。
プログラムの制作には、enchant.jsを使用しています。
運勢占いの(ような)文章を、日替わりで表示します。
今日の運勢
・操作方法
テキストボックスに名前を入力して、「占う」ボタンを押してください。
※表示された文章の内容については一切の責任を持ちません。
プログラムの制作には、enchant.jsを使用しています。
HTML5ゲーム:くるんくる~ぱ ― 2013/11/09
球をくるくる回して入れ替えて、三角に揃えてぱっと消すアクションパズルです。
アクションパズル
くるんくる~ぱ
・ルール
回転軸(白い丸)をタッチすると、周りの3つの球が右方向に回転して位置が入れ替わります。このとき同じ色の球が3つ三角に並ぶと球は消え、上の球が落下してきます。
一度に多くの球を消したり、連続して消したりすることによってCOMBOが上昇し、球を消した時の点数がアップします。
制限時間の1分間が経過するとゲーム終了です。
・ゲームのコツ
最初は玉を回転させた結果がイメージしづらいとは思いますが、まずは三角形に揃うパターンを覚えてください。
アクションパズル
くるんくる~ぱ
・ルール
回転軸(白い丸)をタッチすると、周りの3つの球が右方向に回転して位置が入れ替わります。このとき同じ色の球が3つ三角に並ぶと球は消え、上の球が落下してきます。
一度に多くの球を消したり、連続して消したりすることによってCOMBOが上昇し、球を消した時の点数がアップします。
制限時間の1分間が経過するとゲーム終了です。
・ゲームのコツ
最初は玉を回転させた結果がイメージしづらいとは思いますが、まずは三角形に揃うパターンを覚えてください。

消せるところをすばやく見つけて、COMBOを切らさないように続けて消していってください。
また、球が複数の三角形にまたがるように消すと少ない球で多くの三角形を作ることができます。効率が良くなるので狙えるところは狙ってください。

テクスチャキャッシュ ― 2013/11/10
テクスチャを描画するときデータはVRAMに転送して使用しますが、VRAMの容量には限りがあります。アプリの規模がある程度大きくなり、一度に全てのテクスチャをVRAMに乗せられなくなると、場面によってVRAM上のテクスチャデータを入れ替える必要が出てきます。
場面がはっきりと分かれていて、一つ一つの場面で使用するテクスチャが十分小さい場合は自前でテクスチャを入れ替えても良いのですが、なかなかそうもいかなかったり、面倒だったりするのでテクスチャキャッシュという機構を使ってシステムにやらせてみます。
※"テクスチャキャッシュ"というと、VRAM上でキャッシュに乗せてGPUが高速にアクセス…みたいな話だったりしますが、ここではVRAMに乗せるテクスチャ自体をキャッシュするということになります。
テクスチャキャッシュ概要
・テクスチャが必要なとき(描画時)、キャッシュにそのテクスチャがあるか検索する。
・キャッシュにあった場合、すでにVRAMに読み込まれているのでそれを使用する。また、キャッシュ上での優先度を上げる。
・キャッシュに無かった場合、テクスチャをVRAMに読み込み、優先度を上げてキャッシュに登録する。このとき、登録されているテクスチャの総容量(枚数、またはサイズ)がキャッシュの容量を超えていた場合、優先度の低いテクスチャをVRAMとキャッシュから削除する。
Texture.h
Texture.cpp
・テクスチャ取得
テクスチャリソースの指定は、メモリ(アドレス指定)または assetsのファイル(ファイル名指定)で行います。
まず同じリソースのテクスチャをキャッシュから検索します。このとき処理速度のことを考えて、ファイルの一致はファイル名文字列の中身の比較ではなく、アドレスを比較することにしています。
キャッシュから見つかった場合(179行目から)、優先度を上げて(他のテクスチャの優先度を下げて、先頭に登録する)そのテクスチャを返します。
見つからなかった場合(191行目から)、はじめにキャッシュ上の総数がオーバーしていたときは優先度最低の一枚を削除します。
次にキャッシュ上の総数の半分の優先度で登録します。優先度を最高ではなく半分にしているのは、今キャッシュに無いテクスチャは一時的なものかもしれないということによります。この値が最も効率が良いのかはわかりません。
最後に、キャッシュ上の総サイズがオーバーしていたときは、サイズを下回るまで優先度の低いテクスチャから削除します。テクスチャを登録してから削除しているので一時的にVRAM上でのサイズがオーバーしているのですが、流れをわかりやすくするためにこうしています。
スプライトをテクスチャキャッシュに対応させます。
Sprite.cpp
リソース指定によるスプライトの設定部分です。
テクスチャを読み込まないと決定しない値があるので、状態を statusに覚えておいて読み込んだ時に設定するようにします。
描画部分です。
キャッシュからテクスチャを読み込んで、未設定の値を設定します。あとは通常の描画と同じです。
使用例です。
テクスチャキャッシュの容量を5枚(def.hの TEX_CACHE_NUMで定義)にして、11枚のテクスチャを扱っています。
キャッシュの枚数が5枚なのはあくまでテストのためであって、通常はもっと大きくするものです。少なくとも、1度に画面に出るテクスチャの枚数を超える必要があります。
AppMain.cpp
テクスチャは持たず、リソースを指定してスプライトを設定しています。
描画方法に変更はありません。
場面がはっきりと分かれていて、一つ一つの場面で使用するテクスチャが十分小さい場合は自前でテクスチャを入れ替えても良いのですが、なかなかそうもいかなかったり、面倒だったりするのでテクスチャキャッシュという機構を使ってシステムにやらせてみます。
※"テクスチャキャッシュ"というと、VRAM上でキャッシュに乗せてGPUが高速にアクセス…みたいな話だったりしますが、ここではVRAMに乗せるテクスチャ自体をキャッシュするということになります。
テクスチャキャッシュ概要
・テクスチャが必要なとき(描画時)、キャッシュにそのテクスチャがあるか検索する。
・キャッシュにあった場合、すでにVRAMに読み込まれているのでそれを使用する。また、キャッシュ上での優先度を上げる。
・キャッシュに無かった場合、テクスチャをVRAMに読み込み、優先度を上げてキャッシュに登録する。このとき、登録されているテクスチャの総容量(枚数、またはサイズ)がキャッシュの容量を超えていた場合、優先度の低いテクスチャをVRAMとキャッシュから削除する。
Texture.h
/**************************
テクスチャキャッシュ
**************************/
class TexCache : public Texture
{
static TexCache** cache; // キャッシュ
static int cache_num; // キャッシュ数
static u32 cache_mem_size; // キャッシュ使用メモリサイズ
static void clear_cache(void); // 最後尾のテクスチャを削除
public :
// リソース種類
enum
{
RES_MEMORY = 0, // メモリ
RES_ASSET, // assetsファイル
};
static void init(void); // 初期化
static void quit(void); // 削除
static Texture* get_texture(short, const void*); // テクスチャ取得
short type; // リソース種類
const void* data; // リソースデータ
u32 mem_size; // VRAM占有サイズ
TexCache(short, const void*); // コンストラクタ
};
Texture.cpp
TexCache** TexCache::cache; // キャッシュ
int TexCache::cache_num; // キャッシュ数
u32 TexCache::cache_mem_size; // キャッシュ使用メモリサイズ
/**********************
キャッシュ初期化
**********************/
void TexCache::init(void)
{
cache = new TexCache *[TEX_CACHE_NUM]; // キャッシュ作成
cache_num = 0;
cache_mem_size = 0;
}
/********************
キャッシュ削除
********************/
void TexCache::quit(void)
{
for (int i = 0; i < cache_num; i++) { // テクスチャ削除
delete cache[i];
}
delete[] cache;
}
/****************************************
テクスチャ取得
引数 _type = リソース種類
_data = リソースデータ
****************************************/
Texture* TexCache::get_texture(short _type, const void* _data)
{
int i, j;
for (i = 0; i < cache_num; i++) {
if ( (_data == cache[i]->data) && (_type == cache[i]->type) ) { // 登録済み
if ( i > 0 ) {
TexCache* _tmp = cache[i];
for (j = i; j > 0; j--) {
cache[j] = cache[j - 1];
}
cache[0] = _tmp; // 先頭に登録
}
return (Texture*)cache[0];
}
}
// 新規登録
if ( cache_num == TEX_CACHE_NUM ) { // 枚数オーバー
clear_cache();
}
j = cache_num/2;
for (i = cache_num; i > j; i--) {
cache[i] = cache[i - 1];
}
cache[j] = new TexCache(_type, _data); // リソース読み込み
cache_num++;
cache_mem_size += cache[j]->mem_size;
while ( cache_mem_size > TEX_CACHE_MEM ) { // メモリサイズオーバー
clear_cache();
}
return (Texture*)cache[j];
}
/******************************
最後尾のテクスチャを削除
******************************/
void TexCache::clear_cache(void)
{
cache_num--;
cache_mem_size -= cache[cache_num]->mem_size;
delete cache[cache_num]; // テクスチャ削除
}
/****************************************
リソース読み込み
引数 _type = リソース種類
_data = リソースデータ
****************************************/
TexCache::TexCache(short _type, const void* _data)
{
type = _type; // リソース種類
data = _data; // リソースデータ
switch ( _type ) {
case RES_MEMORY : // メモリ
load_png((const u8*)_data);
break;
case RES_ASSET : // assetsファイル
{
u8* _p = (u8*)load_asset((const char*)_data);
load_png(_p);
free(_p);
}
break;
default :
assert(FALSE);
break;
}
switch ( format ) { // VRAM占有サイズ計算
case FORMAT_RGBA :
mem_size = width*height*4;
break;
case FORMAT_RGB :
mem_size = width*height*3;
break;
}
}
・テクスチャ取得
テクスチャリソースの指定は、メモリ(アドレス指定)または assetsのファイル(ファイル名指定)で行います。
まず同じリソースのテクスチャをキャッシュから検索します。このとき処理速度のことを考えて、ファイルの一致はファイル名文字列の中身の比較ではなく、アドレスを比較することにしています。
キャッシュから見つかった場合(179行目から)、優先度を上げて(他のテクスチャの優先度を下げて、先頭に登録する)そのテクスチャを返します。
見つからなかった場合(191行目から)、はじめにキャッシュ上の総数がオーバーしていたときは優先度最低の一枚を削除します。
次にキャッシュ上の総数の半分の優先度で登録します。優先度を最高ではなく半分にしているのは、今キャッシュに無いテクスチャは一時的なものかもしれないということによります。この値が最も効率が良いのかはわかりません。
最後に、キャッシュ上の総サイズがオーバーしていたときは、サイズを下回るまで優先度の低いテクスチャから削除します。テクスチャを登録してから削除しているので一時的にVRAM上でのサイズがオーバーしているのですが、流れをわかりやすくするためにこうしています。
スプライトをテクスチャキャッシュに対応させます。
Sprite.cpp
/******************************************
設定(リソース指定)
引数 _type = リソース種類
_data = リソースデータ
_coord = UV座標
_origin = 原点位置
******************************************/
void Sprite::set(short _type, const void* _data, SRect const* _coord, int _origin)
{
res_type = _type; // リソース設定
res_data = _data;
status = 1; // UV座標未設定
texcoord[0][X] = (GLfloat)_coord->x; // 仮UV座標
texcoord[0][Y] = (GLfloat)_coord->y;
texcoord[1][X] = (GLfloat)(_coord->x + _coord->w);
texcoord[2][Y] = (GLfloat)(_coord->y + _coord->h);
width = _coord->w; // 幅
height = _coord->h; // 高さ
ox = _origin;
}
void Sprite::set(short _type, const void* _data, int _origin)
{
res_type = _type; // リソース設定
res_data = _data;
status = 2; // 幅・高さ未設定
texcoord[0][X] = texcoord[2][X] = 0.0f; // UV座標
texcoord[0][Y] = texcoord[1][Y] = 0.0f;
texcoord[1][X] = texcoord[3][X] = 1.0f;
texcoord[2][Y] = texcoord[3][Y] = 1.0f;
ox = _origin;
}
リソース指定によるスプライトの設定部分です。
テクスチャを読み込まないと決定しない値があるので、状態を statusに覚えておいて読み込んだ時に設定するようにします。
void Sprite::draw(GLfloat* _vertex)
{
if ( res_type >= 0 ) { // テクスチャキャッシュ
Renderer::use_shader(Renderer::SHADER_TEXTURE); // シェーダ
texture = TexCache::get_texture(res_type, res_data); // テクスチャ取得
texture->bind(); // テクスチャ
if ( status != 0 ) {
switch ( status ) {
case 1 : // UV座標設定
texcoord[0][X] /= texture->width; texcoord[2][X] = texcoord[0][X];
texcoord[0][Y] /= texture->height; texcoord[1][Y] = texcoord[0][Y];
texcoord[1][X] /= texture->width; texcoord[3][X] = texcoord[1][X];
texcoord[2][Y] /= texture->height; texcoord[3][Y] = texcoord[2][Y];;
break;
case 2 : // 幅・高さ設定
width = texture->width;
height = texture->height;
break;
}
set_origin(ox);
status = 0;
}
Renderer::set_texcoord(&texcoord[0][0]); // UV座標
}
else if ( texture ) { // テクスチャ有り
Renderer::use_shader(Renderer::SHADER_TEXTURE); // シェーダ
texture->bind(); // テクスチャ
Renderer::set_texcoord(&texcoord[0][0]); // UV座標
}
else { // テクスチャ無し
Renderer::use_shader(Renderer::SHADER_PLAIN); // シェーダ
}
sys::Renderer::set_vertex(_vertex); // 頂点
Renderer::set_color((GLubyte*)spr_color); // カラー
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // 描画
}
描画部分です。
キャッシュからテクスチャを読み込んで、未設定の値を設定します。あとは通常の描画と同じです。
使用例です。
テクスチャキャッシュの容量を5枚(def.hの TEX_CACHE_NUMで定義)にして、11枚のテクスチャを扱っています。
キャッシュの枚数が5枚なのはあくまでテストのためであって、通常はもっと大きくするものです。少なくとも、1度に画面に出るテクスチャの枚数を超える必要があります。
AppMain.cpp
#include "common.h"
#include "Sprite.h"
// スプライト
enum
{
SPR_PHOTO = 0, // 背景
SPR_FISH, // 魚
SPR_MAX = SPR_FISH + 10,
};
static sys::Sprite sprite[SPR_MAX]; // スプライト
static int cnt; // カウンタ
/************
初期化
************/
void init_app(void)
{
static const
char* tex_name[SPR_MAX] =
{
"photo.png",
"animal_dolphin.png",
"animal_hoojirozame.png",
"fish_buri.png",
"fish_ishidai.png",
"fish_katsuo.png",
"fish_kingyo.png",
"fish_mola.png",
"fish_tako.png",
"fish_tatsunootoshigo.png",
"sakana_mure.png",
};
for (int i = 0; i < SPR_MAX; i++) { // スプライト初期化(リソース指定)
sprite[i].set(sys::TexCache::RES_ASSET, tex_name[i]);
}
cnt = 0; // カウンタ
}
/******************************
稼働
戻り値 アプリ続行か
******************************/
Bool update_app(void)
{
sprite[SPR_PHOTO].draw(0.0f, 0.0f); // 背景
// 魚
sprite[SPR_FISH + (((cnt*4 + 640)/1280)*2 % 10)].draw(640 - ((cnt*4 + 640) % 1280), -128.0f);
sprite[SPR_FISH + (((cnt*4/1280)*2 + 1) % 10)].draw(640 - (cnt*4 % 1280), -128.0f);
cnt++;
return TRUE;
}
/**************** End of File *************************************************/
テクスチャは持たず、リソースを指定してスプライトを設定しています。
描画方法に変更はありません。

サスペンド…そしてレジューム ― 2013/11/11
Androidでは電源ボタンを押すなどサスペンド時に、OpenGLで設定したものがクリアされてしまいます。そこでレジューム(再開)時に再設定しなければいけません。
今までは開始時も含めてレジューム時に全て初期化していましたが、メモリを解放しないまま確保し直すなど行儀の悪いことになっていました。
今回はきちんとサスペンド・レジュームの処理をやってみます。
久々に java側のソースです。
BaseActivity.java
終了・一時停止・再開時に native側の関数を呼んでいるだけですが、再開時だけ少し変えています。
Androidでは一旦電源ボタンを押してサスペンドし、もう一度ボタンを押すとレジュームで onResume()が呼ばれますが、このとき画面はロック状態になっています。
ゲームなどでは画面が見えないのに動いてしまっては都合が悪いので、ロック状態の場合は解除を待ってからアプリを再開させています。
native側のソースです.
SysMain.cpp
ポーズ時の処理で描画管理を終了させています。
テクスチャキャッシュをクリアしていますので、テクスチャのVRAMからの削除はシステムに任せられます。
アプリ側の処理は、
・init_app() 開始時
・quit_app() 終了時
・pause_app() 一時停止時
・resume_app() 再開時
を、それぞれのタイミングで呼んでいます。
サンプルではログを表示しているだけなので、ソースは省略します。
プロジェクト一式は、こちらです。
今までは開始時も含めてレジューム時に全て初期化していましたが、メモリを解放しないまま確保し直すなど行儀の悪いことになっていました。
今回はきちんとサスペンド・レジュームの処理をやってみます。
久々に java側のソースです。
BaseActivity.java
/**********
終了
**********/
@Override
protected void onDestroy()
{
super.onDestroy();
quitNative(); // native部終了
executor.shutdown();
}
/**************
一時停止
**************/
@Override
protected void onPause()
{
super.onPause();
if ( future != null ) { // 定期実行停止
future.cancel(false);
future = null;
synchronized (renderer)
{
pauseNative(); // native部一時停止
}
}
surface_view.onPause();
}
/**********
再開
**********/
@Override
protected void onResume()
{
super.onResume();
if ( ((KeyguardManager)getSystemService(Context.KEYGUARD_SERVICE)).inKeyguardRestrictedInputMode() ) {
registerReceiver(receiver, new IntentFilter(Intent.ACTION_USER_PRESENT)); // スクリーンロック解除待ち
}
else {
surface_view.onResume();
}
}
private UnLockReceiver receiver = new UnLockReceiver(); // スクリーンロック解除検知用
private class UnLockReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
unregisterReceiver(receiver); // レシーバー登録を解除
surface_view.onResume();
}
}
終了・一時停止・再開時に native側の関数を呼んでいるだけですが、再開時だけ少し変えています。
Androidでは一旦電源ボタンを押してサスペンドし、もう一度ボタンを押すとレジュームで onResume()が呼ばれますが、このとき画面はロック状態になっています。
ゲームなどでは画面が見えないのに動いてしまっては都合が悪いので、ロック状態の場合は解除を待ってからアプリを再開させています。
native側のソースです.
SysMain.cpp
/************
初期化
************/
JNIEXPORT int JNICALL Java_sys_BaseActivity_initNative(JNIEnv* env, jobject, jint width, jint height, jobject mgr)
{
LOGI("initNative (&d, &d)", width, height);
asset_manager = AAssetManager_fromJava(env, mgr); // asset読み込みマネージャー
assert(asset_manager != NULL);
Renderer::init(width, height); // 描画管理初期化
if ( !init_flag ) {
init_app(); // アプリメイン初期化
init_flag = TRUE;
}
else {
resume_app(); // アプリメイン再開
}
return FRAME_PERIOD;
}
/**********
終了
**********/
JNIEXPORT void JNICALL Java_sys_BaseActivity_quitNative(JNIEnv*, jobject)
{
LOGI("quitNative");
quit_app(); // アプリメイン終了
init_flag = FALSE;
}
/**************
一時停止
**************/
JNIEXPORT void JNICALL Java_sys_BaseActivity_pauseNative(JNIEnv*, jobject)
{
LOGI("pauseNative");
if ( init_flag ) {
pause_app(); // アプリメイン一時停止
}
Renderer::quit(); // 描画管理終了
}
ポーズ時の処理で描画管理を終了させています。
テクスチャキャッシュをクリアしていますので、テクスチャのVRAMからの削除はシステムに任せられます。
アプリ側の処理は、
・init_app() 開始時
・quit_app() 終了時
・pause_app() 一時停止時
・resume_app() 再開時
を、それぞれのタイミングで呼んでいます。
サンプルではログを表示しているだけなので、ソースは省略します。
プロジェクト一式は、こちらです。
楽天のセールなんてものは ― 2013/11/12
楽天の日本一セールでの不当表示の問題が結構大ごとになっていますが、楽天のセールなんて安い商品に飛びつくためのものじゃないです。
そもそもセールのウリになっているような割引き商品は、開始直後に売り切れてとても買えない、という印象です(全部が全部そうとは限りませんが)。
セールの時は買い回りでポイントが増えるとか割引クーポンが使えるとかあるので、日用品や消耗品を購入したり、ゲームの予約購入をしたりするようにしています。必要な物をそのタイミングで買っているだけで、セールに乗せられて余計なものを買ってはいない…はずです。
ただ、安いものを買っても送料で高くなってしまっては意味がないので、いくらか購入すると送料が無料になるような店を選んでいます。
日用品の品揃えが良くて、結構低い値段で送料無料になるのはこのあたりでしょうか。
爽快ドラッグ
ケンコーコム
値段合わせのために、洗剤を3つも4つも買ったりするようなこともありますが。
そもそもセールのウリになっているような割引き商品は、開始直後に売り切れてとても買えない、という印象です(全部が全部そうとは限りませんが)。
セールの時は買い回りでポイントが増えるとか割引クーポンが使えるとかあるので、日用品や消耗品を購入したり、ゲームの予約購入をしたりするようにしています。必要な物をそのタイミングで買っているだけで、セールに乗せられて余計なものを買ってはいない…はずです。
ただ、安いものを買っても送料で高くなってしまっては意味がないので、いくらか購入すると送料が無料になるような店を選んでいます。
日用品の品揃えが良くて、結構低い値段で送料無料になるのはこのあたりでしょうか。
爽快ドラッグ
ケンコーコム
値段合わせのために、洗剤を3つも4つも買ったりするようなこともありますが。
最近のコメント