2018-10-21 22:17:08 qq_41686773 阅读数 437

在此记录,以防遗忘。在尝试独立制作坦克大战时遇到了一些意想不到的问题,现做一下汇总。

一、Mesh Colider下的Convex选项

       Convex的中文意思是凸面体(有道词典)。Convex勾选后,unity会将碰撞体的凹凸面自动补平,这也是为什么勾选后,进不去模型的凹面区域的原因。参考百度知道(Unity3d 中MeshCollider组件下Convex勾选有什么用?)

二、取消自动渲染(unity版本号5.6.5f1)

      

      将Auto Generate勾选掉即可,但之后场景中的部分模型会有大面积的黑色,这时点击上图右侧的Generate Lighting按钮即可为场景渲染一次。

三、Awake函数和Start函数的区别、Update函数和FixedUpdate函数

       网上有很好的解释,这里引用一篇个人认为不错的文章。引用作者silent-bobo的文章    

       Update函数的执行次数会受电脑的性能影响。而FixedUpdate函数是按照一定时间周期执行的,不会受电脑性能影响。所以一般FixedUpdate函数用来进行一些物理模拟的语句。

四、物体的速度,角速度设置

        两者的设置均是Rigibody组件下的设置,均为Vector3类型数据。

五、Find函数_查找游戏物体

       相关解释参考作者Teng的世界的一篇相关文章。

六、物体销毁时实例化例子系统、播放声音

        由于执行GameObject.Destroy函数后整个物体都会消失,其中的声音组件或粒子系统也会瞬间消失导致无法正常使用。所以一般使用AudioSource.PlayClipAtPoint函数(在某位置播放声音)或GameObject.Instantiate()函数(物体实例化)来完成目标。

七、发送消息 SendMessage函数

       发送消息后会执行对应的物体的函数。

碰撞时如果对方的Tank标签是"Tank",那么就向对方发送TankDamage的消息,对方应有名为TankDamage方法。我会在以后的学习中更加深入了解SendMessage函数。

先记录这些吧。

2019-01-18 11:44:57 QIJINGBO123 阅读数 916

坦克大战学习笔记

1. 工程创建、素材导入;
2. 游戏中预制体的制作(环境预制体和动画预制体)
<1> 环境预制体制作:
游戏物体Player;
墙体Wall;
障碍物Obstacle;
水流River;
小草Gress;
老窝Family;
<2> 动画预制体:
坦克本身自带出场效果Shild;
坦克发射子弹效果Born;
坦克爆炸效果Explosion;

3. 控制游戏中Player的移动
<1> 获取水平和垂直方向上的变化;

float h = Input.GetAxis("Horizontal"); // 水平方向 返回值为1或-1
float v = Input.GetAxis(""Vertical); // 垂直方向

<2> 给游戏物体添加水平和垂直方向上的速度;

public float speed = 10.0f;
tansform.Translate(Vector3.right * h * speed * Time.deltaTime);// 水平
tansform.Translate(Vector3.up * v * speed *Time.deltaTime);// 垂直

4. 控制游戏在左右移动过程中,坦克图片(方向)切换
<1> 通过控制切换图片来控制坦克的方向移动;
a. 首先创建SpriteRenderer的对象sr;

private SpriteRenderer sr;

b. 然后通过sr来获取SpriteRenderer的引用;

sr = GetComponent<SpriteRenderer>();

c. 其次定义坦克需要切换的数组;

public Sprite[] tankSprite;

d. 将所需要的图片拖入Tank Sprite中;
e. 通过判断h/v的是否大于0来判断选用那张图片。

if(h > 0)
{
	// right    
    sr.sprite = tankSprite[1];
}
else if(h < 0)
{
	// left
    sr.sprite = tankSprite[3];
}

<2> 通过控制Z轴的方向来控制坦克的方位旋转。

5. 碰撞器的添加
发生碰撞的条件:
发生碰撞的两个物体,身上必须有碰撞器,其中一方身上必须要有刚体,并且要是能运动的。
碰撞器分类:2D碰撞器和3D碰撞器
<1> 给Player和环境预制体(除Gress外)添加Box Collider 2D碰撞器;
<2> 给Player添加刚体Rigidbody 2D;
<3> 设置Player游戏对象身上的Constraints的Z轴的旋转,防止发生旋转。

