2015-09-01 17:41:17 wuyt2008 阅读数 1739

开始学习unity3d游戏制作。


using UnityEngine;

public class PlayerController : MonoBehaviour
{
	/// <summary>
	/// The current touch positon.
	/// </summary>
	private Vector3 cTP = new Vector3 ();
	/// <summary>
	/// The start touch position.
	/// </summary>
	private	Vector3 sTP = new Vector3 ();
	/// <summary>
	/// The start transform position.
	/// </summary>
	private Vector3 sTfP = new Vector3 ();
	
	/// <summary>
	/// Update is called once per frame
	/// </summary>
	private	void Update ()
	{
		if (Input.touchCount == 1) {
			//current Touch
			Touch cT = Input.touches [0];
			if (cT.phase == TouchPhase.Moved) {
				cTP = Camera.main.ScreenToWorldPoint (cT.position);
				transform.position = new Vector3 (
					cTP.x - sTP.x + sTfP.x,
					cTP.y - sTP.y + sTfP.y,
					sTfP.z);
			} else if (cT.phase == TouchPhase.Began) {
				sTP = Camera.main.ScreenToWorldPoint (cT.position);
				sTfP = transform.position;
			}
		}
	}
}


示例代码:http://download.csdn.net/detail/wuyt2008/9071187

2019-10-21 14:32:45 qq_34229678 阅读数 141

Unity3D 2D角色根据鼠标方向改变动画

本篇文章是通过动画控制器 (Animator) 中的混合树 (Blend Tree) 来实现2D角色看向鼠标方向,希望能对您有帮助。

还记得我曾经的毕设,是一款2D解谜游戏,游戏中的小人会根据鼠标位置看向不同的方向。那个时候我通过动画控制器 (Animator) 实现了这个功能,但这个方法给我造成了下图的困扰。。。
如此之多的状态让状态机一片混乱!
看,如此之多的状态让动画控制器 (Animator) 一片混乱!

由于游戏中玩家有待机、移动、死亡等状态,而每个状态又有四种朝向,这就使得动画控制器需要控制状态数乘 4 数量的状态,从而使得动画控制器 (Animator) 里一片混乱。

不过还好有混合树 (Blend Tree) ,它可以帮助我们更好的管理自己的动画。你只需要在动画控制器 (Animator) 中右键 -> Creat State -> From New Blend Tree 就能创建它。
无

因为我们要通过鼠标来控制它,所以要先在动画控制器 (Animator) 的 Parameters 窗口创建两个 Float 。(注意:这里的命名最好和我一样,不然用下面我给出的代码运行会报错)
无

双击你创建的混合树 (Blend Tree) 即可编辑它,将其 Blend Type 改为 2D Freeform Directional (当然你也可以试试其它选择,效果会有细微的差别),并在其 Parameters 中填写你刚才创建的两个 Float 的名称。(注意:本人使用的 Unity 版本为 2019.2 ,早期版本的 Blend Type 中可能没有我的选项,那就选 2D 即可)无

接下来,在 Motion 窗口加入四个方向的动画,并在其 Pos X 、 Pos Y 下输入如下值。
无

最后,在你动画控制器控制的角色或物体上加入脚本并写入如下代码。

    Animator myAnimator;//角色自身动画控制器 

    private void Start()
    {
        myAnimator = GetComponent<Animator>();//获取角色自身动画控制器
    }    
    
    private void Update()
    {
        PlayerLookMouse();//角色看向鼠标方向
    }    
    
    //角色看向鼠标方向
    void PlayerLookMouse()
    {
        //获取鼠标坐标
        Vector2 worldMousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);//获取鼠标的世界坐标
        Vector2 localMousePosition = transform.InverseTransformPoint(worldMousePosition);//获取鼠标对于自身的局部坐标
        
        //通过鼠标坐标改变动画方向
        myAnimator.SetFloat("MousePositionX", localMousePosition.x);
        myAnimator.SetFloat("MousePositionY", localMousePosition.y);
    }

运行,会发现角色或物体会根据鼠标方向改变动画。

