野球ゲームの変化球の軌道について

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

野球ゲームの変化球の軌道について

#1

投稿記事 by SINA » 13年前

野球ゲームでの変化球の軌道についての質問です。
現在、変化球の実装を試みているのですがゲームをするに当たって支障は無いのですが
少しボールの挙動が変なので質問させていただきました。

どのように変なのかと言いますと現在ボールの挙動はあらかじめボールの終着点であるBallXENDとBallYEND
を乱数で決めてそこにボールの座標とのラジアンをatan2でとりsinとcosでを使ってボールの座標であるBallX,BallYを増加させて
いるのですがストレートを投げる分にはそれでいいのですが横に変化するようなボールを投げた時にBallXENDとBallYEND
を通りすぎると急に軌道がストレートに変わってしまいます。(言葉だけではちょっと伝えにくいのでgifをつけました^^;)
恐らくラジアンが0に近づくために起きると思っているのですがどうすればいいかわかりません。どうかよろしくお願いします。
画像
以下野球部分のソースとボール部分のソース

コード:

/*yakyuu*/
#include<DxLib.h>
#include<math.h>
#include<time.h>
#include"grand.h"
#include"keybord.h"
#include"player.h"
#include"ball.h"
#define PAI 3.1415926535897932384//円周率
//プロトタイプ宣言
bool CollisionCC(double r1,double r2,double x1,double x2,double y1,double y2);
// WinMain関数
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
 LPSTR lpCmdLine, int nCmdShow )
{
 // ウインドウモードに変更
 ChangeWindowMode( TRUE );
 // DXライブラリ初期化
 if( DxLib_Init() == -1 )
  {
	 return 0;
  }
 SetDrawScreen( DX_SCREEN_BACK );
 /////////////////ゲーム用///////////////////
 Player_t Player;//バッター
 Ball_t Ball;//ボール

 double radmeat;//ミートの中心とボールの角度
 double direction;//曲がる時進むべき角度
 bool change=false;//変化球フラグ
 bool hit=false;//ヒットフラッグ
 bool SWING=false;//スイングフラッグ
 bool PITCH=true;//投球フラッグ
 bool NOWPITCH=false;//投球中フラッグ
 
 int batter[3];//バッターの画像
 int count=0;//アニメーション管理用
 int Cr ;
	 Cr= GetColor( 255 , 255, 255 ) ;	// 白色の値を取得
 LoadDivGraph( "bat.bmp" , 3, 1 , 3, 310 , 270, batter ); // 画像の分割読み込み
 Player_Initialize(&Player);//プレイヤー初期化
 int i;

 while(ProcessMessage()==0)
 {
	 
	 if(SWING==true)
	 {
		count++;
	 }
	 ClearDrawScreen(); // 画面を消す
	 Keyboard_Update();//キーの初期化

	 grand();//グランド描写
	 Player_meat(&Player);//ミートカーソル
	 DrawBox(270,330,370,430,GetColor(255,100,0),FALSE);//ストライクゾーン描画

	 if(CheckHitKey( KEY_INPUT_C) ==1&& PITCH==true)//ピッチング用
	 {
		 Ball_Initialize( &Ball);//ボール初期化
		 PITCH=false;
		 NOWPITCH=true;
	 }
	 if( CheckHitKey( KEY_INPUT_Z) == 1 && SWING==false)//Zが入力されている
	 {
		 SWING=true;
	 }

	 ////////////////////カーソル移動/////////////////////////////////////////
	 if(SWING==false)
	 {
		 Player_Update(&Player);
	 }
	 
	 /////////////////////////////////////////////////////////////////////////////

	 if(SWING==true&&count<=5)//スイングの構えと途中の切り替え
	 {
		Player_Draw1(&Player);
		///////////////ミートの判定//////////////////////////////
		if(7.5>=Ball.BallZ&&Ball.BallZ>=6&&CollisionCC(6,Player.meat,Ball.BallXEND,Player.X+320,Ball.BallYEND,Player.Y+380)==true)
		{
			hit=true;
		}
	 }
	 
	 else if(SWING==true && NOWPITCH==true||5<count&&count<=50)//スイングして0.5秒後に振り終わりに
	 {
		Player_Draw2(&Player);
	 }
	 else if(SWING==true&&PITCH==true)//振り終わって訳1秒後にフラッグをfalse
	 {
		 SWING=false;
		 count=0;
	 }
	 else
	 {
		hit=false;
		Player_Draw0(&Player);
	 }
	 if(NOWPITCH==true)
	 {
		Ball_Draw( &Ball );
	 }
	 if(Ball.BallZ<=8)
	 {
		Ball.BallZ=Ball.BallY/60;
	 }
	 if(Ball.BallY>=540||Ball.BallY<0)//ボールが画面外に行けば次に行く
	 {
		NOWPITCH=false;
		PITCH=true;
	 }
	
	 //変化球テスト
	 if(200<Ball.BallY&&Ball.BallY<Ball.BallYEND&&hit==false)
	 {
		 Ball.BallXEND+=2;
	 }
	 /////////////////////////////////////////

	 if(NOWPITCH==true)
	 {
		if(hit==false)
		{
			Ball_Update(&Ball );
		}
		else//ボールがミートされた時
		{
			radmeat=atan2(Ball.BallYEND-Player.Y,Ball.BallXEND-Player.X);
			Ball.BallY+=sin(radmeat*180/PAI)*Ball.BallSpeed;//ボールの縦ベクトル
			Ball.BallX+=cos(radmeat*180/PAI)*Ball.BallSpeed;//ボールの横ベクトル
		}

	 }
	 ///////////////////デバッグ用////////////////////////////////////////////
	 DrawFormatString( 30, 30, Cr, "BallZ=%d", (int)Ball.BallZ ) ;//デバッグ用
	 DrawFormatString( 30, 50, Cr, "BallX=%d", (int)Ball.BallX ) ;//デバッグ用
	 DrawFormatString( 30, 70, Cr, "BallY=%d", (int)Ball.BallY ) ;//デバッグ用
	 DrawFormatString( 30, 130, Cr, "rad=%f",Ball.rad*180/PAI) ;//デバッグ用
	 DrawFormatString( 30, 90, Cr, "BallTXEND=%d", (int)Ball.BallTXEND ) ;//デバッグ用
	 DrawFormatString( 30, 110, Cr, "BallTYEND=%d", (int)Ball.BallTYEND ) ;//デバッグ用

	 ScreenFlip(); //裏画面を表画面に反映
 }
 DxLib_End() ;			// DXライブラリ使用の終了処理
 return 0;
}
ボール

