实验记录。(4.2Update-finish)
全景图来自网络素材,原本这一步实现图片的拼接也是可以的,但是觉得那样过于无关了点,网上随便扒了张图下来。(可能会换)

利用unity创造模型,实现球内贴图。一开始的贴图是在球面即外部,需要使用着色器改成内部
参考博客: https://blog.csdn.net/wuyt2008/article/details/5431347
Shader "InsideVisible" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader {
Tags { "RenderType"="Opaque" }
Cull front // ADDED BY BERNIE, TO FLIP THE SURFACES
LOD 100
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata_t {
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
struct v2f {
float4 vertex : SV_POSITION;
half2 texcoord : TEXCOORD0;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata_t v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
// ADDED BY BERNIE:
v.texcoord.x = 1 - v.texcoord.x;
o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.texcoord);
return col;
}
ENDCG
}
}}

这种情况下在scene里固然可以通过alt+左键的方式环绕浏览全景图,但是game模式下相机的视角是固定的 需要通过编写脚本将相机和鼠标或者键盘的操纵绑定起来。此处因为我们希望鼠标还有后续的ui操作互动,所以不能使用直接看不见鼠标->鼠标直接引导方向旋转的方式。
不过找到了一份很不错的直接引导旋转的代码,先存一下
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class SmoothMouseLook : MonoBehaviour {
public float sensitivity = 4.0f;
[HideInInspector]
public float sensitivityAmt = 4.0f;//actual sensitivity modified by IronSights Script
private float minimumX = -360f;
private float maximumX = 360f;
private float minimumY = -85f;
private float maximumY = 85f;
[HideInInspector]
public float rotationX = 0.0f;
[HideInInspector]
public float rotationY = 0.0f;
[HideInInspector]
public float inputY = 0.0f;
public float smoothSpeed = 0.35f;
private Quaternion originalRotation;
private Transform myTransform;
[HideInInspector]
public float recoilX;//non recovering recoil amount managed by WeaponKick function of WeaponBehavior.cs
[HideInInspector]
public float recoilY;//non recovering recoil amount managed by WeaponKick function of WeaponBehavior.cs
void Start(){
if (GetComponent<Rigidbody>()){GetComponent<Rigidbody>().freezeRotation = true;}
myTransform = transform;//cache transform for efficiency
originalRotation = myTransform.localRotation;
//sync the initial rotation of the main camera to the y rotation set in editor
Vector3 tempRotation = new Vector3(0,Camera.main.transform.eulerAngles.y,0);
originalRotation.eulerAngles = tempRotation;
sensitivityAmt = sensitivity;//initialize sensitivity amount from var set by player
// Hide the cursor
Cursor.visible = false;
}
void Update(){
if(Time.timeScale > 0 && Time.deltaTime > 0){//allow pausing by setting timescale to 0
//Hide the cursor
Screen.lockCursor = true;
Cursor.visible = false;
// Read the mouse input axis
rotationX += Input.GetAxisRaw("Mouse X") * sensitivityAmt * Time.timeScale;//lower sensitivity at slower time settings
rotationY += Input.GetAxisRaw("Mouse Y") * sensitivityAmt * Time.timeScale;
//reset vertical recoilY value if it would exceed maximumY amount
if(maximumY - Input.GetAxisRaw("Mouse Y") * sensitivityAmt * Time.timeScale < recoilY){
rotationY += recoilY;
recoilY = 0.0f;
}
//reset horizontal recoilX value if it would exceed maximumX amount
if(maximumX - Input.GetAxisRaw("Mouse X") * sensitivityAmt * Time.timeScale < recoilX){
rotationX += recoilX;
recoilX = 0.0f;
}
rotationX = ClampAngle (rotationX, minimumX, maximumX);
rotationY = ClampAngle (rotationY, minimumY - recoilY, maximumY - recoilY);
inputY = rotationY + recoilY;//set public inputY value for use in other scripts
Quaternion xQuaternion = Quaternion.AngleAxis (rotationX + recoilX, Vector3.up);
Quaternion yQuaternion = Quaternion.AngleAxis (rotationY + recoilY, -Vector3.right);
//smooth the mouse input
myTransform.rotation = Quaternion.Slerp(myTransform.rotation , originalRotation * xQuaternion * yQuaternion, smoothSpeed * Time.smoothDeltaTime * 60 / Time.timeScale);
//lock mouselook roll to prevent gun rotating with fast mouse movements
myTransform.rotation = Quaternion.Euler(myTransform.rotation.eulerAngles.x, myTransform.rotation.eulerAngles.y, 0.0f);
}else{
//Show the cursor
Screen.lockCursor = false;
Cursor.visible = true;
}
}
//function used to limit angles
public static float ClampAngle (float angle, float min, float max){
angle = angle % 360;
if((angle >= -360F) && (angle <= 360F)){
if(angle < -360F){
angle += 360F;
}
if(angle > 360F){
angle -= 360F;
}
}
return Mathf.Clamp (angle, min, max);
}
}
这份代码甚至考虑到了旋转的微弱惯性,真是有意思。
下面是直接鼠标点击拖动(game窗口中有鼠标)实现旋转:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class Test01 : MonoBehaviour
{
public float moveSpeed = 1;//物体旋转速度
public GameObject target;
private Vector2 oldPosition;
private Vector2 oldPosition1;
private Vector2 oldPosition2;
private float distance = 0;
private bool flag = false;
//摄像头的位置
private float x = 0f;
private float y = 0f;
//左右滑动移动速度
public float xSpeed = 250f;
public float ySpeed = 120f;
//缩放限制系数
public float yMinLimit = -360;
public float yMaxLimit = 360;
//是否旋转
private bool isRotate = true;
//计数器
private float count = 0;
public static Test01 _instance;
//初始化游戏信息设置
void Start()
{
_instance = this;
Vector3 angles = transform.eulerAngles;
x = angles.y;
y = angles.x;
if (GetComponent< Rigidbody >())
GetComponent< Rigidbody >().freezeRotation = true;
}
// Update is called once per frame
void Update()
{
if (isRotate)
{
target.transform.Rotate(Vector3.down, Time.deltaTime * moveSpeed,Space.World);
}
if (!isRotate)
{
count += Time.deltaTime;
if (count > 5)
{
count = 0;
isRotate = true;
}
}
//触摸类型为移动触摸
if (Input.GetMouseButton(0))
{
//根据触摸点计算X与Y位置
x += Input.GetAxis("Mouse X") * xSpeed *Time.deltaTime;
y -= Input.GetAxis("Mouse Y") * ySpeed * Time.deltaTime;
isRotate = false;
}
//判断鼠标滑轮是否输入
float temp = Input.GetAxis("Mouse ScrollWheel");
if (temp!=0)
{
if (temp>0)
{
// 这里的数据是根据我项目中的模型而调节的,大家可以自己任意修改
if (distance > -15)
{
distance -= 0.5f;
}
}
if (temp<0)
{
// 这里的数据是根据我项目中的模型而调节的,大家可以自己任意修改
if (distance < 20)
{
distance += 0.5f;
}
}
}
}
//计算距离,判断放大还是缩小。放大返回true,缩小返回false
bool IsEnlarge(Vector2 oP1, Vector2 oP2, Vector2 nP1, Vector2 nP2)
{
//old distance
float oldDistance = Mathf.Sqrt((oP1.x - oP2.x) * (oP1.x - oP2.x) + (oP1.y - oP2.y) * (oP1.y - oP2.y));
//new distance
float newDistance = Mathf.Sqrt((nP1.x - nP2.x) * (nP1.x - nP2.x) + (nP1.y - nP2.y) * (nP1.y - nP2.y));
if (oldDistance < newDistance)
{
//zoom+
return true;
}
else
{
//zoom-
return false;
}
}
//每帧执行,在Update后
void LateUpdate()
{
if (target)
{
//重置摄像机的位置
y = ClampAngle(y, yMinLimit, yMaxLimit);
var rotation = Quaternion.Euler(y, x, 0);
var position = rotation *(new Vector3(0.0f, 0.0f, -distance)) + target.transform.position;
transform.rotation = rotation;
transform.position = position;
}
}
float ClampAngle(float angle,float min,float max) {
if (angle < -360)
angle += 360;
if (angle > 360)
angle -= 360;
return Mathf.Clamp(angle, min, max);
}
}
将这份脚本绑到main camera后需要手动将main camera拖进在inspector中的脚本参数设置【固定旋转中心
在可以确保基本的全景图浏览后,开始考虑我们的ui要怎么做了。
懒得做场景跳转,想来想去还是模仿了前辈作业“逃出二次元”,其实就只是场景中有物体、点击物体触发事件。
游戏规则:进入游戏场景,从场景中通过点击揪出六只企鹅就结束。


