Unity学习笔记 - Roguelike Tutorial(中)

// Unity学习笔记(零基础入坑),自用的同时也许也能帮助别人

// 初学者,没太多编程基础,所以难免可能会有写错的地方,请见谅

//详细教程视频都有,笔记只记重点

传送门:  Unity学习笔记 - Roguelike Tutorial(上)

五、让游戏元素动起来


1. 创建了一个基类

为玩家和敌人提供运动功能,玩家和敌人的脚本会继承这个基类。

public abstract class MovingObject : MonoBehaviour {}

关于abstract:

The Abstract keyword enables us to create classes and class members that are incomplete and must be implemented in the derived class.

https://msdn.microsoft.com/en-gb/library/sf985hc5.aspx

2.变量

public float moveTime = 0.1f;    //移动 1 point 的时间

public LayerMask blockingLayer;  //检测碰撞的层

private BoxCollider2D boxCollider;

private Rigidbody2D rb2D;

private float inverseMoveTime;


3. 函数1 - Start函数


获取到会用到的变量

4. 函数2 - 平滑运动函数 SmoothMovement


使玩家和敌人呈现连续、平滑的运动。

输入目的地的Vector3即可实现当前物体向目的地的连续、平滑的直线运动

逻辑:和终点有距离——>向终点方向移动一“步”(inverseMoveTime * Time.deltaTime)并刷新距离——>停一帧——> 和终点有距离 ……

Magnitude是向量的长度,sqrMagnitude是长度的平方:

一个向量V的长度计算方法是Mathf.Sqrt(Vector3.Dot(v, v))。然而,sqrt计算是相当复杂的,需要更长的时间比正常执行算术操作。计算长度平方来代替直接计算长度速度更快,除掉开根号计算是基本相同的。如果你只是使用大小比较的距离,那么你同样可以比较平方长度大小来比较距离,得到相同的结果。

http://wiki.ceeger.com/script:unityengine:classes:vector3:vector3.sqrmagnitude

public static Vector3 MoveTowards(Vector3 current, Vector3 target,  float maxDistanceDelta);

MoveToward的作用是将当前值current移向目标target。(对Vector3是沿两点间直线)

maxDistanceDelta就是每次移动的最大长度。

返回值是当current值加上maxDistanceDelta的值,如果这个值超过了target,返回的就是target的值。

文/fan2b(简书作者)

原文链接:http://www.jianshu.com/p/6287f18260f5


5. 函数3 - Move


输入移动方向,返回是否有障碍及障碍物体

没有障碍则触发“平滑运动函数” SmoothMovement (有障碍的问题会在后两个函数中处理)

out”在这里被用来让函数返回多个值,即不止返回一个bool值,还会返回一个raycastHit2D类型的值(hit)。

The out keyword causes arguments to be parsed by reference. In this case we're using it to return more than one value from our Move function.

boxCollider.enabled = false;

We're going to disable the attached box collider2D to make sure that when we are casting our ray that we're not going to hit our own collider.

hit = Physics2D.Linecast(start, end, blockingLayer);

Physics2D.Linecast会返回一个RaycastHit2D,即射线检测到的第一个物体。


6. 函数4 - AttemptMove 获取障碍物


接收Move函数返回的障碍物,

获取到障碍物的component并作为参数传入函数5 OnCantMove,并运行OnCantMove。

泛类型 <T>

public T GenericMethod <T> (T param)

在函数被实际调用时,T会被具体的类型替代。

http://unity3d.com/cn/learn/tutorials/topics/scripting/generics

*之所以使用泛类型是因为,在继承类player、和继承类enemy中障碍的类型是不同的(墙、player)。

泛型类型约束——关键字 where

protected virtual void AttemptMove(intxDir,intyDir)    where T:Component

{ ... }

限定泛类型的范围

四种限制类型:

Class, Struct, new (), interfaces

https://msdn.microsoft.com/zh-cn/library/bb384067.aspx


7. 函数5 - OnCantMove

abstract函数,在基类中未定义具体功能,在继承类中会被重写,以实现在不同继承类中的不同功能。

2016.08.10 这篇脚本 对一个零编程基础的“玩家”真心够复杂,而我的技巧就是适度地 不 求 甚 解!


六、墙的逻辑


C# Wall,撞一下会碎,撞多了会消失。

墙被撞的时候,调用函数DamageWall就可以了。

返回unity,要把这个脚本挂在8块墙上,每块墙的dmgSprite变量处要放入对应的被撞碎的墙的图片。

七、Player动画控制器设置


打开Player的Animator Controller。

1. 参数列表里,新建两个trigger,一个用来触发攻击,一个用来触发受伤。

