[番外編 #1] ばねのような動きを再現

<!--
 <font color="c00000"></font> 赤
-->
## はじめに
皆様お疲れ様です。
この **「番外編」** ではまさに誰得？というような記事を作成して参ります。
今回はプログラム関連で **「ベクター運動」** について紹介いたします。

今回紹介するのは超シンプルな「ベクター運動」になります。
**そういうもんなのかー**という認識で大丈夫です。私もその認識でいきましたから:thinking:
## ばねの動き
ばねと聞いて思い浮かべるのは「ビヨヨ～ン」とした動きかなと思います。

ばねに力を加えた（投げたり、押したり）後に、ばねが行ったり来たりの繰り返しで段々と距離が縮まっていき、元に戻るようなあの動きです。

## ばね運動の基本的なしくみ
以下の図をご覧ください。
今回は**人のモデル**と**ボール**を用いてばね運動の<font color="c00000">**基本な仕組み**</font>を紹介して参ります。
![bangai_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806875/d84ebe08-40ec-20b4-19a3-bcfcc7f263aa.png)
ばねのような動きを再現するためにも図を例にすると「ボールの位置」から「人の位置」を指す **「相対ベクター」** というものを取得する必要があります。

※相対 -> ざっくり言うと **「向かい合っている」** こと。
※ベクター（ベクトル）-> **「力の向き」** を指します。

その相対ベクターからさらに **「加速成分ベクター」** というものを作って「運動ベクター」に「毎フレーム加算」をするとボールが **「バネ運動」** をするようになります。

### 相対ベクターの取得方法
![bangai_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806875/c9743b32-670a-87f8-db54-491c5adcbacd.png)


「相対ベクター」というのは図のように
**『目標の座標 - 始点となる座標』** という計算で取得することができます。

### 縮尺の計算
縮尺計算のイメージになります。
![bangai_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806875/33dda9a8-af8f-b53a-792f-014eeb446c0a.png)

### 振幅する仕組み
図で表すとこんなイメージになります。
![bangai_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806875/116abf37-1055-8003-3737-b5f51a5d5e1a.png)

## 作成したコード
作成したコードの紹介をいたします。
今回はマウスカーソルでボールと線分を移動させてみたいと思います。

作成する環境は何でも良いと思います（Unity、C#やアンリアルエンジンのBP（ブループリント）、JavaScriptなど・・・）。

今回私はC++のDxLibを用いて作成してみたいと思います。
[C++とは？](https://products.sint.co.jp/topsic/blog/c-plus)
[Dxライブラリについて](https://dxlib.xsrv.jp/)
[DXライブラリの使い方](https://dxlib.xsrv.jp/dxuse.html)
```c++ 
// spring.h（ヘッダーファイル）
#include "DxLib.h"
#include "iostream"

// float変数.
float DistanseX;		// 移動距離X.
float DistanseY;		// 移動距離Y.

float SpeedX = 0.0;		// 移動速度X.
float SpeedY = 0.0;		// 移動速度Y

float TargetX = 0.0;	// 移動目標となる座標X.
float TargetY = 0.0;	// 移動目標となる座標Y.

// ここの設定はお好みで
float PosX = 300;		// 実行した時の現在座標X.
float PosY = 300;		// 実行した時の現在座標Y.

float scale = 0.01;		// 相対ベクターを100分の1に縮尺するための変数.
float damp = 0.98;		// 減衰ベクター.

float PickupX;			// 加速成分ベクターX.
float PickupY;			// 加速成分ベクターY.

// int変数.
int mouseX;				// マウス座標X.
int mouseY;				// マウス座標Y.
```
```c++
/********************************************************************
	「概要」
	・マウスカーソルの操作ができるようにプログラムします.
	・線はDxLibのDrowLine()を用います.
	・操作するオブジェクトは画像データで代用します.
********************************************************************/
// ヘッダファイルを読み込む.
#include"Spring.h"

// プログラムは WinMain から始まります.
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
	ChangeWindowMode(true);			// trueにするとウインドウモードで起動.
	if (DxLib_Init() == -1)			// ＤＸライブラリ初期化処理.
	{
		return -1;					// エラーが起きたら直ちに終了.
	}
 
// 実行画面のスクリーンサイズ(画面サイズX, 画面サイズY ,カラービット数 (16 or 32) 
// 基本的には32bitを使ってます.
	SetGraphMode(1080, 720, 32);	

	// 画像データを格納する配列.
	int Handle[1];

     // ボールは拾った画像を用います.
	 Handle[0] = LoadGraph("091a.png");	// LoadGraph():画像データを読み込む関数.
	
    // ループ処理.
	while (1)
	{
		if (ProcessMessage() != 0) 
		{										// メッセージ処理.
            // ウィンドウの×ボタンが押されたらループを抜ける.
			break;								
		}

		if (CheckHitKey(KEY_INPUT_ESCAPE) != 0)	// ESCAPEキーが押されているかを調べる.
			break;								// 押されていたらメインループを抜ける.

		ClearDrawScreen();						// 画面を消す(画像が重複されるため).
		GetMousePoint(&mouseX, &mouseY);		// マウス座標の取得.

		// ①相対ベクターは『目標座標－始点座標』という単純計算で取得できます.
		// ②加速成分ベクターは、相対ベクターを100分の１に縮尺して作ります.
		
		// 相対ベクターの取得(X).
		DistanseX = TargetX - PosX;				// 目標座標 - 始点座標.
		PickupX = scale * DistanseX;			// 縮尺計算.
		SpeedX = damp * (SpeedX + PickupX);		// 速度計算(0.97 * (移動速度 + 加速成分ベクター)).
		PosX += SpeedX;							// 速度分を現在の座標に加算.

		// 相対ベクターの取得(Y).
		DistanseY = TargetY - PosY;
		PickupY = scale * DistanseY;
		SpeedY = damp * (SpeedY + PickupY);
		PosY += SpeedY;

		// 読みこんだグラフィックを縮小描画（描画のサイズ調整をしています）.
		DrawExtendGraph(PosX - 80, PosY - 80, PosX + 80, PosY + 80, Handle[0], TRUE);

		// マウス座標を移動目標の座標に代入.
		TargetX = mouseX;
		TargetY = mouseY;

        // 白線の描画（10は太さの値を指定）.
		DrawLine(mouseX, mouseY, PosX, PosY, GetColor(255,255,255), 10);				
		
		ScreenFlip();	// 裏画面を表画面に反映.
	}
	DxLib_End() ;				// ＤＸライブラリ使用の終了処理.
	return 0 ;					// ソフトの終了. 
}
```
### 動作確認
上記で作成したコードを実行してみます。(gifなので少し粗いです:upside_down:)
![bandicam2024-07-0820-47-28-870-ezgif.com-video-to-gif-converter.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806875/451fba73-400c-56a0-c551-5056aa281cad.gif)

これで一応バネっぽい動きになりました。

:::note warn
あくまで一例のやり方なので参考程度としてください
:::


## おわりに
ベクトルの仕組みは私も完璧ではないところが多々あります。
（この運動の仕組みはそういうものなんだという認識でいたからです:thinking:）

この[番外編]では今後も**ちょっと変わった**記事を作成して参ります。
最後まで読んで頂きありがとうございました！
> **「サイト」**
[バネの動きを実現する方法](https://nn-hokuson.hatenablog.com/entry/2017/05/23/204718)
>
> **「サイト」**
[【JavaScript】オブジェクトにバネ運動させる](https://www.sojudo.net/programming/javascript/spring)