コード:

/*ball*/
#include "DxLib.h"
#include "Keybord.h"
#include "Ball.h"
#include<time.h>
#include<math.h>
//////////////////////////////////////////////////
// srand関数で、乱数パターンを初期化する
unsigned int    now = (unsigned int)time( 0 );
////////////////////////////////////////////////

// 初期化をする
void Ball_Initialize( Ball_t *Ball)
{
		Ball->BallX=320;
		Ball->BallY=120;
		Ball->BallZ=1;
		Ball->BallXEND=270+(int)( rand() * (370 - 270 + 1.0) / (1.0 + RAND_MAX) );
		Ball->BallYEND=330+(int)( rand() * (430 - 330 + 1.0) / (1.0 + RAND_MAX) );
		Ball->BallSpeed=5;
		Ball->BallA=((Ball->BallYEND-120)/(Ball->BallXEND-320));
		Ball->BallTYEND=120+1.5*(Ball->BallYEND-120);
		Ball->BallTXEND=320+1.5*(Ball->BallXEND-320);
		//////////////////ボールの影定義//////////////
		if(400<=Ball->BallYEND)
		{
			Ball->Ballkage=50;//高さ90,70,50,
		}
		else if(Ball->BallYEND<=360)
		{
			Ball->Ballkage=90;//高さ90,70,50,
		}
		else
		{
			Ball->Ballkage=70;
		}
		///////////////////////////////////////////////
}

