GameMaker 日本語掲示板

views
17 フォロー
1,148 件中 441 から 480 までを表示しています。
10

>> 9
ご丁寧にありがとうございます!
program_directoryやworking_directoryは最初省略してたんですが恐らくほかの原因で上手くいかないのが続いてて疑心暗鬼になってたのでつけてました・・・
よく読んで外してやってみます!助かります

9
名前なし 2022/08/03 (水) 07:43:46 修正 >> 7

test_game.exe
 └system
  └scroll_player.dat

file_text_open_readで読み込むときは、working_directory等を付けなくても読み込むことが可能です。

▼マニュアル working_directoryについて
https://manual.yoyogames.com/GameMaker_Language/GML_Reference/File_Handling/File_Directories/working_directory.htm

dir = "system/";
fid = file_text_open_read(dir + "scroll_player.dat");

で読み込めます。

file_text_open_read実行時には、ゲームの実行ファイルのある場所が基準となりますので、事項ファイルのある場所以下のパスを入れることで読み込むことができます。デバッグ時も変わらないはずです。

上にあった、appdata等からも読み込むことができますが、優先順位があります。

file_text_open_readなどで読み込む際には、ファイルが存在するか?読み込めるか調べて無かった場合、順位が下のファイルが存在するか?読み込めるかを調べていくようです。

1.「%localappdata%<ゲーム名>」or「%appdata%<ゲーム名>」のパス以下
2.ゲームの実行パス以下

ビルド前に

dir = program_directory + "/system/";

を有効化する必要もないと思います。

fid = file_text_open_read("system/scroll_player.dat");

なら、実行ファイルのある場所以下systemフォルダのscroll_player.datを読み込めます。

datafilesに入れたフォルダやファイルは、exeのある場所にそのまま配置されるので、デバッグ時でもプログラムを変える必要はないと思います。デバッグ時もexeが出来たときと同じように読み書きできます。

datafiles(インクルードファイル)
 └system
  └scroll_player.dat

で実行ファイルを作成するとファイルの配置は

test_game.exe
 └system
  └scroll_player.dat

となります。

マニュアルのFile Systemページにファイルの仕組みが解説されていますので参考にしてみてください。
https://manual.yoyogames.com/Additional_Information/The_File_System.htm

3

コードエディタで Alt + マウス左ボタンでドラッグ で、ブロック選択ができます。
複数行まとめて入力、編集できるので便利。

2

Alt + N  Noteを作ります。
メモなどに使えます。Scriptと違い完全にメモ帳みたいなもので、コンパイルの対象外です。
画像1

検索の対象からも外したい場合は、検索窓でNotesを除外します。
画像1

8

最終的に、やっぱりインストーラーより実行ファイルが良い!となったので以下のように落ち着きました。
フォルダにdatファイルを並べてdatafilesフォルダに入れておき、以下のコードでビルド前に以下のコードのworking_directoryとprogram_directoryを入れ替えることで正しく動く…というやり方です。(exeファイルより深い階層であれば良かったので、フォルダを作れることが分かっただけで解決する話でした)

// テキストファイルのディレクトリ
//
// ビルド時にはdatafilesフォルダの中身を更新してprogram_directoryを読み込む

//dir = program_directory + "/system/";
dir = working_directory + "/system/";


// ファイルからテキストを読み込むための変数
fid = 0;

readA = array_create(30, "");
readB = array_create(30, "");
readC = array_create(30, "");


// テキストファイルの読み込み
fid = file_text_open_read(dir + "scroll_player.dat");
for(i=0;i<18;i++){
	readA[i] = file_text_read_string(fid);
	file_text_readln(fid);
}
file_text_close(fid);
1

> そもそも、オブジェクト等が同名だったら上書きするかどうかとか聞いてくればいいのになと思ったりしました。

今このあたりの問題で日々苦しんでいるので、100回くらい頷きました。

