構造体と関数

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
s-rush

構造体と関数

#1

投稿記事 by s-rush » 16年前

いつもお世話になっています。
ポケモンのゲームを作っていて、少しわからないところがあるのでまた質問させていただきに来ました。

構造体の中に、自作の関数って組み込むことはできるのでしょうか?

今ポケモンの技のリストを作っています。
ゲームをやったことがある方はご存知かと思いますが、技の中には何%の確率でステータス以上を
起こす技があります。

たとえば、
技名 :かみなり
 属性 :でんき
 タイプ:とくしゅ
 効果 :まひ
 確率 :30%
があったとして、この”30%の確率でまひを起こす”
というのが、どのようにすればいいのか分からないのです。

ダメもとでこのようなコードを書きました。
int effect(int status, int probability)
{
========================================
各種ステータス以上を引き起こす判定。
========================================
}

typedef struct{
	int number;		//識別番号
	char name[32];		//技の名前
	int kind;			//技の種類(物理/特殊)
	int power;		//技の威力
	int type;			//技のタイプ

         int effect(int status, int probability);    //この技の持つステータス異常を引き起こす判定関数
}poke_skill;

バトルプログラムで技を使用した時に、effect関数を呼び出して判定する、
という感じにしたかったのですが、当然のことながらエラーが出るので
この考え方はできないようなのです。

もう1つアイデアがあるのですが、先攻後攻を決める際に少し問題が出てしまうので、
実現することが少し厳しくなりそうです。

どのように実装すればいいのでしょうか?
あまり良いアイデアというかアルゴリズムが思い浮かばないので、皆さんのお力を貸してください。

Dixq (管理人)

Re:構造体と関数

#2

投稿記事 by Dixq (管理人) » 16年前

携帯なので具体的にかけないですが、C++の機能である「クラス」がそれです。
このキーワードで調べてみてください。

BEMANI

Re:構造体と関数

#3

投稿記事 by BEMANI » 16年前

s-rushさんへ。
ポケモン仕上がることを楽しみにしています・・・
陰ながらこっそりすぎるほど、こっそりと応援させて頂きます><



構造体の中に関数を入れることは可能です。
30%の確率で麻痺する・・・というプログラムを構造体の中に入れてみました。

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>


typedef struct _Sample
{
	int a;

	// 30%の確率でマヒする計算
	void BiriBiri(void)
	{
		if( (a = (rand()%100)) < 30)
			printf("麻痺しました。100ターン動けません。::%d\n", a);
		else
			printf("麻痺しませんでした。::%d\n", a);
	}

}SAMPLE;




int main (void)
{
	SAMPLE Sample;			// SAMPLE構造体
	Sample.a = 0;			// 初期化
	srand((unsigned)time(NULL));	// 初期化


	printf("ここから先はwhile文で永久ループです。\n"</font);
	printf("何かキーを押すことで同じ処理を繰り返します。\n");
	printf("抜けたければ、ウインドウを閉じてください。\n\n\n");

	while(1)
	{
		Sample.BiriBiri();	// 30%でマヒする関数呼び出し
		getch();		// 何かキーが押されるまで待つ
	}

	return 0;

}

BEMANI

Re:構造体と関数

#4

投稿記事 by BEMANI » 16年前

すいません・・・fontタグで微妙に囲えていない所がございました。
失礼しました;;

s-rush

Re:構造体と関数

#5

投稿記事 by s-rush » 16年前

返事が遅くなってしまい申し訳ないです。
管理人さんのおっしゃる『クラス』について調べて勉強していました。

”メンバ関数”っていうんですね。
宣言の仕方や使い方は大体理解できたと思います。
だけど勉強しているともう1つ分からないことが出てきました。

技の中には、ステータス異常をもたらすもの以外に能力を変化させる技や、
HPを回復する技もあります。
ほかにも”ほえる”のようなバトルの強制終了もしくはポケモンの強制交代や
”へんしん”の相手と全く同じものをコピー?するなどの技もあります。

