忍者ブログ
  • 2024.10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 2024.12
[PR]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

【2024/11/24 11:25 】 |
新しいプロジェクトを新しいgitリポジトリで作るまでの手順
元々あるプロジェクトを元に
新しいプロジェクトを作る場合の手順。git-hub使用。

側かえのような場合。

0.
新しいプロジェクトのiOS dev center アカウント、バンドルIDなど決めておく。
必要ならprovisioning profileも用意しておく。

1.
git-hubに行き、新しいプロジェクト用のリモートgitリポジトリを作る

2.
元プロジェクトのgitに行き、新しいプロジェクトをリモートに追加する
$ git remote add new_name new_repository

3.
元プロジェクトの中身を新リポジトリにpush
$ git push new_name master

4.
git-hubで新プロジェクトを作る

5.
新プロジェクトを作るディレクトリに行き、git clone。

6.
新プロジェクトでpull
$ git pull origin master
ここで一度ビルドできるか確認しても良い

7.
(必要なら)ディレクトリ名を変更し、コミット
$ git mv old_dir_name/ new_dir_name/
$ git commit

8.
プロジェクト設定の変更
・プロジェクト名の変更
・スキーム名の変更
・バンドルIDの変更
・provisioning profileの設定

9.
その他変更
・アプリ名変更
・アプリアイコン変更
・スプラッシュ変更
・不要なライブラリパスなどを変更・削除
など

10.
ビルドして実行できることを確認

11.
commitしてpushする
$ git add
$ git commit
$ git push origin master

12.
過去プロジェクトのコミットログが不要の場合は、コミットをまとめてしまってもよい。
$ git rebase -i --root
で最初のコミットから全部rebaseできる。
PR
【2015/02/05 13:25 】 | ゲーム開発一般 | 有り難いご意見(0)
AndroidのIntent
Intentには設定できるプロパティがいろいろある。

action Intent.ACTION_VIEWなど
data
type MIME data type とか
class Intent呼び出し時に使用するクラスを指定。そのクラスは onReceive(Context, Intent) メソッドをオーバーライドしていて、その中でextraなどを取得して処理を行う
category Actionの振る舞いを明確にする。Intent.CATEGORY_BROWSABLEなど
flag 呼び出される側の起動する振る舞い。例えばバックグラウンドで呼び出される場合はIntent.FLAG_FROM_BACKGROUND
extra 付加情報。例えばIntent.EXTRA_TEXTを使えば、twitterクライアントを起動したとき、本文として表示させたいテキストなどをセットする




参考



Intent i = new Intent(getApplicationContext(), LocalNotificationReceiver.class);
i.putExtra("notification_id", tag);
i.putExtra("message", message);

PendingIntent sender = PendingIntent.getBroadcast(this, tag, i, PendingIntent.FLAG_UPDATE_CURRENT);

AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), sender);



PendingIntentは時間差でIntentを作るクラス。
calendar には起動させたい時刻が入っているとする。

LocalNotificationReceiver というクラスに onReceive() メソッドが定義されている。
これによってローカル通知が実装できることになる。


【2015/02/03 14:13 】 | Android | 有り難いご意見(0)
Androidでtwitterにテキストと画像を投稿(Intent)
twitterに投稿したい。
手軽なので、Intentを使いたい。


◯テキストだけの場合
めちゃ簡単。


String encodedText;
try {
encodedText = URLEncoder.encode(text, "UTF-8");
} catch ( java.io.UnsupportedEncodingException ignore ) {
encodedText = text;
}

String encodedUrl = "http://twitter.com/share?text=" + encodedText;
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(encodedUrl));
getContext().startActivity(intent);




◯画像も投稿する場合

twitterにテキストと画像を投稿する参考
【2015/01/29 14:42 】 | Android | 有り難いご意見(0)
ファイルやディレクトリが作成できない
Fileクラスの
createNewFile()……IOExceptionが投げられる
mkdirs()……falseが返る
などが実行できないとき

マニフェストに

を書くこと。

権限をアプリに持たせないと、外部ストレージに書き込みができない。



