マルチタッチ・ジェスチャー「ピンチ」「回転」

更新:2022年8月21日   HSPトップへもどる


『 ピンチ 』スマホサイズ ◆ブラウザ上で動作するページ


『 ピンチ 』タブレットサイズ ◆ブラウザ上で動作するページ


『 ピンチ 』(※作成途中 ) ◆ブラウザ上で動作するページ


『 ピンチ 』(hspmath.as使用 ) ◆ブラウザ上で動作するページ


『 ローテート(回転) 』 ◆ブラウザ上で動作するページ
 

★このスクリプトは WebDish素材のみ使用し、独自画像を使用していませんので、WebDishサービスにそのまま登録できます

!注意!
このスクリプトは「マルチタッチ・ジェスチャー」の「ピンチ(ふたつの指でタッチしてつまむ、ひろげる)、「ローテート(回転)」のサンプルです。
実行して試すには、スマホ、タブレット、タッチ対応端末が必要です。

サンプルスクリプト ①

#include "hsp3dish.as"
	// スマホ画面サイズ用
	title "Pinch"					// 「ピンチ」というタッチ操作のサンプル
	screen 0,320,480				// 画面サイズを指定
	//screen 0,640,800				// 画面サイズを指定
	buffer 1,128,128				// 画像読み込み用バッファ
	celload "king_knight.png",1		// セル画像をID 1 へ読み込む
	celdiv	1,128,128,64,64			// セル1個の大きさを指定
									// ★重要 回転する場合この「回転基点設定」が重要(64,64で128,128の中心点
	gsel 0							// 描画先を0にもどしておく
	gmode 2							// 透明色あり
	
	// 変数定義
	joutai = ""				//状態メッセージ(開発用
	ks = 0.0				//拡大縮小の値 (上限チェック必要
	add = 0.04				//増減値(大きくすれば変化大きくなる
	//kt = 0.0				//回転の値
							// ★わかりやすくするため、このスクリプトでは回転処理をいれていません!