2015-02-16 13:16:55 book_longssl 阅读数 1948



  1.创建一个项目
  2.将Camera设置为正交投影
  游戏的输出画面是通过摄像机所观察的场景来实现的,将场景呈现到2D的计算机屏幕上具有两种不同的投影方式:透视投影和正交投影,默认状态下是透视投影.
  透视投影
  

  正交投影
  

  3.添加相关对象模型
  移动摄像机物体,灯光到如下效果
  

  添加游戏物体移动超出边框的控制
  using UnityEngine;
  using System.Collections;
  public class Player:MonoBehaviour {
  public float playerSpeed;
  // Use this for initialization
  void Start () {
  }
  // Update is called once per frame
  void Update () {
  float amtToMove = Input.GetAxis("Horizontal")*Time.deltaTime*playerSpeed;
  gameObject.transform.Translate(Vector3.right*amtToMove);
  if(transform.position.x-7.5){
  //如果方块移动超出游戏窗体右边,方框将从左边窗口进入
  transform.position = new Vector3(5.25f,transform.position.y,transform.position.z);
  }
  if(transform.position.x5.25){
  //如果方块移动超出游戏窗体右边,方框将从左边窗口进入
  transform.position = new Vector3(-7.5f,transform.position.y,transform.position.z);
  }
  }
  }
  4.创建炮弹[create-Capsule]
  

  根据需要调整炮弹的大小


  选择炮弹模型,单机Component菜单,选择Physics-RigidBody,将炮弹设置为刚体,以便后面实现碰撞检测.
  为炮弹添加移动操作脚本
  using UnityEngine;
  using System.Collections;
  public class bulletTile : MonoBehaviour {
  public float bulletSpeed ;
  private Transform mytransform;
  // Use this for initialization
  void Start () {
  mytransform = gameObject.transform;
  }
  // Update is called once per frame
  void Update () {
  //定义炮弹移动速度
  float amtToMove = bulletSpeed * Time.deltaTime;
  //让炮弹垂直向上移动
  mytransform.Translate(Vector3.up * amtToMove);
  //如果炮弹移动超出游戏场景则销毁炮弹
  if(mytransform.position.y5.15){
  Destroy(this.gameObject);    //销毁当前对象
  }
  }
  }
  对象重用
  在Project中创建一个Prefab对象,然后将要重用的对象模型拖动到该Prefab对象上,即可实现模型对象的重用.
  发射子弹的实现
  在Player脚本中创建Prefab可重用对象实例
  using UnityEngine;
  using System.Collections;
  public class Player:MonoBehaviour {
  public float playerSpeed;
  public GameObject bulletPrefab;
  // Use this for initialization
  void Start () {
  }
  // Update is called once per frame
  void Update () {
  float amtToMove = Input.GetAxis("Horizontal")*Time.deltaTime*playerSpeed;
  gameObject.transform.Translate(Vector3.right*amtToMove);
  if(transform.position.x-7.5){
  //如果方块移动超出游戏窗体右边,方框将从左边窗口进入
  transform.position = new Vector3(5.25f,transform.position.y,transform.position.z);
  }
  if(transform.position.x5.25){
  //如果方块移动超出游戏窗体右边,方框将从左边窗口进入
  transform.position = new Vector3(-7.5f,transform.position.y,transform.position.z);
  }
  //获取发射器位置 发射器的正上方
  Vector3 position = new Vector3(transform.position.x,transform.position.y+transform.localScale.y/2.0f,transform.position.z);
  //按下空格键发射子弹
  if(Input.GetKeyDown("space")){
  //实例化一个炮弹对象
  Instantiate(bulletPrefab,position,Quaternion.identity);
  }
  }
  }
  

  拖动表示将属性实例化,因为我们脚本中定义的是public属性,在这里我们可以手动为public属性赋值,此时运行程序,用左右键控制发射器的移动,用space发射子弹.
  

  应用实例:
  游戏中声音的添加与控制
  支持的声音文件:*.aiff,*.wav,*.mp3,*.ogg
  .AIFF
  转换为无压缩音频导入,最适合短音效果。可以在编辑器中按需求压缩。
  .WAV
  转换为无压缩音频导入,最适合短音效果。可以在编辑器中按需求压缩
  .MP3
  转换成Ogg格式导入,最适合较长的音乐曲目。
  .OGG
  压缩音频格式(与iPhone设备和某些Android设备不兼容),最适合较长的音乐曲目。
  添加声音控制按钮,
  void OnGUI(){
  GUI.Button (new Rect (10,10,100,35), "播放音乐");
  GUI.Button (new Rect (10,60,100,35), "暂停播放");
  GUI.Button (new Rect (10,110,100,35), "停止音乐");
  }
  

  为按钮添加事件
  void OnGUI(){
  if(GUI.Button (new Rect (10,10,100,35), "播放音乐")){
  gameObject.audio.Play();
  }
  if(GUI.Button (new Rect (10,60,100,35), "暂停播放")){
  gameObject.audio.Pause().
  }
  if(GUI.Button (new Rect (10,110,100,35), "停止音乐")){
  gameObject.audio.Stop();
  }
  }
  5.为发射炮弹添加声音
  选中bulletPrefab,单机窗体中的Component-Audio-AudionSource
  

  