// 動きを計算する
void Ball_Update( Ball_t *Ball )
{
		Ball->rad=atan2((double)Ball->BallYEND-(double)Ball->BallY,(double)Ball->BallXEND-(double)Ball->BallX);
		Ball->BallTYEND=120+1.5*(Ball->BallYEND-120);
		Ball->BallTXEND=320+1.5*(Ball->BallXEND-320);
		if(sin(Ball->rad)>0)
		{
			Ball->BallX+=cos(Ball->rad)*Ball->BallSpeed;
			Ball->BallY+=sin(Ball->rad)*Ball->BallSpeed;
		}
		else
		{
			Ball->BallX+=cos(Ball->rad)*Ball->BallSpeed;
			Ball->BallY+=sin(-Ball->rad)*Ball->BallSpeed;
		}

}

// 描画する
void Ball_Draw( Ball_t *Ball )
{
    DrawCircle( Ball->BallX , Ball->BallY , Ball->BallZ ,GetColor(255,255,255), TRUE) ;// ボールを描画
	DrawCircle( Ball->BallX , Ball->BallY +Ball->Ballkage, Ball->BallZ-2, GetColor(0,0,0) , TRUE) ;//ボールの影
	DrawCircle( Ball->BallXEND ,Ball->BallYEND, 6, GetColor(255,0,0) , FALSE);//ストライクゾーンのボール
}



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

Re: 野球ゲームの変化球の軌道について

#2

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

単体で動くコードを添貼ってもらうと答えも付くかと思います。
余分なコードが多くて、完全に分かってないですがボールの変化球の動きを円運動で近似していると言うことでしょうか?
※ 現実の動きはマグナス効果と言うとても複雑な動きをするみたいですが。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

SINA

Re: 野球ゲームの変化球の軌道について

#3

投稿記事 by SINA » 13年前

余分なコードが多くてすいません未熟なもので。単体で動くと言うとこんな感じでしょうか
それとも分けずに1つのファイルで変数を宣言した方が良いのでしょうか?

コード:

#include<DxLib.h>
#include<math.h>
#include<time.h>
#include"ball.h"
#include"grand.h"
#include"keybord.h"

// WinMain関数
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
 LPSTR lpCmdLine, int nCmdShow )
{
 // ウインドウモードに変更
 ChangeWindowMode( TRUE );
 // DXライブラリ初期化
 if( DxLib_Init() == -1 )
  {
	 return 0;
  }
 SetDrawScreen( DX_SCREEN_BACK );
 Ball_t Ball;//ボール
 Ball_Initialize( &Ball);//ボール初期化
 bool NOWPITCH=false;

 while(ProcessMessage()==0)
 {
	 ClearDrawScreen(); // 画面を消す
	 Keyboard_Update();//キーの初期化
	 grand();//グランド描写
	 DrawBox(270,330,370,430,GetColor(255,100,0),FALSE);//ストライクゾーン描画

	 if(CheckHitKey( KEY_INPUT_C) ==1&&NOWPITCH==false)//ピッチング用Cを押すと投げる
	 {
		 Ball_Initialize( &Ball);//ボール初期化
		 NOWPITCH=true;
	 }
	 if(NOWPITCH==true)
	 {
		Ball_Draw( &Ball );
	 }
	 if(Ball.BallZ<=8)//ボールの大きさ
	 {
		Ball.BallZ=Ball.BallY/60;
	 }
	 if(Ball.BallY>=540||Ball.BallY<0)//ボールが画面外に行けば次に行く
	 {
		NOWPITCH=false;
	 }
	 //変化球テスト
	 if(200<Ball.BallY&&Ball.BallY<Ball.BallYEND)
	 {
		 Ball.BallXEND+=2;
	 }
	 if(NOWPITCH==true)
	 {
		Ball_Update(&Ball );
	 }
	 ScreenFlip(); //裏画面を表画面に反映
 }
 DxLib_End() ;			// DXライブラリ使用の終了処理
 return 0;
}
常にボールの終点との角度を求めて円運動でうごかしている感じです。
なので変化球の時は無理やり終点を変えているのですが根本的に考え方が違うのでしょうか?

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

