3D 世界中自定义模型的使用恐怕是重中之重,因为系统自身提供的模型肯定是无法满足GD对游戏的策划,所以为了让游戏更加绚丽,我们须要调用美术制作的精品模型与动画,本章MOMO将带领盆友们学习Unity3D中模型的载入与动画的播放,哇咔咔~~
由于MOMO手头上没有现成的模型,所以我将在Unity3D 官网中下载官方提供的游戏DEMO 中的模型来使用。另外官方提供了很多Unity3D 游戏DEMO,与详细的文档。可以帮助我们学习Unity.有兴趣的盆友可以去看看哈。
下载页面:http://unity3d.com/support/resources/
本章博文的目的是利用上一章介绍的游戏摇杆来控制人物模型的移动,与行走动画的播放。
如上图所示Create中的文件夹male中存放着模型动画与贴图等,这个应该是美术提供给我们的。然后将整个male用鼠标拖动到左侧3D世界中,通过移动,旋转,缩放将人物模型放置在一个理想的位置。右侧红框内设置模型动画的属性。
Animation
idle1 该模型默认动画名称为idle1
Animations
size 该模型动画的数量
Element 该模型的动画名称
Play Automatically 是否自动播放
Animation Physics 是否设置该模型物理碰撞
Animation Only if Visable 是否设置该模型仅自己显示
给该模型绑定一个脚本Controller.cs 用来接收摇杆返回的信息更新模型动画。
Controller.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
using UnityEngine; using System.Collections; public class Controller : MonoBehaviour { //人物的行走方向状态 public const int HERO_UP= 0; public const int HERO_RIGHT= 1; public const int HERO_DOWN= 2; public const int HERO_LEFT= 3; //人物当前行走方向状态 public int state = 0; //备份上一次人物当前行走方向状态 //这里暂时没有用到 public int backState = 0; //游戏摇杆对象 public MPJoystick moveJoystick; //这个方法只调用一次,在Start方法之前调用 public void Awake() { } //这个方法只调用一次,在Awake方法之后调用 void Start () { state = HERO_DOWN; } void Update () { //获取摇杆控制的方向数据 上一章有详细介绍 float touchKey_x = moveJoystick.position.x; float touchKey_y = moveJoystick.position.y; if(touchKey_x == -1){ setHeroState(HERO_LEFT); }else if(touchKey_x == 1){ setHeroState(HERO_RIGHT); } if(touchKey_y == -1){ setHeroState(HERO_DOWN); }else if(touchKey_y == 1){ setHeroState(HERO_UP); } if(touchKey_x == 0 && touchKey_y ==0){ //松开摇杆后播放默认动画, //不穿参数为播放默认动画。 animation.Play(); } } public void setHeroState(int newState) { //根据当前人物方向 与上一次备份方向计算出模型旋转的角度 int rotateValue = (newState - state) * 90; Vector3 transformValue = new Vector3(); //播放行走动画 animation.Play("walk"); //模型移动的位移的数值 switch(newState){ case HERO_UP: transformValue = Vector3.forward * Time.deltaTime; break; case HERO_DOWN: transformValue = -Vector3.forward * Time.deltaTime; break; case HERO_LEFT: transformValue = Vector3.left * Time.deltaTime; break; case HERO_RIGHT: transformValue = -Vector3.left * Time.deltaTime; break; } //模型旋转 transform.Rotate(Vector3.up, rotateValue); //模型移动 transform.Translate(transformValue, Space.World); backState = state; state = newState; } } |
上一章介绍了javaScript脚本使用游戏摇杆的方法,本章MOMO告诉大家使用C#脚本来使用游戏摇杆,上面我用 Controller.cs C#脚本来接收系统提供的Joystick.js是肯定无法使用的,须要修改成.cs文件,我在国外的一个网站上看到了一个老外帮我们已经修改了,那么我将他修改后的代码贴出来方便大家学习,有兴趣的朋友可以研究研究。哇咔咔~
MPJoystick.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
using UnityEngine; /** * File: MPJoystick.cs * Author: Chris Danielson of (monkeyprism.com) * // USED TO BE: Joystick.js taken from Penelope iPhone Tutorial // // Joystick creates a movable joystick (via GUITexture) that // handles touch input, taps, and phases. Dead zones can control // where the joystick input gets picked up and can be normalized. // // Optionally, you can enable the touchPad property from the editor // to treat this Joystick as a TouchPad. A TouchPad allows the finger // to touch down at any point and it tracks the movement relatively // without moving the graphic */ [RequireComponent(typeof(GUITexture))] public class MPJoystick : MonoBehaviour { class Boundary { public Vector2 min = Vector2.zero; public Vector2 max = Vector2.zero; } private static MPJoystick[] joysticks; // A static collection of all joysticks private static bool enumeratedJoysticks = false; private static float tapTimeDelta = 0.3f; // Time allowed between taps public bool touchPad; public Vector2 position = Vector2.zero; public Rect touchZone; public Vector2 deadZone = Vector2.zero; // Control when position is output public bool normalize = false; // Normalize output after the dead-zone? public int tapCount; private int lastFingerId = -1; // Finger last used for this joystick private float tapTimeWindow; // How much time there is left for a tap to occur private Vector2 fingerDownPos; //private float fingerDownTime; //private float firstDeltaTime = 0.5f; private GUITexture gui; private Rect defaultRect; // Default position / extents of the joystick graphic private Boundary guiBoundary = new Boundary(); // Boundary for joystick graphic private Vector2 guiTouchOffset; // Offset to apply to touch input private Vector2 guiCenter; // Center of joystick void Start() { gui = (GUITexture)GetComponent(typeof(GUITexture)); defaultRect = gui.pixelInset; defaultRect.x += transform.position.x * Screen.width;// + gui.pixelInset.x; // - Screen.width * 0.5; defaultRect.y += transform.position.y * Screen.height;// - Screen.height * 0.5; transform.position = Vector3.zero; if (touchPad) { // If a texture has been assigned, then use the rect ferom the gui as our touchZone if ( gui.texture ) touchZone = defaultRect; } else { guiTouchOffset.x = defaultRect.width * 0.5f; guiTouchOffset.y = defaultRect.height * 0.5f; // Cache the center of the GUI, since it doesn't change guiCenter.x = defaultRect.x + guiTouchOffset.x; guiCenter.y = defaultRect.y + guiTouchOffset.y; // Let's build the GUI boundary, so we can clamp joystick movement guiBoundary.min.x = defaultRect.x - guiTouchOffset.x; guiBoundary.max.x = defaultRect.x + guiTouchOffset.x; guiBoundary.min.y = defaultRect.y - guiTouchOffset.y; guiBoundary.max.y = defaultRect.y + guiTouchOffset.y; } } public Vector2 getGUICenter() { return guiCenter; } void Disable() { gameObject.active = false; //enumeratedJoysticks = false; } private void ResetJoystick() { gui.pixelInset = defaultRect; lastFingerId = -1; position = Vector2.zero; fingerDownPos = Vector2.zero; } private bool IsFingerDown() { return (lastFingerId != -1); } public void LatchedFinger(int fingerId) { // If another joystick has latched this finger, then we must release it if ( lastFingerId == fingerId ) ResetJoystick(); } void Update() { if (!enumeratedJoysticks) { // Collect all joysticks in the game, so we can relay finger latching messages joysticks = (MPJoystick[])FindObjectsOfType(typeof(MPJoystick)); enumeratedJoysticks = true; } int count = Input.touchCount; if ( tapTimeWindow > 0 ) tapTimeWindow -= Time.deltaTime; else tapCount = 0; if ( count == 0 ) ResetJoystick(); else { for(int i = 0; i < count; i++) { Touch touch = Input.GetTouch(i); Vector2 guiTouchPos = touch.position - guiTouchOffset; bool shouldLatchFinger = false; if (touchPad) { if (touchZone.Contains(touch.position)) shouldLatchFinger = true; } else if (gui.HitTest(touch.position)) { shouldLatchFinger = true; } // Latch the finger if this is a new touch if (shouldLatchFinger && (lastFingerId == -1 ¦¦ lastFingerId != touch.fingerId )) { if (touchPad) { //gui.color.a = 0.15; lastFingerId = touch.fingerId; //fingerDownPos = touch.position; //fingerDownTime = Time.time; } lastFingerId = touch.fingerId; // Accumulate taps if it is within the time window if ( tapTimeWindow > 0 ) tapCount++; else { tapCount = 1; tapTimeWindow = tapTimeDelta; } // Tell other joysticks we've latched this finger //for ( j : Joystick in joysticks ) foreach (MPJoystick j in joysticks) { if (j != this) j.LatchedFinger( touch.fingerId ); } } if ( lastFingerId == touch.fingerId ) { // Override the tap count with what the iPhone SDK reports if it is greater // This is a workaround, since the iPhone SDK does not currently track taps // for multiple touches if ( touch.tapCount > tapCount ) tapCount = touch.tapCount; if ( touchPad ) { // For a touchpad, let's just set the position directly based on distance from initial touchdown position.x = Mathf.Clamp( ( touch.position.x - fingerDownPos.x ) / ( touchZone.width / 2 ), -1, 1 ); position.y = Mathf.Clamp( ( touch.position.y - fingerDownPos.y ) / ( touchZone.height / 2 ), -1, 1 ); } else { // Change the location of the joystick graphic to match where the touch is Rect r = gui.pixelInset; r.x = Mathf.Clamp( guiTouchPos.x, guiBoundary.min.x, guiBoundary.max.x ); r.y = Mathf.Clamp( guiTouchPos.y, guiBoundary.min.y, guiBoundary.max.y ); gui.pixelInset = r; } if (touch.phase == TouchPhase.Ended ¦¦ touch.phase == TouchPhase.Canceled) ResetJoystick(); } } } if (!touchPad) { // Get a value between -1 and 1 based on the joystick graphic location position.x = ( gui.pixelInset.x + guiTouchOffset.x - guiCenter.x ) / guiTouchOffset.x; position.y = ( gui.pixelInset.y + guiTouchOffset.y - guiCenter.y ) / guiTouchOffset.y; } // Adjust for dead zone var absoluteX = Mathf.Abs( position.x ); var absoluteY = Mathf.Abs( position.y ); if (absoluteX < deadZone.x) { // Report the joystick as being at the center if it is within the dead zone position.x = 0; } else if (normalize) { // Rescale the output after taking the dead zone into account position.x = Mathf.Sign( position.x ) * ( absoluteX - deadZone.x ) / ( 1 - deadZone.x ); } if (absoluteY < deadZone.y) { // Report the joystick as being at the center if it is within the dead zone position.y = 0; } else if (normalize) { // Rescale the output after taking the dead zone into account position.y = Mathf.Sign( position.y ) * ( absoluteY - deadZone.y ) / ( 1 - deadZone.y ); } } } |
导出 build and run 看看在iPhone 上的效果,通过触摸游戏摇杆可以控制人物的上,下,左,右 ,左上,右上,左下,右下 8个方向的移动啦,不错吧,哇咔咔~~
最后欢迎各位盆友可以和MOMO一起讨论Unity3D游戏开发,本来昨天就想发表这篇文章,结果晚上去打高尔夫球连挥N杆,打的回家后浑身酸痛,回家就睡觉啦~希望大家在学习的同时别忘了多运动。哇咔咔~~~ 附上Unity3D工程的下载地址,Xcode项目我就不上传了,须要的自己导出。
下载地址:http://vdisk.weibo.com/s/abvxH
- 本文固定链接: https://www.xuanyusong.com/archives/532
- 转载请注明: 雨松MOMO 于 雨松MOMO程序研究院 发表
摇杆的拖动事件与相机跟随的旋转视角事件冲突,请问要如何做到跑动的同时不干扰缩放与旋转视角?
这个人物移动时双腿会摆动吗?是不是我导入时出问题了。
unity5里面原生动画状态机播放动画有延迟,单次没循环的动画甚至很难播放出来,请问这个可以解决吗?
我想问下 现在已经是unity4.6时代了,做3d用原生动画状态机好 还是老一套的好?
新的好。。unity说 新版动画比老版动画 效率高20%
在测试本篇代码时,发现人物移动时方向不对,后来打印了state的日志,发现初始时是2,才发现是start方法里的语句导致的,注释后就好了,不知道其他同学有没有这样的问题。
为什么你的网站有乐蜂网的广告啊,被我女朋友看到了,非要点进去,然后把电脑抢过去浏览她的化妆品了,都没电脑学习了。55555
啊…… 嘿嘿。。。。。。 可惜这一届中央候补委员我没选上…. 下届如果我选上了,一定找你做个 省长什么的!! 这么好的人 嘿嘿… 代码搞去用了哈哈 嘿嘿
蛤蛤 过奖啦。。
宣老师,我看过你出的Unity3D游戏开发的书,我现在遇到一个问题先请问下你,我把动画和模型分开导入到Project中,我把模型放到Hierarchy后拖一个动画给他,点击播放后模型就变了,请问是怎么会事啊?请指教,谢谢!
是不是模型带了默认的动画? 播放的时候 先执行他的默认动画。。
用C#写脚本和用JAVASCRIPT写脚本有什么区别呢?我看博主比较喜欢用C#写,是个人习惯还是用C#写比较好呢?如果C#写比较好,能说说C#写的优点吗?谢谢了。
c#脚本是可以调用js脚本的。。关键在于编译顺序。。js脚本在c#脚本之前先完成编译就可以了。。