unity 2d lookatlookat 第二参数怎么理解

在unity中,有许多的函数非常的简单,同时又非常的好用和有趣。LookAt就是其中一个。
顾名思义,LookAt就是使一个对象始终朝向另一个对象的一个方法。我们知道,许多的3D游戏中就用到了这一点。
我们举例说明LookAt的用法。
我们让一个球滚动,然后让摄像机始终朝向球,就如同第一人称视角看球运动一样。
首先声明一个目标对象:public T
然后 在update函数里面调用
gameObject.transform.LookAt( go);
接着给go 赋对象,也就是 小球,在面板中将小球拖到go 处;
最后,我们要实现摄像机朝向小球,那么,把脚本拖到相机面板上即可。
我们搭建如图所示的一个场景:给小球添加一个RigidBody组件,勾选重力,让小球可以自由下落,然后会碰到方块,最后滚下地面。
具体实现过程如下:
然后,将脚本拖给相机,并将 小球赋给 “go”
我们用几幅图看小球的运动和相机的视角:
我们可以看到,相机始终是朝向小球的。这就是LookAt的用法。当然,我们也可以将脚本给其他运动的物体,那么这个物体也是始终朝向小球的。Unity3d与iOS交互开发——接入平台SDK必备技能
前言废话:开发手机游戏都知道,你要接入各种平台的SDK。那就需要Unity3d与iOS中Objective-C的函数有交互,所以你就需要用到如下内容:
一、Unity3d
1、创建一个C#文件 SdkTo.cs 这是调用iOS函数的接口:
public class SdkToIOS: MonoBehaviour
//平台接入开关
public static bool isOpenPlatform =
//导入定义到.m文件中的C函数
[DllImport("__Internal")]
private static extern void _PlatformInit();
//定义接口函数供游戏逻辑调用
public static void InitSDK()
if (isOpenPlatform)
_PlatformInit();
2、编写与接口对应的Objective-c函数:
MyIOSSdk.h
@interface MyIOSSdk : NSObject
MyIOSSdk.m
#import "MyIOSSdk.h"
//这里引用SDK的头文件
#import "SDKPlatform.h"
#if defined(__cplusplus)
extern "C"{
extern void UnitySendMessage(const char *, const char *, const char *);
extern NSString* _CreateNSString (const char* string);
#if defined(__cplusplus)
//*****************************************************************************
@implementation MyIOSSdk
//**********************
//message tools
+ (void)sendU3dMessage:(NSString *)messageName param:(NSDictionary *)dict
NSString *param = @"";
if ( nil != dict ) {
for (NSString *key in dict)
if ([param length] == 0)
param = [param stringByAppendingFormat:@"%@=%@", key, [dict valueForKey:key]];
param = [param stringByAppendingFormat:@"&%@=%@", key, [dict valueForKey:key]];
UnitySendMessage("SDK_Object", [messageName UTF8String], [param UTF8String]);
//**********************
//初始化SDK
-(void)SDKInit
SDKcfg *cfg = [[[SDKcfg alloc] init] autorelease];
cfg.appid =123456;
cfg.appKey =@"aoaoaoaoaoaoaoaoaoaoaoaoaaoaoaoaoaoaoao";
cfg.orientation = UIDeviceOrientationLandscapeL
//调用SDK的初始化函数
[[SDKPlatform defaultPlatform] SDKInit:cfg];
//添加回调监听
[[SDKPlatform defaultPlatform] addObserver:self selector:@selector(SNSInitResult:) name:(NSString *)kInitNotification object:nil];
//获取用户ID
-(NSString*)SDKGetUserID
[[SDKPlatform defaultPlatform] SDKGetUserID];
//**********************
//call back fun
//初始化更新回调
- (void)SNSInitResult:(NSNotification *)notify
[MyIOSSdk sendU3dMessage:@"SDKMsgInit" param:nil];
//*****************************************************************************
#if defined(__cplusplus)
extern "C"{
//字符串转化的工具函数
NSString* _CreateNSString (const char* string)
if (string)
return [NSString stringWithUTF8String: string];
return [NSString stringWithUTF8String: ""];
char* _MakeStringCopy( const char* string)
if (NULL == string) {
return NULL;
char* res = (char*)malloc(strlen(string)+1);
strcpy(res, string);
static MyIOSSdk *mySDK;
//供u3d调用的c函数
void _PlatformInit()
if(mySDK==NULL)
mySDK = [[MyIOSSdk alloc]init];
[lsSDK SDKInit];
//注意这个函数是返回字符串
const char* _PlatformGetUin()
if(lsSDK==NULL)
lsSDK = [[MyIOSSdk alloc]init];
return _MakeStringCopy([[lsSDK SDKGetUserID] UTF8String]);
#if defined(__cplusplus)
值得一提的是在上面的代码中特意写了一个返回字符串的例子,因为你要获取用户ID 、昵称什么的。对应在cs文件中导入函数如下:
[DllImport ("__Internal")]
private static extern string _PlatformGetUin();这里的const char* 会被C#自动转换成string因为在m文件中使用了内存申请,该段内存自然是处在堆内存中,这样转成string符合的内存管理机制,我们不用担心它的释放问题。
3、在你的工程目录中找个地方保存iOS的文件
打包出XCode工程后导入进去,加入你的SDK就可以了。
有一点需要说明,如果存放目录为\Assets\Plugins\iOS,那么Unity3d会自动将该目录下的所有文件(暂不支持子文件夹)当做插件文件打包到Xcode工程下的Libraries目录下,这样你就不需要在手动添加了,否则会报错重复声明什么的。
这种文件各个平台会有多个,可以使用同一头文件且定义的C函数名也都相同,这样更有利于多版本管理。
二、iOS To
这个在上面的 MyIOSSdk.m 文件中已经有剧透了,就是利用unity3d 的UnitySendMessage函数,其中参数1是场景中接受消息的对象,参数2是要执行的函数名,参数3为传入参数,只要按照如下步骤就可以实现这个机制:
1、在场景中创建一个对象用于接受iOS消息,或者用现有的也可以;
2、为SDK消息写一个脚本,里面包含各种消息函数;
3、将脚本挂到之前创建的对象上完事;
需要注意:这个对象在场景切换时候要始终存在,或者你在每个场景中都加个这玩意也可以,总之只要能收到消息就行了;
另外,针对参数的传递对应上面的sendU3dMessage函数,我还在消息接受脚本中写过一个消息参数的解析:
void ParseMsg(string msg, out Dictionary dicMsg){
if( null == msg || 0 == msg.Length ){
dicMsg = new Dictionary();
string[] msgArray = msg.Split('&');
for( int i=0; i<msgArray.L i++){
string[] elementArray = msgArray[i].Split('=');
dicMsg.Add(elementArray[0],elementArray[1]);
这个我自己都还没有实际使用过,有错误自行解决大致是这样。
ps:关于SDK的接入还有 android版本的尚未研究网上有很多可以参照;
pps:SDK多版本管理和研究我也在摸索中,哪位大神比较熟悉不吝赐教,本人万分感激,之前到是看过这个https://www.xuanyusong.com/archives/2418#comments
ppps:转载请注明来自:https://blog.csdn.net/zhao_yin//回头再看,发现这个方法是再造轮子
对于四元数没有理解,Quaternion的方法是一个简洁明了的方式
Quaternion.FromToRotation(Vector3 fromDir,Vector3 toDir):Quaternion
返回一个从fromDir到toDir的旋转表示
可以理解为从一个方向到另一个方向,该如何旋转
整个过程可以分解为两步:
1-炮管旋转,对准目标
2-坦克身体旋转,与坡度的法线重合
那么就是这样的一个代码:
void QuaternionRotation(){
targetPos = target.transform.
selfPos = transform.
Vector3 pUp = transform.
Vector3 headDir = targetPos-selfP
//rotate to heading to the target
Quaternion headRotation = Quaternion.FromToRotation(transform.forward,headDir);
transform.rotation = headRotation*transform.
//rotate to original transform up , that is the normal of the slope
Quaternion bodyRotation = Quaternion.FromToRotation(transform.up,pUp);
transform.rotation = bodyRotation*transform.
//回头再看,发现这个方法是再造轮子
Unity中,transform有一个很有意思的方法:
TransForm.LookAt(Transform target, Vector3 WorldUp);
Transform.LookAt(Transform target);
这个方法可以理解成为:
1-目的是,使得自身的transform.forward指向目标对象
2-将自身以世界坐标的transform.up为转动轴,rotate,使得1得以实现
好比是一个人的身子绕头顶--脚心的轴转动,让自己的眼镜,看着对象。
方法很简洁实用。然而有局限性,主要在于转动轴上。设想如下一个问题:一个斜坡上有一辆坦克,需要转动炮塔,对准并不在这个斜坡上的一个物体。
上方侧视图中示意了坦克在斜面上,黄色物体在上方的水平面上。下方的透视图中,可以看到这二者的空间位置关系。
我们希望坦克用炮管对准这个黄色物体,这里的对准,其实是平面对准,让炮管的指向在坦克和物体构成的平面中。
示意一下,这个效果:
坦克旋转了,炮管指向了物体,并且这个旋转,使得坦克的transform.up方向还是垂直于所在的斜面。
先简单用LookAt来试试?
void Update () {
transform.LookAt(target.transform);
Debug.DrawRay(transform.position,10f*transform.forward,Color.red);
Debug.DrawRay(transform.position,3f*transform.up,Color.green);
在Update中不断更新这个tranform.LookAt(),我们得到的是这样一个效果:炮管指向了物体,但是坦克旋转的轴向,并不是transform.up,而是WorldUp,显然,坦克翘起了脚,脱离了所在的斜面。
不能用简单的LookAt来实现,于是回归到基础的分析:
如果物体O,在坦克的水平面上,也就是图左所示。那么问题比较简单,向量AO就是向量forward需要转到的最终方向lookV,计算一下两者的夹角,按照A.transform.up作为旋转轴,旋转这个角度;至于顺时针还是逆时针,取决于两个向量的叉乘(另文已述)。
如果物体O,不在坦克的水平面上,如图右所示。A的旋转轴只能是A.transform.up,因此A的lookV,是向量AO&,这个 &O& & 是O在坦克水平面上的投影,也就是说,需要计算出AO在坦克水平面的投影向量。
查找了一些资料,关于计算向量在平面上的投影向量,最靠谱的是这个:
那么,在unity中,这样来实现它:
1-计算A.transform.up与AO的点乘,,由于A.transform.up的模长为1,
点乘得到的结果为图右中PA的长度,可以转化为向量AP:
Vector3 projectV =
Vector3.Dot(targetPos-selfPos,transform.up)*transform.//project to up-axis
2-AO&就是PO&,容易得到向量AO 减去 向量AP,就可以得到
lookDir = targetPos-selfPos-projectV;
3-转化为在同一个平面中,旋转的lookV的问题了
void LookAtTarget(){
targetPos = target.transform.
selfPos = transform.
if(targetPos != selfPos){//targetPos == selfPos, no where to look
Vector3 projectV =
Vector3.Dot(targetPos-selfPos,transform.up)*transform.//project to up-axis
lookDir = targetPos-selfPos-projectV;
if(lookDir !=Vector3.zero){//lookDir == 0,target is up the head ,no where to look
Vector3 crossV = Vector3.Cross(lookDir,transform.forward).
if(crossV !=Vector3.zero){//crossV == 0 , target is looking at ,no need to rotate
if(crossV == transform.up){
transform.Rotate(transform.up,-Vector3.Angle(lookDir,transform.forward),Space.World);
transform.Rotate(transform.up,Vector3.Angle(lookDir,transform.forward),Space.World);
另外有一些细节的问题,已经在代码中注释。
总体来说,这个方法,由于特定的轴向旋转,而不是世界坐标轴,而其中向量点乘用于计算投影向量,向量叉乘用于计算旋转的顺时针逆时针。
阅读(...) 评论()unity lookat 第二参数怎么理解_百度知道
unity lookat 第二参数怎么理解
我有更好的答案
我用中文描述了) 定义变量:是否按下A=false用个麻烦点的方法:例如(A+B组合键
为您推荐:
其他类似问题
&#xe675;换一换
回答问题,赢新手礼包&#xe6b9;
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。3204人阅读
Unity(43)
写在前面:
&&& 游戏中,经常遇到的情况是,需要角色对着敌人(或者一个指定方向),或者敌人对着角色。如果直接用LookAt() 去实现,那么非常生硬(立即就转过去对着了),如果是操作角色的话,也没有手感、所以需要写一个算法,来解决这个问题。
实现思路:
&&& 实现的办法有很多种,这里我用的是这种办法:
1,记录转身前的角度。
2,获得准备面向的角度,(就是LookAt() 之后的那个角度)。
3,计算转身前的角度,和即将面对的角度的差,也就是转身转了多少度。
4,根据要转身的角度,计算出lerp速度(这样可以保证,转的角度大,转的时间就长。也就是角速度)
5,在update里,利用 Quaternion.Lerp() 实现转动。
以下是伪代码:
注意,由于全部粘贴出来会比较长,只能粘伪代码,大家整理一下放到自己的逻辑里就行了。
// 这里是类变量 -------------------
// 记录转身前的角度
private Quaternion raw_
// 准备面向的角度
private Quaternion lookat_
// 转身速度(每秒能转多少度)
private float per_second_rotate = 1080.0f;
// 旋转角度越大, lerp变化速度就应该越慢
float lerp_speed = 0.0f;
// lerp的动态参数
float lerp_tm = 0.0f;
// --------------------------------
// 旋转之前的初始化
void Init_Rotate(){
// 记录转身前的角度
raw_rotation = m_trans.
// 记录目标角度
m_trans.LookAt(move_location_pos);
lookat_rotation = m_trans.
// 还原当前角度
m_trans.rotation = raw_
// 计算旋转角度
float rotate_angle = Quaternion.Angle(raw_rotation, lookat_rotation);
// 获得lerp速度
lerp_speed = per_second_rotate / rotate_
Debug.Log(&Angle:& + rotate_angle.ToString() + & speed:&+lerp_speed.ToString());
lerp_tm = 0.0f;
// 旋转逻辑, 在update中调用
void Rotate_Func(){
lerp_tm += Time.deltaTime * lerp_
m_trans.rotation = Quaternion.Lerp(raw_rotation, lookat_rotation, lerp_tm);
if (lerp_tm &= 1) {
m_trans.rotation = lookat_
// 此时, 转身完毕, 已经对着目标物体
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:2893804次
排名:千里之外
原创:171篇
评论:371条
(1)(2)(4)(1)(1)(2)(2)(2)(1)(1)(1)(1)(3)(3)(1)(4)(2)(3)(2)(3)(1)(3)(1)(4)(1)(4)(3)(3)(4)(7)(4)(5)(2)(6)(2)(2)(5)(2)(7)(12)(1)(2)(3)(2)(1)(1)(8)(3)(9)(2)(3)(1)(2)(3)(4)(4)(2)(4)(2)(2)(3)
(window.slotbydup = window.slotbydup || []).push({
id: '4740887',
container: s,
size: '250,250',
display: 'inlay-fix'}

我要回帖

更多关于 unity lookat 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信