查看: 5021|回复: 5
打印 上一主题 下一主题

[学习心得]Unity 3d学习笔记

[复制链接]

5472

主题

6

听众

1万

积分

版主

Rank: 7Rank: 7Rank: 7

纳金币
76544
精华
23

活跃会员 荣誉管理 突出贡献 优秀版主 论坛元老

跳转到指定楼层
楼主
发表于 2012-8-23 09:52:38 |只看该作者 |倒序浏览
图兰多双胞胎(TornadoTwins.com)其中一个录的入门视频。8月份看完了,边看边记笔记。这里也贴一份,完全是最粗浅的记录,不要指望从里面学到任何东西。如果不动手去做的话,我自己也会迅速的忘掉吧。



顺序是按教程顺序来的,语速很适中,还很幽默,推荐听原文啊。





关于Local和Global

基本上而言,你在动了物体的方向后,它的XYZ(RGB)会跟着自己的轴心指向新方向。你只有点了Global按钮,它才会重新指向场景轴心方向。



关于脚本

公共变量会在component界面出现

私有变量则不会(两种方法设置私有变量,一是在函数内部声明,另一个是在函数外部用private声明)

可以由其他脚本调用的变量则这样声明:static var ...



射出一个小盒子(注意,盒子prefab实现在工程中创建好,在脚本写完后,再往components里面拖):



var speed = 3.0;

var cratePrefab:Transform;



function Update ()

{

    //find out if a fire button is pressed   

    if(Input.GetButtonDown("Fire1"))

    {

        //create the prefab      

        var crate = Instantiate(cratePrefab, transform.position,Quaternion.identity);

      

        //add force to the prefab

        crate.rigidbody.AddForce(transform.forward * 2000);

    }

   

}



关于Terrain,天空盒
在地形模块的最后一个工具,Terrain Setting里,有一组选项是关于wind的,调整后可以改变物理风速对长草的影响。
可以通过Terrain -> Mass Place Trees, 直接在场景中加大量的树木。


如果用第三方软件导入树木的模型,注意:
The pivot point of the tree mesh must be exactly at the root of the tree, that is at the point where the tree should meet the surface it is placed on.



有两种办法添加天空盒:
一,在camera (比如First Person Controller这个prefab下的main camera)中,新增一个skybox组件(在components-> rendering 下)。通过这种方法所加的天空盒只在游戏调用相应的摄像机时候才会渲染。



二,直接在Edit -> Redering Setting 中设置天空盒的材质。这样设置的天空盒无论在什么摄像机下都会渲染。






关于GUI


在Project目录中选好一个GUI资源文件,然后:
GameObject -> Create Other -> GUI Texture

同理,往Project相应目录里拖一个font文件(.ttf),然后:
GameObject -> Create Other -> GUI Text

可以通过调整transform position中的 z值来决定GUI的覆盖顺序。

GUI 脚本范例:


function Awake () {
guiText.text = “”+0;
}

创建好脚本,写完之后,将之attach到游戏目录中的GUIText文件上。

***创建3D主菜单***
GameObject -> Create Other -> Cube

可以同时打开Game Scene来实时的看Camera的调整状况

可以在Create Other中添加3D Text

如果想改3D Text的字体可以直接将工程目录的字体文件拖到3D Text 的属性中(font material 要另外拖到材质球选项中)

- 解决字体模糊的方法:第一,将字体文件的尺寸变大, 第二,将字符本身的尺寸(character size)变小

加好3D效果的菜单文字后通过 Component -> Physics -> Box Collider 为这个字加碰撞组件



***在项目中添加新的Scene并获得Scene的order标记数字***
  
***3D菜单 脚本***

var isQuitBtn = false;   //检查某个按钮是否是退出APP的按钮
function onMouseEnter ()
{

     renderer.material.color = Color.red;
}


function onMouseExit ()
{
     renderer.material.color = Color.red;
}

function onMouseUp ()
{
     if(isQuitBtn)
     {
     Application.Quit();
     }
     else
     {
     Application.LoadLevel(1);  //这也就是前面说到的Level的Order Number了
     }
}








导入3D模型资源

1. 先把Texture Map放到Project目录中。

2.在同一目录中创建空的材质球(Material)

