1つのファイルにキャラ名、HP、顔画像データを保存する方法

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Killery
記事: 7
登録日時: 11年前

1つのファイルにキャラ名、HP、顔画像データを保存する方法

#1

投稿記事 by Killery » 8年前

1つのセーブデータdatファイルに、
キャラクター名、HP、顔画像を保存する方法を教えてください
構造体は

コード:

typedef struct _DATA{
 NSString *name;
 NSInteger HP;
 NSImage *img;
}DATA;
と、なっております
これをまとめて一つのファイルに保存する方法を教えてください
なお、画像は間接参照ではなく、名前、HPと同じファイルにバイナリ形式などを取ります

inec0310
記事: 15
登録日時: 8年前
住所: 埼玉県

Re: 1つのファイルにキャラ名、HP、顔画像データを保存する方法

#2

投稿記事 by inec0310 » 8年前

顔画像はどうしようか考えましたが
とりあえずhttp://dixq.net/g/03_11.htmlが大きなヒントになると思います。
顔写真については、例えばfaceフォルダーを作ってその中に001.pngから順に作れるようなプログラムを組めばいいかとそしてその番号を記憶するなりすれば
いいと思います

Killery
記事: 7
登録日時: 11年前

Re: 1つのファイルにキャラ名、HP、顔画像データを保存する方法

#3

投稿記事 by Killery » 8年前

inec0310 さんが書きました:顔写真については、例えばfaceフォルダーを作ってその中に001.pngから順に作れるようなプログラムを組めばいいかとそしてその番号を記憶するなりすれば
いいと思います
間接参照の方法は知っているのですが、それでは満足いきません
重要なのは、別のステータスデータと一緒に画像データも一つのファイルに入ってることです

例えば、

名前:名無し
HP:100
画像参照:nanashi.png(画像ファイルの名前で参照することによって読み込む方法)

ではなく、

名前:名無し
HP:100
画像バイナリデータ:(画像のデータのバイナリコード)

としたいのです

Killery
記事: 7
登録日時: 11年前

Re: 1つのファイルにキャラ名、HP、顔画像データを保存する方法

#4

投稿記事 by Killery » 8年前

それと、
http://dixq.net/g/03_11.html
のやり方は以前ググって分かりました

ここのやり方は、ポインターを取り扱った構造体セーブデータのやり方が書かれていません
int型の通常の変数だけです

ポインターをセーブデータにするのは、アドレスが保存されるだけなので、無意味ということですが、
ポインターが示している実態の内容をセーブデータに保存し、同じアドレスで内容を参照するのは
どうすればいいのでしょうか?

moba_

Re: 1つのファイルにキャラ名、HP、顔画像データを保存する方法

#5

投稿記事 by moba_ » 8年前

素人がでしゃばって回答させていただきます。
間違っていたらごめんなさい。

ハンドルを直接保存せず、クッションを挟むのがいいと思います。特別な環境でなければ、ゲームを起動する度に、毎回同じメモリ位置に同じデータを読み込むのは不可能です。
例えば、メモリのサイズは様々なので、あるpcでは表せない範囲のメモリ位置を保存するかもしれません。すでにその範囲が使用されていた場合でも、奪うわけにもいきません。

画像ファイルは、アドレスをセーブして、特定のタイミングでアドレスをハンドルに自動で変換するのはどうでしょうか。良い方法は分かりませんが具体的には次のような手があると思います。

(前提)
・全ての画像をスプライトとして表示する
・スプライトは、画像のアドレスや描画位置の情報を持つ(シーングラフを想定しています)

(実装)
・画像のアドレスをセーブする
・画像のアドレスからスプライトを作る。そのとき、自動的に画像のアドレスをハンドルに変換する

アドレスにさらにクッションを挟むこともできます。例えば、タグ(文字列)や番号をセーブする手もあります。セーブしない部分でこそ使いそうですが…(例えば効果音をcancelSoundとして設定するとき)

Killery
記事: 7
登録日時: 11年前

Re: 1つのファイルにキャラ名、HP、顔画像データを保存する方法

#6

投稿記事 by Killery » 8年前

ハンドルを直接保存せず、クッションを挟むのがいいと思います。特別な環境でなければ、ゲームを起動する度に、毎回同じメモリ位置に同じデータを読み込むのは不可能です。
例えば、メモリのサイズは様々なので、あるpcでは表せない範囲のメモリ位置を保存するかもしれません。すでにその範囲が使用されていた場合でも、奪うわけにもいきません。

