[C++]クリックしたらボールが発生して自由落下

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

[C++]クリックしたらボールが発生して自由落下

#1

投稿記事 by たらお » 10年前

C++言語でDxlibを用いて、クリックした場所にボールが発生して自由落下するプログラムを作りたいと考えています。
どなたか参考になるプログラムなど教えていただけないでしょうか?
初投稿ですが、よろしくお願いします。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: [C++]クリックしたらボールが発生して自由落下

#2

投稿記事 by softya(ソフト屋) » 10年前

自分で作りたいということであるのなら、コードを貰う前にご自身で出来るだけ頑張らないと身につきません。

> クリックしたらボールが発生して自由落下
というモノであるなら。

1.クリックの処理が分かり、座標も取得できる。
2.ボールを任意の座標に表示できる
3.ボールを自由落下させる事が出来る

と3つの要件をクリアするだけです。
この内出来ない事はどれでしょうか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

たらお
記事: 19
登録日時: 10年前

Re: [C++]クリックしたらボールが発生して自由落下

#3

投稿記事 by たらお » 10年前

この中でわからないのは、
1.クリックの処理が分かり、座標も取得できる。
です。
現状、クリックすると、ボールが出現するのですが、クリックを離すとボールが消えてしまいます。
また、画面上をクリック連打すると連打に応じて大量にボールが出現する処理というものがわかりません。
何か良い方法はないでしょうか?

アバター
Hiragi(GKUTH)
記事: 167
登録日時: 14年前
住所: 大阪府
連絡を取る:

Re: [C++]クリックしたらボールが発生して自由落下

#4

投稿記事 by Hiragi(GKUTH) » 10年前

クリックされると、フラグが立って、フラグが立ったボールを処理する...
などといった方法が簡単だと思いますが。

取りあえず現状のソースコードを張ってみてください。
だいがくせい!

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: [C++]クリックしたらボールが発生して自由落下

#5

投稿記事 by みけCAT » 10年前

クリックされた時、そこの位置を初期位置としたボールのデータを線形リスト(std::list)に入れ、
各フレームでリスト内のデータを順に処理(速度と位置の計算、および描画)を行うのがいいと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

たらお
記事: 19
登録日時: 10年前

Re: [C++]クリックしたらボールが発生して自由落下

#6

投稿記事 by たらお » 10年前

返信ありがとうございます。
現状のソースコードは以下のようになっています。
#include "DxLib.h"
#define g 9.8
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen( DX_SCREEN_BACK ); //ウィンドウモード変更と初期化と裏画面設定
int mx,my;//マウス座標
int Handle,Handle2; // 画像格納用ハンドル
Handle = LoadGraph( "ball.png" ); // ball画像のロード
Handle2= LoadGraph( "ground.png" );//地面画像のロード
double F,a;//力と加速度
//初期値
double y=0;//y座標
double v=0;//速度
double m=1.0;//質量
double r=25.0;//半径
double k=0.5;//ばね定数
double c=2.5;//粘性係数
double dt=0.1;//時間変化
// while( 裏画面を表画面に反映, メッセージ処理, 画面クリア )
while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0&&CheckHitKey(KEY_INPUT_ESCAPE) == 0 ){

//マウスの入力状態取得
GetMousePoint(&mx,&my);
if( ( GetMouseInput() & MOUSE_INPUT_LEFT ) != 0 ){//マウスをクリックしたら
F=m*g;//自由落下
//バウンド処理
if(y>450){
F=-m*g;
if(y>r){
F+=k*(r-y)-c*v;
}
}
a=F/m;//加速度
v+=a*dt;//加速度から速度
y+=v*dt;//速度から座標
DrawGraph( mx,y, Handle, TRUE ); //ball画像の描画
DrawGraph( 0, 470, Handle2, TRUE ); //地面画像の描画
}
}

DxLib_End(); // DXライブラリ終了処理
return 0;
}