同名のアセットがある場合、

  • 置き換える
  • 置き換えずにスキップする
  • 改名してインポートする
    を選ばせてくれればいいのに、と思っています。
1
asa 2022/07/26 (火) 13:15:28 修正

コードエディタで CTRL+G  指定した行へ飛べます

Ctrl + TAB  workspaceに開いてるアセットの一覧から選んで飛びます

Ctrl + T  アセットを検索します

Ctrl + Shift + F  検索窓を開きます

コードエディタで Ctrl + F  開いてるコードが対象の検索窓を開きます

コード中の関数やアセットにカーソルを乗せてF1  対象を開きます

F12  ワークスペースのサイドバー(何と呼ぶか分からない)を開閉します

7

おお、すごい情報・・・
返事遅くなりすみません、ありがとうございます。

file_text_open_readはそういえばセーブデータの管理に使っていました。
最初からファイルを置くことは無理だと思っていましたがインストーラーを作ることで出来るんですね。

参考にさせていただきます。

6
asa 2022/07/24 (日) 12:27:47 修正

保存場所、サンドボックスの設定はこれで、
画像1

インストーラー作成時のNSISについての設定がこれですね。
画像2

NSISというのでデプロイに関して指定できるんでしょうか、NSISというのは全然知りませんでした!
ここで教えてもらえてよかったです!

haniguraさんのやりたいこともこれで実現できるでしょうか。

5
名前なし 2022/07/22 (金) 18:49:06 修正

「exeファイルと同じ階層に並べたくはない」というのは、

test_game.exe
└scenario
 ├en
 └ja
  └test01.txt

という形式でtest01.txtなどを置きたくないということなのでしょうか?

データファイルを読み込むために使う「file_text_open_read(file_path)」などは、ゲームオプション設定で保存場所として設定した場所なら読み書きできます。
Windowsの場合は、「%localappdata%<ゲーム名>」「%appdata%<ゲーム名>」か選べる様になっているので、そのフォルダ以下にファイルやフォルダがあれば読み込むことができます。

%localappdata%<ゲーム名>
└scenario
 ├en
 └ja
  └test01.txt

fname = "scenario\\ja\\test01.txt";
fh = file_text_open_read(fname);
text01 = file_text_read_string(fh);

とすれば、localappdataのゲーム名フォルダ以下にあるファイルを読み込むことができます。

exeファイルと同じ階層に並べたくはないという要望があった場合、私ならlocalappdataなどにシナリオの言語リソースを入れます。
そのまま中身が見える問題は、暗号化や難読化したりすれば良いと思います。

localappdataなどにファイルをどうやって置くかは、インストーラーなどでファイルをコピーするなどが考えられます。

GameMaker標準機能でインストーラーを作る場合、「NSIS(Nullsoft Scriptable Install System)」というインストーラー作成システムを使用しています。
ゲームオプション設定でインストーラーを作るためのNSIS用スクリプトを指定できるので、標準状態の(NSIS用スクリプト)設定から変えることで、好きなファイルを好きな場所に入れることができます。
NSIS用スクリプトは、インストーラーの持っているファイルをどこにコピーする、といった様なスクリプトになっています(他にもいろいろなことができます)ので、NSISの公式サイトのマニュアルやgoogleなどで検索すれば、設定スクリプトの書き方が出てきます。

しかし、好きなところにコピーできたとしても、上記しましたが、GameMaker製のゲームから見える世界は、ゲーム自身があるフォルダ、ゲームオプション設定で選んだ「%localappdata%<ゲーム名>」か「%appdata%<ゲーム名>」しかないので、それ以外のフォルダにファイルを入れても読み込むことはできません。

1
umaaaaaa 2022/07/21 (木) 13:32:07

SEで使おうと思ってた機能なので助かります!

4

なるほど逆転の発想・・・
しかしキャラがよく喋るゲームで、最終的に何文字になるかも分からないので今回は外部ファイルの方向性で行くつもりです。
ありがとうございました!