2018-10-22 13:50:04 o0xiaoyin0o 阅读数 1170

最近刚开始看unity3d游戏开发,感觉2d游戏似乎简单些,所以先从2d游戏入手试试看吧。

2d游戏大约要分为背景,角色(需要控制的己方角色car,敌机enemy,奖励物品prop),ui(分数显示,暂停继续等),音乐(背景音乐,攻击音乐,死亡音乐等)

大约长这样,emmm,原视频是主角是小飞机,背景是天空,也给有素材,但起初学习的时候想稍微更改下,就自己制作了小汽车主角和马路的背景,之后。。。觉得有点麻烦还是用了源素材,所以忽略这种突兀的感觉吧!

1.首先背景移动,需要两张背景交替向下移动,实现背景连续移动的效果。挂在背景图片上。

 

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

public class move : MonoBehaviour {        //背景移动

    public float speed = 2f;        //速度
    
    // Update is called once per frame
    void Update ()
    {
        this.transform.Translate (Vector3.down * speed * Time.deltaTime);        //每帧向下移动
        Vector3 postion = this.transform.position;
        if (postion.y <= -20.48f) {        //如果移动超过。。则向上移动,实现循环
            this .transform .position = new Vector3 (postion .x,postion .y + 20.48f*2,postion .z);
        }
    }
}

2.主角car(好吧假装是个飞机)实现发射子弹与主角的移动

创建两个空物体作为主角的子对象,放在子弹发射的起始位置,这样子弹就会相对主角的位置移动,只用实现子弹生成与移动就好了。为子弹添加2d碰撞检测器,当子弹碰到敌机时调用敌机的死亡脚本

子弹生成

public class gun : MonoBehaviour {

    public float rate = 0.1f;       //子弹生成时间间隔
    public float speed = 2f;        //子弹生成速度
    public GameObject bullet;
    // Use this for initialization


    public void fire ()
    {
        GameObject .Instantiate (bullet,transform .position ,Quaternion .identity );
    }
    public void openfire(){
        InvokeRepeating ("fire",1,rate);    //1秒后开始生成子弹,之后每隔rate个时间生成一个
    }
    public void stopfire ()
    {
        CancelInvoke ("fire");
    }

}

子弹移动

public class bullet : MonoBehaviour {    //子弹移动

    public float speed = 5f;


    void Update ()
    {
        transform.Translate (Vector3.up * speed * Time.deltaTime);
        if (transform.position.y >= 8.5f) {          //如果子弹移动出屏幕范围,销毁
            Destroy (this .gameObject );
        }
    }

    void OnTriggerEnter2D (Collider2D other)
    {
        if (other.tag == "enemy") {        //击中敌机,调用敌机的BeHit方法并将自身删除
            if (!other.GetComponent <enemy > ().isDeath) {
                other.gameObject.SendMessage ("BeHit");
                GameObject.Destroy (this.gameObject);
            }
        }
    }
}

将子弹生成脚本挂在空物体上,在Bullet后找到相应的子弹物体

