2018-06-08 00:09:20 animalcoder 阅读数 5008
  • Unity3D实战入门之第三人称射击游戏(TPS)

    这是一套第三人称射击游戏开发的入门基础课程。 本课程以一款小型的第三人称射击游戏为案例,手把手教你如何搭建一款3D射击游戏的雏形。麻雀虽小,五脏俱全,这款小游戏难度不大,但第三人称射击游戏该有的模块、功能它都有涉及。通过案例游戏的开发,学习者可以对第三人称射击游戏入门,对后续复杂大中型3D游戏的开发有实际的借鉴意义。 这套课程,对初次接触3D射击类游戏的学习者而言,是一块极好的跳板。

    1755 人正在学习 去看看 伍晓波

参考:unity5实战第三章,慢慢学习

放两个东西

一个是玩家,主摄像机附在上面,配上Mouselook.cs,FPSInput.cs使其能响应键盘移动跟鼠标移动

Mouselook.cs,FPSInput.cs的实现前面有

一个是敌人,附上Reactive.cs受击反馈脚本,实现在下面

现在要做的是:按下左键,射出子弹,被射中区域显示球(子弹),被射中的敌人受击反馈消失


现在给玩家的主摄像机配上rayshoot.cs ,摄像机可以射出射线。

rayshoot.cs编写思路:

0.OnGUI()写个准星

1.响应左键,使用carema的API在摄像机位置产生射线

2.如果射中了(不一定是敌人)

    A.射中敌人,命令敌人调用受击反馈函数,敌人1s后消失

    B.射中别的,产生(子弹)小球附上射中的点上,子弹1s后消失

            由于需要延时消失,用协程来实现

实现如下

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class RayShooter : MonoBehaviour {
    private Camera _camera;
	// Use this for initialization
	void Start () {
        _camera = GetComponent<Camera>();
	}
	void OnGUI()
    {
        int size = 12;
        float posX = _camera.pixelWidth / 2 - size / 4;
        float posY = _camera.pixelHeight / 2 - size / 2;
        GUI.Label(new Rect(posX, posY, size, size), "*");
    }
	// Update is called once per frame
	void Update () {
        //响应左键
        if (Input.GetMouseButton(0)==true) {
            Vector3 point = new Vector3(_camera.pixelWidth / 2, _camera.pixelHeight/2, 0);
            Ray ray=_camera.ScreenPointToRay(point);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit))//hit就是被击中的目标
            {
                // Debug.Log(point);
                //获取打到的物体
                GameObject hitobj = hit.transform.gameObject;
                ReactiveTarget RT = hitobj.GetComponent<ReactiveTarget>();
                if (RT != null){
                    RT.Reacttohit();//调用敌人的被击反馈
                }
                else{
                    StartCoroutine(F(hit.point));//用协程造子弹,因为要编写子弹要1s后消失的效果
                }
            }
        }
	}
    private IEnumerator F(Vector3 pos)//协程
    {
        GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
        sphere.transform.position = pos;
        yield return new WaitForSeconds(1);
        Destroy(sphere);//1s后消失
    }
}

 敌人需要受击反馈,1.5s后消失,使用协程,ReactiveTarget.cs如下

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ReactiveTarget : MonoBehaviour {
    public void Reacttohit()
    {
        StartCoroutine(Die());
    }
    private IEnumerator Die()
    {
        this.transform.Rotate(-75, 0, 0);
        yield return new WaitForSeconds(1.5f);
        Destroy(this.gameObject);
    }
	// Use this for initialization
	void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
		
	}
}

2018-11-30 13:05:22 weixin_43435964 阅读数 522
  • Unity3D实战入门之第三人称射击游戏(TPS)

    这是一套第三人称射击游戏开发的入门基础课程。 本课程以一款小型的第三人称射击游戏为案例,手把手教你如何搭建一款3D射击游戏的雏形。麻雀虽小,五脏俱全,这款小游戏难度不大,但第三人称射击游戏该有的模块、功能它都有涉及。通过案例游戏的开发,学习者可以对第三人称射击游戏入门,对后续复杂大中型3D游戏的开发有实际的借鉴意义。 这套课程,对初次接触3D射击类游戏的学习者而言,是一块极好的跳板。

    1755 人正在学习 去看看 伍晓波