点击某只企鹅后左上角出现的企鹅是固定的(直接用多个脚本绑到一起),其实可以通过一个长一点的脚本直接实现绑定多个企鹅触发器,但我偷懒了(。)

好,效果讲完了,这是技术部分。
由于没有找到如何实现单张图片(非canvasUI)的3D物体建模(如果是厚度为0的cube,会出现透明底图片翻转出现的情况),所以选择了把企鹅直接拼到全景图中的方法。

目标是点击/移动到企鹅位置时触发文字和图片效果。所以为每个企鹅添加cube+box collider

然后是鼠标移动/点击时的代码内容
using UnityEngine;
using System.Collections;
public class Cube0 : MonoBehaviour
{
// public Transform cube;
bool isShowTip;
public bool WindowShow = false;
public GameObject qe1;
// // Use this for initialization
void Start()
{
isShowTip = false;
WindowShow = false;
}
void OnMouseEnter()
{
isShowTip = true;
//Debug.Log (cube.name);//可以得到物体的名字
}
void OnMouseExit()
{
isShowTip = false;
}
void OnGUI()
{
if (isShowTip)
{
GUIStyle style1= new GUIStyle();
style1.fontSize = 20;
style1.normal.textColor = Color.white;
GUI.Label(new Rect(Input.mousePosition.x, Screen.height - Input.mousePosition.y, 450, 100),"!我还没来得及藏呢!", style1);
}
// if (WindowShow)
// GUI.Window(0, new Rect(30, 30, 200, 100), MyWindow, "Cube");
}
//对话框函数
void MyWindow(int WindowID)
{
GUILayout.Label("你想写入的内容");
}
//鼠标点击事件
void OnMouseDown()
{
Debug.Log("find");
// Debug.Log("show");
if (WindowShow)
WindowShow = false;
else
WindowShow = true;
qe1.SetActive(true);
}
}
里面有一些无用代码,为了以后可能用到所以保留。(参考博客:
https://blog.csdn.net/hanguangfei/article/details/78094214
无用☞点击cube在界面左上角出现一个文字提示框。反复点击反复开关
添加了☞绑定image的开关
接下来是找到所有企鹅以后跳出中心文字提示。
实现方法:因为之前把脚本拆开来写,就没有全局的统计揪了多少只企鹅,所以通过检测image的显示情况(所有图标都出现==成功),引入函数GameObject.activeSelf
(附带:Unity GameObject.activeSelf, activeInHierarchy, SetActive和SetActiveRecursively区别 https://blog.csdn.net/qq_17758883/article/details/80175215
一开始试图把检测脚本绑到显示成功的文本,但是无论怎样都无法成功实现。猜测可能在游戏开始时是false,所以不执行里面的update。在canvas左下角添加一个看不见的button(alpha==255),在update里添加代码:
if (qe1.activeSelf && qe2.activeSelf && qe3.activeSelf && qe4.activeSelf && qe5.activeSelf && qe6.activeSelf)
{
findall.SetActive(true);
}
好,主要的说完了,剩下的是零零散散:
·所有UI都可以直接添加button组件,实现点击效果。
·已经有了触发器的cube,不必搞什么相机射线检测一类复杂脚本,直接写void OnMouseDown()写点击事件
·Input.GetAxis(“Mouse ScrollWheel”);检测滚轮输入情况,本实验中注释掉了因为没啥用,否则要注意数值情况要不然一滚就飞出天外。
·Fin…..?