このソースコードでは、クリックしたら1つのボールが自由落下して地面でバウンドして減衰していきます。
問題点は、
1.クリックを離すと、ボールが消える。
2.ボールを複数個に対応させたい。
この2点を考えています。
現状考えているのは、ballのクラスまたは構造体を作り、そこからクリックのカウントに応じて新しく配列からボールを呼び出そうと思っています。
何か、良いアイデアがあればご教示いただければ幸いです。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: [C++]クリックしたらボールが発生して自由落下

#7

投稿記事 by softya(ソフト屋) » 10年前

コードタグをご利用くださいね。
使うとこんなふうに表示されます。

コード:

#include "DxLib.h"
#define g 9.8
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
        ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen( DX_SCREEN_BACK ); //ウィンドウモード変更と初期化と裏画面設定
		int mx,my;//マウス座標
		int Handle,Handle2;     // 画像格納用ハンドル
        Handle = LoadGraph( "ball.png" ); // ball画像のロード
		Handle2= LoadGraph( "ground.png" );//地面画像のロード
		double F,a;//力と加速度
		//初期値
		double y=0;//y座標
		double v=0;//速度
		double m=1.0;//質量
		double r=25.0;//半径
		double k=0.5;//ばね定数
		double c=2.5;//粘性係数
		double dt=0.1;//時間変化
        // while( 裏画面を表画面に反映, メッセージ処理, 画面クリア )
        while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0&&CheckHitKey(KEY_INPUT_ESCAPE) == 0 ){
             
				//マウスの入力状態取得
				GetMousePoint(&mx,&my);
				if( ( GetMouseInput() & MOUSE_INPUT_LEFT ) != 0 ){//マウスをクリックしたら
				F=m*g;//自由落下
				//バウンド処理
				if(y>450){
				F=-m*g;   
				if(y>r){
					F+=k*(r-y)-c*v;
				}
			}
				a=F/m;//加速度
				v+=a*dt;//加速度から速度
				y+=v*dt;//速度から座標
				DrawGraph( mx,y, Handle, TRUE ); //ball画像の描画         	
				DrawGraph( 0, 470, Handle2, TRUE ); //地面画像の描画         
			}	
		  }
        
        DxLib_End(); // DXライブラリ終了処理
        return 0;
}
ついでにインデントを整理すると更に見やすいです。

コード:

#include "DxLib.h"
#define g 9.8
int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) {
	ChangeWindowMode( TRUE ), DxLib_Init(), SetDrawScreen( DX_SCREEN_BACK ); //ウィンドウモード変更と初期化と裏画面設定
	int mx, my; //マウス座標
	int Handle, Handle2; // 画像格納用ハンドル
	Handle = LoadGraph( "ball.png" ); // ball画像のロード
	Handle2 = LoadGraph( "ground.png" ); //地面画像のロード
	double F, a; //力と加速度
	//初期値
	double y = 0; //y座標
	double v = 0; //速度
	double m = 1.0; //質量
	double r = 25.0; //半径
	double k = 0.5; //ばね定数
	double c = 2.5; //粘性係数
	double dt = 0.1; //時間変化
	// while( 裏画面を表画面に反映, メッセージ処理, 画面クリア )
	while( ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 ) {

		//マウスの入力状態取得
		GetMousePoint( &mx, &my );
		if( ( GetMouseInput() & MOUSE_INPUT_LEFT ) != 0 ) { //マウスをクリックしたら
			F = m * g; //自由落下
			//バウンド処理
			if( y > 450 ) {
				F = -m * g;
				if( y > r ) {
					F += k * ( r - y ) - c * v;
				}
			}
			a = F / m; //加速度
			v += a * dt; //加速度から速度
			y += v * dt; //速度から座標
			DrawGraph( mx, y, Handle, TRUE ); //ball画像の描画
			DrawGraph( 0, 470, Handle2, TRUE ); //地面画像の描画
		}
	}

	DxLib_End(); // DXライブラリ終了処理
	return 0;
}

さて、現状の問題はですがインデントを直した版をみてもらうと分かりやすいですがマウスクリックしたらのif文に落下処理が内包されてますよね?
内包しているということはif文が真の間しか実行されてないと言うことです。
つまり、マウスをクリックしていないと落下しないし表示もされないようにご自身で書いてしまっているわけですね。
これを思った通りしたいとしたら、マウスをクリックしたことを何かの変数に覚えておいて、その変数がクリック後の値に成っていたら表示するというふうにすれば良いんじゃないでしょうか。

