C++における鉛直投げ上げ+反射のプログラム

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

C++における鉛直投げ上げ+反射のプログラム

#1

投稿記事 by 酢だこ » 13年前

はじめまして。

この度C++の勉強を始めて、グラフィック処理でのプログラムを組んでいるのですがどうしても行き詰ったので質問させていただきます。

プログラムとしては指定した場所から指定した初速度(y方向、x方向)で球を投げ上げ、重力加速度により落ちていき、そのあとは反発係数を指定してバウンドしていくというものにしたいと思っています。

投げあげてから重力加速度に従って球が落ちるところまではできたのですが、その先どのように球を反発させればよいかがわかりません。

ifを使ってどうにかしようとはしたのですがうまくいかないのでご教授願えたらと思います。

コード:


			 float xo,yo,u,r,gy,dt;
			 Graphics^ gr;
			 Brush^ br;
			 Brush^ brwhite;
			 Pen^ p1;
			 Pen^ p2;
			 Pen^ p3;
			 float t,xt,yt,vx,vy,vx0,vy0,g,a,h;
			 //グラフィック環境設定とパラメータの読み込み
			 void InitGraph(){
				 gr=pictureBox1->CreateGraphics();
				 p1=gcnew Pen(Color::Blue,1);
				 brwhite=gcnew SolidBrush(Color::White);
				 xo=150;
				 yo=300;
				 u=10;
				 //ビルの大きさを指定する
				 a=Convert::ToSingle(textBox1->Text);
				 h=Convert::ToSingle(textBox2->Text);
				 //初速度を指定する
				 vx0=Convert::ToSingle(textBox3->Text);
				 vy0=Convert::ToSingle(textBox4->Text);
				 //重力加速度を指定する
				 g=9.8;
				 //球の半径を指定する
				 r=0.1;
				 //微小時間を指定する
				 dt=0.05;
			 }

			 //座標軸を描く
			 void Drawaxis(){
				 float gx,gy;
				 gr->FillRectangle(brwhite,0,0,500,400);
				 gr->DrawLine(p1,xo-3*u,yo,xo+20*u,yo);
				 gr->DrawLine(p1,xo,yo-25*u,xo,yo+5*u);
				 //ビルを描く
				 gr->DrawRectangle(p1,xo,yo-h*u,a*u,h*u);
			 }

			 void ball(float x,float y,float r,int c){
				 float gx,gy,rr;
				 gx=xo+x*u;
				 gy=yo-y*u;
				 rr=u*r;
				 if(c==1){
					 br=gcnew SolidBrush(Color::Blue);
				 }else{
					 br=gcnew SolidBrush(Color::White);
				 }
				 gr->FillEllipse(br,gx-0.5*rr,gy-0.5*rr,rr,rr);
			 }

private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
			 InitGraph();
			 Drawaxis();
			 t=0;
			 timer1->Enabled="True";
		 		 }

private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e) {
			 ball(xt,yt,0.7,0);
			 t=t+dt;
			 xt=a+vx0*t;
			 yt=h+vy0*t-0.5*g*t*t;
			 ball(xt,yt,0.7,1);
			 
		 }
};
}

酢だこ

Re: C++における鉛直投げ上げ+反射のプログラム

#2

投稿記事 by 酢だこ » 13年前

一度反射させることはできましたが、それ以降球が落ちてこなくなってしまいました。

対処法等わかる方がいましたらご教授願います。

コード:

