HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2015
0205
こんとん関数の型について7解決


こんとん

リンク

2015/2/5(Thu) 16:28:26|NO.67281

HSPプログラミングでモジュールの関数を使って処理の一部を簡略化したいと思います。
関数に受け渡す型についてドキュメントライブラリなどを見ても一部違いがよく分からない
ものがありました。

int :整数値
var :変数(配列なし)
array :変数(配列あり)
str :文字列
double :実数値
local :ローカル変数

ということですが、整数と配列なし変数の具体的な違いと扱い方はどういったものでしょう?
試しに関数で画像をロードするプログラムを組んでみましたが、「文法が間違っています」とエラーが出ました

#module

#defcfunc title_img int v_screen,str f_name,array i_x,array i_y

alCreateImageByFile v_screen,f_name
i_x(0)=400:i_y(0)=300

return

#global

title_img 0,"タイトル.png"



この記事に返信する


FunnyMaker

リンク

2015/2/5(Thu) 19:43:18|NO.67284

>文法が間違っています」とエラーが出ました

これは当然ですね。モジュール自体が Artlet2D に依存していますから、ちゃんと動かすためには a2d.hsp をインクルードしてやらなければなりません。
まぁこれは単なるミスであって、こんとんさんが気にしていることの本質ではないと思うのでので軽く流します。

提示された例では #defcfunc を使っていますが、これだと「命令 (command)」ではなく「関数 (function)」が作成されるということは理解していますか?(※命令を作るときは #defcfunc ではなく #deffunc を使います。)
釈迦に説法かもしれませんが、HSPでは「能動的に仕事をするもの」として「命令」と「関数」があります。
両者ともにほとんどの場合「パラメータ (parameter)」を受け取って宜しく処理します。

(パラメータが無い(必要としない)命令・関数も考えることはできます。
例えばただ単にプログラムを終了する(オプション一切なしで) end という命令を考えたとすると、こいつはパラメータを必要としませんよね。呼び出し側の都合などどうでもいい命令ですから。
また、ナンセンスではありますが、常に1を返す関数 one を作ったとすると、こいつもまたパラメータを必要としません。)

「関数」は「多変数から1変数への写像」と考えればよく、これは何らかの値を返します。
一般的には、 (戻り値) = f(x1,x2,...,xn) と書きます。もちろん、x1~xn はパラメータで、fから見て定数であったり変数であったり。そこは自由に設計できます。
提示されたサンプルでは title_img を関数として作成しておきながら return で明示的に何も返しておらず(※HSPの親切設計(?)により、こういう場合は多分statの値が戻り値として使われていると思いますが。)、
関数として意味を成していません。(こんとん さんの意図をくみ取って、ここでは終了コードを返したいのだと考えました。alCreateImageByFile は失敗すると stat に -1 を返すそうなので、title_img 関数の戻り値もそれを踏襲するのがいいでしょう。)
さらにおかしなことに、「関数」である title_img をまるで「命令」のように記述してしまっています。これではコンパイルできないのも当たり前です。
また、 title_img 「関数」がパラメータとして想定している「i_x」,「i_y」というエイリアス(「別名」)で与えられるはずの変数も実際には渡されていません。変数は勝手に湧いては出てきません。与えてやらねばなりません。
title_img 関数によって i_x,i_y に格納された値を外部から見たいのでしょう?(でなければその変数が存在する意味がない)

以上を踏まえてサンプルを書き直すと、下のようになります。


#module #defcfunc title_img int v_screen,str f_name,array i_x,array i_y alCreateImageByFile v_screen,f_name i_x(0)=400:i_y(0)=300 return stat #global #include "a2d.hsp" dim x,1 : dim y,1 result = title_img(0, "タイトル.png", x,y)


次。

>整数と配列なし変数の具体的な違いと扱い方はどういったものでしょう?

具体的もなにも、激しく違います。
ここで言われている「整数」というのは、それを渡された 命令/関数 から見て「定数」です。
命令/関数 側から書き換えることはできません。
一方、「配列なし変数 (※配列あり でも同じこと)」はそれを渡された 命令/関数 から見て「変数」です。
命令/関数 側からその中身を書き換えることができます。


モジュールはHSPにおいては大変便利で、是非理解して使えるようになって欲しいものです。頑張ってくださいね。



こんとん

リンク

2015/2/5(Thu) 23:45:33|NO.67285

詳しいご説明をありがとうございます。
a2d.hspのインクルードについてはインクルードしてあることを前提にしてますので、
あえて省略してました。説明不足ですみません。
どうやら#defcfuncと#deffuncを知識不足で間違えていたようです。
#defcfuncはC言語で言う戻り値のある関数、#deffuncはVoid型関数という風に考えてよいのですね?

