2019-08-11 16:55:31 qq_39588003 阅读数 110

用一张小图片当做小地图,再用一个特别小的图片当做小地图上的人物,将两张图片赋值给相应变量。

using UnityEngine;
using System.Collections;

public class E4_10 : MonoBehaviour
{
    //大地图地形对象
    GameObject plane;
    //大地图主角对象
    GameObject cube;

    //大地图的宽度
    float mapWidth;
    //大地图的高度
    float mapHeight;
    //地图边界的检测数值
    float widthCheck;
    float heightCheck;

    //小地图主角的位置
    float mapcube_x = 0;
    float mapcube_y = 0;

    //GUI按钮是否被按下
    bool keyUp;
    bool keyDown;
    bool keyLeft;
    bool keyRight;

    //小地图的背景贴图
    public Texture map;
    //小地图的主角贴图
    public Texture map_cube;

    void Start()
    {
        //得到大地图对象
        plane = GameObject.Find("Plane");
        //得到大地图主角对象
        cube = GameObject.Find("Cube");
        //得到大地图默认宽度
        float size_x = plane.GetComponent<MeshFilter>().mesh.bounds.size.x;
        //得到大地图宽度的缩放比例
        float scal_x = plane.transform.localScale.x;
        //得到大地图默认高度
        float size_z = plane.GetComponent<MeshFilter>().mesh.bounds.size.z;
        //得到大地图高度缩放地理
        float scal_z = plane.transform.localScale.z;

        //原始宽度乘以缩放比例计算出真实宽度
        mapWidth = size_x * scal_x;
        mapHeight = size_z * scal_z;

        //越界监测的宽度
        widthCheck = mapWidth / 2;
        heightCheck = mapHeight / 2;

        check();
    }

    void OnGUI()
    {
        keyUp = GUILayout.RepeatButton("向前移动");

        keyDown = GUILayout.RepeatButton("向后移动");

        keyLeft = GUILayout.RepeatButton("向左移动");

        keyRight = GUILayout.RepeatButton("向右移动");

        //绘制小地图背景
        GUI.DrawTexture(new Rect(Screen.width - map.width, 0, map.width, map.height), map);
        //绘制小地图上的“主角”
        GUI.DrawTexture(new Rect(mapcube_x, mapcube_y, map_cube.width, map_cube.height), map_cube);
    }

    void FixedUpdate()
    {
        if (keyUp)
        {
            //向前移动
            cube.transform.Translate(Vector3.forward * Time.deltaTime * 5);
            check();
        }

        if (keyDown)
        {
            //向后移动
            cube.transform.Translate(-Vector3.forward * Time.deltaTime * 5);
            check();
        }

        if (keyLeft)
        {
            //向左移动
            cube.transform.Translate(-Vector3.right * Time.deltaTime * 5);
            check();
        }

        if (keyRight)
        {
            //向右移动
            cube.transform.Translate(Vector3.right * Time.deltaTime * 5);
            check();
        }
    }

    //越界检测
    void check()
    {
        //得到当前主角在地图中的坐标
        float x = cube.transform.position.x;
        float z = cube.transform.position.z;

        //当控制主角超过地图范围时,重新计算主角坐标
        if (x >= widthCheck)
        {
            x = widthCheck;
        }
        if (x <= -widthCheck)
        {
            x = -widthCheck;
        }
        if (z >= heightCheck)
        {
            z = heightCheck;
        }
        if (z <= -heightCheck)
        {
            z = -heightCheck;
        }

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

        //根据比例计算小地图“主角”的坐标
        mapcube_x = (map.width / mapWidth * x) + ((map.width / 2) - (map_cube.width / 2)) + (Screen.width - map.width);
        mapcube_y = map.height - ((map.height / mapHeight * z) + (map.height / 2));
    }
}

2016-07-11 14:12:15 axlxzero 阅读数 2803

快要一个月没有更新了,这段时间也没闲着。今天就把这段时间学到的东西稍微总结一下。

前段时间开始看一些实战开发的内容和教程。一些是来自于麦子学院的视频,一些来自于蛮牛教育,还有一部分官方教学视频。最终选择试着跟着官方的教程,尝试敲一次这个叫做拾荒者的官方示例。