【2015/01/29 13:15 】 | Android | 有り難いご意見(0)
cocos2d-x 3.2 android化
Xcodeで作った物を、Eclipseで動かすための必要な作業


・コンパイルファイル設定
Android.mk

CPP_FILES := $(shell find $(LOCAL_PATH)/../../Classes -name *.cpp)
LOCAL_SRC_FILES := hellocpp/main.cpp
LOCAL_SRC_FILES += $(CPP_FILES:$(LOCAL_PATH)/%=%)
LOCAL_C_INCLUDES := $(shell find $(LOCAL_PATH)/../../Classes -type d)





cocos2d/extensionsの機能を使う場合は、以下の2行をコメントアウト。

LOCAL_WHOLE_STATIC_LIBRARIES += cocos_extension_static
$(call import-module,extensions)





・パスの変更

#include "cocos-ext.h"
#include "CCVector.h"

#include <extensions/cocos-ext.h>
#include <base/CCVector.h>




その他にも、
#include
など、Xcodeでは不要だがEclipseだと明示的にインクルードが必要なものなど出てくるので注意。



◯ライブラリプロジェクト使用時の注意


外部ライブラリが必要になる場合がある。
単体のjarファイル1つあればよいときは、libsディレクトリにjarファイルを配置するだけでよいので話が早い。
git addすれば、他の人もそのまま使えるので便利。
android-support-v4.jar や、各種広告SDKはそういう形になっている。


しかしそうではなく、Eclipse上でライブラリプロジェクトとして登録し、それへのリンクを保持する必要がある場合もある。
例えばlibcocos2dもそうだし、google-play-servicesなどもそれにあたる。



このプロジェクトをEclipseに登録する。
File -> New -> Other -> Android Project from Existing Code


Eclipseに表示される


で、これを自分のプロジェクトからリンクする。


これで完了……ではない。

ライブラリプロジェクトの中身を見ると、
libs/google-play-services.jar
というファイルがあるが、実際に使うのはこれではない。

ビルドしてみると分かるが、エラーになる。
bin/google-play-services-lib.jar
という名前のjarファイルが存在しない、というエラーになる。

このjarは、ライブラリプロジェクトをビルドすると生成される。

ので、ビルドしよう。
ライブラリプロジェクトを右クリック→Build Projectをする。

しかし、このときエラーが出ることがある。
プロジェクトのプロパティを見ると、Project Build Target が選択されていないことがある。

正しいバージョンを選択し、再度ビルド。

これで成功し、bin/ 以下にjarファイルが生成される。

これで、自分のプロジェクトもビルドに成功する。



◯cocos2d-xのライブラリ
また、
couldn't load cocos2dcpp



というエラーが出ることがある。

これは、proj.androidで
$ ./build_native.py
または
$ ./build_native.sh
を実行し、cocos2dcppを作成することで治る。

libs/armeabi/libcocos2dcpp.so
obj/local/armeabi/libcocos2dcpp.so

などが生成される。


【2015/01/20 12:59 】 | cocos2d-x | 有り難いご意見(0)
androidでフォント追加
ttfファイルをどこかからダウンロード。

PROD_DIR/proj.android/assets/fonts/XXX.ttf
に配置。

EclipseのPackageExplorerで F5 を押してrefreshすると、表示される。

Label::createで
"fonts/XXX.ttf"
を指定。ファイル名やフォント名でなく、assets以下のフルパスで指定することに注意。

これで表示されるようになる。
簡単。


なお、iOSではフォント名での指定なので、OSによって変える必要がある。
イケてないね。
【2015/01/19 12:16 】 | cocos2d-x | 有り難いご意見(0)
libcurlが悪さする


Xcodeで作っていたcocosプロジェクトを、androidで動かそうとしたときにエラー。


relocation overflow in R_ARM_THM_CALL



とか言われる。
調べてみると
参考
libcurlというライブラリが問題らしい。