#pragma once
#include<stdlib.h>
#include<time.h>
			 float xo,yo,u,r,gy,dt;
			 Graphics^ gr;
			 Brush^ br;
			 Brush^ brwhite;
			 Pen^ p1;
			 Pen^ p2;
			 Pen^ p3;
			 float t,xt,yt,vx,vy,vx0,vy0,g,a,h;
			 //グラフィック環境設定とパラメータの読み込み
			 void InitGraph(){
				 gr=pictureBox1->CreateGraphics();
				 p1=gcnew Pen(Color::Blue,1);
				 brwhite=gcnew SolidBrush(Color::White);
				 xo=150;
				 yo=300;
				 u=10;
				 //ビルの大きさを指定する
				 a=Convert::ToSingle(textBox1->Text);
				 h=Convert::ToSingle(textBox2->Text);
				 //初速度を指定する
				 vx0=Convert::ToSingle(textBox3->Text);
				 vy0=Convert::ToSingle(textBox4->Text);
				 //重力加速度を指定する
				 g=9.8;
				 //球の半径を指定する
				 r=0.1;
				 //微小時間を指定する
				 dt=0.05;
			 }

			 //座標軸を描く
			 void Drawaxis(){
				 gr->FillRectangle(brwhite,0,0,500,400);
				 gr->DrawLine(p1,xo-3*u,yo,xo+20*u,yo);
				 gr->DrawLine(p1,xo,yo-25*u,xo,yo+5*u);
				 //ビルを描く
				 gr->DrawRectangle(p1,xo,yo-h*u,a*u,h*u);
			 }

			 void ball(float x,float y,float r,int c){
				 float gx,gy,rr;
				 gx=xo+x*u;
				 gy=yo-y*u;
				 rr=u*r;
				if(c==1){
					 br=gcnew SolidBrush(Color::Blue);
				 }else{
					 br=gcnew SolidBrush(Color::White);
				 }
				 gr->FillEllipse(br,gx-0.5*rr,gy-0.5*rr,rr,rr);
				 
			 }

private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
			 InitGraph();
			 Drawaxis();
			 t=0;
			 timer1->Enabled="True";
			}

private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e) {
			 ball(xt,yt,0.7,0);
			 t=t+dt;
			 xt=a+vx0*t;
			 yt=h+vy0*t-0.5*g*t*t;
			 if(yt<=0){
				 yt=-0.7*(h+vy0*t-0.5*g*t*t);
			 }else{
			 }
			 
			 ball(xt,yt,0.7,1);
			
		 }
};
}



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

Re: C++における鉛直投げ上げ+反射のプログラム

#3

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

時間で反射までは制御できません。
速度と加速度を使ってベクトルで管理する方法に改めたほうが良いと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

酢だこ

Re: C++における鉛直投げ上げ+反射のプログラム

#4

投稿記事 by 酢だこ » 13年前

返信ありがとうございます。
加速度でベクトル管理とありますが、加速度は時間tを使わないでどう表現したらよいのでしょうか?
softya(ソフト屋) さんが書きました:時間で反射までは制御できません。
速度と加速度を使ってベクトルで管理する方法に改めたほうが良いと思います。

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

Re: C++における鉛直投げ上げ+反射のプログラム

#5

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

速度に必要なのは最初からの経過時間では無く前フレームからの経過時間です。これは1/60秒とか一定ではありませんか?
加速度は単位時間あたりの数値が一定の重力加速度だと思いますので、1/60秒あたりの加速度は求められますよね?
速度も1/60秒あたりの速度で保持していれば、これに1/60秒あたりの加速度を足せば新しい速度になります。

この速度は上昇と下降を表すので+-のあるベクトルとして使います。
前フレームの座標にベクトル速度を足すだけで現在の座標を求めることができるので、これを繰り返すわけです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

酢だこ

Re: C++における鉛直投げ上げ+反射のプログラム

#6

投稿記事 by 酢だこ » 13年前

返信ありがとうございます。

色々と試してみたのですがどうしても反射したあと球が落ちてきませんでした。

そこで質問なのですが加速度を指定するプログラムはtimerの中にいれるということで間違いはないでしょうか?

またもしよろしければ加速度を表すようなプログラムの例を出していただけると幸いです。

よろしくお願いします。
softya(ソフト屋) さんが書きました:速度に必要なのは最初からの経過時間では無く前フレームからの経過時間です。これは1/60秒とか一定ではありませんか?
加速度は単位時間あたりの数値が一定の重力加速度だと思いますので、1/60秒あたりの加速度は求められますよね?
速度も1/60秒あたりの速度で保持していれば、これに1/60秒あたりの加速度を足せば新しい速度になります。

この速度は上昇と下降を表すので+-のあるベクトルとして使います。
前フレームの座標にベクトル速度を足すだけで現在の座標を求めることができるので、これを繰り返すわけです。

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

Re: C++における鉛直投げ上げ+反射のプログラム

#7

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

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

酢だこ

Re: C++における鉛直投げ上げ+反射のプログラム

#8

投稿記事 by 酢だこ » 13年前