过程中遇到了许多之前不明白的知识,所以虽然代码量不是很大,但是仍然消耗了大量的时间用于查询其中一些使用的方法和技巧。

最终当然是仿照着实例成功地将游戏做了出来(虽然其中大部分东西只要跟着敲都问题不大。)

以下我将一些自己的见解以注释的形式写入了代码中。

首先是一个叫做BoardMannager的脚本,这个脚本用于生成每张地图。由于游戏是设计为一个Roguelike类型的游戏的,那么随机生成的地图一定是必不可少的。

using UnityEngine;
using System; //为了使用其中的Serializable
using System.Collections.Generic;
using Random = UnityEngine.Random;

public class BoardMannager : MonoBehaviour {

    [Serializable]//序列化,<span style="font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; line-height: 25.2px;"><span style="font-size:10px;">使得变量可以被Inspector界面获得</span></span>
    public class Count //之后用于存储随机生成最小数量和最大数量的值
    {
        public int minimum;
        public int maximum;
        public Count(int min,int max)
        {
            minimum = min;
            maximum = max;
        }
    }

    public int columns = 8;
    public int rows = 8;
    public Count wallCount = new Count(5, 9);
    public Count foodCount = new Count(1, 5);
    public GameObject exit;
    public GameObject[] floorTiles;
    public GameObject[] wallTiles;
    public GameObject[] foodTiles;
    public GameObject[] enemyTiles;
    public GameObject[] outerWallTiles;

    private Transform boardHolder;//将所有通过代码生成的对象整合在boardHolder中
    private List<Vector3> gridPositions = new List<Vector3>();//存储网格位置信息

    void InitialiseList()
    {
        gridPositions.Clear();

        for (int x = 1; x < columns-1; x++)
        {
            for (int y = 1; y < rows-1; y++)
            {
                gridPositions.Add(new Vector3(x, y, 0f));//通过二重循环获得整个网格的位置
            }
        }
    }

    void BoardSetup()//生成外墙和场景内的地面
    {
        boardHolder = new GameObject("Board").transform;
        for (int x = -1; x < columns + 1; x++)
        {
            for (int y = -1; y < rows + 1; y++)
            {
                GameObject toInstantiate = floorTiles[Random.Range(0,floorTiles.Length)];
                if (x==-1|| x==columns||y==-1||y==rows)//判断是否是外墙位置
                {
                    toInstantiate=outerWallTiles[Random.Range(0,outerWallTiles.Length)];
                }
                GameObject instance = Instantiate(toInstantiate, new Vector3(x, y, 0f), Quaternion.identity) as GameObject;//prefab实例化
                instance.transform.SetParent(boardHolder); //将实例化的对象放到board中
            }
        }
    }

    Vector3 RandomPosition() //随机获取一个地图内的位置
    {
        int randomIndex = Random.Range(0, gridPositions.Count);
        Vector3 randomPosition = gridPositions[randomIndex];
        gridPositions.RemoveAt(randomIndex);
        return randomPosition;
    }


    void LayoutObjectAtRandom(GameObject[] tileArray, int minimum, int maxmum)  //将物品在地图中实例化
    {
        int objectCount = Random.Range(minimum,maxmum+1);

        for (int i = 0; i < objectCount; i++)
        {
            Vector3 randomPosition = RandomPosition();
            GameObject tileChoice = tileArray[Random.Range(0, tileArray.Length)];
            Instantiate(tileChoice,randomPosition,Quaternion.identity);
        }
    }

    public void SetupScene(int level) //调用之前的函数,完成一张地图的生成
    {
        BoardSetup();
        InitialiseList();
        LayoutObjectAtRandom(wallTiles, wallCount.minimum, wallCount.maximum);
        LayoutObjectAtRandom(foodTiles, foodCount.minimum, foodCount.maximum) ;
        int enemyCount = (int)Mathf.Log(level,2f);
        LayoutObjectAtRandom(enemyTiles, enemyCount, enemyCount);
        Instantiate(exit, new Vector3(columns - 1, rows - 1, 0f), Quaternion.identity);
        
    }
}

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