>現状考えているのは、ballのクラスまたは構造体を作り、そこからクリックのカウントに応じて新しく配列からボールを呼び出そうと思っています。
>何か、良いアイデアがあればご教示いただければ幸いです。

これについては、みけCAT さんがすでに提案してくれていますね。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

たらお
記事: 19
登録日時: 10年前

Re: [C++]クリックしたらボールが発生して自由落下

#8

投稿記事 by たらお » 10年前

softyaさんのアドバイスを元に、ソースコードを以下のように変えてみたら、クリックしたあともボールは描画されるようになりました。
ありがとうございます。

コード:

 
#include "DxLib.h"
#define g 9.8
int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) {
	ChangeWindowMode( TRUE ), DxLib_Init(), SetDrawScreen( DX_SCREEN_BACK ); //ウィンドウモード変更と初期化と裏画面設定
	int mx, my; //マウス座標
	int Handle, Handle2; // 画像格納用ハンドル
	Handle = LoadGraph( "ball.png" ); // ball画像のロード
	Handle2 = LoadGraph( "ground.png" ); //地面画像のロード
	double F, a; //力と加速度
	//初期値
	int    count=0;
	double y = 0; //y座標
	double v = 0; //速度
	double m = 1.0; //質量
	double r = 25.0; //半径
	double k = 0.5; //ばね定数
	double c = 2.5; //粘性係数
	double dt = 0.1; //時間変化
	// while( 裏画面を表画面に反映, メッセージ処理, 画面クリア )
	while( ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 ) {

		//マウスの入力状態取得
		GetMousePoint( &mx, &my );
		if( ( GetMouseInput() & MOUSE_INPUT_LEFT ) != 0 ) { //マウスをクリックしたら
			count=1;
		}
		if(count==1){
			F = m * g; //自由落下
			//バウンド処理
			if( y > 450 ) {
				F = -m * g;
				if( y > r ) {
					F += k * ( r - y ) - c * v;
				}
			}
			a = F / m; //加速度
			v += a * dt; //加速度から速度
			y += v * dt; //速度から座標
			DrawGraph( mx, y, Handle, TRUE ); //ball画像の描画
			DrawGraph( 0, 470, Handle2, TRUE ); //地面画像の描画
		}
	}

	DxLib_End(); // DXライブラリ終了処理
	return 0;
}
次は、みけCATさんのアドバイスを参考にボールを複数個呼び出せるように改良していきたいと思います。

たらお
記事: 19
登録日時: 10年前

Re: [C++]クリックしたらボールが発生して自由落下

#9

投稿記事 by たらお » 10年前

現在、ballの構造体を作り、そこに座標などの情報を格納しました。
そして、配列を作り、ball[10]の中から、42行目のfor文で、
クリックしたら一つ目のボール:ball[0]を呼び出して、
次にクリックすると、二つ目のボール:ball[1]が呼び出されるように
クリックするたびにボールを最大10個発生させたいのですが、
現状、ボールが一個しか発生しなくて困ってます。
修正すべき部分を教えていただければ幸いです。
コードは以下のようになっています。

コード:

#include "DxLib.h"
#define g 9.8
const int MAXN=10;
int ball[MAXN];