代码示例:


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class fpsShoot : MonoBehaviour {

private Camera _camera;
private void Start()
{
    _camera = GetComponent<Camera>();
}
private void Update()
{
    if(Input.GetMouseButtonDown(0))
    {
        Vector3 point = new Vector3(_camera.pixelWidth / 2, _camera.pixelHeight / 2, 0.0f);
        Ray ray = _camera.ScreenPointToRay(point);//从摄像头发一条射线到point
        RaycastHit hit;//存留第一个碰撞信息
        if(Physics.Raycast(ray,out hit))
        {
            Debug.Log("Hit" + hit.point);
        }
    }
}

}

2014-06-27 17:26:37 shiyigongteng 阅读数 2964
  • Unity3D实战入门之第三人称射击游戏(TPS)

    这是一套第三人称射击游戏开发的入门基础课程。 本课程以一款小型的第三人称射击游戏为案例,手把手教你如何搭建一款3D射击游戏的雏形。麻雀虽小,五脏俱全,这款小游戏难度不大,但第三人称射击游戏该有的模块、功能它都有涉及。通过案例游戏的开发,学习者可以对第三人称射击游戏入门,对后续复杂大中型3D游戏的开发有实际的借鉴意义。 这套课程,对初次接触3D射击类游戏的学习者而言,是一块极好的跳板。

    1755 人正在学习 去看看 伍晓波


本示例利用U3D2.5中的Island Demo项目为例,加入代码,显示Unity3D与Web之间的通信方法。运行环境为Unity4D 4.0

由我的导师进行总结,很棒!

 

1、Unity3D中设置

在U3D下建立空物体WebConnect,为其添加代码WebConnect.js

具体代码如下

WebConnect.js

//接收第一人称参数

var fpc:GameObject;

 

//从Web接收信息,设置当前相机

function SelectCamera(index:int)

{

       CameraSelect.currentCamera=index;

}

 

////从Web接收信息,设置第一称位置

function SetFpcPosition(posString:String)

{

       var pos:String[]=posString.Split(char.Parse(","));

       var x:int=parseInt(pos[0]);

       var y:int=parseInt(pos[1]);

       var z:int=parseInt(pos[2]);

      

       fpc.transform.position=Vector3(x,y,z);

}

 

给FPC第一称移动时添加代码,向Web传递信息

在第一人称的FPSWalker.JS代码添加下面代码,向Web发送当前位置信息

 

function FixedUpdate()

{

……

Application.ExternalCall("ShowPosition",transform.position.x,transform.position.z);

}

 

2、Web设置

 

主要代码如下

Web.html

Head头中添加脚本

<script type="text/javascript">

               function CameraSelect(camIndex)

                     {

                            u.getUnity().SendMessage("WebConnect","SelectCamera",camIndex);

                     }

                     function ShowPosition(x,z)

                     {

                            var pos=document.getElementById("position");

                            pos.innerHTML="当前位置,x="+x+",z="+z;

                     }

                     function SetFpcPosition(x,y,z)

                     {

                            u.getUnity().SendMessage("WebConnect","SetFpcPosition",x+","+y+","+z);

                     }

 </script>

Body中Html控件

<p class="header">我的海岛</p>

<p><a href="#" onclick="SetFpcPosition(500,200,500)">设置玩家位置</a></p>

<p>请选择

          <select id="camselect" onchange="CameraSelect(camselect.options.selectedIndex)">

            <option value=0 selected>主相机</option>

            <option value=1 >鸟群1</option>

            <option value=2 >鸟群2</option>                     

          </select>

</p>

<p>

        <div id="position">当前位置</div>

</p>

 

 

3、最后运行Web效果