public class GameManager : MonoBehaviour {
//GameManager脚本主要用于管理整个的逻辑运行
    public float levelStartDelay = 2f;
    public float turnDelay = .1f;
    public static GameManager instance = null;//单例设计,保证在游戏运行中永远只有一个GameManager
    public BoardMannager boardScript;
    public int platerFoodPoints = 100;
    [HideInInspector]public bool playersTurn = true;

    private Text levelText;
    private GameObject levelImage;
    private int level = 1;
    private List<Enemy> enemies;
    private bool enemiesMoving;
    private bool doingSetup;


    void Awake() {
        if (instance==null)
        {
            instance = this;
        }
        else if (instance!=null)
	            Destroy(gameObject);//单例设计部分
        DontDestroyOnLoad(gameObject);
        enemies=new List<Enemy>();
        boardScript=GetComponent<BoardMannager>();//获取boardMannager脚本
        InitGame();    
    }

    private void OnLevelWasLoaded(int index)
    {
        level++;
        InitGame();
    }

    void InitGame() {
        doingSetup = true;
        levelImage = GameObject.Find("LevelImage");
        levelText = GameObject.Find("LevelText").GetComponent<Text>();
        levelText.text = "Day " + level;
        levelImage.SetActive(true);
        Invoke("HideLevelImage", levelStartDelay); //UI部分,显示第几日、显示黑色的背景等等

        enemies.Clear();
        boardScript.SetupScene(level); //调用BoardMannager生成新地图
    
    }

    private void HideLevelImage()
    {
        levelImage.SetActive(false);
        doingSetup = false;
    }
    IEnumerator MoveEnemies( )
    {
        enemiesMoving = true;
        yield return new WaitForSeconds(turnDelay);
        if (enemies.Count==0)
        {
            yield return new WaitForSeconds(turnDelay);
        }
        for (int i = 0; i < enemies.Count; i++)
        {
            enemies[i].MoveEnemy();
            yield return new WaitForSeconds(enemies[i].moveTime);
        }
        playersTurn = true;
        enemiesMoving = false;
    }

    public void AddEnemyToList(Enemy script)
    {
        enemies.Add(script);
    }


    public void GameOver()
    {
        levelText.text = "After " + level + " days,you starved.";
        levelImage.SetActive(true);
        enabled = false; //游戏结束时显示的UI
    }
	
	void Update () {
        if (playersTurn || enemiesMoving||doingSetup)
            return;
        StartCoroutine(MoveEnemies());
	
	}
}
通过以上两段脚本,能够实现地图的生成、游戏关卡的管理、以及一些简单的GUI的显示与关闭,接下来则是用于控制角色与敌人的脚本。

首先是用于可移动物体的基类MovingObject:

using UnityEngine;
using System.Collections;

public abstract class MovingObject : MonoBehaviour {
    public float moveTime = .1f;
    public LayerMask blockingLayer;
    
    public BoxCollider2D boxCollider;
    private Rigidbody2D rb2D;
    private float inverseMoveTime;
	
	protected virtual void Start () {
        boxCollider = GetComponent<BoxCollider2D>();
        rb2D = GetComponent<Rigidbody2D>();
        inverseMoveTime = 1f / moveTime;
	}
    protected bool Move(int xDir, int yDir, out RaycastHit2D hit)//通过传入两个坐标值与碰撞检测来返回能否进行移动
    {<span style="white-space:pre">	</span>
        Vector2 start = transform.position;
        Vector2 end = start + new Vector2(xDir, yDir);

        boxCollider.enabled = false;

        hit = Physics2D.Linecast(start,end,blockingLayer);//使用射线碰撞检测
        boxCollider.enabled = true;
        if (hit.transform==null)
        {
            StartCoroutine(SmoothMovement(end));
            return true;
        }
        return false;
    }

    protected IEnumerator SmoothMovement(Vector3 end)
    {
        float sqrRemainingDistance = (transform.position - end).sqrMagnitude;
        //sqrMagnitude用于计算向量长度的平方,其效率比计算长度高
        while (sqrRemainingDistance>float.Epsilon)//Epsilon表示一个极小的数
        {
            Vector3 newPosition = Vector3.MoveTowards(rb2D.position, end, inverseMoveTime * Time.deltaTime);
            rb2D.MovePosition(newPosition);
            sqrRemainingDistance = (transform.position - end).sqrMagnitude;
            yield return null;
        }
    }