int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) {
	ChangeWindowMode( TRUE ), DxLib_Init(), SetDrawScreen( DX_SCREEN_BACK ); //ウィンドウモード変更と初期化と裏画面設定
	int mx,my;		//マウス座標
	int Handle, Handle2; // 画像格納用ハンドル
	Handle = LoadGraph( "ball.png" ); // ball画像のロード
	Handle2 = LoadGraph( "ground.png" ); //地面画像のロード
	double F, a; //力と加速度
	//マウスの入力状態取得
	GetMousePoint( &mx, &my );
	//初期値
	int    count=0;
	struct Ball{
		double x ; //x座標
		double y ; //y座標
		double v ; //速度
		double m ; //質量
		double r ; //半径
		double k ; //ばね定数
		double c ; //粘性係数
		double dt; //時間変化
	}ball[MAXN];

	for(int i=0;i<10;i++){
		ball[i].x=mx;
		ball[i].y=my;
		ball[i].v=0;
		ball[i].m=1.0;
		ball[i].r=25.0;
		ball[i].k=0.5;
		ball[i].c=2.5;
		ball[i].dt=0.1;
	}
	// while( 裏画面を表画面に反映, メッセージ処理, 画面クリア )
	while( ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 ) {


		for(int i=0;i<10;i++){
			if( ( GetMouseInput() & MOUSE_INPUT_LEFT ) != 0 ) { //マウスをクリックしたら
				count=1;
			}
			if(count==1){
				F = ball[i].m * g; //自由落下
				//バウンド処理
				if( ball[i].y > 450 ) {
					F = -ball[i].m * g;
					if( ball[i].y > ball[i].r ) {
						F += ball[i].k * ( ball[i].r -ball[i]. y ) - ball[i].c *ball[i]. v;
					}
				}
				a = F / ball[i].m; //加速度
				ball[i].v += a * ball[i].dt; //加速度から速度
				ball[i].y += ball[i].v * ball[i].dt; //速度から座標
				DrawGraph( ball[i].x, ball[i].y, Handle, TRUE ); //ball画像の描画

			}	
			DrawGraph( 0, 470, Handle2, TRUE ); //地面画像の描画

		}

	}

	DxLib_End(); // DXライブラリ終了処理
	return 0;
}
よろしくお願いします。

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: [C++]クリックしたらボールが発生して自由落下

#10

投稿記事 by usao » 10年前

まず落ち着いて どういう手順で何をすればいいのか を整理できてからコーディングした方が良いように見受けます.
いろいろと混乱していませんか?
(例えば,countという変数は何なのか(何を表しているのか)具体的に説明できますか?)


とりあえず,各フレームにおいてやること:「最初にAをして,次にBをして…」という手順を書きだす等してみてはいかがでしょう.
で,各々の要素AやBは具体的にはどうやって実現していくのか,
 例えば処理Aというのは細かく見ると,「処理aをして,次に変数bの状態を判定して bがxxxだったら処理c,そうでなければ処理d を行うのだ」
という風により具体的に分解……→最終的に全ての箇所がコードで書ける単位にまで.

(その過程で 「処理aというのが必要だと思うが,どうやって実現すればいいのかわからん」
 とかいうことがあれば,それを質問するとか.)

[hr]

[追記]
上記だけでは何なので,気になる点をいくつか書いておきます.

・「マウスをクリックしたら」という判定は各フレームで1回だけやればよいのでは?
・クリック時に「さっき[2]番目の玉を発生させたから今回は[3]番目だな」みたいなことを決めるための処理が存在していない
・玉の運動処理や描画処理は,現在存在する玉についてのみ行えば良いと思うが,玉が存在しているのか?という判定処理が見当たらない.

たらお
記事: 19
登録日時: 10年前

Re: [C++]クリックしたらボールが発生して自由落下

#11

投稿記事 by たらお » 10年前

皆さんのアドバイスとこちらのサイト
http://takabosoft.com/19991219151646.html
を参考にコードを修正しましたが、思うとおりにいきません。
現在クリックすると、ボールがつながって表示されてしまいます。
どこが原因で、どのように修正すべきか教えていただければ幸いです。

コード:

#include <windows.h>
#include "DxLib.h"
#define g 9.8
#define BMAX 10
int mx,my;		//マウス座標
int click =0;
//初期値
float F, a; //力と加速度	
struct Ball{
	BOOL enable;	//使用:1  未使用:0
	float x ; //x座標
	float y ; //y座標
	float v ; //速度
	float m ; //質量
	float r ; //半径
	float k ; //ばね定数
	float c ; //粘性係数
	float dt; //時間変化
}ball[BMAX];

void InitGame(){

	int Handle2 = LoadGraph( "ground.png" ); //地面画像の
	DrawGraph( 0, 470, Handle2, TRUE ); //地面画像の描画

	//弾データ初期化
	for(int i=0;i<BMAX;i++)
		ball[i].enable=0;
}

