unity2d视频教程获取精灵全部坐标

使用Unity创建2D游戏
本文主要译自。
简介在这篇文章中,将讲解怎样使用C#和Unity创建移动2D游戏。将使用Unity杜比音频插件展示游戏音频体验。游戏很简单,到达另外一边,躲避敌人,收集金币。
在这篇文章中,将学习Unity游戏开发的以下方面:
在Unity中设置2D项目
创建Prefabs(预设)
移动和动作的按钮
运用物理碰撞
使用sprite sheet(精灵表)
集成杜比音频API
步骤和说明以下一共34个步骤。
我使用的Unity版本是:4.3.4f1
1. 创建新的Unity项目打开Unity,在File菜单中选择New Project,打开新项目对话框:
设置项目保存的路径
设置为2D项目
2. 构建设置创建项目后,会进入Unity用户界面。
在File菜单中选择Build Settings,然后选择Android作为目标平台。
3. 设备当开发2D游戏的时候,第一件事情是选择平台,之后就是选择艺术素材的尺寸。因为Android是开放的平台,因此市场上,有各种设备,它们有各不相同的屏幕分辨率和像素密度。比如以下是比较常见的:
Samsung Galaxy SIII: 720px x 1280px, 306 ppi
Asus Nexus 7 Tablet: 800px x 1280px, 216 ppi
Motorola Droid X: 854px x 480px, 228 ppi
虽然本文使用的是Android平台,但使用相同代码,可构建到Unity支持的其他目标平台上。
4. 导出图为了适应使用的设备,你可能需要将艺术素材转换为推荐的尺寸和像素密度。这件事情可以用你喜欢的图片编辑器完成。
我使用Mac OSX,预览就有这个功能,菜单项在这里:
然后在这个对话框里设置转换的参数:
5. Unity用户界面在开始之前,还需要调整一下Unity界面。
设置场景为2D(默认是3D的):
另外,可在Game控制面板里设置分辨率:
6. 游戏界面
游戏界面和直白。上面截图,可让你了解到艺术粗才最终在游戏界面的样子。后续文章将给出艺术素材的源文件。
7. 编程语言在Unity中,可选的编程语言有3种:
UnityScript,一个JavaScript的变种
以上语言各有利弊,你需要根据自己喜好选择其中的一种。
文章作者选择了C#,我打算先按照作者的C#过一遍,然后再用UnityScript替代。
如果选择其他语言,可参阅。
8. 2D图Unity是一个在不同平台上创建3D游戏的著名平台,比如微软的Xbox360,任天堂的Wii,Web,以及其他移动平台。
不过,在Unity4.3版本以后,它也可用于2D游戏开发。因为是2D游戏,我们将使用图片作为精灵表,而不是使用3D游戏中的材质。
9. 音效本文将使用一系列声音创建良好的游戏音效。本文中使用的音效来源于:
10. 导入Assets在写代码之前,需要加入asserts到Unity项目中。可使用以下几种方式之一:
在Assets菜单中选择Import New Asset
将assets条目加入到项目的assets文件夹中
将assets拖拽到项目窗口中
我一般用最后一种。
这一步做好,就可在Project面板的Assets文件夹中看到这些assets。
11. 创建场景将对象拖拽到Hierachy面板或者Scene面板中,就会创建默认场景。
另外,只要在创建项目后command+s保存,也可以创建默认场景。
12. 背景将背景图片拖拽到Hierarchy面板中,会自动显示在Scene面板中。
我在操作的时候,怎么拽图片,也无法放在Hierarchy面板里去。
后来借助文章,找到问题了:
The Default Behavior Mode defines the default import settings for your project’s art assets. When set to 3D, Unity assumes you want to create a Texture asset from an imported image file (e.g. a .PNG file); when set to 2D, Unity assumes you want an asset of type Sprite. You’ll read more details about Sprite assets and import settings throughout this tutorial.
需要设置:
然后,如果你之前就没有设置项目的这个属性,重新将图片拽到Assets面板中,然后再拖拽到Hierarchy面板中。
另外,需要将Main Camera在Inspector面板中的属性做下修改,透视投影改为正交投影,Size设置为1.58。
13. 地面将地面的素材图,导入到Assets,然后,拖拽到Scence面板中,再微调拼接好。
看起来效果是这样的:
14. 地面碰撞为了让人物在接触到地面时被检测到,我们需要为地面增加Component,Box Collider 2D。
在Scene面板中选择地面,然后打开Inspector面板,点击Add Component按钮,在Component列表中的Physics 2D中选择Box Collider 2D,见下面图:
15. 跳跃按钮我们将使用按钮控制游戏中的主要人物。拖拽跳跃按钮图到Scene面板,然后为它加上Circle Collider2D组件。
完成这步后,可在Game面板看到类似这样的效果:
做到这里碰到了问题,跳跃按钮会在运行时,会隐藏在当前图的后面,我现在的解决办法是:
Order in layer默认都是0,设置为1,就可见了。
16. 跳跃的声音在Scene面板里选择跳跃按钮,然后在Inspector面板里点击Add Component按钮。在Audio里选择Audio Source。
然后需要取消Play on Awake勾选项。再然后做如下操作,见图:
17. 跳跃脚本现在需要创建脚本来控制人物。选择跳跃按钮,点击Add Component按钮,选择New Script,命名脚本为Jump,不要忘记选择C#语言,默认的脚本语言是JavaScript。
系统将自动呼出MonoDevelop作为脚本的IDE。将下面代码粘贴进去:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465using UnityEusing System.Cpublic class Jump : MonoBehaviour{ public float jumpF private GameO
void Start() {
hero = GameObject.Find("Hero");
void Update() {
if (Application.platform == RuntimePlatform.Android)
if (Input.touchCount & 0)
if (Input.GetTouch(0).phase == TouchPhase.Began)
CheckTouch(Input.GetTouch(0).position, "began");
} else if (Input.GetTouch(0).phase == TouchPhase.Ended)
CheckTouch(Input.GetTouch(0).position, "ended");
if (Application.platform == RuntimePlatform.OSXEditor)
if (Input.GetMouseButtonDown(0))
CheckTouch(Input.mousePosition, "began");
if (Input.GetMouseButtonUp(0))
CheckTouch(Input.mousePosition, "ended");
} }
void CheckTouch(Vector3 pos, string phase) {
Vector3 wp = Camera.main.ScreenToWorldPoint(pos);
Vector2 touchPos = new Vector2(wp.x, wp.y);
Collider2D hit = Physics2D.OverlapPoint(touchPos);
if (hit.gameObject.name == "JumpButton" && hit && phase == "began")
hero.rigidbody2D.AddForce(new Vector2(0f, jumpForce));
audio.Play();
} }}
这部分代码很直白。获取hero对象,这是一个GameObject类的实例。我们后面会用到它。然后,我们检测用户是否点击了跳跃按钮,如果是这样,就给hero对象一个力,最后,我们播放跳跃的声音。
为了能立即执行这个代码,比如在andorid下,我屏蔽了部分还用不上的代码,比如创建hero对象。
做到这一步,我们就可以通过Build & Run部署到Android设备上运行了。或者直接在Game视图中运行。目前的一个问题是,只要点击了跳跃按钮,声音就开始不停的重复播放。需要做如下设置:
18. 移动按钮在界面中添加按钮asserts,左和右。
其实2个按钮是同一个图片asserts,需要将图形做一个转换:
19. 移动脚本创建一个新的脚本,名为MoveLeft,附加在向左移动的按钮上:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677using UnityEusing System.Cpublic class MoveLeft : MonoBehaviour{
public Vector3 moveSpeed = new Vector3();
private bool moving = false;
private GameObject[]
private GameO
void Start()
scene = GameObject.FindGameObjectsWithTag("Moveable");
bg = GameObject.Find("Background");
void Update()
if (Application.platform == RuntimePlatform.Android)
if (Input.touchCount & 0)
if (Input.GetTouch(0).phase == TouchPhase.Began)
CheckTouch(Input.GetTouch(0).position, "began");
} else if (Input.GetTouch(0).phase == TouchPhase.Ended)
CheckTouch(Input.GetTouch(0).position, "ended");
if (Application.platform == RuntimePlatform.OSXEditor)
if (Input.GetMouseButtonDown(0))
CheckTouch(Input.mousePosition, "began");
if (Input.GetMouseButtonUp(0))
CheckTouch(Input.mousePosition, "ended");
if (moving && bg.transform.position.x & 4.82f)
for (int i = 0; i & scene.L i++)
if (scene [i] != null)
scene [i].transform.position += moveS
void CheckTouch(Vector3 pos, string phase)
Vector3 wp = Camera.main.ScreenToWorldPoint(pos);
Vector2 touchPos = new Vector2(wp.x, wp.y);
Collider2D hit = Physics2D.OverlapPoint(touchPos);
if (hit.gameObject.name == "LeftButton" && hit && phase == "began")
moving = true;
if (hit.gameObject.name == "LeftButton" && hit && phase == "ended")
moving = false;
} }
这里要提到,tag(标签),是操作多个GameObject(游戏对象)的方法。我们可以在Unity界面中给多个游戏对象,比如floor(地面)和Background(背景)对象标识为Moveable的标签。
这样,如果我们需要Hero(英雄)移动的时候,可以反方向移动floor(地面)和Background(背景)。
tag是需要添加的:
添加后就可以这样设置tag:
类似的,我们可以创建MoveRight脚本,将它附加在向右移动的按钮上。代码类似这样:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126using UnityEusing System.Cpublic class MoveRight : MonoBehaviour{
public Vector3 moveSpeed = new Vector3();
private bool moving = false;
private GameObject[]
private GameO
public AudioClip completeS
private GameObject[]
private GameObject completeT
private bool ended = false;
public Font goodD
void Start()
scene = GameObject.FindGameObjectsWithTag("Moveable");
bg = GameObject.Find("Background");
buttons = GameObject.FindGameObjectsWithTag("Buttons");
void Update()
if (Application.platform == RuntimePlatform.Android)
if (Input.touchCount & 0)
if (Input.GetTouch(0).phase == TouchPhase.Began)
CheckTouch(Input.GetTouch(0).position, "began");
} else if (Input.GetTouch(0).phase == TouchPhase.Ended)
CheckTouch(Input.GetTouch(0).position, "ended");
if (Application.platform == RuntimePlatform.OSXEditor)
if (Input.GetMouseButtonDown(0))
CheckTouch(Input.mousePosition, "began");
if (Input.GetMouseButtonUp(0))
CheckTouch(Input.mousePosition, "ended");
if (moving && bg.transform.position.x & -4.8f)
for (int i = 0; i & scene.L i++)
if (scene [i] != null)
scene [i].transform.position -= moveS
if (bg.transform.position.x &= -4.8f && ended == false)
Alert("complete");
void CheckTouch(Vector3 pos, string phase)
Vector3 wp = Camera.main.ScreenToWorldPoint(pos);
Vector2 touchPos = new Vector2(wp.x, wp.y);
Collider2D hit = Physics2D.OverlapPoint(touchPos);
if (hit.gameObject.name == "RightButton" && hit && phase == "began")
moving = true;
if (hit.gameObject.name == "RightButton" && hit && phase == "ended")
moving = false;
public void Alert(string action)
ended = true;
completeText = new GameObject();
completeText.AddComponent("GUIText");
completeText.guiText.font = goodD
completeText.guiText.fontSize = 50;
completeText.guiText.color = new Color(255, 0, 0);
if (action == "complete")
AudioSource.PlayClipAtPoint(completeSound, transform.position);
completeText.guiText.text = "Level Complete!";
completeText.guiText.transform.position = new Vector3(0.24f, 0.88f, 0);
} else
completeText.guiText.text = "Game Over";
completeText.guiText.transform.position = new Vector3(0.36f, 0.88f, 0);
bg.GetComponent&AudioSource&().Stop();
for(int i = 0; i & buttons.L i++)
buttons[i].renderer.enabled = false;
Invoke("restart", 2);
void restart()
Application.LoadLevel(Application.loadedLevel);
}}
这里的Alert函数用来创建提示玩家的信息,并播放附加在对应背景对象的声音。然后让所有按钮隐藏,然后间隔2秒后重新开始游戏。
TODO 这里播放声音需要解释
20. 精灵表我们将使用精灵表(sprite sheet)展现游戏的其他元素。Unity有一个精灵表编辑器,使得设置精灵表变得很容易。
精灵表是一张图:
这张图来源于:
需要将它导入到Unity,成为asserts。然后,在Inspector面板中设置它为Multiple,默认是Single:
然后,点击Sprite Editor按钮,在弹出的对话框里点击Slice,这是自动识别精灵表的每个元素:
这之后,精灵表看起来就是这样的了:
21. 英雄然后,我们就可以从精灵表中将英雄拖拽到Scene视图中:
然后,给它加上Collider 2D组件,这是原文的写法,不过有多种Collider 2D组件,我先使用Box Collidar 2D组件,如果以后发现不妥再修改。
22. 英雄2D刚体为了能对英雄检测碰撞,需要至少给碰撞的一方设置位RigidBody 2D组件。也就是2D刚体。我们给英雄设置一下这个组件。
我们不希望英雄在碰撞后发生角度变化,因此需要勾选Fixed Angle:
如果地面当时忘记设置Box Collider 2D,那么设置RigidBody 2D后,英雄会掉落而不是站在地面上。
这时候,可以运行一下这个游戏,看是否能借助前面跳跃的脚本,让英雄跳跃起来。
23. 英雄的声音当英雄被敌人击中,我们要为游戏玩家播放另外一个声音。首先需要加入这个声音,和跳跃按钮添加声音类似。
24. 收集金币收集金币,是很多2D游戏有的需求。我们需要在游戏中多次使用金币。后面我们会将金币转换为Prefab(预设),这样就可以在所有需要的地方添加它了。
在这一步,我们还是将金币的图,从Assets中拖拽到游戏场景中,然后像上面类似的为它添加Box Collider2D组件。
25. 金币的声音和添加英雄声音类似,给金币设置声音。
26. 金币的脚本和Prefab(预设)和跳跃脚本的添加方式类似,代码是:
123456789101112131415161718using UnityEusing System.Cpublic class GrabCoin : MonoBehaviour{
void OnTriggerEnter2D(Collider2D other) {
Debug.Log("play sound....");
if (other.gameObject.name == "Hero")
audio.Play();
Destroy(gameObject.collider2D);
gameObject.renderer.enabled = false;
Destroy(gameObject, 0.47f);
} }}
另外,别忘记给金币设置为trigger:
否则当英雄碰撞金币的时候不会触发OnTriggerEnter2D方法。
然后是将这个金币生成为Prefab,操作很简单,只需要将Hierarchy面板中的coin拖拽到下面的Assets中即可。
27. 敌人和上面操作类似,添加敌人:
需要为敌人创建2个Collider 2D,下面的是检测敌人碰到英雄的(失败),另外一个放在敌人头上,用于检测英雄从上面下来碰撞到敌人(敌人被杀死)
不要忘记勾选Is Trigger
然后是添加脚本,见下面
最后,将敌人设置为Prefab
123456789101112131415161718192021222324252627282930313233343536373839404142using UnityEusing System.C public class Enemy : MonoBehaviour{
public Vector3 moveS
public AudioClip hitS
public GameObject alertB
void Start()
void Update()
transform.position -= moveS
void OnCollisionEnter2D(Collision2D other)
if (other.gameObject.name == "Hero")
AudioSource.PlayClipAtPoint(hitSound, transform.position);
Destroy(gameObject);
void OnTriggerEnter2D(Collider2D other)
if (other.gameObject.name == "Hero")
other.gameObject.audio.Play();
Destroy(other.gameObject.collider2D);
other.gameObject.renderer.enabled = false;
Destroy(other.gameObject, 0.626f);
alertBridge.GetComponent().Alert("gameover");
}}
28. 砖头砖头的逻辑比较简单,无非是:
添加Collider 2D组件
转换为Prefab
29. 结束最后,我们需要创建一个重点游戏对象。当英雄碰到它触发完成游戏。
30. 杜比音频插件略。
31. 测试略。
32. 播放器设置略。
33. 图标和开场画面略。
34. 构建和播放略。Unity 2D 屏幕点击选中实现--精灵透明处理篇
可能在手机端做2D屏幕点击,选中精灵的操作还是比较少的,所以这方面的可以查到的资料也比较匮乏,很多都是3D中的选中算法,实际原理也比较简单,就是射线命中法,从相机到屏幕点击点发出射线,命中的精灵就是点击选中的精灵了,当然精灵要有物理碰撞的区域,不然无法检测。实际原理都是一样
的,查了下资料两种方法,可以参考下篇,/flyFreeZn/p/4026081.html,这里把代码也一并贴出来作为记录
1.Raycast法
原理相同于3D中得Raycast法,具体使用略有区别。
2.Overlap法
个人觉得这个方法对于2D更合适一些,判断点击的点落在了哪些collider中。
以上代码中用到的是mousePosition,对于触摸的Touch原理完全相同。
现在方法有了剩下的就是如何实践实现的问题了,在我看来具体实现涉及到两个问题,一个是鼠标点击选中,另一是选中后如何呈现。真正实现了这两点才算是一个及格的学习实践。最终实现效果如下图所示:
这里有了背景分析后,我们的需求是这样:
“通过鼠标点击场景中的精灵,置精灵为选中状态(这里采用的方式是透明化)”。
有了需求,我们开始技术分析,大体需要一下几个知识点,我们逐一破结,学习
1、鼠标点击
2、2D精灵命中测试,需要2D物理碰撞
3、给精灵添加物理碰撞
4、命中的深度测试(根据原理被射线穿透的可能有多个精灵而我们应该选中的应该是离相机最近的,也就是深度最小的且唯一)
5、选中精灵的透明化处理
列出这五点出来,我也有点惊讶了,竟然这么多技术功能点,汗!
1、鼠标点击
有两种方式实现,
传统方式在Update中添加鼠标点击处理,如下所示:
void Update () {
if (Input.GetMouseButtonDown(0))
这种方法的缺点,就是放在Update中的逻辑较多,当代码复杂的时候,可读性比较差
用Unirx实现,有点像传统的winform事件订阅方式
void Start()
//鼠标点击控制
Observable.EveryUpdate().Where(_ =& Input.GetMouseButtonDown(0)).Subscribe(LeftMouseClick2);
2、2D精灵命中测试
这个基本就是用资料中的Overlap法 ,这里代码就不贴出来了,在4中会贴出完整代码。
3、给精灵添加物理碰撞
这里可以用传统的方式在Unity IDE中可视化的为GameObject添加 ColliderBox组件,然后设置Size也就是鼠标点击区域
由于教程中的精灵是动态创建的,所以我的Box Collider 2D插件也是用代码动态添加的,这里当然也可以不局限Box Collider 2D如果需要更好的物理选中效果,也可以采用更精确的,我的代码如下所示:
//动态添加碰撞
其中qxPlayer就是我的精灵GameObject了。
4、命中的深度测试
实际上要解决的问题就是“根据原理被射线穿透的可能有多个精灵而我们应该选中的应该是离相机最近的,也就是深度最小的且唯一”
如何获取最近的精灵的我查阅了下Unity API文档 关键部分我用红色字标出来了:
Get a list of all colliders that overlap a point in space.
This function is similar to OverlapPoint except that all colliders that overlap the point are returned. The colliders in the returned array are sorted in order of increasing Z coordinate. An empty array is returned if there are no colliders over the point.
Note that this function will allocate memory for the returned Collider2D array. You can use OverlapPointNonAlloc to avoid this overhead if you need to make the check frequently.
有了Unity卓越的工作,再加上本身我的精灵对象使用的画家算法,自然数组中第一就是离相机(屏幕)最近的了,接下来只要根据Name获得第一个精灵即可,如下代码所示
其中Find函数通过gameObject.Name遍历查找我在场景中所有的精灵对象的封装函数,比较简单就不解释了
5、选中精灵的透明化处理
设置选中精灵的半透明就变的轻松加愉快了,代码如下比较简单
至此一套完整的Unity 2D 精灵鼠标点击选中的解决方案完成了,希望对您有帮助。
蛮牛社区(<)分享最新的游戏研发和虚拟现实相关技术内容。
责任编辑:
声明:本文由入驻搜狐号的作者撰写,除搜狐官方账号外,观点仅代表作者本人,不代表搜狐立场。Unity2D,怎样从资源里加载一个图集中的一个sprite
Unity2D,怎样从资源里加载一个图集中的一个sprite,图集是一个png文件。选择了sprite 模式是multiple。要从中取得任意一个Sprite,有什么办法?
要评论请先&或者&
如果是图集里的图片,直接给sprite就容易了,直获取UISprite.spritename = “想要获取的精灵名称”;
:如果是图集里的图片,直接给sprite就容易了,直获取UISprite.spritename = “想要获取的精灵名称”; 我说的不是NGUI里面的,是unity里面的2d工具,动态的换sprite
:我说的不是NGUI里面的,是unity里面的2d工具,动态的换sprite 额,, 没有过unity的2d工具,抱歉~~帮不到你了
:额,, 没有过unity的2d工具,抱歉~~帮不到你了 没事,谢谢!
GameObject go = new GameObject();
go.name = &sprite&;
go.transform.localScale = new Vector3(,,);
SpriteRenderer sr = go.AddComponent&SpriteRenderer&();
sr.sprite &= Resources.Load&Sprite&(&&);
:GameObject go = new GameObject();
go.name = &sprite&;
go.transform.localScale = new Vector3(,,);
SpriteRenderer sr... 我取的是sprite,也就是资源中的纹理里面的一部分。你这样取取到的是一张纹理吧。
:我取的是sprite,也就是资源中的纹理里面的一部分。你这样取取到的是一张纹理吧。 你这要求太风骚了
可以通过Resources.LoadAll&Sprite&(TexturePath);加载所有sprite,然后根据名字选择一个需要的
中上所述还是NGUI比较靠谱}

我要回帖

更多关于 cocos2d 获取精灵坐标 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信