    protected virtual void AttemptMove<T>(int xDir, int yDir) //使用泛型T,在子类中可以指定不同的对象
        where T : Component
    {
        RaycastHit2D hit;
        bool canMove = Move(xDir,yDir,out hit);
        if (hit.transform==null)
        {
            return;
        }
        T hitComponent = hit.transform.GetComponent<T>();//使用泛型T作为一个公共的方法
        if (!canMove && hitComponent != null)
            OnCantMove(hitComponent);
    }

    protected abstract void OnCantMove<T>(T component)
        where T : Component;

}
接下来是继承自MovingObject的子类Player和Enemy

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class Player : MovingObject{

    public int wallDamage = 1;
    public int pointsPerFood = 10;
    public int pointsPerSoda = 20;
    public float restartLevelDelay = 1f;
    public Text foodText;
    public AudioClip moveSound1;
    public AudioClip moveSound2;
    public AudioClip eatSound1;
    public AudioClip eatSound2;
    public AudioClip drinkSound1;
    public AudioClip drinkSound2;
    public AudioClip gameOverSound;

    private Animator animator;
    private int food;
    private Vector2 touchOrigin = -Vector2.one;
	protected override void Start () {
        animator = GetComponent<Animator>();//获取Animator以便更改Trigger
        food = GameManager.instance.platerFoodPoints;//获取食物可增加的点数
        foodText.text = "Food: " + food;//更新UI
        base.Start();

	}
    private void OnDisable()
    {
        GameManager.instance.platerFoodPoints = food;
    }
    protected override void AttemptMove<T>(int xDir, int yDir)
    {//重写父类中的移动方法
        food--;//每移动一次食物值减一
        foodText.text = "Food: " + food;//更新UI
        base.AttemptMove<T>(xDir, yDir);//调用父类中的移动方法
        RaycastHit2D hit;
        if (Move(xDir,yDir,out hit))
        {
            SoundManager.instance.RandomizeSfx(moveSound1, moveSound2);//如果移动成功,播放移动音效
        }
        CheckIfGameover();
        GameManager.instance.playersTurn = false;
    }

    private void CheckIfGameover()
    {//检测游戏是否结束,如果food小于等于0则结束,显示UI播放音效
        if (food <= 0)
        {
            SoundManager.instance.PlaySingle(gameOverSound);
            SoundManager.instance.musicSource.Stop();
            GameManager.instance.GameOver();
        }

            
    }
    protected override void OnCantMove<T>(T component)
    {//重写父类中的OnCantMove,可以对墙造成伤害,后见Wall类脚本
        Wall hitWall = component as Wall;
        hitWall.DamageWall(wallDamage);
        animator.SetTrigger("PlayerChop");//通过SetTrigger播放Chop的动画
    }
    private void Restart()
    {
        Application.LoadLevel(Application.loadedLevel);
    }
    public void LoseFood(int loss)
    {//受到攻击时减少food值,播放音效,更新UI
        animator.SetTrigger("PlayerHit");
        food -= loss;
        foodText.text = "-" + loss + "Food: " + food;
        CheckIfGameover();
    }
    private void OnTriggerEnter2D(Collider2D other)
    {//碰撞物体发生的事件,如果是Exit进入下一关,如果是Food或者Soda,增加food值,播放音效更新UI
        if (other.tag == "Exit")
        {
            Invoke("Restart", restartLevelDelay);
            enabled = false; 
        }
        else if (other.tag == "Food")
        {
            food += pointsPerFood;
            SoundManager.instance.RandomizeSfx(eatSound1, eatSound2);
            foodText.text = "+" + pointsPerFood + "Food: " + food;
            other.gameObject.SetActive(false);
        }
        else if (other.tag == "Soda")
        {
            food += pointsPerSoda;
            SoundManager.instance.RandomizeSfx(drinkSound1, drinkSound2);
            foodText.text = "+" + pointsPerSoda + "Food: " + food;
            other.gameObject.SetActive(false);
        }
        
    }
	
	void Update () {
        if (!GameManager.instance.playersTurn) return;
        int horizontal = 0;
        int vertical = 0;
    #if UNITY_STANDALONE||UNITY_WEBPLAYER //多平台操控,如果是PC或者WEBPALYER可以直接使用键盘WSAD或者方向键操作
        horizontal = (int)Input.GetAxisRaw("Horizontal");
        vertical = (int)Input.GetAxisRaw("Vertical");
        if (horizontal != 0)
            vertical=0;
        
    #else
        if (Input.touchCount>0) //如果是手机端则可以使用滑动触摸屏的方法进行操作
	    {
		 Touch myTouch=Input.touches[0];
            if (myTouch.phase==TouchPhase.Began)
	    {
		    touchOrigin=myTouch.position;
	    }
            else if (myTouch.phase==TouchPhase.Ended&&touchOrigin.x>=0)
	    {
		     Vector2 touchEnd=myTouch.position;
                float x=touchEnd.x-touchOrigin.x;
                float y=touchEnd.y-touchOrigin.y;
                touchOrigin.x=-1;
                if(Mathf.Abs(x)>Mathf.Abs(y))
                    horizontal=x>0?-1:1;
                else
                    vertical=y>0?-1:1;
	    }
	}
#endif
        if (horizontal != 0 || vertical != 0)
            AttemptMove<Wall>(horizontal,vertical);
	}
}
using UnityEngine;
using System.Collections;