引数の型についてもintは30などの数値を直接引き渡せて、varはa=10などで代入した変数aそのものを引き渡すということですね。
よく分かりました。

今、自分が作りたいのはタイトルのメニュー画面で、イメージとしては
画像の読み込みをモジュールで行い、モジュールでの結果をグローバルに持ってきて画像を出すという感じなのですが…
そもそもモジュール空間の数値などはグローバルに持ってこれないんですね。
#defcfuncでの戻り値も一つしかもってこれないみたいですし。

以下みたいなサブルーチンだと上手くいくのですが、やっぱり記述や行が多くなるので面倒くさい…
モジュールで一纏めにした方が後々に修正する時も手間がかからなくなると思うのですが…


;これがソース ※省略してますが、開始時にgotoで*title_screenにジャンプしてます

*title_img
alCreateImageByFile v_screen,f_name
alGetFileWidth f_name, img_sx(cnt), img_sy(cnt)
return


*title_screen

repeat 2
if cnt=0 {
f_name="タイトル.png"
v_screen=0
img_x(cnt)=400
img_y(cnt)=300
}else : if cnt=1{
f_name="タイトルテキスト.png"
v_screen=1
img_x(cnt)=200
img_y(cnt)=400
}
gosub *title_img

loop

repeat 100
redraw 0
alCopyModeAlpha 0.2
alStretchImageToScreen 0,0,,,img_sx(0),img_sy(0),img_x(0)/2,img_y(0)/3,img_sx(0)*2,img_sy(0)*2
alStretchImageToScreen 1,0,,,img_sx(1),img_sy(1),img_x(1)/2,img_y(1)/3,img_sx(1)*2,img_sy(1)*2
wait 6
redraw 1
loop

ちなみにこれだと仮想イメージ1の画像が微妙に透けてる…



FunnyMaker

リンク

2015/2/6(Fri) 09:34:44|NO.67286

まず、不思議に思ったところから。

「タイトル.png」等というものは当然私の環境にはありませんので、せっかくコードを提示してもらっても動かすことができません。
(そりゃ、代わりの画像をこちらで作れば動きますけれども、わざわざ代わりの画像を作ってまで相手をしてくれるほど親切な人はそうそういません。皆忙しいのです...。
私もしばらく掲示板ご無沙汰で、春休みが近づき空きコマも増えてきたところで息抜きついでに久々にこうやって回答しています。)
どうしても画像が必要ならスクリプトと画像一式をtarかzipにでもまとめてどこかにアップロードして、回答してくれる人が直ぐに本質に取り掛かれるようにお膳立てしておくとよいです。

辛口なことを言いましたが、怒っているわけではありません。あなたの質問態度に悪意は感じません。今後気を付けてくだされば結構です。



次に、本題です。


>#defcfuncはC言語で言う戻り値のある関数、#deffuncはVoid型関数という風に考えてよいのですね?

とりあえずそのイメージでよいと思います。


>画像の読み込みをモジュールで行い、モジュールでの結果をグローバルに持ってきて画像を出すという感じなのですが…

発想は良いと思います。


>そもそもモジュール空間の数値などはグローバルに持ってこれないんですね。

惜しい。
こんとんさん、ここで歯痒い思いをしていますね...?
実は可能。2つの方法があります。一つは全うな方法で、もう一つは一般には邪道と言われそうな方法です(※私は高速化のために自作モジュールの中でこの方法をしばしば慎重に使いますが。むやみに使うとめちゃくちゃになります)。

① モジュール空間(V_m)に入っている関数(f1_V)(※命令でもよいが、終了コードが欲しいという前提でここでは関数を採用する。結局どちら使おうと工夫でなんとでもなるのでその辺はプログラマ次第。)
  のパラメタとして変数(Var1)を渡し(※渡せる変数は1つとは限らず、いくつでも都合に応じて好きなだけ渡せばよい(Var2,Var3,...)。それらは配列でもよい。)、f1_V 側の処理の結果を Var1 に書き込む。
  f1_V から復帰して処理がグローバルに戻ってきたら、 Var1 から所望の値を取り出す。
 
  例えば画像を読み込んでそのx,yサイズを取得する一連の手続きをまとめてモジュール化して f1_V として実装することを考えると、
  f1_V に定めるべきパラメタとして例えば次が考えられる。

param1 : fpath : 文字列型定数 : 読み込み対象のファイルのフルパス
param2 : picsize : int型1次元2要素配列 : 読み込んだ画像のx,yサイズの格納先。要素(0),(1)にそれぞれx,yサイズが格納されるものとする。 もちろん、この「格納する」処理は f1_V でやる。