3.为材质球赋予纹理贴图,如果需要其他shader,则增加shader,然后将相应纹理贴图拖上去(例如Normal就拖到Bumped Diffuse上)

4.可以将这个完成的材质球直接拖到场景中的3D模型身上。

5.或者,直接将材质球拖到创建好的prefab中的3D物体的材质模块中。



http://unity3d.com/unity/features/asset-importing
6.可以在Texture的组件中找到一个选项叫做Generate Bumpmap,来利用Unity创建法线贴图




关于粒子特效

1. 如果要让特效随着物体转动(比如枪管喷射的火焰),则在粒子特效的Ellipsoid Particel Emitter中,关掉“simulate in worldspace”选项。

2. 要调整粒子的拉伸方式,进入Particle Renderer模块,调整Stretch Particles的模式(Billboard改为Stretched),然后将Velocity Scale调整之。



关于动画

1. 进行动画编辑前,先把动画面板打开

2. 0:00,前面是时间,后面是帧数

3.将play automatically的选项关掉,就不会自动播放了

4.调用脚本触发动画(直接撞上去才能开,需要给door加一个tag):

function OnControllerColliderHit(hit : ControllerColliderHit)

{

    if(hit.gameObject.tag == "door")

    {

        hit.gameObject.animation.Play("door_open");

    }

}

5.那么如何做一个感应门呢?这就要用到Raycasting了。

function Update()

{

    var hit : RaycastHit;

    //check if we're colliding

    if(Physics.Raycast(transform.position, transform.forward, hit, 5))  

//这里的5距离你可以在函数声明前定义一个变量,然后替换,比如 var RaycastLength = 5;,然后在游戏的脚本组件中显示出来,并实时地改变看效果



    {

        //...with a door

        if(hit.collider.gameObject.tag == "door")

        {

            //open the door

            hit.collider.gameObject.animation.Play("door_open");

        }

    }

}








关于拾取物品


1. 首先,让主角和拾取物产生碰撞
function OnControllerConlliderHit(hit: ControllerColliderHit)
{

    if(hit.gameObject.tag == "crateGrenades")

    {

      print("BOX OF AMMO FOUND!")

    }

}



2. 其次,让可拾取物在碰撞后会消失,消失后给你物品栏中的相应物品增加数量:

Destroy(hit.gameObject);

GRENADE_AMMO += 8;



3.然后在射击逻辑里(调用该物品的逻辑),做一个if判断,就行了

    if(Collide.GRENADE_AMMO > 0)

        {

        //create the prefab

        var crate = Instantiate(cratePrefab, transform.position,Quaternion.identity);

      

        //add force to the prefab

        crate.rigidbody.AddForce(transform.forward * 2000);

      

        Collide.GRENADE_AMMO --;

        print("YOU NOW HAVE" +  Collide.GRENADE_AMMO   + "GRENADES");

        }

有一点要注意,因为GRENADE_AMMO是全局变量,在其他脚本可以调用,调用时前面直接加该脚本文件名即可



4. 最后,对于手榴弹而言,如果你不想让它从屏幕中间飞出来(因为脚本挂靠的是Main Camera),可以另建一个低一点的Camera给shoot脚本挂上去



5. 在看到手榴弹爆炸特效的脚本这一节:通常的做法是把资源扔到场景中看效果,并且调整效果 —> 然后创建prefab,把调整好的GameObject扔进去 —> 删除场景中的instance —> 以后都从prefab调用这个物件



6. 怎么让爆炸效果和手榴弹prefab绑定呢:

var creationTime = Time.time;

var explotionPrefab : Transform;  //在手榴弹prefab内部强行创建一个空的prefab,稍后将爆炸特效的prefab拖进来落实

var lifeTime = 3;



function Awake()

{

    creationTime = Time.time;

}



function Update ()

{

    if(Time.time > (creationTime+lifeTime))

    {

        Destroy(gameObject);

        Instantiate(explotionPrefab, transform.position, Quaternion.identity);

    }

}








关于AI

1. 如何让AI转向我?非常简单,只有一行代码:

var lookAtTarget : Transform;

function Update ()

{

    transform.LookAt(lookAtTarget);

}

然后将该代码附着于你想让其转向的Game Object(这将在它的组件中创建一个变量Look At Target)。然后再把Player这个Game Object,直接拖到变量Look At Target上。