public class Enemy : MovingObject {
//同样继承自MovingObject类
    public int playerDamage;
    private Animator animator;
    private Transform target;
    private bool skipMove;
    public AudioClip enemyAttack1;
    public AudioClip enemyAttack2;


	protected override void Start () {
        GameManager.instance.AddEnemyToList(this);
        animator = GetComponent<Animator>();
        target=GameObject.FindGameObjectWithTag("Player").transform;
        base.Start();
    }

    protected override void AttemptMove<T>(int xDir, int yDir)
    {
        if (skipMove)
        {
            skipMove = false;
            return;
        }
        base.AttemptMove<T>(xDir, yDir);
        skipMove = true;

    }

    public void MoveEnemy()
    {
        int xDir = 0;
        int yDir = 0;
        if (Mathf.Abs(target.position.x - transform.position.x) < float.Epsilon)//先判断敌人与玩家X轴之间是否相差,如果相差先移动X方向
        {
            yDir = target.position.y > transform.position.y ? 1 : -1; //判断移动向玩家的方向

        }
        else
            xDir = target.position.x > transform.position.x ? 1 : -1; //同理的判断Y轴移动的方向
        AttemptMove<Player>(xDir, yDir); //传入泛型<Player>
    }

    protected override void OnCantMove<T>(T component)
    {
        Player hitPlayer = component as Player;
        animator.SetTrigger("enemyAttack");//播放Attack动画
        hitPlayer.LoseFood(playerDamage); //攻击使得玩家减少food值
        SoundManager.instance.RandomizeSfx(enemyAttack1, enemyAttack2);
    }
}
接下来是墙的脚本Wall
using UnityEngine;
using System.Collections;

public class Wall : MonoBehaviour {

    public Sprite dmgSprite;
    public int hp = 4;
    public AudioClip chopSound1;
    public AudioClip chopSound2;
    private SpriteRenderer spriteRenderer;
	
	void Awake () 
    {   
        spriteRenderer=GetComponent<SpriteRenderer>();
	
	}

    public void DamageWall(int loss)
    {
        SoundManager.instance.RandomizeSfx(chopSound1, chopSound2);
        spriteRenderer.sprite = dmgSprite;
        hp -= loss;
        if (hp <= 0)//每堵墙有4点生命值,当生命值为0时就会被设置为Disable
            gameObject.SetActive(false);
    }
}
using UnityEngine;
using System.Collections;
 //SoundManager类用于管理游戏中会出现的背景音乐以及音效
public class SoundManager : MonoBehaviour {
    public AudioSource efxSource;
    public AudioSource musicSource;
    public static SoundManager instance = null;

    public float lowPitchRange = .95f;
    public float highPitchRange = 1.05f;
	// Use this for initialization
	void Awake () {
        if (instance == null)
            instance = this;
        else if (instance != this)
            Destroy(gameObject);
        DontDestroyOnLoad(gameObject);
	
	}
    public void PlaySingle(AudioClip clip)
    {
        efxSource.clip = clip;
        efxSource.Play();
    }