② グローバル空間から、モジュール空間内の変数を覗き見する。
  モジュールを作るとき、
  #module mod1
  #global
  とすると、何が起こるか?
  そのモジュール空間の変数/命令等の正式名称が、末尾に「@mod1」を伴ったものになります。
  また、モジュール内の命令/関数内で新規に作成した変数は、その命令/関数が終了したあとも破棄されることなく残っています。(驚いたでしょうか?)
  (C言語でもひたすら static すればそういうことができると思いますが。ただ、相変わらずスコープの外から覗けないと思います。(私はまだ C++ を始めて間もないのでこの辺に関して拙いところがあるかと思います。間違い等ありましたらご指摘ください。))
  例えば、上述のモジュールの関数内で「a」と記述した変数をモジュールの外部から覗こうと思ったら、「a@mod1」と書けばいいのです。

(例)

#module mod1 #deffunc cmd1 x = rnd(10)-5 return #global randomize cmd1 mes x@mod1 ;見えた!

  この例では覗いているだけですが、書き換えることもできます。
 また、「a@mod1」という名前は「正式な名前」なので、この空間内でもこの呼び名は通用します。つまりこの空間内では「a」と書こうが「a@mod1」と書こうが、実は同じなのです。
  さらに突っ込んだ話をすると、モジュール内部からグローバル変数を覗き見したいなら、末尾に「@」を付けるだけでよいです。

(例)

#module mod1 #deffunc cmd1 mes buf@ buf@ = "誓って故郷を出たからは~..." ;このように、書き換えることもできる。 return #global buf = "勝ってくるぞと勇ましく~..." cmd1 mes buf

  もう気づいたかと思いますが、HSPの「モジュール化」とは、詰まる所この程度のものなのです。落胆したでしょうか...? 残念ですが特性だと思って受け入れるしかありません。
  多種のデータが飛び交い、関数がタイミング的に複雑に絡むようなプログラムをHSPで作るのは骨の折れる仕事になります。


さて、2つの方法を述べましたが、私としては極力 ① を使うことおすすめします。
どうでしょうか。ヒントになりましか?
こんとんさんに考えてほしかったので、あえて画像読み込みのモジュール化のサンプルは作っていません。しかしヒントを参考にして簡単に作れると思います。

分かりやすく説明したつもりですが、何か不明な点,取り残した点,私の勘違い等見つけられたら復た聞いてください。時間があるときに答えます。では、頑張ってください。



こんとん

リンク

2015/2/6(Fri) 14:40:18|NO.67289

ソースの件についてはこちらも見てくださる方への配慮不足でした。誠に申し訳ございません。
以後は気をつけます。

モジュールから結果を持ってくる方法は色々とあるのですね。
自分は②の方が使いやすい感じがしたので、そちらの手法で組んでみることにします。
ありがとうございました。



skyblue

リンク

2015/2/6(Fri) 16:35:59|NO.67294

解決済みになっていますが、deffuncとdefcfuncの違いは返り値を返すかではなくて
HSP上での形式が違うだけで一緒のものだったはずです。



FunnyMaker

リンク

2015/2/7(Sat) 12:10:27|NO.67307

>skyblueさん

私はHSPのコードを見たわけではないので断言できませんが多分その認識で合っていると思いますよ。
定義された手続きが「命令」なのか「関数」なのか判別してパラメタを全部集めてしまえば
そこから return に至るまでに違いはありませんから。(どちらも内部的には gosub 同様サブルーチン。同じスクリプトエンジンで処理するだけ)

#deffunc, #defcfunc の使い方で躓いている人へのアドバイスの中でそこまで言及していませんでした。



こんとん

リンク

2015/2/7(Sat) 14:39:27|NO.67309

既に解決した事項なのですが、一つだけ分かったことをコメントします。
ドキュメントライブラリといったサンプルなどでは関数や命令の定義などは
モジュール空間内で行っているものばかりだったのでモジュール空間内のみでしか
定義できないと思い込んでいましたが、グローバル空間でも関数や定義の設定もできるんですね

その場合だと引数や戻り値などが設定できるサブルーチンみたいなものになるので、
自分がやりたかった関数内で行った命令の結果(picloadでバッファにロードする画像など)を
保持したまま次の処理に移り、これまで保持してきた結果を全てまとめて利用するということができました
(モジュール空間内で定義するとそれができませんでした…)

良い勉強になりました



ONION software Copyright 1997-2025(c) All rights reserved.