コンパイルオプションをつけると解決できるとか、NDKのバージョンを戻すと治るとか治らないとか情報が交錯しているが、
cocos2d-x 3.3rc2
以降だとlibcurlの問題が解決しているらしく、
最新のcocos2d-xをダウンロードして、
cocos2d-x-3.3rc2/external/curl/
ディレクトリをまるっとコピペしたら治った。
【2015/01/16 17:57 】 | cocos2d-x | 有り難いご意見(0)
cocos2d-xの3.xで、スクロールビューとメニューを同時に使う
cocos2d-xで、スクロールビューの中身にメニューを配置したい。

簡単なことのようだが、実は問題がある。

メニューのアイテムをタッチすると、画面がスクロールできないのである。
つまり、アイテムの配置されていない箇所に指を触れてからスワイプしないと、画面がスクロールさせられないのである。
これは不便だしかっこわるい。


どうしてこうなっているのかというと…
メニュー(Menu)にtouchBeganイベントが処理されると、イベントが飲み込まれ、ScrollViewのtouchBeganイベントが処理されなくなるのである。


◯優先度について

cocos2d-xでは、EventDispatcherクラスにタッチイベントを登録する際(タッチ以外にも、マウスやキーボードイベントなども登録できる)、優先度を指定して登録する。

2種類の方法がある。

getEventDispatcher()->addEventListenerWithSceneGraphPriority(_touchListener, this);
getEventDispatcher()->addEventListenerWithFixedPriority(_touchListener, -100);






1つめの方法は、シーングラフの優先度と同じ優先度になる。
つまり、描画順序と同じく、シーン上の親から子への順序でイベントが処理される。

2つめの方法は、第2引数で指定した固定優先度で実行される。値が小さいほど優先度が高い。マイナス値も使えるので、-INT_MAXが一番優先度が高くなる。

混ぜて使う場合、

固定優先度がマイナス値のもの。-INT_MAX→-1

シーングラフ優先度が高いものから低いもの

固定優先度が0またはプラス値のもの。0→INT_MAX

という順番で処理される。
実装はEventDispatcher::dispatchEventToListeners()にある。


さて、メニューとスクロールビュー、どちらのタッチイベントが先に処理されるかというと、この優先度順序に依る訳である。

実装部分を見てみると、


void ScrollView::setTouchEnabled(bool enabled)
{
// :
//略
// :
_touchListener = EventListenerTouchOneByOne::create();
_touchListener->onTouchBegan = CC_CALLBACK_2(ScrollView::onTouchBegan, this);
_touchListener->onTouchMoved = CC_CALLBACK_2(ScrollView::onTouchMoved, this);
_touchListener->onTouchEnded = CC_CALLBACK_2(ScrollView::onTouchEnded, this);
_touchListener->onTouchCancelled = CC_CALLBACK_2(ScrollView::onTouchCancelled, this);

_eventDispatcher->addEventListenerWithSceneGraphPriority(_touchListener, this);
// :
//略
// :
}

bool Menu::initWithArray(const Vector<MenuItem*>& arrayOfItems)
{
// :
//略
// :
auto touchListener = EventListenerTouchOneByOne::create();
touchListener->setSwallowTouches(true);

touchListener->onTouchBegan = CC_CALLBACK_2(Menu::onTouchBegan, this);
touchListener->onTouchMoved = CC_CALLBACK_2(Menu::onTouchMoved, this);
touchListener->onTouchEnded = CC_CALLBACK_2(Menu::onTouchEnded, this);
touchListener->onTouchCancelled = CC_CALLBACK_2(Menu::onTouchCancelled, this);

_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
// :
//略
// :
}






という風に、どちらもシーングラフの優先度通りに実行されるようになっている。

当然といえば当然なのだが、これだと困る。

どんなときでも常にメニューが優先されるからだ(スクロールビューよりメニューが手前に表示されるはずなので)。
だからメニューのアイテム上をタッチしたときは、touchBeganイベントはスクロールビューに回ってこない。

メニューをタップしたいときはこれでいいが、スクロールしたいときは困る。