2017-03-01 15:42:46 cbbbc 阅读数 1936
  • Unity3D实战入门之第三人称射击游戏(TPS)

    这是一套第三人称射击游戏开发的入门基础课程。 本课程以一款小型的第三人称射击游戏为案例,手把手教你如何搭建一款3D射击游戏的雏形。麻雀虽小,五脏俱全,这款小游戏难度不大,但第三人称射击游戏该有的模块、功能它都有涉及。通过案例游戏的开发,学习者可以对第三人称射击游戏入门,对后续复杂大中型3D游戏的开发有实际的借鉴意义。 这套课程,对初次接触3D射击类游戏的学习者而言,是一块极好的跳板。

    1755 人正在学习 去看看 伍晓波

解决什么问题?

动画分层可以用来解决什么样的问题呢?试想一下如果你要开发一款第三人称的射击游戏,那么肯定是希望身体的动画分为上下两部分,上方根据瞄准的位置和是否射击进行动画播放,下方根据移动播放动画。最好的例子就是Unity4.x自带的示例AngryBots了。

Avatar Mask

下面我们就使用Avatar Mask来实现人物在奔跑中招手的效果。

我们先添加一个人物到场景,同时为其添加一个Animator Controller并设定好跳转条件,如下:


接下来我们添加下面的脚本来控制动画的播放,对了为了不让角色因为播放动画而移动,记得把“Apply Root Motion”取消,方便我们查看动画播放的效果。

添加的脚本如下:

using UnityEngine;
using System.Collections;

public class MaskTest : MonoBehaviour
{
    private Animator _animator;

    void Start()
    {
        _animator = this.GetComponent<Animator>();
    }
    
    void Update()
    {
        if(Input.GetKeyDown(KeyCode.R))
        {
            _animator.SetBool("run", true);
        }
        if(Input.GetKeyUp(KeyCode.R))
        {
            _animator.SetBool("run", false);
        }

        AnimatorStateInfo state = _animator.GetCurrentAnimatorStateInfo(0);
        if(state.shortNameHash == Animator.StringToHash("Run") && Input.GetKeyDown(KeyCode.J))
        {
            _animator.SetTrigger("jump");
        }
    }
}

接下来我们希望按下空格时人物播放招手动画,但是跑动跳跃的动画不能停止播放。

我们需要添加一个新的Layer来管理招手动画的播放:


同时我们要配置好招手动画,这里的Idle可以不添加任何动画,仅仅表示空就可以了,同时还添加了一个Trigger“wave”表示进入招手动画的条件。

接下来我们设置一下该层,将其权重设置为1:


好了,我们修改一下代码试试看吧:

using UnityEngine;
using System.Collections;

public class MaskTest : MonoBehaviour
{
    private Animator _animator;

    void Start()
    {
        _animator = this.GetComponent<Animator>();
    }
    
    void Update()
    {
        if(Input.GetKeyDown(KeyCode.R))
        {
            _animator.SetBool("run", true);
        }
        if(Input.GetKeyUp(KeyCode.R))
        {
            _animator.SetBool("run", false);
        }

        AnimatorStateInfo state = _animator.GetCurrentAnimatorStateInfo(0);
        if(state.shortNameHash == Animator.StringToHash("Run") && Input.GetKeyDown(KeyCode.J))
        {
            _animator.SetTrigger("jump");
        }

        if(Input.GetKeyDown(KeyCode.Space))
        {
            _animator.SetTrigger("wave");
        }
    }
}


运行一下,发现当播放招手动画时其它动画都会停止,该怎么办呢?

答案是我们需要创建一个Avatar Mask来表示我们只希望播放动画的部分,即手部动画播放,其它部分不播放,在Project窗口右击创建一个Avatar Mask文件:


将右手部分以外的区别关闭即可:


这里说一个Transform这个选项,该选项是控制每个骨骼是否参与动画使用的,如果我们的人物有翅膀和尾巴之类的东西就要使用它了。

最后一步我们将这个Avatar Mask拖入Animator Controller的Wave层中即可:


再次运行下游戏,我们需要的效果是不是已经出来了呢。

设置解说

下面我们来详解一下Layer面板的设置:



Weight

动画层的权重,默认的Base Layer必须为1。如果设置为0则当前层的动画不会播放,1则会播放,0-1之间会采用类似融合的情况来播放动画,比如之前的招手的例子,如果设置为0.5则招手动画播放时手部只会抬到脖子附近。

Mask

动画遮罩,上方已经详解就不赘述。