3
生高橋 2022/07/17 (日) 20:57:44

翻訳者の人が作業中にどうしても実行中に値を変更したい場合はどうしようもないですが
別にそうでないなら翻訳者のデータをそのまま構造体や配列などに変換して直接ソースコードにコピーするのも手です。
データを隠蔽できますし、ファイル読み込み処理もなくて済みます。
ただし、翻訳者のデータが変更されるたびにソースコードに変換する作業が必要になりますけどね...

2

ありがとうございます!
やっぱり場所は変えられないんですね…
自分も絶対見られてはいけない訳ではないので、ひとまず1ファイルで管理できるiniファイルに差し替えてやっていくことにしました。(iniファイルなら覗かれにくいと信じて…)

私も他の方の方法も気になるので、解決とは書かずに置いておきます。

1

私の場合、exeと同じ場所に外部ファイルがある形にしてます。
(exeファイルと同じ場所に置きたくないという要望を満たす回答にはならずすみません)

雑にしか理解してないんですが、GMS1.4の頃は外部ファイルも全部exeファイルの中に入る形にビルドされていたので、配布するゲームは外部ファイルが見えない(というか存在しない)形になっていたんですが、GMS2になってそれができなくなり、今の形になりました。
インストーラーで外部ファイルを展開する場所をC:\Users\username\AppData\以下などに指定できたらいいのですが、その方法は、私の知る限りは無いようです。

■すぐに見つからない場所に置く(隠す)
上記のように、方法は無いっぽいです。

■拡張子を変える
少しは効果があるかもしれませんが、データを見てやろうという意思がある人は開いちゃうと思います。

■難読化する
ファイルを開いても内容を読めなくすることは選択肢の1つだと思います。これも完全じゃないですが多くの人は読むことを諦めるでしょう。



ということで現在は「ソロプレイのゲームなら」という条件つきですが、「読みたい人は読めばいい、プレイする本人が自分の意志で見たくて見るならそれを止める理由は無いかもしれないな」と開き直って、それ以上考えないようにしてます!🙈

他の人がどうやってるのか、私も知りたいです!

9

ステート毎に終了条件(遷移条件)が違い遷移先も条件で複数変わるので、仕方なくステート内にそれらを書いていましたが、ステートをインスタンス化するときにこういう方法でfunctionを渡すことができるんですね。

あと、進行方向とアニメの向きが必ずしも一致しないというのはその通りですね。後退しながら攻撃したり、体を対象の方に向けながら歩き回ったり。
ステートを、アニメの開始から終わりまでという単位で考えていたのでステートとアニメを一体化して捉えていましたが分けたらスッキリするなら分けたいですね。

考え方とサンプルコードで勉強になります。参考にさせて頂きます。
ありがとうございます!

8
hayate212 2022/07/15 (金) 10:10:18

何に関心(AI,メニュー遷移,etc...)を持って実装をするかで大きく構造が変わるなと思い
オブジェクトの Sprite を管理するステートマシンを実装してみました

asa さんが最初に提示した実装例から以下のようなことを考えました

  • ステート内に遷移条件が実装されている
    • 開発が進むにつれステート内部が複雑になっていきそう
  • ステート内に挙動とアニメーション管理が実装されている
    • 前方への攻撃アニメーションを再生しつつ後退する場合、後退が行われた瞬間に攻撃アニメーションはキャンセルされる?
      • 場合によっては前方への攻撃アニメーションを残しつつ後退することも考えられるので、挙動=アニメーションではないはず
  • 新たにジャンプステートを実装する場合、ジャンプしながらの横移動処理はジャンプステートにも実装される?
    • 実装の重複は修正漏れ考えると避けたい・・・