「メニューをタップしてそのまま離したときは、メニューのtouchBegan,touchEndedを処理。
メニューをタップして指を滑らしたときは、スクロールビューのtouchBegan,touchMoved,touchEndedを処理」
というふうにしたいのだ。

ということは、touchBeganの時点では、スクロールビューとメニューの両方で処理を走らせる必要がある。


◯swallow設定

cocos2d-xのイベントには、スワローというメンバ変数がある。
スワローの意味は「飲み込む」。
複数のイベントリスナーが登録されているとき、1つのイベントは上記で見た優先度順に処理されていく訳だが、
その途中でswallowがtrueになっているイベントリスナーがあると、そこで処理が終了してしまう。それ以降のイベントリスナーには処理がわたらないようになっている(これが飲み込む、の意)

で、もう一度さっきの実装コードを見てみると、メニューは
touchListener->setSwallowTouches(true);
と描いている。
つまり、タッチイベントはメニューに処理されると、それ以降他のノードには渡されなくなるのだ。もちろんスクロールビューにも、である。

なるほど、だからメニュー上をタップするとスクロールしないのか。

逆に、スクロールビューではスワロー設定をしていないので、デフォルトのfalseのままである。


ということは、
「メニューより先にスクロールビューでタッチイベントを処理すればいい」
のである。
スクロールビューで処理しても、優先度が低いイベントリスナーにも処理を渡すからだ。

ということで、スクロールビューのイベント登録部分を改造する。

void ScrollView::setTouchEnabled(bool enabled)
{
// :
//略
// :
_touchListener = EventListenerTouchOneByOne::create();
_touchListener->onTouchBegan = CC_CALLBACK_2(ScrollView::onTouchBegan, this);
_touchListener->onTouchMoved = CC_CALLBACK_2(ScrollView::onTouchMoved, this);
_touchListener->onTouchEnded = CC_CALLBACK_2(ScrollView::onTouchEnded, this);
_touchListener->onTouchCancelled = CC_CALLBACK_2(ScrollView::onTouchCancelled, this);

//_eventDispatcher->addEventListenerWithSceneGraphPriority(_touchListener, this);
_eventDispatcher->addEventListenerWithFixedPriority(_touchListener, -100); //<- br=""> // :
//略
// :
}





優先度値はマイナス値ならとりあえず何でもいい。

これで試してみると、メニューをタップしてもちゃんとスクロールするようになる!!


◯メニュータップのタッチ処理を止める

しかし、ちょっと動かしてみると少し違和感がある。

確かにメニュー上をタップしてもスクロールするようになるのだが、
スクロールしたあと指を離したときに、メニューアイテムが押されるのである。
指をメニューアイテムの無い場所で離せば何も起きないが、
要するにメニューのタッチイベントがまだ生きているのである。
よく見てみれば、タップしたメニューアイテムはselected状態のスプライトが表示されたままに鳴っている。

メニューのtouchBeganで始まった処理が有効で、指を離したときにtouchEndedが発生すると、その通りメニューアイテムを選択してしまうのである。


これはちょっといやだ。
スクロールした時点で、メニューのタッチイベントは終わらせたい。

そういう処理はなかったか?
もちろんある。

onTouchCancelledだ。
これはタッチイベントが中断されたときに呼び出されるメソッドだ。
本来はタップ中に電話がかかってきてアプリが中断されたときとかに呼ばれる想定だが、今回の目的はまさにこのメソッドを呼ぶことにある。


つまり、「スクロールビューのスクロールが発生した時点で、登録されている他のすべてのイベントリスナーのonTouchCancelledを呼び出す」
ということである。
onTouchMovedやonTouchEndedは呼び出させないのだ。


さてどうするか。
そもそもonTouch***系を呼び出している部分のコードを見てみる。