2. 在PlayerIdle和PlayerAttack之间建立双向Transitions

PlayerIdle --> PlayerAttack: Has Exit Time不勾选,即触发后立即切换动画

PlayerIdle <-- PlayerAttack: Has Exit Time勾选,即当前动画结束后切换动画,Exit Time =1,即完全播完后切换

Transition Duration都改为0,因为2D的基于sprite的动画切换无法实现过渡,3D才需要。

3. 触发条件设定:PlayerIdle --> PlayerAttack的Condition选上建好的Trigger

4. PlayerIdle和PlayerDamage同理

动画转换测试:

点击左下参数列表里的Trigger即可触发相应动画:

2016.08.11 


八、Player的脚本 —— 控制player的移动


先在GameManager中补充了一些要用到的东西:

几个变量
一个函数

新建脚本Player

继承与变量

1. 函数 - Start


重写基类函数:

protected override void Function ()

    {    重写内容……

     base.Function();

    重写内容…… }

2. 函数 - CheckIfGameOver


3. 函数 - 重写 AttemptMove


4. 自启动函数 - Update


上图有个错误Horizontal

##两次栽在Input.GetAxis的这个“Horizontal”上了,是“Horizontal”不是“Horizonal”啊!

调用AttemptMove,同时设定泛类型T-->Wall,并传入获取到的输入参数。

*泛类型在函数被执行时,需将泛类型具体化。

AttemptMove运行时会调用基类中的Move函数和OnCantMove函数,而Move函数又会调用SmoothMovement函数。

Input.GetAxisRaw:

Since input is not smoothed, keyboard input will always be either -1, 0 or 1. This is useful if you want to do all smoothing of keyboard input processing yourself.


5. 函数 - 重写OnCantMove


6. 函数 - Restart


7. 自启动函数 - OnTriggerEnter2D


8. 自启动函数 - OnDisable


当前物体disable的时候,将分数值传给GameManager

9. 函数 - LoseFood


当前脚本中未被调用,留在enemy脚本中产生攻击时调用。

最后,Player脚本挂到player上,Blocking Layer选好。

2016.08.12  Fighting


九、Enemy的脚本 —— enemy的移动和攻击


1. 继承MovingObject,重写Start函数

获取自身动画和player的transform。

2. 重写AttemptMove函数

增加是否移动的判断,enemy动一帧停一帧,不会连续动。

3. 新增函数 MoveEnemy —— 智能判断趋向player的移动方向

这个函数的作用是判断往哪个方向移动,先选X or Y,再选 正 or 负。

MoveEnemy是这个脚本的核心,它调用AttemptMove,而AttemptMove则调用其他基类中的函数。但enemy脚本中并不包含Update,MoveEnemy会被GameManager调用。这大概是因为当前是否让enemy移动的判断要写在GameManager里,并且场景中会有多个enemy。

public void MoveEnemy()

This is going to be called by the GameManager when it issues the order to move to each of our enemies in our Enemies list.


Mathf.Abs()是取绝对值。

这里也凸显了float.Epsilon作为一个无限接近于0的数值的作用。

条件表达式:

基本格式        表达式1? 表达式2:表达式3

1为真则返回2的值,1为假则返回3的值。

http://blog.csdn.net/liyzh_inspur/article/details/3080769

4. 重写OnCantMove

动画那句应该是弄好animator  controller之后加

最后要返回编辑器把脚本挂在两个enemy上,把playerDamage参数设定上,还有blockingLayer。

2016.08.13 


十、Enemy动画控制和行动触发


1. enemy动画控制器

跟player动画控制器的操作基本相同

Enemy1Idle ---> Enemy1Attack :No Has Exit Time,Condition +Trigger "enemyAttack"

Enemy1Idle <--- Enemy1Attack :Has Exit Time, Exit Time = 1

Transition Duration都改为0

2. GameManager中调度enemy的移动


变量:

Awake新加List

每次开始新level,GameManager重新加载,Awake运行,清空上一关的敌人:

加敌人到列表的函数,在enemy脚本中调用:

协程,调用enemy脚本中的移动函数:

*为什么如果没有敌人,要多停一下,player再动?不知道。

Update 调用协程MoveEnemies,MoveEnemies调用enemy上的MoveEnemy完成移动:

2016.08.14

PS: 今天测试的时候发现,动画Trigger名字的大小写又搞错了,然后OutWall没有加Collider

2016.08.15

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,406评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,976评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,302评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,366评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,372评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,457评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,872评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,521评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,717评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,523评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,590评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,299评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,859评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,883评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,127评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,760评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,290评论 2 342

推荐阅读更多精彩内容