*main
	// メインループ ====================================================
	redraw 0				// 仮想画面を書き換えるだけで画面にまだ出さずにおく
	mtlist touchid			// 現在タッチされている情報を持つポイントIDリストを取得
	num = stat				// mtlist実行直後の stat には「ポイントIDの数」が入っています

	// タッチ状態を判定
	if  num = 0 : joutai = ""		//ポイントIDが0個ならタッチされていない状態
	// ポイントIDが1個または2個ならシングルタッチ(マルチタッチでない)
	if  num = 1 || num = 2 { joutai = "シングルタッチです" }
	if  num > 2 { joutai = "マルチタッチです!"				//★要注意★ 2本指タッチは値が「3」になる!

		id = touchid(0)			//ポイントID 1つめ (特殊事情で使用していません。マウス用?)
		mtinfo touch0,id

		id = touchid(1)			//ポイントID 2つめ(指一本目)
		mtinfo touch1,id

		id = touchid(2)			//ポイントID 3つめ(指二本目)
		mtinfo touch2,id
	
			// ふたつの指のx座標		★要注意★ touchid(1)とtouchid(2)のなかみをとってます!
			tmp_a_x = touch1(1)		// 1番目の指のx座標
			tmp_b_x = touch2(1)		// 2番目の指のx座標

			tmp_a_y = touch1(2)		// 1番目の指のy座標
			tmp_b_y = touch2(2)		// 2番目の指のy座標

			// 指と指の距離、大きいほうから小さいほうを引いて距離を算出		
			if tmp_a_x > tmp_b_x { kyori_x = tmp_a_x-tmp_b_x }	// 指2点の横幅の動きで算出
			if tmp_b_x > tmp_a_x { kyori_x = tmp_b_x-tmp_a_x }

			if tmp_a_y > tmp_b_y { kyori_y = tmp_a_y-tmp_b_y }	// 指2点の縦幅の動きで算出
			if tmp_b_y > tmp_a_y { kyori_y = tmp_b_y-tmp_a_y }

			// 距離の変化がより大きかったほうに従って拡大縮小を実行する(指と指が大きく動いたのは横方向か縦方向か)
			if kyori_x >= kyori_y {
				
				if kyori_x > bak_kyori_x { ks = ks + add }	//さっきよりも指の距離が広がっていれば拡大
				if kyori_x < bak_kyori_x { ks = ks - add }	//さっきほりも指の距離が狭まっていれば縮小

			}else{

				if kyori_y > bak_kyori_y { ks = ks + add }	//さっきよりも指の距離が広がっていれば拡大
				if kyori_y < bak_kyori_y { ks = ks - add }	//さっきほりも指の距離が狭まっていれば縮小
			}

			bak_kyori_x = kyori_x	//現在の距離を次回と比較できるように保持しておく
			bak_kyori_y = kyori_y	
	}
	//------------------------------------------------------
	// 《 描画 》
	color 0,0,128 : boxf		//画面エリアを一旦ぬりつぶしてクリア

	//画像を拡縮表示
	pos 100,200
	celput 1,0,1.0+ks,1.0+ks,kt							//回転は 6.28で1回転(3.14で半回転)
														// 元画像の左上起点で回転。
														// 時計回り(右回り)。マイナス値で逆回転
	//マウス位置表示(開発用)
	color 255,255,255
	pos 0,4 : mes "  "+mousex+","+mousey+" num="+num+" "+joutai //状態をメッセージ表示
	pos 0,40 : mes " 画面に指2本でタッチしたまま、"	//操作説明
	pos 0,70 : mes " つまんだり、ひろげたりします(ピンチ・ジェスチャ)"	//操作説明
	//------------------------開発用情報表示
	if  num > 2 {
		pos 0,400 : mes touch0(0)	// タッチ状態(1=ON/0=OFF)
		pos 0,430 : mes touch0(1)	// X座標
		pos 0,460 : mes touch0(2)	// Y座標
		pos 0,490 : mes touch0(3)	// タッチ識別用ID
		pos 0,500 : mes "------------------"
		pos 0,520 : mes touch1(0)
		pos 0,550 : mes touch1(1)
		pos 0,580 : mes touch1(2)
		pos 0,610 : mes touch1(3)
		pos 0,620 : mes "------------------"
		pos 0,640 : mes touch2(0)
		pos 0,670 : mes touch2(1)
		pos 0,700 : mes touch2(2)
		pos 0,730 : mes touch2(3)
	}
	//------------------------
	redraw 1				//実際の画面へ表示する
	await 20				//待ち時間 await と wait がある 
goto *main
stop
//================================================================
//【メモ】
// このスクリプトでは拡大縮小の大きさを「足し算」で処理していますが、
// 掛け算を使ったほうが良い場合もあります。
// 例:元画像のサイズが小さい時に「足し算」だと影響が大きく極端になる場合がある

より良い「ピンチ操作の判定方法」を思いついたら、ぜひ自分なりに改良してみてください。

・改良案: ピンチした距離に応じて加算減算の値(度合い)を変化させるとより良くなります。

・ここではなるべく簡単な誰にでもわかりやすいスクリプトを心がけています。
(基本的な手持ちの知識のなかだけでも、発想や、やり方によってはできる方法がある例を見せたいと思いました。)

・わかりやすいようにわざわざ一度別の変数を用意して代入しているモノもあります。
 開発者が混乱しなければ、配列(0)の形で値を計算や処理に直接使っても大丈夫です。

このサンプル以外にも、「2点間の距離」を算出する「三平方の定理(ピタゴラスの定理)」というやり方でスクリプトを書くこともできます。


・③の「作成途中」になっているスクリプトは
 ・画像の部分をタッチしたときだけ移動できる
 ・タッチした時にすこしだけ左上座標にずらして(浮き上がらせ)、さらに、影画像(マスク・半透明)も描画する
などの処理を追加すると、より良い表現になります


8/20 追記:
 hspmath.as の distance2関数を使用して 二点間の距離を簡単に算出するサンプルを追加しました。

サンプルスクリプト ④