void Createball(float x,float y){
	int i;
	int no=-1;	//作成する弾のデータ番号

	//構造体の中で、空いている(未使用)データを探す
	for(i=0;i<BMAX;i++)
		if(ball[i].enable==0){
			no=i;
			break;
		}

		//空いているデータが見つからなかったら作成せずに戻る
		if(no==-1)
			return;

		//データ詰める
		ball[no].x=x;
		ball[no].y=y;
		ball[no].enable=1;	//使用中にする
}
void Shoot(){
	//ボール発射判定
	if( ( GetMouseInput() & MOUSE_INPUT_LEFT ) != 0 )//マウスをクリックしたら				
		click=1;
	if(click==1)
		Createball(mx,my);

}
void MoveBall(){
	int i;

	for(i=0;i<BMAX;i++){
		if(ball[i].enable==0) //未使用データだったら次の処理へ
			continue;

		//移動
		F = ball[i].m * g; //自由落下
		//バウンド処理
		if( ball[i].y > 450 ) {
			F = -ball[i].m * g;
			if( ball[i].y > ball[i].r ) {
				F += ball[i].k * ( ball[i].r -ball[i]. y ) - ball[i].c *ball[i]. v;
			}
		}
		a = F / ball[i].m; //加速度
		ball[i].v += a * ball[i].dt; //加速度から速度
		ball[i].y += ball[i].v * ball[i].dt; //速度から座標

	}
}

void Show(){
	int i;
	int Handle = LoadGraph( "ball.png" ); // ball画像のロード
	//ボール表示

	for(i=0;i<BMAX;i++)
		if(ball[i].enable==1)
			DrawGraph( ball[i].x, ball[i].y, Handle, TRUE ); //ball画像の描画
}
//----------[ メインループ ]--------------------------------------------------------------------
void GameLoop(void){
	for(int i=0;i<BMAX;i++){
		Shoot();                    //弾発射判定

		MoveBall();               //弾移動

		Show();					//画像表示

	}
}

int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) {
	ChangeWindowMode( TRUE ), DxLib_Init(), SetDrawScreen( DX_SCREEN_BACK ); //ウィンドウモード変更と初期化と裏画面設定
	//マウスの入力状態取得
	GetMousePoint( &mx, &my );
	//初期値
	int i;
	for(i=0;i<BMAX;i++){
		ball[i].x=mx;
		ball[i].y=my;
		ball[i].v=0;
		ball[i].m=1.0;
		ball[i].r=25.0;
		ball[i].k=0.5;
		ball[i].c=2.5;
		ball[i].dt=0.1;
	}
	// while( 裏画面を表画面に反映, メッセージ処理, 画面クリア )
	while( ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 ) {

		InitGame();

		GameLoop();

	}

	DxLib_End(); // DXライブラリ終了処理
	return 0;
}

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: [C++]クリックしたらボールが発生して自由落下

#12

投稿記事 by softya(ソフト屋) » 10年前

こちらと
http://takabosoft.com/19991219151646.html
このサイトのゲームプログラミングの館のある章の
http://dixq.net/g/02_09.html
は、ある程度似たことしているのですがお気づきですか?
その部分が全く反映されていないので起きている問題です。
【補足】 よく考えたら、慣れていない人には似ても似つかない処理に見えるかもしれないので、ゲームプログラミングの館の方を参考にして下さい。

それとLoadGraph( "ball.png" )を毎フレームやるとメモリリークで落ちますよ。
正確に言うとDXライブラリの画像ハンドルを使い過ぎでDXライブラリが異常終了します。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
Hiragi(GKUTH)
記事: 167
登録日時: 14年前
住所: 大阪府
連絡を取る:

Re: [C++]クリックしたらボールが発生して自由落下

#13

投稿記事 by Hiragi(GKUTH) » 10年前