然后不管它是什么,都会很恐怖的盯着你看了……



2.现在,让炮筒不要那么傻乎乎的:
var target : Transform;
var range = 10.0; //让炮筒对我有侦测范围
function Awake()
{

      //让炮筒找到我,我的Tag是默认的

      target = GameObject.FindWithTag("layer").transform;
}

function Update()

{
      if(targe && CanAttackTarget())  //既能找到我,也能攻击我
     {

      var targetRotation = Quaternion.LookRotation(target.position - transform.position, Vector3.up);

      transfomr.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 2.0);

     }
}
     //构造“是否启动攻击”的函数
     function CanAttackTarget()
{
      // Check if the target is close enough



      if(Vector3.Distance(transform.postion, target) > range)
      {

      print("Out of Range");//太远啦

      return false; //确定该函数返回值是布尔变量。
      }




var hit : RaycastHit;
//check if there collision inbetween turret and target

//看turret的视线里是不是有别的物体,还是能看见玩家


if(Physics.Linecast(transform.position, target.position, hit))

{

       if(hit.collide.gameObject.tag != "layer")

       {

        print("Item in the way:" +hit.collide.gameObject.name);
        return false;

       }

       else

       {

        print("layer detected!");

        return ***e;

       }

}
return ***e;

}
如果发现RaycastHit侦测到了对象自己,就在属性的Layer里选“Ignor Raycast”

关于Quaternion.Slerp

static function Slerp (from : Quaternion, to : Quaternion, t : float) : Quaternion

意思是:Spherically interpolates from towards to by t.




3.如何让物件的分部分播放动画?比如让榴弹炮的炮管伸缩?


在脚本的最前面:
先加两个变量

var leftFlame : GameObject;

var rightFlame : GameObject;
然后把枪管的火焰attch到这两个变量开放的值上(直接拖)
在脚本的最后面:
InvokeRepeating("FalconAnimate", 0, 0.05);

//多长时间FalconAnimation这个函数会被执行
function FalconAnimate()
{
     if (leftFlame && rightFlame)

     {
          if(leftFlame.renderer.enabled)

           {

            leftFlame.renderer.enabled = false;

            rightFlame.renderer.enabled = ***e;

           }




           else

           {
            leftFlame.renderer.enabled = ***e;

            rightFlame.renderer.enabled = false;

           }

     }
     else

     {

         print("Effects on Turret not set!")

     }
}

4.为了让榴弹炮真正的在看到我的时候才射击,需要设定Turret的状态机。


在最前面加一个变量
static var mode = "idle";
在invoke之前加两个函数


function Attack()