画像ファイルは、アドレスをセーブして、特定のタイミングでアドレスをハンドルに自動で変換するのはどうでしょうか。
アドレスを保存した場合、次回アプリケーションを起動するとき、
そのアドレスには何もなく一度アプリを終了するとリリースされているので、
読み込むことができなく、アクセスバイオレーションになります

実際、NSImage*のアドレスをvoid*にコピーしたところ、
現在の起動時では読み込めましたが、
次回の起動では画像を読み込めなく、エラーになりました

同じメモリ位置に同じデータで読み込むことが不可能ならば、
アドレスの保存も意味ありません

何か方法はないでしょうか?

Killery
記事: 7
登録日時: 11年前

Re: 1つのファイルにキャラ名、HP、顔画像データを保存する方法

#7

投稿記事 by Killery » 8年前

以前シリアライズすればいいと聞きましたが、
objective cのシリアライズは明らかに効率が悪く面倒なのです
クラスや構造体の場合、メンバーを一つづついちいちシリアライズするためのキーをつけなくてはいけなく、
クラスや構造体のメンバーが多い場合、途方にくれるくらい莫大なコードになるのです

何か簡潔な方法はないでしょうか?

moba_

Re: 1つのファイルにキャラ名、HP、顔画像データを保存する方法

#8

投稿記事 by moba_ » 8年前

すみません、僕はアドレスといいましたが、メモリ位置ではなくてHDD等上のパスのことを言いたかったです。パスを保存するのでいいのではないかと思い、例を出しました。

また、セーブについて答えていなくてすみませんでした。no.3について書いて安心してしまい、質問文をきちんと読めていませんでした。失礼しました。

・画像をセーブするには
→ Data/sampleGraph.pngのようにパスを保存するのはどうでしょうか
・セーブを自動化するには(objective-c)
→ 分かりません…本当にすみません

moba_

Re: 1つのファイルにキャラ名、HP、顔画像データを保存する方法

#9

投稿記事 by moba_ » 8年前

・ポインタをセーブするには
→ 分かりません…

Killery
記事: 7
登録日時: 11年前

Re: 1つのファイルにキャラ名、HP、顔画像データを保存する方法

#10

投稿記事 by Killery » 8年前

・画像をセーブするには
→ Data/sampleGraph.pngのようにパスを保存するのはどうでしょうか
それだと、間接参照と変わらないので意味がありません
一つのファイルに構造体のデータが(画像も含む)全て入っていないといけないのです

しかし、解決しましたw
cとobjective cの混合ですが、載せときます

Test.h

コード:

#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#import <stdio.h>
#import <string.h>
#import <stdlib.h>
#import <limits.h>

#define LEVELMAX (6)
#define UNITMAX (4)

#define IMG_URL1 "kamijousan.jpg"
#define IMG_URL2 "mikocchan.jpg"
#define IMG_URL3 "accelerator.jpg"
#define IMG_URL4 "indextan.jpg"
#define DATAFILE_NAME "data.dat"
#define INSTANT_IMG "image.png"

typedef struct _STATUS{


    NSString *name;
    
    double HP;
    double ATK;

    NSImage *img;
    int imgAdressFix;
    int imgAdressCnt;

}STATUS;

typedef struct _UNIT{

    NSString *UID;
    int Lv;
    struct _STATUS CS;
    struct _STATUS DS;
    struct _STATUS US;
    
    double money;
    double exp;
    double expNext[LEVELMAX];
    
}UNIT;

typedef struct _SAVEDATA{


    struct _UNIT UN[UNITMAX];

}SAVEDATA;

SAVEDATA S;
SAVEDATA data;

int routeCnt;
bool datExistFlag;
NSImage *changedImg;

@interface Test : NSObject
{
    IBOutlet NSImageView *IV1;
    IBOutlet NSImageView *IV2;
    
    IBOutlet NSTextField *TF1;
    IBOutlet NSTextField *TF2;
    NSInteger I1;
    NSInteger I2;
}

-(IBAction)I1Set:(id)sender;
-(IBAction)I2Set:(id)sender;

-(IBAction)IV1Set:(id)sender;

@end

Test.m

コード:

#import "Test.h"

@implementation Test

-(id)init{

    I1 = 0;
    I2 = 1;
    routeCnt = 0;
    [self initPLdata];
    
    return self;
}

-(void)awakeFromNib{
    
    [self inputFileData];
    [TF1 setStringValue:[NSString stringWithFormat:@"%ld", I1]];
    [TF2 setStringValue:[NSString stringWithFormat:@"%ld", I2]];
}