Blending

动画混合方式:

  • Override:覆盖,表示当前层的动画会覆盖掉其它层的动画,比如招手播放时右手就不能播放其它的动画了;
  • Additive:添加,表示当前层的动画的量添加到其它层的动画,比如招手播放时,手部奔跑或站立的甩动也会保留;

Sync

开启了该功能后会多出一些选项,如下:


我们可以将该功能看做复制的功能。

Source Layer:指定当前层是哪个层的副本,设定后当前层的状态会和指定层完全一致或完全同步,但是我们可以修改某一个状态的动画。

该功能提供的效果就是两个状态一致的层可以做出一些不同的调整。

Timing:当前层和Souurce层同一个状态使用的动画时间长度不一致时,不勾选复制的层按Source层的时间播放(效果就是复制层动画可能会变快或变慢,Source层动画播放速度不变),勾选则Source层按复制层的时间播放(效果就是Source层动画可能会变快或变慢,复制层动画播放速度不变)。

IK Pass

表示启动IK动画,上一篇文章已经详解就不赘述。

天道酬勤,功不唐捐!

原文地址:http://www.cnblogs.com/hammerc/p/4832637.html

2017-07-07 20:30:50 a18779148177 阅读数 4028
  • Unity3D实战入门之第三人称射击游戏(TPS)

    这是一套第三人称射击游戏开发的入门基础课程。 本课程以一款小型的第三人称射击游戏为案例,手把手教你如何搭建一款3D射击游戏的雏形。麻雀虽小,五脏俱全,这款小游戏难度不大,但第三人称射击游戏该有的模块、功能它都有涉及。通过案例游戏的开发,学习者可以对第三人称射击游戏入门,对后续复杂大中型3D游戏的开发有实际的借鉴意义。 这套课程,对初次接触3D射击类游戏的学习者而言,是一块极好的跳板。

    1755 人正在学习 去看看 伍晓波

本篇文章基于上一篇文章: 使用unity3d搭建简单的场景以及第一人称角色的控制

1、给角色添加射击功能

通过射线射击,新建RayShooter.cs脚本,将该脚本添加到角色所包含的摄像机对象上,编辑代码。代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RayShooter : MonoBehaviour {

    private Camera _camera;

	// Use this for initialization
	void Start () {
        _camera = GetComponent<Camera>();    //访问相同对象上附加的其他组件
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;                   //隐藏屏幕中心的光标
	}

    void OnGUI()
    {
        int size = 12;
        float posX = _camera.pixelWidth / 2 - size / 4;
        float posY = _camera.pixelHeight / 2 - size / 2;
        GUI.Label(new Rect(posX, posY, size, size), "*");  //GUI.Label()在屏幕上显示文本
    }
	
	// Update is called once per frame
	void Update () {
        if (Input.GetMouseButtonDown(0))    //响应鼠标按键
        {
            Vector3 point = new Vector3(_camera.pixelWidth / 2, _camera.pixelHeight / 2, 0); //屏幕中心是宽高的一半
            Ray ray = _camera.ScreenPointToRay(point); //使用ScreenPointToRay()在摄像机所在位置创建射线
            RaycastHit hit;
            if(Physics.Raycast(ray, out hit))      //Raycast给引用的变量填充信息
            {
                GameObject hitObject = hit.transform.gameObject;
                ReactiveTarget target = hitObject.GetComponent<ReactiveTarget>();
                if(target != null)
                {
                    target.ReactToHit();
                }
                else
                {
                    StartCoroutine(SphereIndicator(hit.point));   //运行协程来响应击中
                }
            }
        }
	}

    private IEnumerator SphereIndicator(Vector3 pos)   //协程使用IEnumerator方法
    {
        GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
        sphere.transform.position = pos;
        yield return new WaitForSeconds(1);   //yield关键字告诉协程在何处暂停
        Destroy(sphere);             //移除GameObject并清除它占用的内存
    }
}

二、响应被击中