とりあえず今書いてみたプログラムの1つ目です。こちらは全くと言っていいほどうまくいきません。

コード:

#pragma once
#include<stdlib.h>
#include<time.h>
#include<math.h>

namespace バウンド2 {

	using namespace System;
	using namespace System::ComponentModel;
	using namespace System::Collections;
	using namespace System::Windows::Forms;
	using namespace System::Data;
	using namespace System::Drawing;

	/// <summary>
	/// Form1 の概要
	/// </summary>
	public ref class Form1 : public System::Windows::Forms::Form
	{
	public:
		Form1(void)
		{
			InitializeComponent();
			//
			//TODO: ここにコンストラクター コードを追加します
			//
		}

	protected:
		/// <summary>
		/// 使用中のリソースをすべてクリーンアップします。
		/// </summary>
		~Form1()
		{
			if (components)
			{
				delete components;
			}
		}
	private: System::Windows::Forms::Button^  button1;
	protected: 
	private: System::Windows::Forms::Button^  button2;
	private: System::Windows::Forms::TextBox^  textBox1;
	private: System::Windows::Forms::TextBox^  textBox2;
	private: System::Windows::Forms::TextBox^  textBox3;
	private: System::Windows::Forms::TextBox^  textBox4;
	private: System::Windows::Forms::PictureBox^  pictureBox1;
	private: System::Windows::Forms::Timer^  timer1;

	private: System::ComponentModel::IContainer^  components;

	private:
		/// <summary>
		/// 必要なデザイナー変数です。
		/// </summary>


#pragma region Windows Form Designer generated code
		/// <summary>
		/// デザイナー サポートに必要なメソッドです。このメソッドの内容を
		/// コード エディターで変更しないでください。
		/// </summary>
		void InitializeComponent(void)
		{
			this->components = (gcnew System::ComponentModel::Container());
			this->button1 = (gcnew System::Windows::Forms::Button());
			this->button2 = (gcnew System::Windows::Forms::Button());
			this->textBox1 = (gcnew System::Windows::Forms::TextBox());
			this->textBox2 = (gcnew System::Windows::Forms::TextBox());
			this->textBox3 = (gcnew System::Windows::Forms::TextBox());
			this->textBox4 = (gcnew System::Windows::Forms::TextBox());
			this->pictureBox1 = (gcnew System::Windows::Forms::PictureBox());
			this->timer1 = (gcnew System::Windows::Forms::Timer(this->components));
			(cli::safe_cast<System::ComponentModel::ISupportInitialize^  >(this->pictureBox1))->BeginInit();
			this->SuspendLayout();
			// 
			// button1
			// 
			this->button1->Location = System::Drawing::Point(27, 35);
			this->button1->Name = L"button1";
			this->button1->Size = System::Drawing::Size(102, 23);
			this->button1->TabIndex = 0;
			this->button1->Text = L"Start";
			this->button1->UseVisualStyleBackColor = true;
			this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click);
			// 
			// button2
			// 
			this->button2->Location = System::Drawing::Point(36, 301);
			this->button2->Name = L"button2";
			this->button2->Size = System::Drawing::Size(84, 22);
			this->button2->TabIndex = 1;
			this->button2->Text = L"Stop";
			this->button2->UseVisualStyleBackColor = true;
			this->button2->Click += gcnew System::EventHandler(this, &Form1::button2_Click);
			// 
			// textBox1
			// 
			this->textBox1->Location = System::Drawing::Point(28, 93);
			this->textBox1->Name = L"textBox1";
			this->textBox1->Size = System::Drawing::Size(104, 19);
			this->textBox1->TabIndex = 2;
			this->textBox1->Text = L"0";
			// 
			// textBox2
			// 
			this->textBox2->Location = System::Drawing::Point(32, 138);
			this->textBox2->Name = L"textBox2";
			this->textBox2->Size = System::Drawing::Size(99, 19);
			this->textBox2->TabIndex = 3;
			this->textBox2->Text = L"5";
			// 
			// textBox3
			// 
			this->textBox3->Location = System::Drawing::Point(31, 178);
			this->textBox3->Name = L"textBox3";
			this->textBox3->Size = System::Drawing::Size(99, 19);
			this->textBox3->TabIndex = 4;
			this->textBox3->Text = L"2";
			// 
			// textBox4
			// 
			this->textBox4->Location = System::Drawing::Point(30, 229);
			this->textBox4->Name = L"textBox4";
			this->textBox4->Size = System::Drawing::Size(99, 19);
			this->textBox4->TabIndex = 5;
			this->textBox4->Text = L"2";
			// 
			// pictureBox1
			// 
			this->pictureBox1->Location = System::Drawing::Point(174, 41);
			this->pictureBox1->Name = L"pictureBox1";
			this->pictureBox1->Size = System::Drawing::Size(673, 426);
			this->pictureBox1->TabIndex = 6;
			this->pictureBox1->TabStop = false;
			// 
			// timer1
			// 
			this->timer1->Tick += gcnew System::EventHandler(this, &Form1::timer1_Tick);
			// 
			// Form1
			// 
			this->AutoScaleDimensions = System::Drawing::SizeF(6, 12);
			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
			this->ClientSize = System::Drawing::Size(1001, 507);
			this->Controls->Add(this->pictureBox1);
			this->Controls->Add(this->textBox4);
			this->Controls->Add(this->textBox3);
			this->Controls->Add(this->textBox2);
			this->Controls->Add(this->textBox1);
			this->Controls->Add(this->button2);
			this->Controls->Add(this->button1);
			this->Name = L"Form1";
			this->Text = L"Form1";
			(cli::safe_cast<System::ComponentModel::ISupportInitialize^  >(this->pictureBox1))->EndInit();
			this->ResumeLayout(false);
			this->PerformLayout();

		}
#pragma endregion
	private: System::Void button2_Click(System::Object^  sender, System::EventArgs^  e) {
				 Application::Exit();
			 }