そこでアニメーションの管理のみを行うステートマシンを実装しました。
以下が仕様です。

  • アニメーションステート(以下ステート)は Sprite を必ずひとつ持つ
  • 遷移条件構造体は遷移条件関数と遷移先のステート名を持つ
    • 遷移条件関数は遷移条件を満たしたかどうかの Bool 値を必ず返す
  • ステートをステートマシンに登録する際には以下の情報が必要
    • ステート名
    • ステート
    • 遷移条件構造体の配列
  • 毎ステップ、条件付きループ(for)で遷移条件構造体の配列の中から順番に遷移条件関数を実行し true が返った場合、遷移条件構造体の遷移先ステート名を元にステートを現在のものから置き換え、ループを抜ける
  • 毎ステップの最後に現在のステートから Sprite をオブジェクトに割り当てる

これにより挙動とアニメーション管理を分離出来ます。

*上記仕様をもとに実装しステートマシンを使用している部分
画像1

7

友人さん ありがとうございます。

characterに各motionインスタンスを全部持たせて、init()とloop()もそっちに移動、
motionはloopから呼ばれるactionのロジックだけにするという構造なんですね。

いろいろ勉強させていただきます。
サンプルコードから詳しい説明まで、ありがとうございます!!

6

別口でご回答させていただきましたが、為念こちらにも。

gameMakerは学んだことがなく知識や仕様理解は暗いですが、気になった点としてインスタンスの生成を上げさせていただきました。
もう1点、idleとwalk内で同様の処理が記述されていることも、冗長になりがちな点と、コピペミス等で不具合が発生する原因になりそうであったため、少し気になりました。

上記2点をとりあえず解決するという目的で、自分ならこうするかな? という観点でコードを記載させていただきます。

先に述べました通り、gameMakerには疎いため、文法等に不備等がありましたらご容赦ください。(withってなんやレベルでした)
あくまで考え方のひとつとして見ていただければと思います。

function character(_obj) constructor {
	obj = _obj;
	cnt;

	current_motion;
	idle = new motion(obj, spr_player_idle, 60, 0.01);
	walk = new motion(obj, spr_player_walk, 60, 0.2, 2);
	
	init = function() {
		cnt = 0;
		idle.next_motion = walk;
		walk.next_motion = idle;
		current_motion = idle;
	}
	
	loop = function() {
		if (cnt >= current_motion.limit) {
			current_motion = current_motion.next_motion();
			cnt = 0;
			obj.sprite_index = current_motion.sprite;
			obj.image_speed = current_motion.image_speed;
		}
		current_motion.action();
		cnt++;
	}
}
function idle(_obj, _sprite, _image_speed, _limit) constructor
{
	obj = _obj;
	sprite = _sprite;
	image_speed = _image_speed;
	limit = _limit;

	next_motion;
	
	action = function() {
	}
}
function walk(_obj, _sprite, _imgspd, _limit, _speed) constructor
{
	obj = _obj;
	sprite = _sprite;
	image_speed = _image_speed;
	limit = _limit;
	speed = _speed;
	next_motion;

	action = function() {
		with (obj) x += speed;
	}
}

以下、メモ書きです。

それっぽくかんがえたこと

  • idleとwalkのインスタンスを別の構造体の中に持たせてみた
      newしないで切り替えできるように
      (ここだけ見ると構成的にo_playerに持たせてもよさそうな?)
      ついでにidleとwalkで共通していた処理も1か所書けばいいようになった気がする
  • 現在のモーション(idleかwalk)を、current_motionに保持
      何かしら実行するときはこれだけ見てればいい
      gameMakerで出来るかどうかは知見のなさ故に不明瞭ですが、たぶんできるやろの精神
  • idleとwalkに、次の遷移先を持たせる
      本当はアドレス指定よりKey値で指定できる形が望ましいと思いますが、とりあえずの形で
      切り替えるときはloopで60cntした時だったところを、limit変数にしてみた
      limitもidleとかに持たせたのでidleは60f, walkは40fとか個別指定もできるかも?
  • idleとwaikからマジックナンバーを消してみた
      全く別のobjからもidleやwalkが使える
      移動量とかも全部インスタンス生成時に設定できるからmotionで指定するとかできそうな気がする
      汎用性は低そうなのでそこまでする必要があるかどうかは不明
  • ソースよりコメントに時間がかかってしまった
      長文になってしまい申し訳ございませぬ・・・
