unity2D平面摄像机滑动缩放
比如2D游戏 地图很大,像植物大战僵尸关卡选择界面,需要对可见的区域进行滑动,缩放等,
1….滑动:通过正交摄像机的orthographicSize和位置和实际大小(可视范围大小),计算出距离世界坐标原点偏移量 来计算出位置
2….缩放,对正交相机的orthographicSize进行修改,达到放缩目的。同样也要计算摄像机实际大小()可视范围大小)
3…..正交相机大小的算法 摄像机实际视界宽度(米)=size*2*屏幕宽高比
当然该方法不限于正交相机 透视相机也可以利用这种思路来计算,当然还要考虑像素和米的换算关系,以下代码块像素米比例是1,即1像素=1米
using System.Collections; using System.Collections.Generic; using UnityEngine; // for map mouse and touch slide and zoom [RequireComponent(typeof(Camera))] public class MapCameraSlider : MonoBehaviour { Camera camera = null; float SCREEN_WIDTH = 1136f;//屏幕宽度 float SCREEN_HEIGHT = 640f; // 屏幕高度 const float max_allow_width = 1024f * 3f; // 最大允许滑动的宽度 const float max_allow_height = 1024f * 3f; // 最大允许滑动的高度 float distanceScale; Vector3 pos1; Vector3 pos2; const float SCALEPOSTION = 1f; // 全局位置缩放大小 bool touchBeg = false; void Start() { SCREEN_HEIGHT = Screen.height; SCREEN_WIDTH = Screen.width; camera = this.GetComponent<Camera>(); if (camera == null) { Debug.LogError("need camera component"); } } void Update() { if (touchBeg) { timeTouch += Time.deltaTime; } // ------------------------------------for mobile touch input if (Input.touchCount == 1) { // slide var data = Input.GetTouch(0); this.Slide(data.deltaPosition * SCALEPOSTION); pos1 = Vector3.zero; pos2 = Vector3.zero; distanceScale = 0f; if (data.phase == TouchPhase.Began) { StopAllCoroutines(); touch_beg = data.deltaPosition * SCALEPOSTION; timeTouch = 0.000001f; touchBeg = true; } if (data.phase == TouchPhase.Ended) { touchBeg = false; this.StartAutoSlide(touch_beg, data.position); } } else if (Input.touchCount == 2) {// scale touchBeg = false; var d1 = Input.GetTouch(0); var d2 = Input.GetTouch(1); if (d1.phase == TouchPhase.Began) { pos1 = d1.position; distanceScale = Vector3.Distance(pos1, pos2); } if (d2.phase == TouchPhase.Began) { pos2 = d2.position; distanceScale = Vector3.Distance(pos1, pos2); } if (pos2 != Vector3.zero && pos2 != Vector3.zero) { float dis = Vector3.Distance(pos1, pos2); if (d1.phase == TouchPhase.Moved || d2.phase == TouchPhase.Moved) { if (dis > distanceScale) { this.ZoomOut(Time.deltaTime * 500f); } else if (dis < distanceScale) { this.ZoomIn(Time.deltaTime * 500f); } } distanceScale = dis; } } else { touchBeg = false; pos1 = Vector3.zero; pos2 = Vector3.zero; distanceScale = 0f; } //--------------------------------- for pc mouse input //slide if (Input.GetMouseButton(0)) { if (lastMousePos == Vector2.zero) { timeTouch = 0.000001f; StopAllCoroutines(); lastMousePos = Input.mousePosition; touch_beg = lastMousePos; return; } else { timeTouch += Time.deltaTime; Vector2 pos = Input.mousePosition; this.Slide(1.25f * (pos - lastMousePos)); lastMousePos = pos; } } else { if (lastMousePos != Vector2.zero) { this.StartAutoSlide(touch_beg, Input.mousePosition); } lastMousePos = Vector2.zero; } //----------------------for pc zoom if (Input.GetAxis("Mouse ScrollWheel") < 0) { this.ZoomOut(Time.deltaTime * 500f); this.Slide(0f, 0f); } //Zoom in if (Input.GetAxis("Mouse ScrollWheel") > 0) { this.ZoomIn(Time.deltaTime * 500f); this.Slide(0f, 0f); } } float maxtime = 3f; //开始惯性动画 void StartAutoSlide(Vector2 orign, Vector2 ended) { if (Mathf.Abs(timeTouch) < 0.01f) { return; } maxtime = 3f; StopAllCoroutines(); Debug.Log("slide map ,speed = " + (Vector2.Distance(orign, ended) / timeTouch / 100f) + " touchTime=" + timeTouch + " posended" + ended + " beg" + orign); StartCoroutine(RunSliderAction(ended.x - orign.x, ended.y - orign.y, Vector2.Distance(orign, ended) / timeTouch / 100f)); timeTouch = 0.000001f; } Vector2 touch_beg; float timeTouch = 0.000001f; IEnumerator RunSliderAction(float dx, float dy, float speed) { float time = 0f; float dis = 0f; while (time < maxtime && speed >= 0f) { yield return new WaitForEndOfFrame(); time += Time.deltaTime; dis += Time.deltaTime * 0.01f; // Debug.LogError(pos + " " + time + " speed=" + speed); speed -= Time.deltaTime * 10f; this.Slide(Time.deltaTime * speed * dx, dy * Time.deltaTime * speed); } } Vector2 lastMousePos = Vector2.zero; //滑动接口,参数是偏移量 void Slide(Vector2 dp) { this.Slide(dp.x, dp.y); } //滑动接口,参数是偏移量 void Slide(float dx, float dy) { dx = -dx; dy = -dy; var pos = transform.position; pos.x += dx; pos.y += dy; transform.position = pos; //实际宽度 float real_width = camera.orthographicSize * 2 * SCREEN_WIDTH / SCREEN_HEIGHT; float real_height = real_width * SCREEN_HEIGHT / SCREEN_WIDTH; //process edge if (transform.position.x <= real_width / 2f) {//x left this.SetPosX(0); } if (transform.position.x >= max_allow_width - real_width / 2f) {// x right this.SetPosX(max_allow_width - real_width); } if (transform.position.y <= real_height / 2f) {// y up this.SetPosY(0); } if (transform.position.y >= max_allow_height - real_height / 2f) {// y down this.SetPosY(max_allow_height - real_height); } } //放大接口 void ZoomOut(float delta) { camera.orthographicSize = camera.orthographicSize + delta; float real_width = camera.orthographicSize * 2 * SCREEN_WIDTH / SCREEN_HEIGHT; float real_height = real_width * SCREEN_HEIGHT / SCREEN_WIDTH; float max_size = max_allow_width * SCREEN_HEIGHT / 2f / SCREEN_WIDTH; if (real_width >= max_allow_width) { camera.orthographicSize = max_size; } } //缩小接口 void ZoomIn(float delta) { camera.orthographicSize = camera.orthographicSize - delta; float real_width = camera.orthographicSize * 2 * SCREEN_WIDTH / SCREEN_HEIGHT; float real_height = real_width * SCREEN_HEIGHT / SCREEN_WIDTH; float min_size = 150f; if (camera.orthographicSize <= min_size) { camera.orthographicSize = min_size; } } // 设置x偏移量,偏移量是从世界坐标原点开始计算 void SetPosX(float offsetX) { float real_width = camera.orthographicSize * 2 * SCREEN_WIDTH / SCREEN_HEIGHT; float real_height = real_width * SCREEN_HEIGHT / SCREEN_WIDTH; var posOld = transform.position; transform.position = new Vector3(real_width / 2f + offsetX, posOld.y, posOld.z); } // 设置y偏移量,偏移量是从世界坐标原点开始计算 void SetPosY(float offsetY) { float real_width = camera.orthographicSize * 2 * SCREEN_WIDTH / SCREEN_HEIGHT; float real_height = real_width * SCREEN_HEIGHT / SCREEN_WIDTH; var posOld = transform.position; transform.position = new Vector3(posOld.x, offsetY + real_height / 2f, posOld.z); } }