void EventDispatcher::dispatchTouchEvent(EventTouch* event)
{
//略
auto oneByOneListeners = getListeners(EventListenerTouchOneByOne::LISTENER_ID);
//略
auto onTouchEvent = [&](EventListener* l) -> bool { // Return true to break
EventListenerTouchOneByOne* listener = static_cast<EventListenerTouchOneByOne*>(l);

//略

if (eventCode == EventTouch::EventCode::BEGAN)
{
if (listener->onTouchBegan)
{
isClaimed = listener->onTouchBegan(*touchesIter, event);
//略
}
}
else if (listener->_claimedTouches.size() > 0
&& ((removedIter = std::find(listener->_claimedTouches.begin(), listener->_claimedTouches.end(), *touchesIter)) != listener->_claimedTouches.end()))
{
isClaimed = true;

switch (eventCode)
{
case EventTouch::EventCode::MOVED:
if (listener->onTouchMoved)
{
listener->onTouchMoved(*touchesIter, event);
}
break;
case EventTouch::EventCode::ENDED:
if (listener->onTouchEnded)
{
listener->onTouchEnded(*touchesIter, event);
}
//略
break;
case EventTouch::EventCode::CANCELLED:
if (listener->onTouchCancelled)
{
listener->onTouchCancelled(*touchesIter, event);
}
//略
break;
//略
}
}
//略
dispatchEventToListeners(oneByOneListeners, onTouchEvent);
//略
}

void EventDispatcher::dispatchEventToListeners(EventListenerVector* listeners, const std::function<bool(EventListener*)>& onEvent)
{
//略
for (; i < listeners->getGt0Index(); ++i)
{
auto l = fixedPriorityListeners->at(i);
if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))
{
shouldStopPropagation = true;
break;
}
}
//略
for (auto& l : *sceneGraphPriorityListeners)
{
if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))
{
shouldStopPropagation = true;
break;
}
}
//略
for (; i < size; ++i)
{
auto l = fixedPriorityListeners->at(i);

if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))
{
shouldStopPropagation = true;
break;
}
}
//略
}





dispatchEventToListeners()の中で、優先度順のループが3つあり(固定優先度がマイナス値のもの、シーングラフ優先度のもの、固定優先度がプラス値のもの)、順番にonEventメソッドを呼んでいる。
onEventメソッドの実体はdispatchTouchEventの中のonTouchEvent というラムダ関数で、
この中でイベントリスナーを処理し、それぞれonTouchXXX関数を呼び出している。


スクロールビューのonTouchMovedの中でスクロールが発生したと判断したときに、
それ以降のイベントリスナーについてはすべてonTouchCancelledを呼び出すようにすればいい。

ということで、EventDispatcherクラスに_touchEventForceCancelled というフラグを用意し、以下のように改造する。


CCEventDispatcher.h