このままだとクリックしている間はずっとボールが放出され続けてしまいます、クリックされた瞬間だけ、ボールを追加する必要があります。
加えてマウスの座標はメインループ外で取得しているので、プログラム起動時の位置しか取得できないのでは?(間違っていたらすいません。)
特にsoftyaさんも仰っていますが、毎フレーム ロード->描画を繰り返すのは良くないと思います。Show関数も同じように画像のロード部分はメインループ外でするべきです。
だいがくせい!

たらお
記事: 19
登録日時: 10年前

Re: [C++]クリックしたらボールが発生して自由落下

#14

投稿記事 by たらお » 10年前

丁寧なご回答ありがとうございます。
言われた点を意識して、ソースコードを修正してみました。
以下が現在のコードです。

コード:

 #include <windows.h>
#include "DxLib.h"
#include<math.h>
#define g 9.8
#define BMAX 10
//----------[ ボール構造体 ]----------------------------------------
struct Ball{
	BOOL enable;	//使用:1  未使用:0
	float x ; //x座標
	float y ; //y座標
	float v ; //速度
	float m ; //質量
	float r ; //半径
	float k ; //ばね定数
	float c ; //粘性係数
	float dt; //時間変化
}ball[BMAX]; 
//----------[ ゲーム初期化 ]----------------------------------------
void InitGame(){

	int Handle2 = LoadGraph( "ground.png" ); //地面画像の
	DrawGraph( 0, 420, Handle2, TRUE ); //地面画像の描画

	//弾データ初期化
	for(int i=0;i<BMAX;i++)
		ball[i].enable=0;
}
//----------[ ボール作成 ]----------------------------------------------
void Createball(float x,float y){
	int i;
	int no=-1;	//作成する弾のデータ番号

	//構造体の中で、空いている(未使用)データを探す
	for(i=0;i<BMAX;i++)
		if(ball[i].enable==0){
			no=i;
			break;
		}

		//空いているデータが見つからなかったら作成せずに戻る
		if(no==-1)
			return;

		//データ詰める
		ball[no].x=x;
		ball[no].y=y;
		ball[no].enable=1;	//使用中にする
}
//----------[ メイン関数 ]----------------------------------------------
int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) {
	ChangeWindowMode( TRUE ), DxLib_Init(), SetDrawScreen( DX_SCREEN_BACK ); //ウィンドウモード変更と初期化と裏画面設定
	int mx,my;      //マウス座標
	int Handle;// 画像格納用ハンドル
	Handle = LoadGraph( "ball.png" ); // ball画像のロード
	float F, a; //力と加速度
	//初期値
	int    clickcount=0;//クリック初期化
	int	   beforeMouseInput = 0;//1フレーム前のマウスの状態
	//マウスの初期化
	GetMousePoint( &mx, &my );
	for(int i=0;i<BMAX;i++){
		ball[i].x=mx;
		ball[i].y=my;
		ball[i].v=0;
		ball[i].m=1.0;
		ball[i].r=25.0;
		ball[i].k=1.0;
		ball[i].c=3.5;
		ball[i].dt=0.1;
	}
	// while( 裏画面を表画面に反映, メッセージ処理, 画面クリア )
	while( ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 ) {
		//マウスの入力状態更新
		GetMousePoint( &mx, &my );
		InitGame();

		for(int i=0;i<BMAX;i++){
			//クリックした瞬間
			if( (beforeMouseInput & MOUSE_INPUT_LEFT ) != MOUSE_INPUT_LEFT
				&& (GetMouseInput() & MOUSE_INPUT_LEFT)== MOUSE_INPUT_LEFT){		
					clickcount=1;
					Createball(mx,my);
			}
			beforeMouseInput = GetMouseInput();

			if(ball[i].enable==0&&clickcount==1){
				F = ball[i].m * g; //自由落下
				//バウンド処理
				if( ball[i].y > 380 ) {
					F = -ball[i].m * g;

					if( abs(ball[i].y-380) < ball[i].r ) {
						F += ball[i].k * ( ball[i].r -ball[i]. y ) - ball[i].c *ball[i]. v;
					}
				}
				a = F / ball[i].m; //加速度
				ball[i].v += a * ball[i].dt; //加速度から速度
				ball[i].y += ball[i].v * ball[i].dt; //速度から座標
				DrawGraph( ball[i].x, ball[i].y, Handle, TRUE ); //ball画像の描画

			}   

		}

	}

	DxLib_End(); // DXライブラリ終了処理
	return 0;
}