解决抖动问题:
c产生都抖动的问题
Player本身添加了刚体,发生碰撞后,物体之间会产生作用力,放在在Update下的话每帧的作用力是不同的,所以需要将Update的处理放置在FixedUpdate()函数中处理。

private void FixedUpdate() 
{
	// 监听水平和垂直方向上的位置
    float h = Input.GetAxisRaw("Horizontal");// 返回值是1或-1
    transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World);
    
    if(h > 0)
    {// right
        sr.sprite = tankSprite[1];
    }
    else if(h < 0)
    {// left
        sr.sprite = tankSprite[3];
    }

    float v = Input.GetAxisRaw("Vertical");
    transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);

    if (v > 0)
    {// right
        sr.sprite = tankSprite[0];
    }
    else if (v < 0)
    {// left
        sr.sprite = tankSprite[2];
    }
}

6. 移动优先级的添加,2D渲染层级问题
<1> 问题:玩家同时按住两个键的时候,Player会斜着走,如何处理该问题?
if(v!=0) return;
<2> 2D渲染层级问题
Player层级设置:
Sorting Layer 添加层级(大层级)
Order in Layer (小层级) 值越大越后渲染

2019-01-21 16:04:44 weixin_44587554 阅读数 214

3D模型物体的基础操作

1.点击模型在弹出的Import Settings 中设置Scale Factor的值,可进行对模型的缩放。
2.贴图可直接托入材质球。
3.用物体坐标系的方法前进(update)。
//设定速度
float speed = 0.5f;
if (Input.GetKey(KeyCode.W))
{
//欧拉角位置,确定一个新位置及角度
transform.eulerAngles = new Vector3(0, 0, 0);
transform.position += transform.forward * speed;
}
else if (Input.GetKey(KeyCode.S))
{
transform.eulerAngles = new Vector3(0, 180, 0);
transform.position += transform.forward * speed;
}
else if (Input.GetKey(KeyCode.A))
{
transform.eulerAngles = new Vector3(0, 270, 0);
transform.position += transform.forward * speed;
}
else if (Input.GetKey(KeyCode.D))
{
transform.eulerAngles = new Vector3(0, 90, 0);
transform.position += transform.forward * speed;
}
4.获取轴向:input.GetAxis(“Horizontal”)为获取横轴轴向的方法。意味着按下左键返回-1,按下右键返回1。Input.GetAxis(“Vertical”)为获取纵轴轴向方法,按上返回1,按下返回-1。
5.Time.deltaTime:指两次update执行的时间间隔。距离=速度*Time.deltaTime。
6.速度的方向。right、up、forward分别代表自身坐标系的X、Y、Z轴。移动位置 = 方向×速度。
7.以物体旋转角度具体代码
//旋转速度
float rotate = 40;
float x = Input.GetAxis(“Horizontal”);//Horizontal水平的
transform.Rotate(0, x * Time.deltaTime * rotate, 0);
//前进后退
float speed = 5f;
float y = Input.GetAxis(“Vertical”);//Vertical垂直的
Vector3 s = y * speed * transform.forward * Time.deltaTime;
transform.transform.position += s;

2014-04-29 02:38:19 wangbin_jxust 阅读数 3074

在着手研究Unity3D的游戏开发时,3D模型可以考虑从unity的assets store去获取,也可以从网上搜索下载,同时咱们也可以尝试下自己动手去做一些简单的模型。

这里就根据unity3d坦克大战教学视频,来制作一个简单的导弹模型:包含弹头,弹身,尾翼。其中,弹头,单身都是使用胶囊来实现,尾翼是使用多边形来实现。

一、制作弹体

打开3dmax后,右侧的工具栏中,选择“扩展基本体”,这时就可以看到可以选择的形状有异面体、环形结等多种。

      

选择胶囊,将光标放到原点处开始拖动,拖动出胶囊物体。

         