Re: 野球ゲームの変化球の軌道について

#4

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

ヘッダを抜いて&動くものをお願いします。
これだと動かないですよね?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

SINA

Re: 野球ゲームの変化球の軌道について

#5

投稿記事 by SINA » 13年前

ヘッダを抜いたものを作成しました。グランド描画はあった方がボールの動きがわかりやすいと思いつけさせていただきましたが
邪魔でしたらすいません。

コード:

#include<DxLib.h>
#include<math.h>
#include<time.h>
// WinMain関数
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
 LPSTR lpCmdLine, int nCmdShow )
{
	double BallY;//ボール高さ120
	double BallX;//ボール横320
	double BallXEND;//ボール終点x
	double BallYEND;//ボール終点y
	double rad;//角度
    double BallZ;//ボール奥行き
	double Ballkage=70;//ボールの影
	double BallSpeed;//速さ
 // ウインドウモードに変更
 ChangeWindowMode( TRUE );
 // DXライブラリ初期化
 if( DxLib_Init() == -1 )
  {
	 return 0;
  }
 ///背景のグランド描写用///////////////////////////////////////////////////
 int Cr ;
 int Cr2;
 int Cr3;
 int Cr4;
 ///////////////////////ここまで////////////////////////////////////////


 //ボール初期化
 SetDrawScreen( DX_SCREEN_BACK );
 BallX=320;
 BallY=120;
 BallZ=1;
 BallXEND=270+(int)( rand() * (370 - 270 + 1.0) / (1.0 + RAND_MAX) );
 BallYEND=330+(int)( rand() * (430 - 330 + 1.0) / (1.0 + RAND_MAX) );
 BallSpeed=5;
 bool NOWPITCH=false;

 while(ProcessMessage()==0)
 {
	  ClearDrawScreen(); // 画面を消す

	  ///////////////////////グランド描画/////////////////////////////////
	  Cr= GetColor( 255 , 255, 255 ) ;	// 白色の値を取得
	  Cr2= GetColor(0,120,0);//緑
	  Cr3= GetColor(186,125,50);//茶色
	  Cr4= GetColor(136,75,20);//こい茶色

	  DrawBox( 0 , 0 , 640 , 480 , Cr2 , TRUE) ;//緑で塗りつぶす
	  DrawOval(320,540,1000,500,Cr3,TRUE);//グランド
	  DrawOval(320,220,70,20,Cr4,TRUE);//まうんど

	  DrawBox(290,440,350,455,Cr,TRUE);//ホームベース
	  DrawTriangle( 290, 455, 350, 455, 320, 470, Cr, TRUE);//ホームベース2

	  DrawLine(270,410,260,480,Cr,5);//バッターボックス
	  DrawLine(270,410,130,410,Cr,5);//バッターボックス2
	  DrawLine(130,410,110,480,Cr,5);//バッターボックス3

	  DrawLine(370,410,380,480,Cr,5);//バッターボックス1
	  DrawLine(370,410,510,410,Cr,5);//バッターボックス2
	  DrawLine(510,410,530,480,Cr,5);//バッターボックス3

	  DrawLine(200,410,0,310,Cr,5);//ライン左
	  DrawLine(440,410,640,310,Cr,5);//ライン右
	  DrawBox(270,330,370,430,GetColor(255,100,0),FALSE);//ストライクゾーン描画
	  /////////////////////////////////ここまで//////////////////////////////////////////////////

	 if(CheckHitKey( KEY_INPUT_C) ==1&&NOWPITCH==false)//ピッチング用Cを押すと投げる
	 {
		 //ボール初期化
		 SetDrawScreen( DX_SCREEN_BACK );
		 BallX=320;
		 BallY=120;
		 BallZ=1;
		 BallXEND=270+(int)( rand() * (370 - 270 + 1.0) / (1.0 + RAND_MAX) );
		 BallYEND=330+(int)( rand() * (430 - 330 + 1.0) / (1.0 + RAND_MAX) );
		 BallSpeed=5;
		 NOWPITCH=true;
	 }
	 if(NOWPITCH==true)
	 {
		 DrawCircle( BallX , BallY , BallZ ,GetColor(255,255,255), TRUE) ;// ボールを描画
		 DrawCircle( BallX , BallY +Ballkage, BallZ-2, GetColor(0,0,0) , TRUE) ;//ボールの影
		 DrawCircle( BallXEND ,BallYEND, 6, GetColor(255,0,0) , FALSE);//ストライクゾーンのボール
		 rad=atan2((double)BallYEND-(double)BallY,(double)BallXEND-(double)BallX);
	 }
	 if(BallZ<=8)//ボールの大きさ
	 {
		BallZ=BallY/60;
	 }
	 if(BallY>=540||BallY<0)//ボールが画面外に行けば次に行く
	 {
		NOWPITCH=false;
	 }
	 //変化球テスト
	 if(200<BallY&&BallY<BallYEND)
	 {
		 BallXEND+=2;
	 }
	 if(NOWPITCH==true)
	 {
		if(sin(rad)>0)
		{
			BallX+=cos(rad)*BallSpeed;
			BallY+=sin(rad)*BallSpeed;
		}
		else
		{
			BallX+=cos(rad)*BallSpeed;
			BallY+=sin(-rad)*BallSpeed;
		}
	 }
	 ScreenFlip(); //裏画面を表画面に反映
 }
 DxLib_End() ;			// DXライブラリ使用の終了処理
 return 0;
}

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