現在、このソースコードで実行すると、一回クリックしたら、ボールが1個発生し、2回目クリックするともう一つのボールが発生するのですが、3回目クリックすると、2回目のボールが消えて新しいボールに更新されてしまいます。2個目以降もボールが画面上に残り続け、ボールがどんどん画面上に発生するためには、どの部分を直せば良いでしょうか?
よろしければ教えていただけると嬉しいです。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: [C++]クリックしたらボールが発生して自由落下

#15

投稿記事 by softya(ソフト屋) » 10年前

ここの部分に違和感を感じます.
> if(ball.enable==0&&clickcount==1){
問題をねじ伏せるために、このコードを書いていませんか?
そもそもの別の間違いが無ければ、こうはならないはずです。

あとクリックの処理を for(int i=0;i<BMAX;i++){のループに入れる理由はないはずです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

たらお
記事: 19
登録日時: 10年前

Re: [C++]クリックしたらボールが発生して自由落下

#16

投稿記事 by たらお » 10年前

皆さんのアドバイスを参考にしたら、完成できました。
ありがとうございます。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: [C++]クリックしたらボールが発生して自由落下

#17

投稿記事 by softya(ソフト屋) » 10年前

たらお さんが書きました:皆さんのアドバイスを参考にしたら、完成できました。
ありがとうございます。
よく直ったつもりで、直っていないことがありますので最終コードを投稿することをオススメします。
あと、他の人に参考になるように投稿して頂くと掲示板としても助かります。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

たらお
記事: 19
登録日時: 10年前

Re: [C++]クリックしたらボールが発生して自由落下

#18

投稿記事 by たらお » 10年前

コード:

/----------[インクルードファイル ]----------------------------------------
#include "DxLib.h"
//----------[マクロ定義部 ]----------------------------------------
#define g 9.8//重力加速度
#define BMAX 100 //ボールの最大出現数を100個に
#define X_MAX 640//画面の最大横幅
//----------[ グローバル変数 ]----------------------------------------
int	Handle,Handle2,Handle3,Handle4,Handle5;//画像格納用ハンドル
int clickcount;//クリック格納変数
int	beforeMouseInput;//1フレーム前のマウスの状態
int mx,my;      //マウス座標
double F, a; //力と加速度
//----------[ ボール構造体 ]----------------------------------------
struct Ball{
	int   flag;//1:使用 0:消去
	double x ; //x座標
	double y ; //y座標
	double v ; //速度
	double m ; //質量
	double r ; //半径
	double k ; //ばね定数
	double c ; //粘性係数
	double dt; //時間変化
}ball[BMAX];
//----------[ 音声・画像ファイルロード ]----------------------------------------
void File_load(){
	Handle= LoadGraph( "tumball.png" ); // ball画像のロード
	Handle2 = LoadGraph( "tumball3.png" ); //ball2画像のロード
	Handle3 = LoadGraph( "ground4.jpg" ); //地面画像のロード
	Handle4=LoadGraph( "background5.jpg" ); //背景画像のロード
	Handle5=  LoadSoundMem( "se1.mp3" );//効果音のロード
}
//----------[ 初期値 ]----------------------------------------
void Ini_Game(){
	clickcount=0;//クリック初期化
	beforeMouseInput = 0;//1フレーム前のマウスの状態
}
//----------[ 背景描画 ]----------------------------------------
void BackGround(){
	DrawGraph( 0, 0, Handle4, TRUE ); //背景画像の描画
}
//----------[ 地面描画 ]----------------------------------------
void DrawGround(){

	DrawGraph( 0, 420, Handle3, TRUE ); //地面画像の描画
	for(int i=0;i<BMAX;i++){
		//ボールが当たったら地面振動
		if(ball[i].flag==1&& ball[i].y+ball[i].r > 395)
			DrawGraph( 10, 420, Handle3, TRUE ); //x軸に10ピクセルずらして地面画像の描画
	}
}
//----------[ ボール作成 ]----------------------------------------------
void Createball(double x,double y){

	//構造体の中で、空いている(未使用)データを探す
	for(int i=clickcount;i<BMAX;i++){
		//データ詰める
		ball[i].x=x;
		ball[i].y=y;
		ball[i].v=0;
		ball[i].m=1.0;
		ball[i].r=25.0;
		ball[i].k=0.5;
		ball[i].c=2.5;
		ball[i].dt=0.1;
		ball[i].flag=1;//使用にする
	}
}
//----------[ ボール発射判定 ]----------------------------------------------
void Shot_Hantei(){

	//クリックした瞬間
	if( (beforeMouseInput & MOUSE_INPUT_LEFT ) != MOUSE_INPUT_LEFT
		&& (GetMouseInput() & MOUSE_INPUT_LEFT)== MOUSE_INPUT_LEFT){		
			clickcount+=1;//クリックカウント増やす
			Createball(mx,my);//マウスの座標にボール作成
			PlaySoundMem(Handle5,DX_PLAYTYPE_NORMAL);//ボール出現音再生
	}
	beforeMouseInput = GetMouseInput();
}
//----------[ ボール移動 ]----------------------------------------------
void Moveball(){

	for(int i=0;i<BMAX;i++){

		if(ball[i].flag==1&&clickcount>=1){//ボールが使用中なら
			F = ball[i].m * g; //自由落下
			//バウンド処理
			if( ball[i].y+ball[i].r > 395 ) {//地面に当たったら
				F = -ball[i].m * g;//バウンドさせる。
				//沈み込み量に応じてバウンド減衰
				if( ball[i].y-370 < ball[i].r ) {
					F += ball[i].k * ( ball[i].r -ball[i]. y) - ball[i].c *ball[i]. v;
				}
			}
			a = F / ball[i].m; //加速度
			ball[i].v += a * ball[i].dt; //加速度から速度
			ball[i].y += ball[i].v * ball[i].dt; //速度から座標
			ball[i].x +=2; //x座標方向への移動
			//画面外に出たらボール消去
			if(ball[i].x<0 || X_MAX<ball[i].x)
				ball[i].flag=0;//消去する
		}
	}
}
//----------[ ボール描画 ]----------------------------------------------
void Drawball(){

	for(int i=0;i<BMAX;i++){
		if(ball[i].flag==1&&clickcount>=1){//ボールが使用中なら
			DrawGraph( ball[i].x, ball[i].y, Handle, TRUE); //ball1画像の描画
			if( ball[i].y+ball[i].r > 395 )//地面に当たったらボール変形
				DrawGraph( ball[i].x, ball[i].y, Handle2, TRUE ); //ball2画像の描画			
		}
	}
}
//----------[ メイン関数 ]----------------------------------------------
int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) {
	ChangeWindowMode( TRUE ), DxLib_Init(), SetDrawScreen( DX_SCREEN_BACK ); //ウィンドウモード変更と初期化と裏画面設定

	File_load();//画像ロード

	Ini_Game();//初期値
	//----------[ メインループ ]----------------------------------------------
	// while( 裏画面を表画面に反映, メッセージ処理, 画面クリア,ESCAPEで終了 )
	while( ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 ) {

		GetMousePoint( &mx, &my );//マウスの入力状態更新

		BackGround();//背景描画

		DrawGround();//地面描画

		Shot_Hantei();//ボール発射判定

		Moveball();//ボール移動

		Drawball();//ボール描画

	}   

	DxLib_End(); // DXライブラリ終了処理
	return 0;
}
/
最終コードです。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: [C++]クリックしたらボールが発生して自由落下

#19

投稿記事 by softya(ソフト屋) » 10年前

ありがとうございます。
一点気になる点が。ボールと地面でバウンド時にバウンド前の描画も同時に行われてますが意図通りなのでしょうか?
つまり、2つの状態(バウンド前と後)の画像が重ね書きされています。画像がないので正しいかどうかは、こちらでは判断不能でした。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

閉鎖

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