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時間)

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

奇跡が起きた。
1週間アプリ開発続いた。
吾輩はやれば出来る子である。
    ∩∩
   (´・ω・)
   _| ⊃/(___
 / └-(____/
  ̄ ̄ ̄ ̄ ̄ ̄ ̄

  • 本日の作業

レベルの概念をどうするか考える。

1.レベルアップでHPが増えるものとする。

2.レベルアップである程度ゴリ押しでクリアできるようになるが、基本的にはちゃんとロジックを組まないとクリアできない(対プレーヤー戦では勝てない)ようにする。

3.レベルは1〜最大99までとし、レベルごとのHPは以下の通りとする。

レベル1〜90のHPは4+レベル
(レベル1は5、レベル2は6、… レベル90は94)
レベル91〜92のHPは95
レベル93〜94のHPは96
レベル95〜96のHPは97
レベル97〜98のHPは98
レベル99のHPは99

4.レベルアップに必要な経験値は以下の通りとする。

レベル1〜10は10+レベル
(レベル1は11、レベル2は12、… レベル10は20)
レベル11〜30は20+(レベル-10)*5
(レベル11は25、…レベル30は120)
レベル31〜90は120+(レベル-30)*10
(レベル31は130、…レベル90は720)
レベル90〜99は720+(レベル-90)*100
(レベル91は820、…レベル99は1620)

レベル99になるのに必要なトータル経験値は38085

5.通常ステージでは敵を倒すことで、敵が所有している経験値の3%(小数切り上げ)を得る。敵を倒す定義は、攻撃により敵のHPを最大HPの1/3以上減らすこととする。

レベル1のキャラが仮にレベル99のキャラを倒した場合、貰える経験値は、38085 * 0.03 = 1143(切り上げ)で、一気にレベル28になる。

6.”競技場”で相手プレーヤーに勝ったら、相手プレーヤーが所有している経験値の3%(小数切り上げ)を得る。競技場で負けたプレーヤーは、経験値の3%を失う。

7.ロジックパネル”コピー”により複製したキャラは、”コピー”を実行したキャラのレベルを引き継ぐものとする。

  • 明日の作業

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

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

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

  • 本日の作業

HP0でのゲームオーバー演出 3時間目(全3時間)

“味方キャラ”が全員死んだら「LOGIC FAILED…」と表示して画面を暗くする。

画面を暗くした際に「LOGIC FAILED…」と表示するだけだと何もできないので、「Retry?」と続け、「YES」と「NO」の選択肢を表示するようにした。(既存のYES/NO選択画面の使い回し)

「YES」を選択すると、ステージの初期状態に戻り、「NO」を選択すると、まだ未作成だがタイトル画面に戻る想定。

  • 明日の作業

レベルの概念をどうするか考える。

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

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

  • 本日の作業

HP0でのゲームオーバー演出 2時間目(全3時間)

HP0でいきなりキャラが消えるのは寂しいので、一定時間点滅してから消えるようにしました。

  • 明日の作業

“味方キャラ”が全員死んだら「LOGIC FAILED…」と表示して画面を暗くする。

大手には作れないアプリを(気持ちだけは(๑•̀ㅂ•́)و✧)