3日坊主で終わらないためのアプリ開発日記 16日目

吾輩はやれば出来る子である。
    ∩∩
   (´・ω・)
   _| ⊃/(___
 / └-(____/
  ̄ ̄ ̄ ̄ ̄ ̄ ̄

  • 本日の作業

ステージクリア演出 3パターン 1時間目(全5時間)

ステージクリア演出の初回は、コーディングをせずに概要をまとめます。

クリア条件は以下の3つです。クリア時に、それぞれのクリア条件に応じたメッセージを一定時間表示します。

1.自ユニットを特定位置に移動
「Logic success!! Moved to goal!」
2.敵ユニットを全滅させる
「Logic success!! Eliminate enemies!」
3.自ユニットの個体数を特定数以上にする
「Logic success!! Seeds of prosperity!」

メッセージを表示してから一定時間後「STAGE SELECT」「TITLE」の2つのボタンを表示します。

  • 明日の作業

ステージクリア演出 3パターン 2時間目(全5時間)

3日坊主で終わらないためのアプリ開発日記 14日目

100日目にはアプリが公開されているはず。楽しみだなぁ。
吾輩はやれば出来る子である。
    ∩∩
   (´・ω・)
   _| ⊃/(___
 / └-(____/
  ̄ ̄ ̄ ̄ ̄ ̄ ̄

  • 本日の作業

ロジックパネルの取得方法をどうするか考える 2時間目(全2時間)

前回挙げた案から、どれを採用するか検討します。

とりあえずサーバーなしで、単純なステージクリア型アプリとして完成させようとしているので、前回挙げた案の中からだと

・・・
・・

1.ステージクリアで取得

各ステージごとに固有のロジックパネルを1回だけ取得出来るようにします。アプリの性質上、同じロジックを組めば何度でも完璧にクリア出来る想定なので、1回だけ取得可能とします。

これしかないな・・・

今日は5分で終わった。
なんか寂しいのでチャーハン作るよをパク・・オマージュしたアプリ作るよのAA貼っときます。

 
  ∧,,∧
 (;`・ω・)  。・゚・⌒) アプリ作るよ!!!
 /   o━ヽニニフ))
 しー-J

  • 明日の作業

ステージクリア演出 3パターン 1時間目(全5時間)

3日坊主で終わらないためのアプリ開発日記 13日目

100日目にはアプリが公開されているはず。楽しみだなぁ。
吾輩はやれば出来る子である。
    ∩∩
   (´・ω・)
   _| ⊃/(___
 / └-(____/
  ̄ ̄ ̄ ̄ ̄ ̄ ̄

  • 本日の作業

ロジックパネルの取得方法をどうするか考える 1時間目(全2時間)

全2回なので、1回目は案を挙げたいと思います。

1.ステージクリアで取得

各ステージごとに固有のロジックパネルを1回だけ取得出来るようにします。アプリの性質上、同じロジックを組めば何度でも完璧にクリア出来る想定なので、1回だけ取得可能とします。

2.ログインボーナス(1日1個) ※サーバ準備前提

1日1個、ランダムでロジックパネルを取得可能とします。

3.対人戦で奪い合う ※サーバ準備前提

対人戦で勝利した場合、相手のロジックボードに実際に配置されていたロジックパネルをランダムで取得可能とします。

4.アイテム課金 ※サーバ準備前提

ちゃんと考えてロジックを組めば、お金をかけたプレーヤーに対人戦で勝てるバランス前提で、アイテム課金で取得可能とします。

  • 明日の作業

ロジックパネルの取得方法をどうするか考える 2時間目(全2時間)

今回挙げた案から、どれを採用するか検討します。

3日坊主で終わらないためのアプリ開発日記 12日目

吾輩はやれば出来る子である。
    ∩∩
   (´・ω・)
   _| ⊃/(___
 / └-(____/
  ̄ ̄ ̄ ̄ ̄ ̄ ̄

  • 本日の作業

ロジックパネルの個数化 5時間目(全5時間)

ロジックパネルを配置したロジックボード全体をセーブ出来ますが、そのデータをロードする際に、所持ロジックパネル数以上のデータをロード出来ないようにします。

下記のように、”slot2″に6つの”歩く”ロジックパネルがセーブされていますが

スクリーンショット 2016-01-03 23.07.39

ユーザーの”歩く”ロジックパネル所持数を3に設定した上でslot2をロードしようとすると、以下のように足りない分は表示されません。

notenough

今回で、ロジックパネルの個数化作業は完了しました。これでロジックパネルをアイテムとして取得・コレクションする楽しみが増したと思います。

  • 明日の作業

ロジックパネルの取得方法をどうするか考える 1時間目(全2時間)

3日坊主で終わらないためのアプリ開発日記 11日目

吾輩はやれば出来る子である。
    ∩∩
   (´・ω・)
   _| ⊃/(___
 / └-(____/
  ̄ ̄ ̄ ̄ ̄ ̄ ̄

  • 本日の作業

ロジックパネルの個数化 4時間目(全5時間)

ロジックボードに、ユーザが所持しているロジックパネル数以上を配置出来ないように制限をかけました。

  • 明日の作業

ロジックパネルの個数化 5時間目(全5時間)

ロジックパネルを配置したロジックボード全体をセーブ出来ますが、そのデータをロードする際に、所持ロジックパネル数以上のデータをロード出来ないようにします。

3日坊主で終わらないためのアプリ開発日記 10日目

吾輩はやれば出来る子である。
    ∩∩
   (´・ω・)
   _| ⊃/(___
 / └-(____/
  ̄ ̄ ̄ ̄ ̄ ̄ ̄

  • 本日の作業

ロジックパネルの個数化 3時間目(全5時間)

ロジックパネルの選択画面で、所持しているロジックパネルの個数を表示するようにしました。
IMG_0343

GameSceneクラスとMainViewクラスの両方でUserDataクラスを参照することになったので、GameViewControllerクラスにUserDataクラスを置き、各クラスに渡して参照することとしました。

————- GameViewController.h ————-

@interface GameViewController : UIViewController {
GameScene *_scene;
MainView *_mainView;
UserData *_UD;
}

————- GameViewController.m ————-

// ユーザーデータのロード
_UD = [[UserData alloc] init];
if (![_UD load]) {
// 初期値
[_UD addLogicPanel:KIND_ACTION data:LP_A_WK num:3];
[_UD addLogicPanel:KIND_ACTION data:LP_A_RT num:2];
[_UD addLogicPanel:KIND_ACTION data:LP_A_LT num:2];
[_UD addLogicPanel:KIND_JUDGE data:LP_J_FW num:1];
}

  • 明日の作業

ロジックパネルの個数化 4時間目(全5時間)

ロジックボードに、ロジックパネルで表示された個数以上を配置出来ないようにします。

3日坊主で終わらないためのアプリ開発日記 9日目

吾輩はやれば出来る子である。
    ∩∩
   (´・ω・)
   _| ⊃/(___
 / └-(____/
  ̄ ̄ ̄ ̄ ̄ ̄ ̄

  • 本日の作業

ロジックパネルの個数化 2時間目(全5時間)

前回、プレーヤーの所持データとして必要なものを

1.どのロジックパネルを何個持っているか

2.獲得累計経験値

としてまとめたので、これを保存/読込するUserDataクラスを作成する。

ロジックパネルのデータは、

種別(“ACTION” もしくは “JUDGE”)

種類(“歩く”や”左を向く”や”前方が壁なら”など)

個数

の3つを1セットとし、この3つの数値をメンバとしてもつLogicPanelUnitクラスを作成する。

UserDataクラスには、このLogicPanelUnitクラスを配列で可変個と、獲得累計経験値を持たせ、saveとloadメソッドを実装する。

誰かの役に立つかはわかりませんが、コードを貼り付けます。

尚、swiftは最適化が進んでいないのかコンパイル/実行速度共に遅いので使ってません。

UserDataクラスにはレベルも持たせていますが、獲得累計経験値から逆算できるのでファイル保存はしていません。

———— LogicPanelUnit.h ————

#ifndef EggOfEvolution_LogicPanelUnit_h
#define EggOfEvolution_LogicPanelUnit_h

@interface LogicPanelUnit : NSObject <NSCoding> {
int _kind;
int _data;
int _num;
}

@property (nonatomic) int kind;
@property (nonatomic) int data;
@property (nonatomic) int num;

@end

#endif /* LogicPanelUnit_h */

———— LogicPanelUnit.m ————

#import <Foundation/Foundation.h>
#import “LogicPanelUnit.h”

@implementation LogicPanelUnit

@synthesize kind = _kind;
@synthesize data = _data;
@synthesize num = _num;

-(id)init {
if (self = [super init]) {
_kind = 0;
_data = 0;
_num = 0;
}
return self;
}

-(void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeInteger:_kind forKey:@”encKind”];
[aCoder encodeInteger:_data forKey:@”encData”];
[aCoder encodeInteger:_num forKey:@”encNum”];
}

-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];

_kind = (int)[aDecoder decodeIntegerForKey:@”encKind”];
_data = (int)[aDecoder decodeIntegerForKey:@”encData”];
_num = (int)[aDecoder decodeIntegerForKey:@”encNum”];

return self;
}

@end

———— UserData.h ————

#ifndef EggOfEvolution_UserData_h
#define EggOfEvolution_UserData_h

@interface UserData : NSObject {
int _lv;
long _exp;
NSMutableArray *_lpa;
}

@property (nonatomic, readonly) int lv;
@property (nonatomic, readonly) long exp;

-(BOOL)addExp:(int)exp;
-(BOOL)delExp:(int)exp;
-(BOOL)addLogicPanel:(int)kind data:(int)data num:(int)num;

-(void)dump;

-(BOOL)save;
-(BOOL)load;

@end

#endif /* UserData_h */

———— UserData.m ————

#import <Foundation/Foundation.h>
#import “UserData.h”
#import “LogicPanelUnit.h”

#define LOGIC_PANEL_MAX_NUM 99
#define MAX_EXP_NUM 38085

#define K_EXP @”kExp”
#define K_LOGICPANEL @”kLogicPanel”
#define K_VERSION @”kVersion”

#define FILENAME_USERDATA @”eoe.dat”

@implementation UserData

@synthesize lv = _lv;
@synthesize exp = _exp;

-(id)init {
if (self = [super init]) {
_lv = 1;
_exp = 0;
}
return self;
}

-(BOOL)addExp:(int)exp {
BOOL bRet = YES;
_exp += exp;
if (MAX_EXP_NUM < _exp) {
_exp = MAX_EXP_NUM;
bRet = NO;
}
[self recalcLv];
return bRet;
}

-(BOOL)delExp:(int)exp {
BOOL bRet = YES;
_exp -= exp;
if (_exp < 0) {
_exp = 0;
bRet = NO;
}
[self recalcLv];
return bRet;
}

-(BOOL)recalcLv {
int preLv = _lv;
int lv = 0;
long exp = _exp;
while (0 < exp) {
lv++;
exp -= [self expAtLv:lv];
}
_lv = lv;
return preLv != _lv;
}

-(long)expAtLv:(int)lv {
if (1 <= lv && lv <= 10) {
return (10 + lv);
} else if (11 <= lv && lv <= 30) {
return (20 + (lv – 10) * 5);
} else if (31 <= lv && lv <= 90) {
return (120 + (lv – 30) * 10);
} else if (91 <= lv && lv <= 99) {
return (720 + (lv – 90) * 100);
}
return 0;
}

-(BOOL)addLogicPanel:(int)kind data:(int)data num:(int)num {
BOOL bRet = NO;

if (nil == _lpa) {
_lpa = [[NSMutableArray alloc] init];
}

for (LogicPanelUnit *unit in _lpa) {
if (unit.kind == kind && unit.data == data) {
unit.num += num;
if (LOGIC_PANEL_MAX_NUM < unit.num) {
unit.num = LOGIC_PANEL_MAX_NUM;
bRet = NO;
}
return bRet;
}
}

LogicPanelUnit *newUnit = [[LogicPanelUnit alloc] init];
newUnit.kind = kind;
newUnit.data = data;
newUnit.num = num;
if (LOGIC_PANEL_MAX_NUM < newUnit.num) {
newUnit.num = LOGIC_PANEL_MAX_NUM;
bRet = NO;
}
[_lpa addObject:newUnit];

return bRet;
}

-(BOOL)save {

NSMutableDictionary *dicSettings = [[NSMutableDictionary alloc]init];

NSString *dir = [NSHomeDirectory() stringByAppendingPathComponent:@”Documents”];
NSString *path = [dir stringByAppendingPathComponent:FILENAME_USERDATA];

[dicSettings setObject:@”1.0.0″ forKey:K_VERSION];
[dicSettings setObject:[NSNumber numberWithLong:_exp] forKey:K_EXP];
if (nil != _lpa) {
[dicSettings setObject:_lpa forKey:K_LOGICPANEL];
}

if ([NSKeyedArchiver archiveRootObject:dicSettings toFile:path]) {
return YES;
}
return NO;
}

-(BOOL)load {
NSString *dir = [NSHomeDirectory() stringByAppendingPathComponent:@”Documents”];
NSString *path = [dir stringByAppendingPathComponent:FILENAME_USERDATA];

NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:path]) {

NSMutableDictionary *dicSettings = (NSMutableDictionary*)[NSKeyedUnarchiver unarchiveObjectWithFile:path];

_exp = [[dicSettings objectForKey:K_EXP] longValue];
[self recalcLv];

_lpa = [dicSettings objectForKey:K_LOGICPANEL];

} else {
return NO;
}
return YES;
}

-(void)dump {
NSLog(@”LV=[%d]”, _lv);
NSLog(@”EXP=[%ld]”, _exp);
for (LogicPanelUnit *unit in _lpa) {
NSLog(@”LOGICPANEL=[%d,%d,%d]”, unit.kind, unit.data, unit.num);
}
}

@end

  • 明日の作業

ロジックパネルの個数化 3時間目(全5時間)

3日坊主で終わらないためのアプリ開発日記 8日目

吾輩はやれば出来る子である。
    ∩∩
   (´・ω・)
   _| ⊃/(___
 / └-(____/
  ̄ ̄ ̄ ̄ ̄ ̄ ̄

  • 本日の作業

ロジックパネルの個数化 1時間目(全5時間)

ロジックパネルの個数化作業ということで、とりあえず初回はコードを書かず、作業内容を文書でまとめる。

ロジックパネルは現在、ロジックボードへ無制限に置くことができる。これを所持数以上は使えないようにする。やはりゲームの要素としてアイテムを集めるというのは楽しい作業だと思う。

プレーヤーの所持データとして各種ロジックパネルとその個数を保存する。1種類のロジックパネルは最大99個まで持てるものとする。
昨日のレベルの概念で決定した経験値も一緒に保存する。保存するデータは以下となる。

1.どのロジックパネルを何個持っているか

2.獲得累計経験値

保存データは可変長となる。

将来的に、対プレーヤー戦も見据えて保存データは暗号したり、サーバー上に置くことも考える。

保存処理を担当するクラスを1つ作成し、MainViewクラスに所持させることとする。

大枠の構成として、現在はGameViewControllerクラスがMainViewクラスやGameSceneクラスを生成して制御している。

MainViewクラスはGLKViewを継承しており、OpenGLによりマップやキャラを描画するクラスである。描画パフォーマンスは高いが、制御が大変で作成に時間がかかる。

GameSceneクラスはSKSceneを継承した2Dグラフィックを扱うクラスで、主にジャギーのない綺麗なUIを描画するクラスである。描画パフォーマンスは低いが、簡単なコードで素早く作成することができる。

場面に応じて、適材適所でMainViewとGameSceneを切り替えて制作を行う。

  • 明日の作業

ロジックパネルの個数化 2時間目(全5時間)