将子弹移动脚本挂在子弹物体上

对于主角car,通过切换两张图片实现主角的动画(我记得sprite有个直接把2d序列帧图片放在一张图片上会自动裁切并且按序列帧播放的,但是没有尝试,之后再说吧),通过检测鼠标按下时的位置来对car进行移动(需要将屏幕坐标转换为世界坐标),判断car在世界坐标中的位置来控制car不移出背景。

public class car : MonoBehaviour
{

    public bool animation = true;
    //动画控制开关

    public int frameCountPersconds = 10;
    //每秒播放10帧

    public Camera TempC;

    public float timer = 0;
    //计时器

    public Sprite[] sprites;

    public float superGunTime = 10f;

    public gun gunRight;

    public gun gunLeft;

    private float resetSuperGunTime;

    private bool isMouseDown = false;

    private  Vector3 lastMoustPosition = Vector3.zero;

    //    private Transform hero;

    private int gunCount = 1;


    void Start ()
    {
//        spreteRender = this .GetComponent <SpriteRenderer >();
//        hero = GameObject .FindGameObjectWithTag ("hero").transform ;        //利用标签找物体
//        TempC  = this.GetComponent <Camera >();
        resetSuperGunTime = superGunTime;
        superGunTime = 0;
        gunLeft .openfire ();
    }

    void Update ()
    {
        if (animation) {        //切换两张图片实现动画
            timer += Time.deltaTime;        //计时
            int frameIndex = (int)(timer / (1f / frameCountPersconds));     //图片切换几次
            int frame = frameIndex % 2;     //将图片切换次数循环
            this.GetComponent <SpriteRenderer > ().sprite = sprites [frame];        //将图片于次数对应
        }
        if (Input.GetMouseButtonDown (0)) {        //检测鼠标是否按下
            isMouseDown = true;
        }
        if (Input.GetMouseButtonUp (0)) {
            isMouseDown = false;
//            lastMoustPosition = Vector3 .zero ;
        }
        if (isMouseDown && scoreShow .instance .gameState == GameState.Runing ) {    //鼠标按下且游戏是运行状态(非暂停)
            if (lastMoustPosition != Vector3.zero) {
        
                //    Camera .main .ScreenToWorldPoint (Input .mousePosition )    将屏幕坐标转化为世界坐标
//                Debug .Log ("Camera.main.ScreenToWorldPoint(Input .mousePosition"+TempC .ScreenToWorldPoint(new Vector3 ( //Input .mousePosition.x,Input .mousePosition .y,10.0f )));
                Vector3 offset = TempC.ScreenToWorldPoint (new Vector3 (Input.mousePosition.x, Input.mousePosition.y, 10f)) - lastMoustPosition;        //坐标不能为0
                transform.position = transform.position + offset;        //移动
                checkPosition ();
            }
            lastMoustPosition = TempC.ScreenToWorldPoint (new Vector3 (Input.mousePosition.x, Input.mousePosition.y, 10f));
        }
        superGunTime -= Time.deltaTime;
        if (superGunTime > 0) {     //切换超级子弹
            if (gunCount == 1) {
                transformToSuperGun ();
            }
        } else {
            if (gunCount == 2) {
                transformToNormalGun ();
            }
        }        
    }

    private void transformToSuperGun ()
    {
        gunCount = 2;
        gunRight.openfire ();
        gunLeft.stopfire ();

    }

    private void transformToNormalGun ()
    {
        gunCount = 1;
        gunRight.stopfire ();
        gunLeft.openfire ();

    }

    private void checkPosition ()           //检测car移动的位置防止移动出背景
    {
        //check -2.1<x<2.1
        //check -3.23<y<2.84
        Vector3 pos = transform.position;
        float x = pos.x;
        float y = pos.y;
        if (x < -2.1f) {
            x = -2.1f;
        }
        if (x > 2.1f) {
            x = 2.1f;
        }
        if (y < -3.23f) {
            y = -3.23f;
        }
        if (y > 2.84f) {
            y = 2.84f;
        }
        transform.position = new Vector3 (x, y, 0);
        
    }