5

遷移する度にインスタンスの破棄とインスタンス化をするのが負荷になる可能性があるという指摘も頂きました。
いろいろ考えるべきことがありますね~

4

stateをオブジェクトにすることでかえって複雑になる可能性があるということですかね。

3
生高橋 2022/07/08 (金) 17:59:24 修正

自分もこんな感じでポーズメニューをつくりました。
自分の知識が浅いからなのか思ったよりも複雑なった印象を受けました。

GameMakerは他の言語と違ってポリモーフィズムをする際の制約がないんですよね。
インターフェースがないのでstateごとに同名の関数の存在が保証されないです。
新しいstateを追加したときに関数の作り忘れが起きてしまったら一気にバグります。
まぁコピペすればいいだけなんですが。

ただし、新しい関数を追加したり名前や引数を変更してしまったら他のstateも全部変更が必要です。
stateが少なければこれもまぁ問題ないかもしれません。
他の言語ではVisualStudioを使っていると名前の一括変換などの機能があるので楽なんですよね。

そして、特定のステートのみの共通な処理や他のstateのデータを利用するとなったとき若干やっかいです。
無理に共通化したりすると他のstateにも影響をうけます。
ここらへんから自分は複雑になってきた印象があります。

ただ自分はまだ設計が浅いのでもしかしたらもっとちゃんと設計すればそれらもスッキリ解決できるんじゃないかと勉強中です。

2

遷移に係わる部分は各stateの、

stateを終了する条件の部分

if (cnt++ == 60) end_state();

と、遷移先のstateを決めて遷移する部分

end_state = function()
{
  with(obj) scr_state_change(new idle(id));
}



これを切り分けてstateの外に実装するのがよいということでしょうか。

1
hayate212 2022/07/08 (金) 17:27:08

idle や walk といったステートは状態の実装のみを責務として、ステートの遷移は実装を切り分けるのはどうでしょうか?
ステート遷移が複雑になるほどステートの内部も複雑化してしまう気がしまして・・・

また、切り分けることでステートを自由に組み合わせることが出来るようになるため使いまわしも用意になるかなと
例えばマグロ🐟は walk <-> attack の遷移しか出来ないことをステートを使いまわした上で表現出来るようになります

5
生高橋 2022/07/08 (金) 17:20:35 >> 4

idを算術演算として利用する人なんているんすね...
本当に近年のプログラムスタイルに近づいて行ってる間隔があります

4
asa 2022/07/07 (木) 08:24:54 修正

不確定な情報ですが。

今まではインスタンスidもブール値も数値で、数値としての計算にも使えていましたが、

  • 未定義、空、の意味で-1やnoone(-4)を使う
  • nooneをfalseと等価に使う
  • boolを0, 1で表現する
    などは、今後は型の区別がされて通用しなくなるかも知れません。

バージョン2022.6.023に関して、公式フォーラムに、
「instance.idは独自の型であるため、算術演算が使えなくなりました」というスタッフからの投稿がありました。
https://forum.yoyogames.com/index.php?threads/2022-6-release-thread.96639/page-2#post-582867

3

IDE 2022.6.0.23

Featherを使ってるとコードエディタがくそ重くなります。
ひどい時は入力してから目に見えるラグの後でようやく画面に入力されます(カーソル移動ももたつきます)。
Featherを切ったら軽くなりましたので、同様の症状が出る人はFeatherオフにしてみてください。

3

確かにオブジェクトだと冗長な場合は struct で問題ないですね👍