-(void)writeInt:(FILE*)fp val:(int)val{
    int counter;
    
    for(counter = INT_MAX;counter > 0;counter>>=8){
        unsigned char nowData = val&0xFF;
        val >>= 8;
        fwrite(&nowData, sizeof(unsigned char), 1, fp);
    }
}

-(void)writeNSString:(FILE*)fp str:(NSString*)str{
    int length = (int)[str length];
    [self writeInt:fp val:length];
    fwrite([str UTF8String], sizeof(str), length, fp);
}

-(void)writeNSImage:(FILE*)fp str:(NSImage*)img{
    unsigned char idat[1024];
    int size;
    FILE *fpx;
    
    NSString *directoryPath;
    
    directoryPath = [[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent];
    [[NSFileManager defaultManager] changeCurrentDirectoryPath:directoryPath];
    
    NSString* Cpath = @"testStructSave.app/Contents/Resources/";
    [[NSFileManager defaultManager] changeCurrentDirectoryPath:Cpath];
    
    NSString *path = @DATAFILE_NAME;
    NSString *path2 = @INSTANT_IMG;
    
    if(!datExistFlag){
    if(routeCnt == 0)
        fpx = fopen(IMG_URL1, "rb");
    if(routeCnt == 1)
        fpx = fopen(IMG_URL2, "rb");
    if(routeCnt == 2)
        fpx = fopen(IMG_URL3, "rb");
    if(routeCnt == 3)
        fpx = fopen(IMG_URL4, "rb");
    [self fcopy:fpx wfp:fp len:0];
    
    fclose(fpx);
    }else{
        NSData *imgData = [S.UN[routeCnt].DS.img TIFFRepresentation];
        NSBitmapImageRep *brep = [NSBitmapImageRep imageRepWithData:imgData];
        imgData = [brep representationUsingType:NSPNGFileType properties:nil];
        [imgData writeToFile:path2 atomically:YES];
        
        fpx = fopen(INSTANT_IMG, "rb");
        [self fcopy:fpx wfp:fp len:0];
        fclose(fpx);
    }
    
    routeCnt++;
}


-(int)fcopy:(FILE *)rfp wfp:(FILE *)wfp len:(int)len{

    unsigned char in_buf[1024], out_buf[1024];
    int rinf;
    
    S.UN[routeCnt].DS.imgAdressCnt = 0;
    S.UN[routeCnt].DS.imgAdressFix = 0;
    
    fpos_t fpt;
    while (!feof(rfp)) {
        fgetpos(wfp, &fpt);
        rinf = fread((void*)in_buf, 1, 1024, rfp);
        if(rinf < 0){
            return (-1);
        }
        memcpy((void*)out_buf, (void*)in_buf, 1024);
        rinf = fwrite((void*)out_buf, 1, rinf, wfp);
        if(rinf < 0){
            return (-1);
        }
        S.UN[routeCnt].DS.imgAdressCnt++;
        S.UN[routeCnt].DS.imgAdressFix = rinf;
    }
    
    fpt -= (S.UN[routeCnt].DS.imgAdressCnt-1)*1024;
    fsetpos(wfp, &fpt);
    [self writeInt:wfp val:(int)S.UN[routeCnt].DS.imgAdressCnt];
    [self writeInt:wfp val:(int)S.UN[routeCnt].DS.imgAdressFix];
    
    fpt = 0;
    fsetpos(rfp, &fpt);
    while (!feof(rfp)) {
        rinf = fread((void*)in_buf, 1, 1024, rfp);
        if(rinf < 0){
            return (-1);
        }
        memcpy((void*)out_buf, (void*)in_buf, 1024);
        rinf = fwrite((void*)out_buf, 1, rinf, wfp);
        if(rinf < 0){
            return (-1);
        }
    }
    
    return(0);
}

-(int)readInt:(FILE*)fp{
    int counter;
    int result = 0;
    int shiftLen = 0;
    
    for(counter= INT_MAX;counter>0;counter>>=8){
        unsigned char nowData = 0;
        fread(&nowData, sizeof(unsigned char), 1, fp);
        result |= (int)nowData << shiftLen;
        shiftLen += 8;
     }

    return result;
}

-(NSString*)readNSString:(FILE*)fp strOut:(NSString*)strOut{
    int length = [self readInt:fp];
    char strOutcc[1024];
    fread(strOutcc, sizeof(strOut), length, fp);
    strOut = [[NSString stringWithUTF8String:strOutcc] retain];
    
    return strOut;
}

-(NSImage*)readNSImage:(FILE*)fp imgOut:(NSImage*)imgOut cnt:(int)cnt dcnt:(int)dcnt dfix:(int)dfix{
    unsigned char idat[1024];
    int size = 0;
    
    NSMutableData *binaryData = [NSMutableData dataWithCapacity:sizeof(idat)];
    
    
    for(int i = 0;i < dcnt;i++){
        fpos_t fpt;
        size += fread(idat, 1, 1024, fp);
        
        if(dcnt-1 == i){
            fpt += dfix;
            fsetpos(fp, &fpt);
        }

        fgetpos(fp, &fpt);
        
        NSMutableData* data = [NSMutableData dataWithBytes:idat length:sizeof(unsigned char)*1024];
        [binaryData appendData:data];
    }
    
    
    imgOut = [[[NSImage alloc] initWithData:binaryData] retain];

    return imgOut;
}

-(void)inputFileData{
    
    [self saveStruct];
    [self loadStruct];
}

-(void)saveStruct{
    NSString *directoryPath;
    
    directoryPath = [[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent];
    [[NSFileManager defaultManager] changeCurrentDirectoryPath:directoryPath];
    
    NSString* Cpath = @"testStructSave.app/Contents/Resources/";
    [[NSFileManager defaultManager] changeCurrentDirectoryPath:Cpath];
    
    NSString *path = @DATAFILE_NAME;
    
    if([[NSFileManager defaultManager] fileExistsAtPath:path]){
        [self loadStruct];
        
        if(changedImg)
            data.UN[I1].DS.img = changedImg;
        
        datExistFlag = true;
    }else{
        datExistFlag = false;
    }
    
    FILE *fpo;
    
    fpo = fopen(DATAFILE_NAME, "wb");
    
    
    
    for(int i = 0;i < 4;i++){
        if(!datExistFlag){
            S.UN[i].DS.img = [NSImage imageNamed:@IMG_URL1];
        if (i == 1) {
            S.UN[i].DS.img = [NSImage imageNamed:@IMG_URL2];
        }
        if (i == 2) {
            S.UN[i].DS.img = [NSImage imageNamed:@IMG_URL3];
        }
        if (i == 3) {
            S.UN[i].DS.img = [NSImage imageNamed:@IMG_URL4];
        }
        }else{
            S.UN[i].DS.img = data.UN[i].DS.img;
        }
        
        [self writeInt:fpo val:(int)S.UN[i].DS.HP];
        [self writeInt:fpo val:(int)S.UN[i].DS.ATK];
        [self writeNSString:fpo str:S.UN[i].UID];
        [self writeNSString:fpo str:S.UN[i].DS.name];
        [self writeNSImage:fpo str:S.UN[i].DS.img];
        
        NSLog(@"\n(保存)%@:%@:HP %g:ATK %g:IMGADRESS %p\n", S.UN[i].UID, S.UN[i].DS.name, S.UN[i].DS.HP, S.UN[i].DS.ATK, S.UN[i].DS.img);
    }
    
    [IV1 setImage:S.UN[I1].DS.img];
    fclose(fpo);
    
    routeCnt = 0;
}

-(void)loadStruct{
    FILE *fpi;
    
    fpi = fopen(DATAFILE_NAME, "rb");
    
    for(int i = 0;i < 4;i++){
        data.UN[i].DS.HP = (double)[self readInt:fpi];
        data.UN[i].DS.ATK = (double)[self readInt:fpi];
        data.UN[i].UID = [self readNSString:fpi strOut:data.UN[i].UID];
        data.UN[i].DS.name = [self readNSString:fpi strOut:data.UN[i].DS.name];
        
        data.UN[i].DS.imgAdressCnt = (int)[self readInt:fpi];
        data.UN[i].DS.imgAdressFix = (int)[self readInt:fpi];
        data.UN[i].DS.img = [self readNSImage:fpi imgOut:data.UN[i].DS.img cnt:i dcnt:data.UN[i].DS.imgAdressCnt dfix:data.UN[i].DS.imgAdressFix];
        
        NSLog(@"\n(読み込み)%@:%@:HP %g:ATK %g:IMGADRESS %p\n", data.UN[i].UID, data.UN[i].DS.name, data.UN[i].DS.HP, data.UN[i].DS.ATK, data.UN[i].DS.img);
    }
    [IV2 setImage:data.UN[I2].DS.img];
    
    fclose(fpi);
}

-(IBAction)I1Set:(id)sender{
    I1 = [TF1 intValue];
    
    if(I1 < UNITMAX){
        [IV1 setImage:data.UN[I1].DS.img];
    }else{
        [IV1 setImage:NULL];
    }
}
-(IBAction)I2Set:(id)sender{
    I2 = [TF2 intValue];
    
    if(I2 < UNITMAX){
        [IV2 setImage:data.UN[I2].DS.img];
    }else{
        [IV2 setImage:NULL];
    }
}

-(IBAction)IV1Set:(id)sender{
    
    changedImg = [[IV1 image] retain];
    
    [self saveStruct];
    [self loadStruct];
    
}

UNIT *getUnit(int num){
    
    return &S.UN[num];
};

-(void)initPLdata{

    NSString *directoryPath;
    
    directoryPath = [[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent];
    [[NSFileManager defaultManager] changeCurrentDirectoryPath:directoryPath];
    
    NSString* Cpath = @"testStructSave.app/Contents/Resources/";
    [[NSFileManager defaultManager] changeCurrentDirectoryPath:Cpath];
    
    NSDictionary *PLdataPlist = [NSDictionary dictionaryWithContentsOfFile:@"PLdata.plist"];


    if(PLdataPlist){
        for(int i = 0;i < [[PLdataPlist valueForKeyPath:@"UNIT"] count];i++){
            
            getUnit(i)->UID =
            [[[PLdataPlist valueForKeyPath:@"UNIT"][i] valueForKeyPath:@"UID"] retain];
            
            getUnit(i)->Lv =
            [[[PLdataPlist valueForKeyPath:@"UNIT"][i] valueForKeyPath:@"Lv"] intValue];
            
            getUnit(i)->money =
            [[[PLdataPlist valueForKeyPath:@"UNIT"][i] valueForKeyPath:@"Money"] intValue];
            
            getUnit(i)->exp =
            [[[PLdataPlist valueForKeyPath:@"UNIT"][i] valueForKeyPath:@"exp"] intValue];
            
            for(int j = 0;j < [[PLdataPlist valueForKeyPath:@"expNext"] count];i++){
                getUnit(i)->expNext[j] =
                [[[PLdataPlist valueForKeyPath:@"UNIT"][i] valueForKeyPath:@"expNext"][j] intValue];
            }
            
            getUnit(i)->CS.name =
            [[[PLdataPlist valueForKeyPath:@"UNIT"][i] valueForKeyPath:@"CS.name"] retain];
        
            getUnit(i)->CS.HP =
            [[[PLdataPlist valueForKeyPath:@"UNIT"][i] valueForKeyPath:@"CS.HP"] intValue];
        
            getUnit(i)->CS.ATK =
            [[[PLdataPlist valueForKeyPath:@"UNIT"][i] valueForKeyPath:@"CS.ATK"] intValue];
            
            getUnit(i)->DS.name =
            [[[PLdataPlist valueForKeyPath:@"UNIT"][i] valueForKeyPath:@"DS.name"] retain];
            
            getUnit(i)->DS.HP =
            [[[PLdataPlist valueForKeyPath:@"UNIT"][i] valueForKeyPath:@"DS.HP"] intValue];
            
            getUnit(i)->DS.ATK =
            [[[PLdataPlist valueForKeyPath:@"UNIT"][i] valueForKeyPath:@"DS.ATK"] intValue];
            
            getUnit(i)->US.name =
            [[[PLdataPlist valueForKeyPath:@"UNIT"][i] valueForKeyPath:@"US.name"] retain];
            
            getUnit(i)->US.HP =
            [[[PLdataPlist valueForKeyPath:@"UNIT"][i] valueForKeyPath:@"US.HP"] intValue];
            
            getUnit(i)->US.ATK =
            [[[PLdataPlist valueForKeyPath:@"UNIT"][i] valueForKeyPath:@"US.ATK"] intValue];
        
        }
        
    }

}


@end
MainMenu.xibのGUIやプロパティーリストは載せられませんが、
だいたい予想はつくと思います
IBOutletで指定した、GUIを用意すればいいのです

http://dixq.net/forum/viewtopic.php?f=3&t=13767

ここがとても参考になりました

構造体ポインタについては未だ分かりませんが、
とりあえず、画像を含んだ構造体を一つのファイルにすることができたので
解決とさせていただきます、ありがとうございました

閉鎖

“C言語何でも質問掲示板” へ戻る