    public void RandomizeSfx(params AudioClip[] clips)
    {
        int randomIndex = Random.Range(0, clips.Length);
        float randomPitch = Random.Range(lowPitchRange, highPitchRange);
        efxSource.pitch = randomPitch;
        efxSource.clip = clips[randomIndex];
        efxSource.Play(); 
    }

	
}
using UnityEngine;
using System.Collections;
//最后将Loader脚本放在MainCamera上,实现开始游戏
public class Loader : MonoBehaviour {
    public GameObject gameManager;
    void Awake()
    {
        if (GameManager.instance == null)
            Instantiate( gameManager);
    }
}








2018-11-23 10:00:49 qq_42292831 阅读数 4128

Scripts:

1> Camera 视角跟随(offset)

2> WSAD (方向键)控制角色移动

3> Click to shoot 单击发射子弹

4> Animation_Loop 动画循环播放

************************************************************************************************************************************

 

一:效果实现

 

 

二:Scripts

1> Camera 视角跟随(offset)

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

public class CameraFollowTarget : MonoBehaviour {

    public Transform Succubus;
    public Vector3 offset;
	// Use this for initialization
	void Start () {
        offset = transform.position - Succubus.position;
	}
	
	// Update is called once per frame
	void Update () {
        transform.position = offset + Succubus.position;
	}
}

 解析:

在Start()函数内部给offset初始化偏移量坐标,相机的坐标-人物的坐标;

然后在Update()更新函数中不断对相机的位置坐标进行更新(人物移动后的坐标+偏移量),

人物的移动可以另外附加脚本进行操作,这里会获取即时的人物坐标来对相机的位置进行赋值。

额外解法:

可以直接将相机物件拖到人物物件下即可(将其作为人物物件的子物件)

 

2> WSAD (方向键)控制角色移动

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

public class BirdMovement : MonoBehaviour {

    public float speed_wsad = 20;
    public float speed_mouse = 20;

    // Use this for initialization
    void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        float d = Input.GetAxis("Mouse ScrollWheel");
        d = d * speed_mouse;
        this.transform.Translate(new Vector3(h, v, d) * Time.deltaTime * speed_wsad);    
    }
}

解析:

这里的WSAD和键盘的上下左右有一致的效果,这里不用去监测WSAD按键的按下,

可以通过另外一种方式来进行移动操作 Input.GetAxis("Horizontal");

 

3> Click to shoot 单击发射子弹

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

public class BirdMovement : MonoBehaviour {

    public float speed = 20;
    public GameObject bullet;

    // Use this for initialization
    void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
        if (Input.GetMouseButtonDown(0))
        {
            //GameObject b = GameObject.Instantiate(this.gameObject, transform.position, transform.rotation);    //暴力分裂效果  transform.position

            GameObject b = GameObject.Instantiate(bullet, new Vector3(transform.position.x, transform.position.y + 2,transform.position.z), transform.rotation);
            Rigidbody rgd = b.GetComponent<Rigidbody>();
            rgd.velocity = this.transform.forward * speed;
        }   
    }
}

解析:

获取子弹bullet对象,在鼠标左键按下的时候实例化该对象,并为对象赋予forward方向初速度; 

 

4> Animation_Loop 动画循环播放

(选中动画 -> Wrap Mode -> Loop)

 

 

 

 

2016-10-05 21:08:55 Acmer_Sly 阅读数 6740

[Unity3D]预设Prefab与实例Instantiate的基本使用

转载自  dengqingwu   http://www.360doc.com/content/13/0718/21/8378920_300921265.shtml

简介:在Unity3D的工程建设中,Prefabs(预设)是最非常用的一种资源类型,是一种可被重复使用的游戏对象。

特点1它可以被置入多个场景中,也可以在一个场景中多次置入。

特点2:当你在一个场景中增加一个Prefabs,你就实例化了一个Prefabs。

特点3:所有Prefabs实例都是Prefab的克隆,所以如果实在运行中生成对象会有(Clone)的标记。