创建敌人预设,并新建响应被击中的脚本ReactiveTarget.cs,将改脚本组件添加到预设中,编辑脚本,代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ReactiveTarget : MonoBehaviour {

    public void ReactToHit()
    {
        WanderingAI behavior = GetComponent<WanderingAI>();
        if(behavior != null)              //检查角色是否有WanderingAI脚本
        {
            behavior.SetAlive(false);
        }
        StartCoroutine(Die());  //通过射击脚本调用的方法
    }

    private IEnumerator Die()
    {
        this.transform.Rotate(-75, 0, 0);    //推到命中物体,等待1.5秒后摧毁命中物体
        yield return new WaitForSeconds(0.5f);
        Destroy(this.gameObject);    //对象能销毁自己,就像一个分开独立的对象
     }

	// Use this for initialization
	void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
		
	}
}

三、让敌人走动起来

新建WanderingAI.cs脚本,添加该脚本组件到敌人对象中。代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class WanderingAI : MonoBehaviour {

    public float speed = 3.0f;        //移动速度的值
    public float obstacleRange = 5.0f;       //对墙壁做出反应的值
    private bool _alive;          //用于跟踪敌人是否存活
    [SerializeField] private GameObject fireballPrefab;
    private GameObject _fireball;



	// Use this for initialization
	void Start () {
        _alive = true;     //初始化值
	}
	
	// Update is called once per frame
	void Update () {
        if (_alive)           //只有当角色存活时才移动
        {
            transform.Translate(0, 0, speed * Time.deltaTime);   //每帧持续向前移动,不管旋转
            Ray ray = new Ray(transform.position, transform.forward);   //和角色相同位置的射线,并且方向相同
            RaycastHit hit;
            if (Physics.SphereCast(ray, 0.75f, out hit))            //使用沿着射线的长度发射射线
            {
                GameObject hitObject = hit.transform.gameObject;
                if(hitObject.GetComponent<PlayerCharacter>())
                {
                    if(_fireball == null)
                    {
                        _fireball = Instantiate(fireballPrefab) as GameObject;
                        _fireball.transform.position = transform.TransformPoint(Vector3.forward * 1.5f);
                        _fireball.transform.rotation = transform.rotation;
                    }
                }
                else if (hit.distance < obstacleRange)
                {
                    float angle = Random.Range(-110, 110);    //转向一个半随机的新方向
                    transform.Rotate(0, angle, 0);
                }
            }
        }
	}

    public void SetAlive(bool alive)     //公有方法允许外部代码影响alive的值
    {
        _alive = alive;
    }
}

四、自动生成敌人

创建一个空对象,新建一个SceneController.cs脚本用于实例化敌人预设,并添加到空对象中。代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SceneController : MonoBehaviour {

    [SerializeField] private GameObject enemyPrefab;  //序列化变量,用于链接预设对象
        private GameObject _enemy;    //一个私有变量,跟踪场景中敌人的实例

	// Use this for initialization
	void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
		if(_enemy == null)    //只用当场景中没有敌人时才产生一个新敌人
        {
            _enemy = Instantiate(enemyPrefab) as GameObject;      //这个方法复制了预设对象
            _enemy.transform.position = new Vector3(0, 1, 1);
            float angle = Random.Range(0, 360);
            _enemy.transform.Rotate(0, angle, 0);
        }
	}
}

五、让敌人主动发起攻击,角色响应攻击

创建制单预设,新建Fireball.cs脚本,用于敌人发起攻击,新建PlayerCharacter.cs脚本,用于角色响应攻击。代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Fireball : MonoBehaviour {

    public float speed = 10.0f;
    public int damage = 1;

	// Use this for initialization
	void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
        transform.Translate(0, 0, speed * Time.deltaTime);
	}

    void OnTriggerEnter(Collider other)
    {
        PlayerCharacter player = other.GetComponent<PlayerCharacter>();
        if(player != null)
        {
            player.Hurt(damage);
        }
        Destroy(this.gameObject);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerCharacter : MonoBehaviour {

    private int _health;

	// Use this for initialization
	void Start () {
        _health = 5;
	}
	
    public void Hurt(int damage)
    {
        _health -= damage;
        Debug.Log("Health: " + _health);
    }

	// Update is called once per frame
	void Update () {
		
	}
}



没有更多推荐了,返回首页