    public void OnTriggerEnter2D (Collider2D collider)      //如果碰撞到标签是prop的物体,切换超级子弹(初始化superGunTime,并逐渐减少)
    {    
        if (collider.tag == "prop") {
            prop prop = collider.GetComponent <prop > ();
            if (prop.type == 0) {
                superGunTime = resetSuperGunTime;
                Destroy (collider .gameObject );
            }
        }
    }
}

  3.敌机与奖励物品生成和移动

创建空物体,放在屏幕外稍微靠上的部位用于敌机和奖励物品的生成。利用随机数控制敌机生成的位置

public class spawn : MonoBehaviour {        //敌机和奖励的生成

    public GameObject enemy0;
    public GameObject enemy1;
    public GameObject enemy2;

    public GameObject prop0;
    public GameObject prop1;

    public float rate0 = 1f;
    public float rate1 = 5f;
    public float rate2 = 8f;

    public float rateProp0 = 3f;
    public float rateprop1 = 5f;

    // Use this for initialization
    void Start () {
        InvokeRepeating ("createnemy0",1,rate0);
        InvokeRepeating ("createnemy1",3,rate1);
        InvokeRepeating ("createnemy2",5,rate2);

        InvokeRepeating ("creatprop0",5,rateProp0);
        InvokeRepeating ("creatprop1",8,rateprop1);
    }
    
    // Update is called once per frame
    void Update ()
    {
    }
    
    public void createnemy0(){
        float x0 = Random .Range (-2.3f,2.3f);
        GameObject .Instantiate (enemy0  ,new Vector3 (x0,this .transform .position .y,0),Quaternion .identity );
        }
    public void createnemy1(){
        float x1 = Random .Range (-2.2f,2.2f);
        GameObject .Instantiate (enemy1  ,new Vector3 (x1,this .transform .position .y,0),Quaternion .identity );
        }
    public void createnemy2(){
        float x2 = Random .Range (-1.8f,1.8f);
        GameObject .Instantiate (enemy2  ,new Vector3 (x2,this .transform .position .y,0),Quaternion .identity );
        }

    public void creatprop0(){
        float x0 = Random .Range (-2.2f,2.2f);
        GameObject .Instantiate (prop0  ,new Vector3 (x0,this .transform .position .y,0),Quaternion .identity );
        }
    public void creatprop1(){
        float x1 = Random .Range (-2.1f,2.1f);
        GameObject .Instantiate (prop1  ,new Vector3 (x1,this .transform .position .y,0),Quaternion .identity );
        }
}

奖励物品比较简单,只用移动,检测到于主角car碰撞后将自身删除就可以了

public class prop : MonoBehaviour {        //奖励物品移动

    public float speed = 1.5f ;
    public GameObject award;
    public int type = 1;
    public float posY;

    // Use this for initialization
    void Start () {
        
    }
    
    // Update is called once per frame
    void Update () {
        this .transform .Translate (Vector3 .down *speed *Time .deltaTime );
        if (this .transform .position .y <= posY ){
            Destroy (this.gameObject );
        }
    }
}

敌机的状态较为复杂,三种敌机分别设置不同的移动速度,有不同的hp值和分数,当子弹碰撞到敌机时切换敌机状态为BeHit状态,hp递减且播放受伤动画(不知道为什么这里的受伤动画一直没弄好)当hp为0时切换为toDie,调用isDeath方法并且增加分数。isDeath为true时播放死亡动画,动画播放完后删除此物体

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

public enum EnumyType{
        smallEnemy,
        middleEnemy,
        bigEnemy
}

public class enemy : MonoBehaviour {        

    public int hp = 1;
    public float speed = 2f;

    public int score = 100;

    public float posY;

    public EnumyType type =  EnumyType.smallEnemy ;

    public bool isDeath = false ;

    public Sprite [] explosionSprites;
    private float timer = 0;
    public int frameCountPersconds = 20;

    private  SpriteRenderer render;

    public float hitTimer = 0.2f;
    private float resetHitTime;
    public Sprite [] hitSprites;
    // Use this for initialization
    void Start () {
        render = this.GetComponent <SpriteRenderer>();

        resetHitTime  = hitTimer ;
        hitTimer = 0f;
    }
    