後々のことを考えると、やはり同じ構造体(クラス)として管理しておきたいのですが、
メンバ関数がそれぞれ違うものになってしまいそうなんです。
ステータス云々の関数は1つにまとめることはできそうですが、
技の追加効果だけはそれぞれの技に対して関数を用意してあげないとできなさそうなんです。
(単に自分のアルゴリズムや知識が悪いだけなんですが^^;)


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

s-rush

Re:構造体と関数

#6

投稿記事 by s-rush » 16年前

BEMANIさん、回答ありがとうございます。
構造体の中にも関数を組み込むことができるんですね^^

私的にはまだ慣れないクラスを使うよりも構造体を使った方が
エラーが起きにくいと思います。

構造体の宣言内で、関数の記述をしなければいけなかったのですかね??

他に多数の関数が必要になるのですが、
なにか実行する識別番号みたいなものを設けて、それに対応する関数を実行するように
ということってできないでしょうか?

組木紙織

Re:構造体と関数

#7

投稿記事 by 組木紙織 » 16年前

出来ますよ。
関数ポインタ配列とかで

BEMANI

Re:構造体と関数

#8

投稿記事 by BEMANI » 16年前

>>構造体の宣言内で、関数の記述をしなければいけなかったのですかね??
 構造体に関数を入れることはできるのですが、
 上に書いたものですと構造体の中身が増え、後々見にくくなりますよね。
 ですので、構造体の中にプロトタイプを書いておき、
 中身は構造体の外に書くことができます。


上の物と動作は全く同じですが
構造体の中にはプロトタイプしか書いていないです。

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>


// サンプル構造体
typedef struct _Sample
{
	int a;			// 何%か表示する変数

	void BiriBiri(void);	// 30%の確率でマヒする計算

}SAMPLE;




// 変わるのはここの赤い所だけです。SAMPLE構造体のメンバ関数BiriBiri
void SAMPLE::BiriBiri(void)
{
	if( (a = (rand()%100)) < 30)
		printf("麻痺しました。100ターン動けません。::%d\n", a);
	else
		printf("麻痺しませんでした。::%d\n", a);
}


// main文
int main (void)
{
	SAMPLE Sample;			// SAMPLE構造体
	Sample.a = 0;			// 初期化
	srand((unsigned)time(NULL));	// 初期化

	while(1)
	{
		Sample.BiriBiri();	// 30%でマヒする関数呼び出し
		getch();		// 何かキーが押されるまで待つ
	}

	return 0;

}

呼び出し方が変わるものでもないので、いつも通り使えるのではないかと思います。
自分も大したこと言えないですが、
もし、自分がやるのであれば種類毎にざくっと分けてしまう感じですかね~。


「凍り判定」や「しびれ判定」などの状態異常構造体。
「水タイプ」のわざを入れておく構造体(例えば、みずてっぽう、なみのり等)
「草タイプ」のわざを入れておく構造体(例えば、つるのむち、はっぱカッター等)
「特殊タイプ」のわざを入れておく構造体(例えば、へんしん、ほえる、じこさいせい等)

「水タイプ」のポケモンを入れておく構造体(例えば、ゼニガメ、コイキング)
「草タイプ」のポケモンを入れておく構造体(例えば、フシギダネ、マダツボミ)
「炎タイプ」のポケモンを入れておく構造体(例えば、ヒトカゲ、ガーディ)
など

こういう風に分けておけば自分の中ではわかりやすいのかな~と思います。
(s-rushさんがどう思うかはわからないですが;)

s-rush

Re:構造体と関数

#9

投稿記事 by s-rush » 16年前

回答ありがとうございます。
組木紙織さん、関数ポインタですね。
ちょっと勉強してきます。

BEMANIさん、わかりやすいサンプルありがとうございます。
技の構造体をタイプ別に分けると管理はしやすいと思うのですが、
今作っている戦闘システムや技を覚えるプログラムでは
すべて技の構造体を1つとして管理、検索するようにしているので少し変えないとできないですね^^;