Re: 野球ゲームの変化球の軌道について

#6

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

実に適当な方法ですが、最後のほうで良い感じの移動ベクトルを残してそれを引き続き使う方法にしてみました。
あとインデントが気になったので直してあります。これをベースに調整してみてください。

コード:

#include<DxLib.h>
#include<math.h>
#include<time.h>
// WinMain関数
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    LPSTR lpCmdLine, int nCmdShow ) {
	double BallY;//ボール高さ120
	double BallX;//ボール横320
	double BallXEND;//ボール終点x
	double BallYEND;//ボール終点y
	double rad;//角度
	double BallZ;//ボール奥行き
	double Ballkage = 70; //ボールの影
	double BallSpeed;//速さ
	double vecX,vecY;
	// ウインドウモードに変更
	ChangeWindowMode( TRUE );
	// DXライブラリ初期化
	if( DxLib_Init() == -1 ) {
		return 0;
	}
	///背景のグランド描写用///////////////////////////////////////////////////
	int Cr ;
	int Cr2;
	int Cr3;
	int Cr4;
	///////////////////////ここまで////////////////////////////////////////


	//ボール初期化
	SetDrawScreen( DX_SCREEN_BACK );
	BallX = 320;
	BallY = 120;
	BallZ = 1;
	BallXEND = 270 + ( int )( rand() * ( 370 - 270 + 1.0 ) / ( 1.0 + RAND_MAX ) );
	BallYEND = 330 + ( int )( rand() * ( 430 - 330 + 1.0 ) / ( 1.0 + RAND_MAX ) );
	BallSpeed = 5;
	bool NOWPITCH = false;

	while( ProcessMessage() == 0 ) {
		ClearDrawScreen(); // 画面を消す

		///////////////////////グランド描画/////////////////////////////////
		Cr = GetColor( 255 , 255, 255 ) ; // 白色の値を取得
		Cr2 = GetColor( 0, 120, 0 ); //緑
		Cr3 = GetColor( 186, 125, 50 ); //茶色
		Cr4 = GetColor( 136, 75, 20 ); //こい茶色

		DrawBox( 0 , 0 , 640 , 480 , Cr2 , TRUE ) ; //緑で塗りつぶす
		DrawOval( 320, 540, 1000, 500, Cr3, TRUE ); //グランド
		DrawOval( 320, 220, 70, 20, Cr4, TRUE ); //まうんど

		DrawBox( 290, 440, 350, 455, Cr, TRUE ); //ホームベース
		DrawTriangle( 290, 455, 350, 455, 320, 470, Cr, TRUE ); //ホームベース2

		DrawLine( 270, 410, 260, 480, Cr, 5 ); //バッターボックス
		DrawLine( 270, 410, 130, 410, Cr, 5 ); //バッターボックス2
		DrawLine( 130, 410, 110, 480, Cr, 5 ); //バッターボックス3

		DrawLine( 370, 410, 380, 480, Cr, 5 ); //バッターボックス1
		DrawLine( 370, 410, 510, 410, Cr, 5 ); //バッターボックス2
		DrawLine( 510, 410, 530, 480, Cr, 5 ); //バッターボックス3

		DrawLine( 200, 410, 0, 310, Cr, 5 ); //ライン左
		DrawLine( 440, 410, 640, 310, Cr, 5 ); //ライン右
		DrawBox( 270, 330, 370, 430, GetColor( 255, 100, 0 ), FALSE ); //ストライクゾーン描画
		/////////////////////////////////ここまで//////////////////////////////////////////////////

		if( CheckHitKey( KEY_INPUT_C ) == 1 && NOWPITCH == false ) { //ピッチング用Cを押すと投げる
			//ボール初期化
			SetDrawScreen( DX_SCREEN_BACK );
			BallX = 320;
			BallY = 120;
			BallZ = 1;
			BallXEND = 270 + ( int )( rand() * ( 370 - 270 + 1.0 ) / ( 1.0 + RAND_MAX ) );
			BallYEND = 330 + ( int )( rand() * ( 430 - 330 + 1.0 ) / ( 1.0 + RAND_MAX ) );
			BallSpeed = 5;
			NOWPITCH = true;
		}
		if( NOWPITCH == true ) {
			DrawCircle( BallX , BallY , BallZ , GetColor( 255, 255, 255 ), TRUE ) ; // ボールを描画
			DrawCircle( BallX , BallY + Ballkage, BallZ - 2, GetColor( 0, 0, 0 ) , TRUE ) ; //ボールの影
			DrawCircle( BallXEND , BallYEND, 6, GetColor( 255, 0, 0 ) , FALSE ); //ストライクゾーンのボール
			rad = atan2( ( double )BallYEND - ( double )BallY, ( double )BallXEND - ( double )BallX );
		}
		if( BallZ <= 8 ) { //ボールの大きさ
			BallZ = BallY / 60;
		}
		if( BallY >= 540 || BallY < 0 ) { //ボールが画面外に行けば次に行く
			NOWPITCH = false;
		}
		//変化球テスト
		if( 200 < BallY && BallY < BallYEND ) {
			BallXEND += 2;
		}
		if( NOWPITCH == true ) {
			if( sin( rad ) > 0 ) {
				double vX = cos( rad ) * BallSpeed;
				double vY = sin( rad ) * BallSpeed;
				BallX += vX;
				BallY += vY;
				if( vY > 2.0 ) {
					vecX = vX;
					vecY = vY;
				}
			} else {
				BallX += vecX;
				BallY += vecY;
			}
		}
		ScreenFlip(); //裏画面を表画面に反映
	}
	DxLib_End() ;          // DXライブラリ使用の終了処理
	return 0;
}
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

SINA

Re: 野球ゲームの変化球の軌道について

#7

投稿記事 by SINA » 13年前

ソースを使わせていただきましたところ良い感じにフェードアウトしてくれました!
本当に何から何まで有難うございます!インデントはまたずれていましたかすいません。
他の方に見せるソースということでいつもより気をつけていたのですが申し訳ないです。

閉鎖

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