#include "hsp3dish.as"
#include "hspmath.as"
							//↑★重要です
	// スマホ画面サイズ用
	title "Pinch distance2"			// 「ピンチ」というタッチ操作のサンプル
	//screen 0,320,480				// 画面サイズを指定
	screen 0,640,800				// 画面サイズを指定
	buffer 1,128,128				// 画像読み込み用バッファ
	celload "king_knight.png",1		// セル画像をID 1 へ読み込む
	celdiv	1,128,128,64,64			// セル1個の大きさを指定
									// ★重要 回転する場合この「回転基点設定」が重要(64,64で128,128の中心点

	gsel 0							// 描画先を0にもどしておく
	gmode 2							// 透明色あり
	
	// 変数定義
	gx = 100				//画像のx位置
	gy = 200				//画像のx位置
	
	joutai = ""				//状態メッセージ(開発用
	ks = 0.0				//拡大縮小の値 (上限チェック必要
	add = 0.04				//増減値(大きくすれば変化大きくなる
	kt = 0.0				//回転の値
							// ★わかりやすくするため、このスクリプトでは回転処理をいれていません!
*main
	// メインループ ====================================================
	redraw 0				// 仮想画面を書き換えるだけで画面にまだ出さずにおく
	mtlist touchid			// 現在タッチされている情報を持つポイントIDリストを取得
	num = stat				// mtlist実行直後の stat には「ポイントIDの数」が入っています

	// タッチ状態を判定
	//-------------------------------------------
	if  num = 0 : joutai = ""		//ポイントIDが0個ならタッチされていない状態
	//-------------------------------------------
	// ポイントIDが1個または2個ならシングルタッチ(マルチタッチでない)
	if  num = 1 || num = 2 {			//※開発中はマウスの操作は1になるので注意!。指一本目は2

		joutai = "シングルタッチです"

		id = touchid(0)			//ポイントID 1つめ(マウス?)

		if num = 2 {
			id = touchid(1)			//ポイントID 2つめ(指一本目)
		}
		
		mtinfo touch1,id

		gx = touch1(1)		// 1番目の指のx座標
		gy = touch1(2)		// 1番目の指のy座標
	}
	//-------------------------------------------//★要注意★ 2本指タッチは値が「3」になる!
	// 2本以上の指でタッチ
	if  num > 2 { joutai = "マルチタッチです!"				

		id = touchid(0)			//ポイントID 1つめ (特殊事情で使用していません。マウス用?)
		mtinfo touch0,id

		id = touchid(1)			//ポイントID 2つめ(指一本目)
		mtinfo touch1,id

		id = touchid(2)			//ポイントID 3つめ(指二本目)
		mtinfo touch2,id

			// ふたつの指のxとy座標		★要注意★ touchid(1)とtouchid(2)のなかみをとってます!
			tmp_a_x = touch1(1)	: tmp_a_y = touch1(2)	// 1番目の指のx y座標
			tmp_b_x = touch2(1)	: tmp_b_y = touch2(2)	// 2番目の指のx y座標

			// ピンチ の判定  "hspmath.as" に含まれる distance2(point_a, point_b)関数を使う方法---

			point_a = bak_a_x, bak_a_y	// 前回の点A point_aが配列になりpoint_a(0)とpoint_a(1)ができる
			point_b = bak_b_x, bak_b_y	// 前回の点B

			bak_kyori = distance2(point_a, point_b) //★重要 二点間の距離を簡単に算出

			point_a = tmp_a_x, tmp_a_y      // 現在の点A
			point_b = tmp_b_x, tmp_b_y      // 現在の点B

			kyori = distance2(point_a, point_b) //★重要 二点間の距離を簡単に算出

			title " kyori = " + kyori		//確認用

			//さっきよりも指の距離が広がっていれば拡大
			if kyori > bak_kyori {			//現在の二点間が前回の二点間より大きければ「広がった」

				zougenkyori = kyori-bak_kyori	//増減した距離
				zouritu = zougenkyori/10		// 増減した距離にあわせて変化率も大きくなる
				ks = ks + add * (1+zouritu)		// ★この3行やめて、ks = ks + add だけでもよい
			}	

			//さっきよりも指の距離が狭まっていれば縮小
			if kyori < bak_kyori {			//現在の二点間が前回の二点間より小さければ「狭まった」

				zougenkyori = bak_kyori-kyori	//増減した距離
				zouritu = zougenkyori/10		// 増減した距離にあわせて変化率も大きくなる
				ks = ks - add * (1+zouritu)		// ★この3行やめて、ks = ks - add だけでもよい
			}	

			//現在の指の位置を保持しておく
			bak_a_x = tmp_a_x : bak_a_y = tmp_a_y
			bak_b_x = tmp_b_x : bak_b_y = tmp_b_y			
	}
	//------------------------------------------------------
	// 《 描画 》
	color 0,0,128 : boxf		//画面エリアを一旦ぬりつぶしてクリア

	//画像を拡縮表示
	pos gx,gy
	celput 1,0,1.0+ks,1.0+ks,kt							//回転は 6.28で1回転(3.14で半回転)
														// 元画像の左上起点で回転。celdivで基点変更可能→中心へ
														// 時計回り(右回り)。マイナス値で逆回転
	//マウス位置表示(開発用)
	color 255,255,255
	pos 0,4 : mes "  "+mousex+","+mousey+" num="+num+" "+joutai //状態をメッセージ表示
	pos 0,40 : mes " 画面に指2本でタッチしたまま、"	//操作説明
	pos 0,70 : mes " つまんだり、ひろげたりします(ピンチ・ジェスチャ)"	//操作説明
	//------------------------開発用情報表示
	if  num > 2 {
		pos 0,400 : mes touch0(0)	// タッチ状態(1=ON/0=OFF)
		pos 0,430 : mes touch0(1)	// X座標
		pos 0,460 : mes touch0(2)	// Y座標
		pos 0,490 : mes touch0(3)	// タッチ識別用ID
		pos 0,500 : mes "------------------"
		pos 0,520 : mes touch1(0)
		pos 0,550 : mes touch1(1)
		pos 0,580 : mes touch1(2)
		pos 0,610 : mes touch1(3)
		pos 0,620 : mes "------------------"
		pos 0,640 : mes touch2(0)
		pos 0,670 : mes touch2(1)
		pos 0,700 : mes touch2(2)
		pos 0,730 : mes touch2(3)
	}
	//------------------------
	redraw 1				//実際の画面へ表示する
	await 20				//待ち時間 await と wait がある 