{

      if(mode != "attack")

      {

      InvokeRepeating("FalconAnimate", 0, 0.05);

      mode = "attack";

      }






function Disengage()

{

      if(mode != "idle")

      {

       CancelInvoke();

       mode = "idle";

       leftFlame.renderer.enabled = false;

       rightFlame.renderer.enabled = false;

      }




}

别忘了在Awake里面加上以下代码:

leftFlame.renderer.enabled = false;

rightFlame.renderer.enabled = false;
这样榴弹炮就不会游戏一开始就自动开打了。


最后,为了触发Attack和Disengage这两个函数,到前面用新的函数替换掉原来相应的“Print”函数。










创建血槽系统




1.首先一点,创建一个血槽UI,方法是,呃,创建10个分别代表不同血量的图片……
2. 然后写一个脚本,写好后把他attach到player身上,然后在player的新组件里把相关的纹理关联上
var h00 : Texture2D;

var h10 : Texture2D;

var h20 : Texture2D;

var h30 : Texture2D;

var h40 : Texture2D;

var h50 : Texture2D;

var h60 : Texture2D;

var h70 : Texture2D;

var h80 : Texture2D;
static var HEALTH = 80;
function update()
{

var g_Health = gameObject.Find("g_Health");



      if(HEALTH > 70)

      {

      g_Health.guiTexture.texture = h80;

      return;

      }

      else if(HEALTH > 60)

      {

      g_Health.guiTexture.texture = h70;

      return;

      }



if(HEALTH > 50)

      {

      g_Health.guiTexture.texture = h60;

      return;

      }

      else if(HEALTH > 40)

      {

      g_Health.guiTexture.texture = h50;

      return;

      }

if(HEALTH > 30)

      {

      g_Health.guiTexture.texture = h40;

      return;

      }

else if(HEALTH > 20)

      {

      g_Health.guiTexture.texture = h30;

      return;

      }

if(HEALTH > 10)

      {

      g_Health.guiTexture.texture = h20;

      return;

      }

else if(HEALTH > 5)

      {

      g_Health.guiTexture.texture = h10;

      return;

      }

else if(HEALTH <= 0)

      {

      g_Health.guiTexture.texture = h00;

      return;

      }

}




3. 测试代码:
InvokeReapting("subtract", 2, 0.5);
function subtract()

{

      HEALTH -= 1;

      print("health is now:" +HEALTH);

}

3. 如何决定炮管是否对我造成伤害?计算角度:
var forward = transform.forward; //炮管的x方向

var targetDir = target.position - transform.position; //炮管指向目标(玩家)的方向

var angle = Vector3.Angle(targetDir, forward); //计算夹角

4. 好了,造成伤害的话,要干掉你的血,接上面的代码:
if(angle < 10.0)

{

      DoDamage

}

else

{
}
var damageTimer = 0.0; //人为设置伤害计时器,否则每帧都会造成伤害
function DoDamage()

{

      if(damageTimer = 0.0)

      {

       damageTimer = Time.time; //伤害计时器初始值与当前时间等同

      }

      if((damageTimer+0.05) > Time.time)

      {

       return;

      }

else

{

      Player.HEALTH -= 1;

      print(Player.HEALTH);//测试代码

      damageTimer = Time.time; //重置伤害计数器

}

}

5.最后,是如何触发结束画面的问题。还记得在Build Setting里设定不同Scene的tag数字吗?
也就是加一行代码:
else if(HEALTH <= 0)

{

g_Health.guiTexture.texture = h00;

Application.LoadLevel(0);// 如果死了,马上Load主菜单场景;

return;

}






创建大规模城市



1.在City Engine中创建城市,然后导入Unity中。这个引擎既可以手动创建城市群,也可以自动生成不同风格的城市(细节由用户决定,甚至可以自动生成交通信号灯,马路上的车流...)。



2. 如何自动生成纹理贴图?他介绍了一个插件叫做Filter Forge,他可以按照你的需求自动生成纹理,也可以制定纹理为法线贴图。



web3D纳金网www.narkii.com丰富多彩。

分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏0 支持支持0 反对反对0
回复

使用道具 举报

955

主题

164

听众

7万

积分

版主

Rank: 7Rank: 7Rank: 7

纳金币
59338
精华
28

活跃会员 荣誉管理 突出贡献 优秀版主 论坛元老

沙发
发表于 2012-8-23 10:53:17 |只看该作者
很详细的资料,值得收藏。
回复

使用道具 举报

498

主题

1

听众

1万

积分

资深设计师

Rank: 7Rank: 7Rank: 7

纳金币
13519
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

板凳
发表于 2012-8-24 19:16:42 |只看该作者
  好东西啊
回复

使用道具 举报

Zack    

459

主题

1

听众

5478

积分

高级设计师

Rank: 6Rank: 6

纳金币
5531
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

地板
发表于 2012-11-25 20:46:07 |只看该作者
学习了。谢谢!
回复

使用道具 举报

may    

8830

主题

80

听众

7万

积分

首席设计师

Rank: 8Rank: 8

纳金币
52320
精华
343

最佳新人 热心会员 灌水之王 活跃会员 突出贡献 荣誉管理 论坛元老

5#
发表于 2012-11-27 02:53:22 |只看该作者
lZ的回复很不错,支持!
回复

使用道具 举报

2206

主题

2

听众

3万

积分

资深设计师

Rank: 7Rank: 7Rank: 7

纳金币
32449
精华
23

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

6#
发表于 2012-11-29 11:29:10 |只看该作者
  不错不错,希望大家共同交流下知识~
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

关闭

站长推荐上一条 /1 下一条

手机版|纳金网 ( 闽ICP备08008928号

GMT+8, 2024-5-22 02:10 , Processed in 0.100713 second(s), 29 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部