    // Update is called once per frame
    void Update ()
    {        //敌机移动
        this.transform.Translate (Vector3.down * speed * Time.deltaTime);
        if (transform.position.y <= posY) {
            Destroy (this.gameObject);
        }
        if (isDeath == true) {        //播放死亡动画

            timer += Time.deltaTime;
            int frameIndex = (int)(timer / (1f / frameCountPersconds));
            if (frameIndex >= explosionSprites.Length) {
                Destroy (this.gameObject);
            } else {
                render.sprite = explosionSprites [frameIndex];
            }        
        } 
//        else {        //播放受伤动画
//            if(type == EnumyType .middleEnemy || type == EnumyType .bigEnemy ){
//                if (hitTimer >0 ){
////                    Debug .Log ("hitTime" +hitTimer );
//                    hitTimer -=Time .deltaTime ;
////                    Debug .Log ("resetHitTime"+resetHitTime);
//                    int frameIndex = (int)((resetHitTime - hitTimer )/(1f/frameCountPersconds ));
//                    int frame = frameIndex %2;
////                    Debug .Log ("frame" + frame );
//                    render.sprite = hitSprites [frame];
//                }
//            }
//        }

    }

    public void BeHit ()        //被击中
    {
        hp -= 1;
        if (hp <= 0) {
            toDie ();
        }
//         else {
//            hitTimer = resetHitTime ;
//        }
    }
    private void toDie ()
    {    
        if (!isDeath) {
            isDeath = true;
            scoreShow .instance.score += score;
        }
    }
}

4.分数的记录显示与游戏的暂停

public enum GameState {
    Runing,
    Pause
}

public class scoreShow : MonoBehaviour {

    public static scoreShow instance ;

    public int score = 0;      //分数

    private GameObject findscrShow;
    private Text txt_score;

    public GameState gameState = GameState.Runing;


    // Use this for initialization
    void Start () {
        instance = this;
        //  txt_score = this.GetComponent<Text>();      //法1:获取到Text(手动挂在scroeShow下)
        findscrShow = GameObject.Find("scoreShow");      //法2  获取scroeShow后获取Text
        txt_score = findscrShow.GetComponent<Text>();
    }
    
    // Update is called once per frame
    void Update () {
        txt_score.text = "score:" + score;
    }

    public void transformGameState() {
        if (gameState == GameState.Runing ) {
            pauseGame();
        }
        else if (gameState==GameState.Pause ) {
            resumeGame();
        }
    }
    public void pauseGame() {
        Time.timeScale = 0;
        gameState = GameState.Pause;
    }
    public void resumeGame() {
        Time.timeScale = 1;
        gameState = GameState.Runing;
    }
}

暂停

public class gamePause : MonoBehaviour {

    private void OnMouseUpAsButton()
    {
        scoreShow .instance.transformGameState();
    }
}

 

2019-06-25 22:03:23 weixin_43149049 阅读数 263

之前我做2D游戏,需求是控制一个3D人物在2D地图上面,这里我在接受重力的情况下 使用力的模式来控制人物,
已经解决一些鬼畜问题,
可以较流畅的实现人物奔跑 按住shift快跑 左右移动 以及简单攻击
项目使用的2D地图是使用Ferr2D制作的 然后只需要加上BoxCollider即可在2D地图上面运行3D角色
脚本可以辨别斜坡的角度 解决了使用transform控制人物的情况下 下陡坡抖动的问题
以及基本的方向判断问题
在制作到一半的过程的时候要求将3D人物改为2D人物,我不舍之前的成果 所以将之前的做的导出一个包保存起来了。
有需要的人可以拿去学习或者使用 导入包之后 记得要新建一个空物体 然后挂上EquipDetect脚本
再将人物放到新建的Plane即可 人物只能够在按下AD键的时候才能移动 如果移动不明显 记得将人物的力弄大些
人物路径在:Assets\Supercyan Character Pack Free Sample\Prefabs\Simple Movement

链接:https://pan.baidu.com/s/15e7xz2p_U7YEkFggQ37pGQ 密码:wydg

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