			 float xo,yo,u,r,gy,dt;
			 Graphics^ gr;
			 Brush^ br;
			 Brush^ brwhite;
			 Pen^ p1;
			 Pen^ p2;
			 Pen^ p3;
			 float t,xt,yt,vx,vy,vx0,vy0,g,a,h;
			 //グラフィック環境設定とパラメータの読み込み
			 void InitGraph(){
				 gr=pictureBox1->CreateGraphics();
				 p1=gcnew Pen(Color::Blue,1);
				 brwhite=gcnew SolidBrush(Color::White);
				 xo=150;
				 yo=300;
				 u=10;
				 //ビルの大きさを指定する
				 a=Convert::ToSingle(textBox1->Text);
				 h=Convert::ToSingle(textBox2->Text);
				 //初速度を指定する
				 vx0=Convert::ToSingle(textBox3->Text);
				 vy0=Convert::ToSingle(textBox4->Text);
				 //重力加速度を指定する
				 g=-9.8;
				 //球の半径を指定する
				 r=0.1;
				 //微小時間を指定する
				 dt=0.05;
			 }

			 //座標軸を描く
			 void Drawaxis(){
				 gr->FillRectangle(brwhite,0,0,500,400);
				 gr->DrawLine(p1,xo-3*u,yo,xo+20*u,yo);
				 gr->DrawLine(p1,xo,yo-25*u,xo,yo+5*u);
				 //ビルを描く
				 gr->DrawRectangle(p1,xo,yo-h*u,a*u,h*u);
			 }

			 void ball(float x,float y,float r,int c){
				 float gx,gy,rr;
				 gx=xo+x*u;
				 gy=yo-y*u;
				 rr=u*r;
				if(c==1){
					 br=gcnew SolidBrush(Color::Blue);
				 }else{
					 br=gcnew SolidBrush(Color::White);
				 }
				 gr->FillEllipse(br,gx-0.5*rr,gy-0.5*rr,rr,rr);
				 
			 }

private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
			 InitGraph();
			 Drawaxis();
			 t=0;
			 timer1->Enabled="True";

			}

private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e) {
float V=15,A=0.9;
			int i=0;
			float vv;
			 ball(xt,yt,0.7,0);

			 if(i==0)
			 {
			//	 vv=V*sin(2.6);
			//	 vy0=vv;
				 yt=h;
				 i++;
			 }
			 t=t+dt;
			 xt+=a+vx0*dt;
			 
			 vy0+=g*dt;
			 
			 if(yt<0){
				vy0=-A*vy0;
				}
			 yt+=vy0*dt;
			 
			 ball(xt,yt,0.7,1);
			
		 }
};
}