2
asa 2022/07/05 (火) 08:32:59 修正

具体的なサンプルコードまである説明をいただきありがとうございます!
なるほどGameMakerでの委譲ってこういうことなんですね。
内包する、所持する、というのは具体的にどういうことなのかバシッと見えてきました。

GameMakerのオブジェクトはいろいろ装備されてますので、諸々の機能が必要なく、最小のものにしたければ下記のようにstructを使うのもありなのでしょうか…


script weaponsBattery(struct)のコンストラクタを書いておく

function Battery(_bullet_remain) constructor
{
  bullet_remain = _bullet_remain;
  
  bullet = function(_x, _y, _deg, _speed)
  {
    bullet_remain = max(0, bullet_remain-1);
    if (bullet_remain == 0) return;

    instance_create_layer(_x, _y, "Instances", objBullet);
  }
}



objShip(船オブジェクト): create eventで砲台を作成して保持し、その機能を使う

battery = new Bullet(10);
battery.bullet(self.x, self.y, deg, speed);



いろいろ試してみようと思います。
ご説明ありがとうございました!

1

移譲は has-a (所持している)関係なので、機能を持たせたいオブジェクトの変数に、オブジェクトのインスタンスを持たせることで実現できます

  • objBattery: 移譲元 (このオブジェクトを拡張したい)
  • objShip: 移譲先 (拡張したオブジェクト)

■objShip の Createイベントで以下のように記述する

// 砲台オブジェクトを所持する
_battery = instance_create_layer(0, 0, "Instances", objBattery);

// 弾を撃つ関数
bullet = function(deg, speed) {
  // objBatteryの機能で弾を撃つ
  return _battery.bullet(self.x, self.y, deg, speed)
};

※サンプルコードはビルドしていないので参考までに…

敵キャラを拡張するために基底となる敵キャラを内包しても良いですし、サンプルコードのように部品(機能)を所持する、という使い方でも良いです

9

IDE 2022.6.0.23
Feather使用

入力補完のリストに存在する変数が出てこなかったりしますね。

2

マルチプレイヤーゲーム作りたい人はいるでしょうね!いるでしょうね!
期待しています。

How to Create a Multiplayer Game | GameMaker
https://www.youtube.com/watch?v=VPgAosG7QSU

8

コードを編集していると

[Feather] Unable find function 'o_bomb_normal_Event_Create$$anon_function_27_24', which should exist!

というようなメッセージがOutputにズラッと出力されます。
***という関数があるはずなのに見つからない!という意味らしいですが、この関数はあるんです。
あるのになぜ見つからないというメッセージが出るのか、原因不明です。

7
生高橋 2022/07/01 (金) 18:53:19

フェザーいいですねぇ。コードエディタ上でアセット名変更はまじでいい機能!!

6

マニュアルを翻訳

アセットリファクタリング
アセットブラウザでアセットの名前を変更すると、Featherはプロジェクトのコード内のアセットに関するすべての言及を自動的に更新するため、これらの参照が壊れることはありません。これは、フェザー設定で有効または無効にできます。

コードエディタを使用してアセットの名前を変更することもできます。テキストカーソルをアセット参照に置き、CTRL / CMD + SHIFT+Rを押します。

5

こういう場合は「エラーとする」、「警告とする」、「提案にする」、「無視する」
というのを、設定できるようになってます。
「とりあえず今はうるさいから、その問題はいちいち指摘しないでくれ!」という時は無視するの「ignore」にすればOKです。

4

下記のようなコードを書くと警告してきます。
今までと違って型を強く意識させられます。

img = spr_player_walk;
if (img == noone) ...
my_number = 100;
my_number = "empty";

こういうことをすると
「おい、違う型使ってるぞ?いいのか?」と言ってきます。

画像1

boolenも文字列も数字もいい加減に使えていましたが、ちゃんと型チェックしてきます。
でもコンパイルは通ります(今のところ)。