选中该胶囊,使用ctrl + c ,ctrl + v复制出两个胶囊,用来作为导弹的弹身。

      

  此时,我们就有三个大小一样的胶囊,使用w快捷键移动胶囊的位置到如上图所示。于是,最上面的胶囊我们可以用来作为弹头,中间的胶囊可以作为连接部分,最下面的胶囊则是弹身,通常是导弹的推进器。

为了让其更像导弹,我们将中间的胶囊缩小变长,最下面的胶囊变大一些。

                                                                                      

如此,基本的导弹形状就有了。

二、制作尾翼

其实尾翼的制作也很简单,就是向导弹的弹身部分添加四个多边形,同时做位移变换和旋转。

使用鼠标中轮将视图拖到最下面的胶囊部分,在右侧工具栏中选择球棱柱,同时参数中的边数设置为3.在弹身位置创建一个三边的球棱柱。

然后对该物体旋转和位移到如下图所示位置,在旋转和位移过程中,尽量使用前、顶、左视图来辅助进行,使位置和角度更加标准。

然后第一个尾翼就成型了,下面我们复制该尾翼,然后旋转90度,并放在弹身的另外一侧,就可以制作出第二个尾翼。此操作建议在顶视图中完成。接下来再复制第三个、第四个尾翼,分别放在弹身的四个侧面,导弹的形状就完成了。


三、填充纹理

我们这里对导弹进行简单的纹理填充。选中导弹的弹头,然后在顶部工具栏中,选中该材质编辑器,,在弹出的对话框中,选择材质颜色,并且运用到该物体上,如图:

色后,导弹的制作完成。

四、导出

为了让unity可以使用,我们这里导出格式为 fbx,导出步骤为:

选中所有的模型->点击左上角的按钮->导出->选择导出格式为fbx->导出选项->完成。由于我们这里没有动画,在导出选项中,可以不要选择动画项。

至此,一个简单的导弹模型已经制作成功。


这里附上该导弹模型的下载地址: http://download.csdn.net/download/wangbin_jxust/7269663

2016-07-03 12:28:11 a58425298 阅读数 657

花了接近两天,试着将已近有的资源用上,开发出了一个简单的游戏。小小地总结下,理清下思路。要制作一个游戏,前期的准备是必不可少的,比如声音资源(AudioClips),一些模型(Models),一些材质(Materials)都是需要制作完成的,想要成为一个独立的游戏开发制作者,必须学会这些东西,比如建模的3dMax,玛雅之类的一些常用的软件,还必须有相当的美术功底。不过,在公司里大家都各司其职吧。
有了这些东西,那么就是要实现程序控制的问题了。
首先是将游戏场景布置好,将坦克模型拖入游戏场景中去,将车位的行走特效放到坦克模型下,使得特效属于坦克。
然后用刚体组件,控制小车行走和转向。在坦克TankMove类中,实现以下代码来控制小车的运动:

        public int Speed=10;
        public int AngularSpeed=10;
         public int NumControl = 1;//增加编号来控制不同的坦克
        private Rigidbody _rigidboyCar;
        void start()
        {
             _rigidboyCar = GetComponent<Rigidbody>();
        }
        void Updata()
        {
            //得到键盘上的方向输入,值在-1到1之间变化
            //HorizontalPlayer1只能由这asdw几个键控制,HorizontalPlayer2由箭头方向键控制。详情见Eidit->project settings->input
            float keyNumQh = Input.GetAxis("VerticalPlayer" + NumControl);   
            //velocity施加速度,transform.forward前后移动
            _rigidboyCar.velocity = transform.forward * keyNumQh * Speed;
            //左右
            float keyNumZy = Input.GetAxis("HorizontalPlayer"+NumControl);
            _rigidboyCar.angularVelocity = transform.up*keyNumZy*AngularSpeed;
        }

然后在炮筒口位置添加一个空的游戏对象,以便在这里实例化子弹,,通过制定按键进行子弹的发射,在TankFire类中实现下面的代码:

`
    private Transform _firePosition;//子弹位置
    public GameObject Shell;//子弹
    public KeyCode Key = KeyCode.Space;//space按键控制发射
    public int FireSpeed = 15;//子弹速度

void Start ()
        {
            _firePosition = transform.Find("FirePositon");//得到指定名字游戏对象的位置
        }
        void Update () {
            if (Input.GetKeyDown(Key))//按键触发实例化
            {                
                  var shellFire= Instantiate(Shell, _firePosition.position, _firePosition.rotation) as GameObject ;//实例化,在指定位置创建子弹
                if (shellFire != null)
                    shellFire.GetComponent<Rigidbody>().velocity = transform.forward*FireSpeed;//通过刚体发射子弹
            }
        }

那么子弹可以发射了,但是发射出去并不爆炸,那么如何控制子弹的爆炸,以及触发爆炸特效?答案是,利用在子弹上添加Capule Collider组件,控制子弹的碰撞检测,另外给子弹添加刚体控件,控制子弹的下落,在ShellExplousion类中实现:

 public GameObject ShellExpol;//爆炸特效对象
 //碰撞检测
        public void OnTriggerEnter(Collider collider)
        {
            Instantiate(ShellExpol, transform.position, transform.rotation);//触发爆炸特效            
            Destroy(this.gameObject);//销毁子弹
            if (collider.tag=="TANK")   
            {
            //如果子弹碰撞到的是坦克的话,给坦克发送消息,控制血量
             collider.SendMessage("TakeDamege");
            }
        }

接下来,给坦克添加标签tag,以便于子弹判断子弹碰撞的是坦克,来控制坦克血量的扣减,最后坦克血量为0后,销毁目标坦克。在控制坦克血量的类TankHealth中,实现下面代码:

public float Hp = 100;
public GameObject TankExplosion;
[CanBeNull] public Slider HpSlider;//血条,其size为0到1,0为完全不填充,1为完全填充
 private const float HpTotal = 100;
  private float _size;//当前血量/100
  private void TakeDamege()
        {           
            if (Hp <= 0)
                return;
            Hp -= Random.Range(0, 20);//0到20随机扣血
            if (HpSlider != null) HpSlider.value = Hp / HpTotal;//血条减少
            if (Hp<=0)//死亡,tank爆炸
            {               
                Instantiate(TankExplosion, transform.position+Vector3.up, transform.rotation);//当前坦克的位置 
                Destroy(this.gameObject); 
            } 
        }

另外游戏中是两个坦克,如何控制相机跟随两个坦克呢?通过得到初始时,得到两个坦克之间与相机的偏移值,然后相机的位置等于偏移值加上两个坦克之间的值除2。在相机对象下,添加Follow类脚本(组件)中实现下面代码:

public Transform Player1;
public Transform Player2;
 private Vector3 _offset;
 private  Camera _camera;
  void Start ()
        {
            _offset = transform.position - (Player1.position + Player2.position)/2;//两个坦克间初始位置的偏移量,以后相机随时保持这个偏移量。
            _camera = GetComponent<Camera>();
        }
        void Update ()
        {
            if (Player1==null||Player2==null ) return;          ;
            transform.position = _offset + (Player1.position + Player2.position)/2;
            float distance = Vector3.Distance(Player1.position, Player2.position);
            float size = distance*0.58f;//两个坦克位置的距离和相机size的比例为0.4,可以使得相机size随着两者距离改变,从而可以看得清楚
            if (size>=10)
            {
                _camera.orthographicSize = size;
            }
            else
            {
                _camera.orthographicSize = 10;
            }
        }

到这里,基本结束。主要有几点要注意:

  • 要在哪个游戏对象上实现特点功能,就在相应的游戏对象上添加组件。比如控制坦克移动,就子在坦克游戏对象下添加控制运动的脚本。
  • 有的功能类型,需要重复使用的游戏对象,可以将游戏对象保存成prefab
  • transform类可以得到位置,刚体组件可以控制运动,
  • collider.SendMessage(“消息名”);可以实现类间的消息传递
  • 在声明public变量的时候,可以将相应对象拖入相应位置,实现初始化。
    还有一些细节,在以后慢慢继续学吧。。
没有更多推荐了,返回首页