class EventDispatcher : public Ref
{
void setTouchEventForceCancelled(){_touchEventForceCancelled = true;} //<-追加
bool _touchEventForceCancelled; //<- br="">};


CCEventDispatcher.cpp

void EventDispatcher::dispatchTouchEvent(EventTouch* event)
{
_touchEventForceCancelled = false; //<-追加

//略
else if (listener->_claimedTouches.size() > 0
&& ((removedIter = std::find(listener->_claimedTouches.begin(), listener->_claimedTouches.end(), *touchesIter)) != listener->_claimedTouches.end()))
{
isClaimed = true;

if (_touchEventForceCancelled){ //<-追加
eventCode = EventTouch::EventCode::CANCELLED; //<-追加
} //<-追加
switch (eventCode)
//略
}


CCScrollView.cpp

void ScrollView::onTouchMoved(Touch* touch, Event* event)
{
//略
if (std::find(_touches.begin(), _touches.end(), touch) != _touches.end())
{
if (_touches.size() == 1 && _dragging)
//略
if (_dragging)
{
//略
_eventDispatcher->setTouchEventForceCancelled(); //<-追加
}
//略
}






とする。
解説。ScrollViewのonTouchMovedで、スクロール発生と判断されたタイミングで、EventDispatcherに、「以降のタッチイベントをすべてキャンセルさせろ」というフラグを立てる。

すると、それ以降のEventDispatcher::dispatchTouchEvent()内の処理で、タッチイベントはすべてEventTouch::EventCode::CANCELLEDに強制的に書き換える、ということである。



これで、メニュー上をタップしても、指を滑らせてスクロールすると、メニューのタッチイベントはキャンセルされる。
スプライトは選択状態のものから通常状態のものに戻るし、指を離してもアイテムは選択されない。


◯スクロールビューの無効化

スクロールビューにはもう一つバグがある。それは
「不可視状態でもタッチイベントが処理され、スクロールしている」
ということである。

正確なことを言うと、
スクロールビュー自体にsetVisible(false) を呼び出していれば処理されないのだが、
スクロールビューの祖先ノードでsetVisible(false)をしていて、スクロールビュー自体の_isVisibleがtrueのままの場合、処理されてしまう。

普通、他の種類のクラス(メニューとか)だと、親が_isVisible==falseなら処理しないようになっているので(普通に考えてそれが正しい)、スクロールビューがバグっている。
スクロールビューはextension扱いだし、どうもこういう不具合がまだ多い。

これに対処するのは割と簡単で、
onTouchXXX()系のすべての関数の先頭に以下のコードを書き足せば良い。

for (Node *c = this->_parent; c != nullptr; c = c->getParent())
{
if (c->isVisible() == false)
{
return;
}
}


このコードは、Menu.cppからコピペしたものである。

【2015/01/15 17:23 】 | cocos2d-x | 有り難いご意見(0)
Alamofireをプロジェクトに追加
swiftで通信を行うフレームワークと言えばAlamofire。
これをプロジェクトに追加する手順。

基本はgit-hubのREADMEの通りにやればよい。
git-hub

文字だけで分かりにくいので、画像付きで。


まず、プロジェクトのトップディレクトリで以下のコマンドを実行
$ git submodule add https://github.com/Alamofire/Alamofire.git
これで、Alamofire/ というディレクトリができ、中にフレームワークがひとそろい配置される

次に、中のAlamofire.xcodeprojをドラッグ&ドロップして自分のプロジェクトに追加


AlamofireのPROJECTペインを選択し(自分のプロジェクトではない)、DeploymentTargetのOSバージョンを設定する。

ここ重要。
ここで設定したOSメジャーバージョン以上の端末でしか動作しなくなる。

自分のプロジェクト側の Build Settings でそれより低いメジャーバージョンを設定すると…


ビルドエラーになる。

注意すること


さらに、自分のプロジェクトの Build Phases を選び、
Target Dependincies にAlamofire.frameworkを追加。

左上の「+」ボタンから、新たに「CopyFramework 」という名前のフェーズを作成し、そこにもAlamofire.frameworkを追加。



これにてAlamofireが使えるようになる。
【2015/01/11 13:09 】 | swift | 有り難いご意見(0)
spriteBatchNodeを使う
cocos2d-xにあるSpriteBatchNodeクラス。

複数のスプライトを効率よく描画したいときに使う。

例えば同じ絵のキャラを大量にわらわらと表示させたいとき。

SpriteBatchNodeクラスのインスタンスのノードを作り、このクラスにテクスチャを登録する。
その子ノードに同じテクスチャを貼ったスプライトを大量に付ける。

すると、一度の描画命令で子ノードが全部描画できる。


ポイントは、SpriteBatchNodeクラスに登録したテクスチャと
「同じテクスチャ」を持つノードしか子ノードにできないこと。
テクスチャでなく、SpriteFrameでも良い。アニメーションする場合や、複数の絵を子ノードに並べたいときはSpriteFrameを使うことになるだろう。


実際に描画回数が減っているかどうかは、
画面左下に出ている。
GL calls が描画回数、
GL verts が頂点数。

GL callsがテクスチャ数より少なくなっていれば、効いている…はず

詳しいところはもう少しコードを追いかけてみる。




ちなみにLabelクラスはSpriteBatchNodeの子クラスである。



…といったところで、
v3.xでは標準でドローをまとめる機能がついたらしく、SpriteBatchNodeは非推奨になったとかなんとか。
参考
【2015/01/08 19:30 】 | cocos2d-x | 有り難いご意見(0)
<<前ページ | ホーム | 次ページ>>