酢だこ

Re: C++における鉛直投げ上げ+反射のプログラム

#9

投稿記事 by 酢だこ » 13年前

こちらは前回からほとんどいじっていません。

しかし球の動きは今のところ一番理想に近い感じです。

コード:


#include<stdlib.h>
#include<time.h>
#include<math.h>


			 float xo,yo,u,r,gy,dt;
			 Graphics^ gr;
			 Brush^ br;
			 Brush^ brwhite;
			 Pen^ p1;
			 Pen^ p2;
			 Pen^ p3;
			 float t,xt,yt,vx,vy,vx0,vy0,g,a,h;
			 //グラフィック環境設定とパラメータの読み込み
			 void InitGraph(){
				 gr=pictureBox1->CreateGraphics();
				 p1=gcnew Pen(Color::Blue,1);
				 brwhite=gcnew SolidBrush(Color::White);
				 xo=150;
				 yo=300;
				 u=10;
				 //ビルの大きさを指定する
				 a=Convert::ToSingle(textBox1->Text);
				 h=Convert::ToSingle(textBox2->Text);
				 //初速度を指定する
				 vx0=Convert::ToSingle(textBox3->Text);
				 vy0=Convert::ToSingle(textBox4->Text);
				 //重力加速度を指定する
				 g=9.8;
				 //球の半径を指定する
				 r=0.1;
				 //微小時間を指定する
				 dt=0.05;
			 }

			 //座標軸を描く
			 void Drawaxis(){
				 gr->FillRectangle(brwhite,0,0,500,400);
				 gr->DrawLine(p1,xo-3*u,yo,xo+20*u,yo);
				 gr->DrawLine(p1,xo,yo-25*u,xo,yo+5*u);
				 //ビルを描く
				 gr->DrawRectangle(p1,xo,yo-h*u,a*u,h*u);
			 }

			 void ball(float x,float y,float r,int c){
				 float gx,gy,rr;
				 gx=xo+x*u;
				 gy=yo-y*u;
				 rr=u*r;
				if(c==1){
					 br=gcnew SolidBrush(Color::Blue);
				 }else{
					 br=gcnew SolidBrush(Color::White);
				 }
				 gr->FillEllipse(br,gx-0.5*rr,gy-0.5*rr,rr,rr);
				 
			 }

private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
			 InitGraph();
			 Drawaxis();
			 t=0;
			 timer1->Enabled="True";

			}

private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e) {
				float v;
			 ball(xt,yt,0.7,0);
			 t=t+dt;
			 xt=a+vx0*t;
			 yt=h+vy0*t-0.5*g*t*t;
			 v=vx0-g*t;
			 
			 if(yt<=0){
				v=-0.7*v;
				yt=v*t-0.5*g*t*t;
			 }else{
			 }
			 
			 
			 ball(xt,yt,0.7,1);
		 }
			
};
}



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

Re: C++における鉛直投げ上げ+反射のプログラム

#10

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

ローカル変数の動作とかを理解されていないようです。
プログラミング自体に不慣れなのでしょうか?

コード:

            int i=0;
             if(i==0)
             {
            //   vv=V*sin(2.6);
            //   vy0=vv;
                 yt=h;
                 i++;
             }
これだと関数に入る度にiが0になるのでi++している意味がありませんし、毎回 yt=h;を行います。
あとインデント(字下げ)が不的確なのとiと言う名前を安易に使うのはバグのもとです。
for( i=0 ;; ) などの限定された用途に留めないと自分でも混乱しますよ。

【補足】
あと処理自体なのですが、時間・距離・速度・加速度の関係が微積分など数学的に理解されていない印象を受けます。

コード:

             t=t+dt;
             xt+=a+vx0*dt;
             
             vy0+=g*dt;
             
             if(yt<0){
                vy0=-A*vy0;
                }
             yt+=vy0*dt;
dtにおける速度を求める式と位置を求める式を数学的に書いてみてください。
vx0とかvy0とか初速がここに出てくる事自体不思議です。

【さらに補足】
あと変数名も数学・物理で使う名前を意識して書くようにお願いします。
gやaは加速度で、v0は初速、tは時間ですよね。
何かルールに外れている名前が多数見受けられます。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

閉鎖

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