using UnityEngine;
using System.Collections;
public class Script_ScreenPointToRay : MonoBehaviour {
void Update()
{
//鼠标按下左键
if(Input.GetMouseButtonDown(0))
{
//创建一条射线以摄像机为原点
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
//射线碰撞到游戏地形时
if (Physics.Raycast(ray, out hit))
{
//创建球体
GameObject objCube = GameObject.CreatePrimitive(PrimitiveType.Sphere);
objCube.transform.position = hit.point;
}
}
}
}
我们看下一个简单的例子,在场景中,我们点选到一个区域,就会生成一个球体,如图
如果问这个有什么用,那试想一下,如果我们点选不是生成一个球体,而是场景中原有的一样物品,比如说一个矿石,我们点选之后,这个矿石Destroy,而我们背包里面add一个,这样就实现了物品的拾取,代码中使用Camera.main.ScreenPointToRay()方法有摄像机选中是发射一条射线,然后用Physics.Raycast()方法计算出改射线与地形之间的交点的位置。
如果觉得这个例子简单,我这里用一个国内u3d专家雨松写的一个例子更直观的说明鼠标点选的用处,
using UnityEngine;
using System.Collections;
public class Npc : MonoBehaviour {
//游戏状态机
//默认状态
public const int TASK_STATE_DEFAULT = 0;
//信息提示状态
public const int TASK_STATE_OVER = 1;
//打开任务窗口状态
public const int TASK_STATE_OPEN = 2;
//游戏状态
public const int TASK_STATE_GAME = 3;
//游戏完成状态
public const int TASK_STATE_COMPLETE = 4;
//游戏结束状态
public const int TASK_STATE_FINSH = 5;
//当前游戏状态
public int gameState = 0;
//脚本对象
Script_Mouse_ray script = null;
//任务窗口显示区域
Rect windowRect = new Rect(100,0,200,100);
void Start()
{
//得到脚本对象
script = GameObject.Find("/Main Camera").GetComponent<Script_Mouse_ray>();
//在游戏存档中读取游戏状态数据
gameState = PlayerPrefs.GetInt("gameState",TASK_STATE_DEFAULT);
}
void OnMouseDown()
{
if(gameState == TASK_STATE_OVER)
{
//进入弹出任务窗口状态
gameState = TASK_STATE_OPEN;
}else
if(gameState ==TASK_STATE_COMPLETE)
{
//进入任务完成状态
gameState = TASK_STATE_FINSH;
}
}
void OnMouseOver()
{
if(gameState == TASK_STATE_DEFAULT)
{
//进入提示信息状态
gameState = TASK_STATE_OVER;
}
}
void OnGUI()
{
//状态机的绘制
switch(gameState)
{
case TASK_STATE_OVER:
GUILayout.Box("点击Npc接一个任务");
break;
case TASK_STATE_OPEN:
windowRect = GUILayout.Window (0, windowRect, AddWindow, "接受任务");
break;
case TASK_STATE_GAME:
GUILayout.Box("目前收集到的宝石数量为:"+script.items);
break;
case TASK_STATE_COMPLETE:
GUILayout.Box("已经收集到10颗宝石,请到NPC处交任务,宝石数量不再累加!");
break;
case TASK_STATE_FINSH:
GUILayout.Box("任务完成");
if(GUILayout.Button("重新开始"))
{
//重置游戏
gameState = TASK_STATE_DEFAULT;
script.items = 0;
PlayerPrefs.SetInt("itemCount", script.items);
PlayerPrefs.SetInt("gameState", gameState);
}
break;
}
}
void AddWindow(int windowID)
{
GUILayout.Label("请在游戏中寻找20块红宝石");
//开始一个水平布局
GUILayout.BeginHorizontal ();
if (GUILayout.Button ("接受任务"))
{
gameState = TASK_STATE_GAME;
}
if (GUILayout.Button ("拒绝任务"))
{
gameState = TASK_STATE_DEFAULT;
}
//关闭水平布局
GUILayout.EndHorizontal ();
}
}
using UnityEngine;
using System.Collections;
public class Script_Mouse_ray : MonoBehaviour {
//红宝石数量
public int items;
//脚本对象
private Npc npc = null;
private int i=0;
void Start()
{
//在游戏存档中读取上次保存游戏时红宝石的数量
items = PlayerPrefs.GetInt("itemCount",0);
//获取脚本对象
npc = GameObject.Find("/NPC").GetComponent<Npc>();
}
void Update()
{
//是否游戏状态为游戏中
if(npc.gameState == Npc.TASK_STATE_GAME)
{
//是否点击鼠标左键
if(Input.GetMouseButtonDown(0))
{
//创建鼠标点击的射线
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
//鼠标是否选中游戏对象
if (Physics.Raycast(ray, out hit))
{
//得鼠标选中到游戏对象
GameObject obj = hit.collider.gameObject;
//是否为红宝石对象
if(obj.name == "cube")
{
//红宝石数量加1
items++;
if(items>=10)
{
//当红宝石数量满足10,标示游戏完成
npc.gameState = Npc.TASK_STATE_COMPLETE;
}
//销毁红宝石对象
Destroy(obj);
//保存红宝石数量以及游戏状态
PlayerPrefs.SetInt("itemCount", items);
PlayerPrefs.SetInt("gameState", npc.gameState);
}else if(obj.name == "NPC"){
i++;
Debug.Log("选择Npc点选次数"+i);
}
}
}
}
}
}
Npc预制件
两个类的挂载,我们稍微分析下源码,Npc.cs里面定义了几个状态,通过void OnMouseDown() void OnMouseOver()两个方法来控制这几个状态的变化,
Script_Mouse_ray的update()方法中,通过发射射线来判断拾取方块,其实这个NPC类的void OnMouseDown() void OnMouseOver()方法其实也可以用射线来实现,参照Script_Mouse_ray中的else if(obj.name == "NPC")这一行,其实效果是一样的,我们看下效果
没有接受任务之前状态是TASK_STATE_DEFAULT和TASK_STATE_OVER,所以点击Npc控制台没有反应,
接受任务之后因为状态进入了,TASK_STATE_GAME所以,我们看到点选Npc控制台会打印出点选的信息,这就是点选最常见的应用,除了这些还能做什么呢?
我开篇的时候说小游戏不加了,但感觉这篇点选的篇幅东西比较少,所以就准备加点格外的东东,用什么做的呢,还是点选,大家看下是什么东西
其实水果忍者就可以用射线选取的方式来做
我们看下代码
using UnityEngine;
using System.Collections;
public class StartController : MonoBehaviour {
public GUISkin mySkin;
private bool isSound1Button=false;
private bool isSound2Button=true;
private AudioSource sound;
// Use this for initialization
void Start () {
sound=gameObject.GetComponent<AudioSource>();
}
// Update is called once per frame
void Update () {
}
void OnGUI(){
GUI.skin=mySkin;
if(GUI.Button(new Rect(180,215,220,66),"",GUI.skin.GetStyle("PlayButton"))){
Application.LoadLevel(1);
}
if(GUI.Button(new Rect(180,285,220,66),"",GUI.skin.GetStyle("MoreButton"))){
//Application.OpenURL("www.sina.com");
}
if(GUI.Button(new Rect(180,355,220,66),"",GUI.skin.GetStyle("CreditButton"))){
//Application.OpenURL("www.sina.com");
}
if(isSound1Button){
Debug.Log("sound开启");
if(GUI.Button(new Rect(25,430,37,31),"",GUI.skin.GetStyle("Sound1Button"))){
sound.Play();
isSound1Button=false;
isSound2Button=true;
}
}
if(isSound2Button){
if(GUI.Button(new Rect(25,430,37,31),"",GUI.skin.GetStyle("Sound2Button"))){
Debug.Log("sound关闭");
sound.Stop();
isSound1Button=true;
isSound2Button=false;
}
}
}
}
using UnityEngine;
using System.Collections;
public class KnifeRayController : MonoBehaviour {
//public Color myColor;
//private LineRenderer lineRenderer;
public GameObject myRay;
public AudioClip KnifeSound;
public bool isHit=false;
public Vector3 rayPosition;
public bool isRay=false;
public GameObject firstFruit;
public GameObject secondFruit;
public GameObject splash;
public GameObject splashV;
public GameObject splashH;
//污渍
private GameObject mySplash;
private GameObject mySplashV;
private GameObject mySplashH;
private Vector3 firstPosition;
private Vector3 secondPosition;
//private Vector3 middlePosition;
private GameObject rayGameObject;
private bool isClicked=false;
private GameObject myFirstFruit;
private GameObject mySecondFruit;
private float angle;
// Use this for initialization
void Start () {
// lineRenderer=gameObject.AddComponent<LineRenderer>();
// lineRenderer.material.color=myColor;
// lineRenderer.SetWidth(0.1f,0.1f);
}
// Update is called once per frame
void Update () {
bool isMouseDown=Input.GetMouseButton(0);
if(isHit){
if(isMouseDown&&!isClicked){
firstPosition=Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,Input.mousePosition.y,1));
// lineRenderer.SetVertexCount(1);
// lineRenderer.enabled=true;
// lineRenderer.SetPosition(0,firstPosition);
isClicked=true;
}else if(isMouseDown){
secondPosition=Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,Input.mousePosition.y,1));
// lineRenderer.SetVertexCount(2);
// lineRenderer.SetPosition(1,secondPosition);
}else if(Input.GetMouseButtonUp(0)){
isRay=true;
secondPosition=Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,Input.mousePosition.y,1));
if(secondPosition.x!=firstPosition.x){
angle=(1.0f/3.14f)*180*Mathf.Atan((secondPosition.y-firstPosition.y)/(secondPosition.x-firstPosition.x));
}else{
angle=0;
}
if((angle<30&&angle>0)||(angle<0&&angle>-30)){
//Debug.Log("splashh");
mySplashH=Instantiate(splashH,transform.position+new Vector3(1.5f,0,0),Quaternion.identity)as GameObject;
setColor(mySplashH);
Destroy(mySplashH,1.0f);
}else if((angle<90&&angle>60)||(angle<-60&&angle>-90)){
//Debug.Log("splashv");
mySplashV=Instantiate(splashV,transform.position+new Vector3(1.5f,0,0),Quaternion.identity)as GameObject;
setColor(mySplashV);
Destroy(mySplashV,1.0f);
}else{
//Debug.Log("splash");
mySplash=Instantiate(splash,transform.position+new Vector3(1.5f,0,0),Quaternion.identity)as GameObject;
setColor(mySplash);
Destroy(mySplash,1.0f);
}
//rayGameObject=Instantiate(myRay,middlePosition,Quaternion.AngleAxis(angle*180/3.14f,Vector3.forward))as GameObject;
rayGameObject=Instantiate(myRay,rayPosition,Quaternion.AngleAxis(angle*180/3.14f,Vector3.forward))as GameObject;
//Destroy(
myFirstFruit=Instantiate(firstFruit,transform.position,Quaternion.AngleAxis(angle*Random.Range(50,180)/3.14f,Vector3.forward))as GameObject;
mySecondFruit=Instantiate(secondFruit,transform.position,Quaternion.AngleAxis(angle*Random.Range(80,150)/3.14f,Vector3.forward))as GameObject;
if(Random.Range(1,10)>5.0f){
myFirstFruit.rigidbody.velocity=new Vector2(5,10);
mySecondFruit.rigidbody.velocity=new Vector2(-8,-10);
}else{
myFirstFruit.rigidbody.velocity=new Vector2(-5,10);
mySecondFruit.rigidbody.velocity=new Vector2(8,-10);
}
Physics.gravity=new Vector3(0,-20,0);
Destroy(myFirstFruit,2.0f);
Destroy(mySecondFruit,2.0f);
if(audio.isPlaying){
audio.Stop();
}
PlaySound(KnifeSound);
Destroy(rayGameObject,0.2f);
isClicked=false;
isHit=false;
// lineRenderer.SetVertexCount(2);
// lineRenderer.SetPosition(1,secondPosition);
//middlePosition=(firstPosition+secondPosition)/2.0f;
//float angle=Mathf.Atan((secondPosition.y-firstPosition.y)/(secondPosition.x-firstPosition.x));
}
}else{
isRay=false;
}
}
void PlaySound(AudioClip soundName){
if(!audio.isPlaying){
AudioSource.PlayClipAtPoint(soundName,new Vector3(0,0,-10));
}
}
void setColor(GameObject myGameobject){
Debug.Log("------------------");
if(gameObject.name=="apple00(Clone)"){
Debug.Log("apple00");
myGameobject.gameObject.transform.renderer.material.color=Color.cyan;
}else if(gameObject.name=="banana00(Clone)"){
Debug.Log("banana00");
myGameobject.gameObject.transform.renderer.material.color=Color.black;
}else if(gameObject.name=="goldApple00(Clone)"){
Debug.Log("goldApple00");
myGameobject.gameObject.transform.renderer.material.color=Color.yellow;
}
else if(gameObject.name=="hamster00(Clone)"){
Debug.Log("hamster00");
myGameobject.gameObject.transform.renderer.material.color=Color.red;
}
else if(gameObject.gameObject.name=="kiwi00(Clone)"){
Debug.Log("kiwi00");
myGameobject.gameObject.transform.renderer.material.color=Color.gray;
}else if(gameObject.name=="pear00(Clone)"){
Debug.Log("pear00");
myGameobject.gameObject.renderer.material.color=Color.white;
}else if(gameObject.name=="waterMelon00(Clone)"){
Debug.Log("waterMelon00");
myGameobject.gameObject.transform.renderer.material.color=Color.green;
}
}
}
using UnityEngine;
using System.Collections;
public class HitByKnife : MonoBehaviour {
public GameObject goldFruit;
public AudioClip fallSound;
public AudioClip hemsterSound;
private GameObject myKnifeScript;
private GameObject myGoldFruit;
private bool isClicked=false;
private RaycastHit hit;
private Ray ray;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
bool isMouseDown=Input.GetMouseButton(0);
if(!isClicked){
//Debug.Log("+++++++++++++++++++++++");
if(isMouseDown){
ray=Camera.main.ScreenPointToRay(Input.mousePosition);
if(collider.Raycast(ray,out hit,100.0f)){
isClicked=true;
transform.GetComponent<KnifeRayController>().isHit=true;
transform.GetComponent<KnifeRayController>().rayPosition=hit.transform.position;
}
}
}else if(transform.GetComponent<KnifeRayController>().isRay){
Debug.Log("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
if(gameObject.name!="hamster00(Clone)"){
if(gameObject.name=="goldApple00(Clone)"){
Debug.Log("goldApple00(Clone)");
myGoldFruit=Instantiate(goldFruit,transform.position,Quaternion.identity)as GameObject;
DigitDisplay.score+=20;
Destroy(myGoldFruit,1.0f);
}else{
DigitDisplay.score+=5;
}
gameObject.active=false;
Destroy(gameObject,1.0f);
}else{
if(audio.isPlaying){
audio.Stop();
}
PlaySound(hemsterSound);
Debug.Log("^^^^^^^^^^^00000000000^^^^^^^^^^^^^^^");
Destroy(gameObject);
Application.LoadLevel(2);
}
}
if(transform.position.y<=-7.1&&gameObject.name!="hamster00(Clone)"){
if(audio.isPlaying){
audio.Stop();
}
PlaySound(fallSound);
DigitDisplay.life--;
Destroy(gameObject);
}
}
void PlaySound(AudioClip soundName){
if(!audio.isPlaying){
AudioSource.PlayClipAtPoint(soundName,new Vector3(0,0,-10));
}
}
}
using UnityEngine;
using System.Collections;
public class DigitDisplay : MonoBehaviour {
//生命
public Texture liftTexture;
public Texture liftTextureX;
public Texture[] lifeNumber;
public static int life=3;
//计分
public static int score=0;
public Texture[] scoreNumber;
//倒计时
float myTime;
public Texture[] timeNumber;
public int leftTime=100;
public int Level=1;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if(life<=0){
Application.LoadLevel(2);
}
myTime+=Time.deltaTime;
if(myTime>1){
if(leftTime>0){
leftTime--;
}else{
Application.LoadLevel(2);
}
myTime=0;
}
if(score>50&&Level==1){
Application.LoadLevel(3);
}
}
void OnGUI(){
GUI.DrawTexture(new Rect(10,10,20,30),liftTexture);
GUI.DrawTexture(new Rect(30,10,35,35),liftTextureX);
for(int i=0;i<life.ToString().Length;i++){
GUI.DrawTexture(new Rect(60+i*20,20,20,20),lifeNumber[System.Int32.Parse((life.ToString())[i].ToString())]);
}
for(int i=0;i<leftTime.ToString().Length;i++){
GUI.DrawTexture(new Rect(300+i*32,20,32,32),timeNumber[System.Int32.Parse((leftTime.ToString())[i].ToString())]);
}
//GUI.Label(new Rect(360,10,80,20),"Score:");
for(int i=0;i<score.ToString().Length;i++){
GUI.DrawTexture(new Rect(500+i*32,20,40,40),scoreNumber[System.Int32.Parse((score.ToString())[i].ToString())]);
}
}
}
using UnityEngine;
using System.Collections;
public class fruitCreate : MonoBehaviour {
public GameObject[] fruit=new GameObject[2];
public int index;
//ctor3
private GameObject myApple;
// Use this for initialization
void Start () {
Physics.gravity=new Vector3(0,-20,0);
InvokeRepeating("Move",0,3.2f);
}
// Update is called once per frame
void Update () {
}
void Move(){
float x=Random.Range(-7.0f,7.0f);
index=Random.Range(0,7);
myApple=Instantiate(fruit[index],new Vector3(x,-7,-9),Quaternion.identity)as GameObject;
if(x>0){
myApple.transform.rigidbody.velocity=new Vector3(Random.Range(-5,0),21.0f,0.0f);
}else{
myApple.transform.rigidbody.velocity=new Vector3(Random.Range(0,5),21.0f,0.0f);
}
//例子
//var temp = transform.position;
//temp.y=0.5f;
//transform.position = temp;
Vector3 temp=myApple.transform.localEulerAngles;
temp.z=Random.Range(-120.0f,120.0f);
//myApple.transform.localEulerAngles=temp;
// myApple.transform.localEulerAngles.z=Random.Range(-120.0f,120.0f);
}
}
using UnityEngine;
using System.Collections;
public class Level1soundGUI : MonoBehaviour {
public GUISkin mySkin;
private bool isSound1Button=false;
private bool isSound2Button=true;
private AudioSource sound;
// Use this for initialization
void Start () {
sound=gameObject.GetComponent<AudioSource>();
}
// Update is called once per frame
void Update () {
}
void OnGUI(){
GUI.skin=mySkin;
if(isSound1Button){
//Debug.Log("sound开启");
if(GUI.Button(new Rect(12,430,21,31),"",GUI.skin.GetStyle("Sound1Button"))){
sound.Play();
isSound1Button=false;
isSound2Button=true;
}
}
if(isSound2Button){
if(GUI.Button(new Rect(12,430,21,31),"",GUI.skin.GetStyle("Sound2Button"))){
//Debug.Log("sound关闭");
sound.Stop();
isSound1Button=true;
isSound2Button=false;
}
}
}
}
这个山寨的小游戏,其实只有6个类,最重要的类HitByKnife.cs和KnifeRayController.cs。也就是产生小刀刀锋的方法就是发射一条射线点选的过程
具体挂载方法如图