1つ思ったのですが、
構造体の中に複数の関数を組み込んでおいて、switch~caseを使って対応した関数を実行する
ということを考えてみたのですが
たとえばこのような感じに
switch (type){
  case 0:
     /*状態異常を判定する処理の関数を実行*/
  case 1:
     /*ステータス変更の処理の関数を実行*/
  case 2:
     ・
     ・
     ・
このように書くと実行(処理)時間は長くなってしまうのでしょうか??
今まであまり処理にかかる時間というのを気にしたことがなかったのでわからないんです。

>void SAMPLE::BiriBiri(void)
::っていうのはC++の機能なんですかね??

BEMANI

Re:構造体と関数

#10

投稿記事 by BEMANI » 16年前

>>すべて技の構造体を1つとして管理、検索するようにしているので少し変えないとできないですね^^;
「全部の技を一つの構造体にまとめてある」ということで宜しいのですよね?;
もし違ったらごめんなさい;


>>このように書くと実行(処理)時間は長くなってしまうのでしょうか??
個人的にですが、処理時間は気にするほどでもないかなーと思います。
ただ、case が沢山ある場合は if で場合分けするよりいいかと思います。


>::っていうのはC++の機能なんですかね??
::はスコープ演算子と呼ばれるもので、主にクラスにアクセスする時に使われ、C++の機能です。
詳しいことは「スコープ演算子」で調べるといいかと思います。

s-rush

Re:構造体と関数

#11

投稿記事 by s-rush » 16年前

BEMANIさん
>>「全部の技を一つの構造体にまとめてある」ということで宜しいのですよね?;
はい、そうです。
他のシステムと関連付けするつもりなので、1つの構造体にまとめておいた方が都合がいいかな
と思ったので。
ですが、まだ検討中です。

caseやifで場合分けしてもあまり変わらないんですね^^
いろいろ試してみてよさそうなのを採用したいと思います。

スコープ演算子について調べてみました。
イメージ的には構造体アクセスの->でいいんですかね?
グローバル変数へのアクセス?にも使うようですが・・・

BEMANI

Re:構造体と関数

#12

投稿記事 by BEMANI » 16年前

ポケモンの技かなり量ありますよね;
ポケモンの数以上に技ってあるような気がします;

>>caseやifで場合分けしてもあまり変わらないんですね^^
 リアルタイムで動きまくるアクションで爽快感を出す!
 みたいな趣旨のゲームであれば気にした方がいいかもですが
 ポケモンなら気にしなくてもよさそうな気がします・・・

 if は、基本前から順に条件に合う条件式が見つかるまで探す。
 case は 対応した場所へジャンプする。です^^

>>イメージ的には構造体アクセスの->でいいんですかね?
>>グローバル変数へのアクセス?にも使うようですが・・・
 スコープ演算子は「どのスコープに属するものなのか」という意味がありますので
 「.」や「->」のようなイメージでいいかと思います。
 もしお時間があるのであれば、「名前空間」で調べるといいかもしれません。

スコープ演算子を使ったサンプルでも載せておきます。
int ABC = 200;

namespace Sample
{
	int ABC = 1000;
}

// main文
int main (void)
{
	int ABC = 300;
	
	printf("%d\n", ::ABC); // グローバル
	printf("%d\n", ABC);   // ローカル
	return 0;
}
実行結果はそれぞれ、200, 300となります。
「ABC = 1000」と書かれているABCを表示するためには
Sample::ABC と書けばいいです。
どこにアクセスしているかが解るかと思います。

グローバル変数が ::ABCでアクセスできるのは
名前がない空間だからです。
イメージ的に「名前がない空間に属する変数ABC」です。

組木紙織

Re:構造体と関数

#13

投稿記事 by 組木紙織 » 16年前

その説明だと勘違いしそうな部分があるので気を付けて。

グローバル空間!=無名空間

#一度C++をしたほうがよさそうと思う。

s-rush

Re:構造体と関数

#14

投稿記事 by s-rush » 16年前

一応関数ポインタ配列を使ってできました。
プログラムに慣れた人が見ると無駄が多いコードかもしれませんが・・・

答えてくださった方、本当にありがとうございました。

今はバトル場面で表示させる(HPやコマンド、グラフィックなど)
プログラムを作っています。
少しわからないことがあるので、調べた上でどうしてもわからない部分があればまた来させていただきます。

追記
一番最初の質問で漢字が間違ってた^^;

閉鎖

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