goto *main
stop
//================================================================
//【メモ】
// このスクリプトでは拡大縮小の大きさを「掛け算」で処理していて、論理としては合ってますが、
// 足し算を使ったほうが仕様として、良い場合もあります。
// 例:足し算のほうが変化がゆるやかで、ユーザーにとっては操作しやすい場合がある

8/21 追記:
 ローテート(回転)のサンプルを追加しました。

サンプルスクリプト ⑤

// 160
#include "hsp3dish.as"
#include "hspmath.as"

	// スマホ画面サイズ用
	title "Pinch"					// 「ピンチ」というタッチ操作のサンプル
	//screen 0,320,480				// 画面サイズを指定
	screen 0,640,800				// 画面サイズを指定
	buffer 1,128,128				// 画像読み込み用バッファ
	celload "king_knight.png",1		// セル画像をID 1 へ読み込む
	celdiv	1,128,128,64,64			// セル1個の大きさを指定
									// ★重要 回転する場合この「回転基点設定」が重要(64,64で128,128の中心点
	//buffer 2,128,128					// 画像読み込み用バッファ (★途中、未使用)
	//celload "king_knight_kage.png",2	// セル画像をID 1 へ読み込む
	//celdiv	2,128,128,64,64				// セル1個の大きさを指定
	gsel 0							// 描画先を0にもどしておく
	gmode 2							// 透明色あり
	
	// 変数定義
	gx = 100				// 画像のx位置
	gy = 200				// 画像のx位置
	joutai = ""				// 状態メッセージ(開発用
	ks = 0.0				// 拡大縮小の値 (上限チェック必要
	add = 0.04				// 増減値(大きくすれば変化大きくなる
	kt = 0.0				// 回転の値
    pi = 3.14159265         // 円周率πパイ
							