特点4:只要Prefabs原型发生改变,所有的Prefabs实例都会产生变化。

Prefabs的用法:如果需要创建一些想要重复使用的东西,就该用它了。

在接下来的案例中,我们要使用预设在场景中创建小方块实例以了解Prefabs的使用


1.搭建基础的场景:

一个地板Plain一个下落的立方体Cube,调整摄像机的角度和位置,加个平行光源DirectionalLight。

同时给立方体加上刚体属性(Component -> Physics -> Rigidbody)。按下键盘的E调整一下方块的角度以便落下时可以滚动一小段距离。

搭建完成的效果如图所示:


2 创建并填充预设

在Preject窗口,右击:Create-> Prefab。此时Prefab为灰色。

然后我们从Hierarchy窗口中将立方体Cube拖到Project窗口新创建的Prefab上。

此时可以看到Hierarchy中的立方体变成了蓝色,Prefabs就完成了填充。


然后你从Preject窗口中将创建的Prefabs拖入Scene窗口中,运行一下便可以看到两个一模一样的小方块



3.在脚本中创建Prefabs实例

接着我们配合Instantiate函数,使用脚本代码创建多个Prefabs的实例。

Instantiate:可以理解成克隆原始物体并且设置位置,角度。

如果一个对象,组件,脚本实例被传入将克隆整个对的层次,以及所有子对象。

下面便是具体的操作过程

首先在Project窗口点Create -> Javascript创建一个脚本

  1. var CubePrefabs : GameObject;  
  2. function Update ()  
  3. {  
  4.     var instance:GameObject=Instantiate(CubePrefabs,transform.position,transform.rotation);  
  5.     //Instantiate用法,注意参数   
  6.     //Pre 用来克隆的Prefabs   
  7.     //transform.position 脚本绑定对象的位置 就像this.transform.…  
  8.     //transform.rotation 脚本绑定对象的角度 就像this.transform.…  
  9. }  

4.写完脚本,我们要把它绑定到一个对象上。这时候,我们删除Hierarchy窗口中的立方体

然后创建一个空的游戏对象(GameObject->Create Empty),放置到原来立方体的位置上。

将脚本拖放到Hierarchy窗口中的新键的空对象上,让它来执行代码。

5.在Hierarchy窗口中单击空对象,在它的Inspector窗口中就能看到绑定的脚本。

然后我们把早前创建的Prefabs,也就是那个Cube,拖到脚本Pre右边的框上,完成了脚本中变量的绑定。

然后点击一下运行按钮,便会出现成千上万个小方块喷涌而出啦~


2016-08-17 09:38:53 vipzjh 阅读数 5104

用处:一般当场景出现两个及两个以上,或者会出现重复的物体的时候,用实例化比较方便
目标:鼠标点击后,在鼠标点击的位置出现一个小球
涉及到:预制件,Instantiate(预制件,newVector(?,?,?),Quaternion.identity);
思路:先在Hierarchy建立一个cube,然后拖入工程建成预制件,删除这个cube,然后建立一个空的GameObject,建立一个新的Script。好了要实现代码部分了。

public class newPre : MonoBehaviour {
public Transform Cubepre;//注意,要把cube的预制件拖入 这个变量Cubepre中
    void Start() {

       for (int y =1; y < 3; y++)
       {
          for (int x =0; x < 3; x++)
          {
            Instantiate(Cubepre, new Vector3(x, y, 0),Quaternion.identity);
         }//里面的参数就是1,是预制件,2是坐标,3是默认的
            //上面的代码的作用是,这些位置产生小球//下面要在update,实现鼠标点击出现小球
       }
    }

3D的好像鼠标定位有点复杂,所以//下面要在update,实现鼠标点击出现小球 这个功能在之前的2D下实现

if(Input.GetMouseButtonDown(0))
      {
     //       Camera.main.ScreenToWorldPoint(Input.mousePosition);//这个是鼠标坐标
Instantiate(Cubepre,Camera.main.ScreenToWorldPoint(Input.mousePosition),Quaternion.identity);
      }

这样就很简单的实现了。

获取Unity3D实例

阅读数 468

一个3D项目,初、中级难度

博文 来自: fjl2007

unity3d _lesson02

阅读数 71

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