*main
	// メインループ ====================================================
	redraw 0				// 仮想画面を書き換えるだけで画面にまだ出さずにおく
	mtlist touchid			// 現在タッチされている情報を持つポイントIDリストを取得
	num = stat				// mtlist実行直後の stat には「ポイントIDの数」が入っています
	
	// タッチ状態を判定
	//-------------------------------------------
	if  num = 0 : joutai = ""		//ポイントIDが0個ならタッチされていない状態
	//-------------------------------------------
	// ポイントIDが1個または2個ならシングルタッチ(マルチタッチでない)
	if  num = 1 || num = 2 {			//※開発中はマウスの操作は1になるので注意!。指一本目は2

		joutai = "シングルタッチです"

		id = touchid(0)			//ポイントID 1つめ(マウス?)

		if num = 2 {
			id = touchid(1)			//ポイントID 2つめ(指一本目)
		}
		
		mtinfo touch1,id

		gx = touch1(1)		// 1番目の指のx座標
		gy = touch1(2)		// 1番目の指のy座標
	}
	//-------------------------------------------//★要注意★ 2本指タッチは値が「3」になる!
	// 2本以上の指でタッチ
	if  num > 2 { joutai = "マルチタッチです!"				

		id = touchid(0)			//ポイントID 1つめ (特殊事情で使用していません。マウス用?)
		mtinfo touch0,id

		id = touchid(1)			//ポイントID 2つめ(指一本目)
		mtinfo touch1,id

		id = touchid(2)			//ポイントID 3つめ(指二本目)
		mtinfo touch2,id

			// ふたつの指のxとy座標		★要注意★ touchid(1)とtouchid(2)のなかみをとってます!
			tmp_a_x = touch1(1)	: tmp_a_y = touch1(2)	// 1番目の指のx y座標
			tmp_b_x = touch2(1)	: tmp_b_y = touch2(2)	// 2番目の指のx y座標
			//---------------------------------------------------------------
		    // ローテートの判定
		    dx = tmp_a_x - tmp_b_x
		    dy = tmp_a_y - tmp_b_y
		    rad = atan(dy, dx)			// ★重要 x軸との角度を計算(-π~+πの値が返ってくる)
		    deg = rad * 180.0 / pi      // 度に換算
		 
		    // 0~360度になるよう計算
		    rad2 = rad
		    if rad2 < 0.0 : rad2 += pi * 2
		    deg2 = rad2 * 180.0 / pi

			// 1度以上変化のあったときだけ回転実行(細かく画像が動きすぎると操作しにくいため)
			setu = "同じ"		//状態確認用メッセージ
			if ( deg2 <  bak_deg2 - 1.0) || ( deg2 >  bak_deg2 + 1.0 ) {
		
				if deg2 <  bak_deg2 { setu="減 回転" :  kt = kt-0.1 }
				if deg2 >  bak_deg2 { setu="増 回転" :  kt = kt+0.1 }
			 
			}

			title ""+setu+" "+deg2			//確認用
			mes
			mes  " 角度 = "+deg2+" "+setu 
			bak_deg2 = deg2					//次回比較用に保持しておく

			// 解説は ↓ atanサンプルを参照してください(角度や三角関数の勉強ができます)
			// https://wiki.hsp.moe/DevMagazin%EF%BC%8F%E4%B8%89%E8%A7%92%E9%96%A2%E6%95%B0.html#i5241892

			//----------------------------------------------------↑ローテートおわり---
			// ピンチ の判定  "hspmath.as" に含まれる distance2(point_a, point_b)関数を使う方法---

			point_a = bak_a_x, bak_a_y	// 前回の点A point_aが配列になりpoint_a(0)とpoint_a(1)ができる
			point_b = bak_b_x, bak_b_y	// 前回の点B

			bak_kyori = distance2(point_a, point_b) //★重要 二点間の距離を簡単に算出

			point_a = tmp_a_x, tmp_a_y      // 現在の点A
			point_b = tmp_b_x, tmp_b_y      // 現在の点B

			kyori = distance2(point_a, point_b) //★重要 二点間の距離を簡単に算出

			title " kyori = " + kyori		//確認用

			//さっきよりも指の距離が広がっていれば拡大
			if kyori > bak_kyori {			//現在の二点間が前回の二点間より大きければ「広がった」

				zougenkyori = kyori-bak_kyori	//増減した距離
				zouritu = zougenkyori/10		// 増減した距離にあわせて変化率も大きくなる
				ks = ks + add * (1+zouritu)		// ★この3行やめて、ks = ks + add だけでもよい
			}	

			//さっきよりも指の距離が狭まっていれば縮小
			if kyori < bak_kyori {			//現在の二点間が前回の二点間より小さければ「狭まった」

				zougenkyori = bak_kyori-kyori	//増減した距離
				zouritu = zougenkyori/10		// 増減した距離にあわせて変化率も大きくなる
				ks = ks - add * (1+zouritu)		// ★この3行やめて、ks = ks - add だけでもよい
			}	

			//現在の指の位置を保持しておく
			bak_a_x = tmp_a_x : bak_a_y = tmp_a_y
			bak_b_x = tmp_b_x : bak_b_y = tmp_b_y		
			//-------------------------------------------↑ピンチおわり
	}
	//------------------------------------------------------
	// 《 描画 》
	color 0,0,128 : boxf		//画面エリアを一旦ぬりつぶしてクリア

	//画像を拡縮表示
	pos gx,gy
	celput 1,0,1.0+ks,1.0+ks,kt							//回転は 6.28で1回転(3.14で半回転)
														// 元画像の左上起点で回転。
														// 時計回り(右回り)。マイナス値で逆回転
	//マウス位置表示(開発用)
	color 255,255,255
	pos 0,4 : mes "  "+mousex+","+mousey+" num="+num+" "+joutai //状態をメッセージ表示
	pos 0,40 : mes " 画面に指2本でタッチしたまま、"	//操作説明
	pos 0,70 : mes " 「ピンチ」や「回転」ができます"	//操作説明
	//------------------------開発用情報表示
	if  num > 2 {
		pos 0,400 : mes touch0(0)	// タッチ状態(1=ON/0=OFF)
		pos 0,430 : mes touch0(1)	// X座標
		pos 0,460 : mes touch0(2)	// Y座標
		pos 0,490 : mes touch0(3)	// タッチ識別用ID
		pos 0,500 : mes "------------------"
		pos 0,520 : mes touch1(0)
		pos 0,550 : mes touch1(1)
		pos 0,580 : mes touch1(2)
		pos 0,610 : mes touch1(3)
		pos 0,620 : mes "------------------"
		pos 0,640 : mes touch2(0)
		pos 0,670 : mes touch2(1)
		pos 0,700 : mes touch2(2)
		pos 0,730 : mes touch2(3)
	}
	//------------------------
	redraw 1				//実際の画面へ表示する
	await 20				//待ち時間 await と wait がある 
goto *main
stop
//================================================================
//【メモ】
// このスクリプトは「タッチ操作 UI 」開発時のヒントになることを目的に作成されています。
// タッチの処理方法は、いくつもの実装方法があり、
// 開発者自身が目的にあった好きな方法を自由に採用すれば良いです。
// 自分で参考になると思った部分だけ切り出して参考にしてください。
// (時間をかければもっとよりよくできるはずです)
// このスクリプトには、「タッチ(タップ)」「ピンチ(つまむ)」「ローテート(回転)」
// のUI処理が含まれています

操作の用語:
「つまむ」ことを「ピンチ」または「ピンチ・イン」
「ひろげる」ことを「ピンチ・アウト」
と表現することがあります。


   HSPトップへもどる