文章目录

  • 0.开发流程一
  • 1.Animation Events
  • 2.Class调用&死亡动画&继承多态
  • 3.音效Audio
  • 4.对话框Dialog&淡入动画效果
  • 5.场景控制SceneManager&Invoke&BuildIndex
  • 6.趴下效果Crouch&Input设置
  • 7.2D光效
  • 8.优化代码Fix code

0.开发流程一

  详见https://blog.csdn.net/xiji333/article/details/109621328。

1.Animation Events

  首先来修改之前代码中的一个问题,你可能已经发现了,就是当人物从高处落下(不是跳跃后落下)时,动画并没有切换到 f a l l i n g falling falling,依然是 i d l e idle idle状态,而且此时落到敌人头上并不会消灭敌人,因为动画不是 f a l l i n g falling falling状态,现在来解决这个问题吧:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class PlayerController : MonoBehaviour
{void SwitchAnimation(){//animator.SetBool("idle", false);if (rb2d.velocity.y < 0 && !boxCollider2D.IsTouchingLayers(ground)) //y轴速度<0且没有接触到地面时{animator.SetBool("falling", true);}}
}

  记得也要修改 p l a y e r player player的状态机。
  接下来制作敌人的动画:

  设置状态机:

  在修改代码之前,我们先来捋一下思路。我们要实现的是青蛙的移动,但是青蛙不能一直在跳跃呀,他需要适时的回到 i d l e idle idle状态,能不能找到一种方法,让青蛙在 i d l e idle idle动画播放完毕后自动跳跃一次呢?可以,通过 A n i m a t i o n E v e n t s Animation\ Events Animation Events我们可以在某个动画的某一帧设置一个事件,让他调用某个函数。那么我们可以在 i d l e idle idle结束的时候设置一个 e v e n t s events events,调用函数使青蛙进入跳跃状态,同时我们还需要在 u p d a t e update update内修改播放的动画,而且青蛙移动的逻辑也需要修改了,如果青蛙在跳跃过程中转向的话肯定会非常奇怪吧?所以我,我们需要提前判断落点位置是否在地面上,如果不在的话就需要提前进行转向啦。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Enemy_Frog : MonoBehaviour
{private Rigidbody2D rb2d;private Animator animator;private CircleCollider2D circleCollider2D;public LayerMask ground;//为了增加游戏的多样性 我们可以设置minSpeed和maxSpeed 随机选择中间的某个值作为青蛙的移动速度public float minSpeed = 2.5f;public float maxSpeed = 4f;public float jumpForce = 4.5f;[SerializeField]private bool faceLeft = true;//记录初始时的y坐标private float initPositionY;// Start is called before the first frame updatevoid Start(){rb2d = GetComponent<Rigidbody2D>();animator = GetComponent<Animator>();circleCollider2D = GetComponent<CircleCollider2D>();initPositionY = transform.position.y;}// Update is called once per framevoid Update(){SwitchAnimation();}//这个函数将通过animation event调用!void Movement(){Vector2 frontPosition = transform.position;frontPosition.y = initPositionY;float speed = Random.Range(minSpeed, maxSpeed);//预测落地 这里并没有精确计算 不过和你的jumpForce有关系if (faceLeft)frontPosition += Vector2.left * speed;elsefrontPosition += Vector2.right * speed;if (!Physics2D.Linecast(frontPosition + Vector2.down, frontPosition, ground) || Physics2D.Linecast(frontPosition, frontPosition + Vector2.up * jumpForce, ground)) //没有检测到地面 或者头上有障碍物 {faceLeft = !faceLeft;transform.localScale = new Vector3(faceLeft ? 1 : -1, 1, 1); //角色反向//注意此时应该结束这个函数 不然frog反向后依然会跳出去 然而你并不能确定这次跳跃的有效性animator.Play("Frog_idle", 0, 0f);return;}rb2d.velocity = new Vector2(faceLeft ? -speed : speed, jumpForce);animator.SetBool("jumping", true);}void SwitchAnimation(){if (animator.GetBool("jumping")) //跳跃状态{if (rb2d.velocity.y < 0){animator.SetBool("jumping", false);animator.SetBool("falling", true);}}else if (animator.GetBool("falling")) //下落状态{if (circleCollider2D.IsTouchingLayers(ground)){animator.SetBool("falling", false);}}}private void OnDrawGizmosSelected(){Vector2 frontPosition = new Vector2(transform.position.x, initPositionY) + Vector2.left * minSpeed * (faceLeft ? 1 : -1);Gizmos.DrawLine(frontPosition + Vector2.down, frontPosition + Vector2.up * jumpForce);frontPosition = new Vector2(transform.position.x, initPositionY) + Vector2.left * maxSpeed * (faceLeft ? 1 : -1);Gizmos.DrawLine(frontPosition + Vector2.down, frontPosition + Vector2.up * jumpForce);}}


  先扯一下 d e b u g debug debug的辛酸历程,首先是青蛙的移动问题,代码中只判断了落点的有效性,然而这并不能证明当前位置和落点之间都是地面,所以青蛙还是有几率会跳出地图外,这取决于你地图的搭建以及 m i n S p e e d 、 m a x S p e e d 、 j u m p F o r c e minSpeed、maxSpeed、jumpForce minSpeed、maxSpeed、jumpForce这三个数的值,不过对于我的地图而言,上面的这种做法够用了;其次是如何拿到落点的有效位置,我这里只能做近似估计,而且要记录青蛙初始的 y y y坐标,否则基于当前坐标再判断落点的话是比较麻烦的;最后是一种比较尴尬的情况,因为 s p e e d speed speed是随机的,那么有可能出现青蛙往左跳往右跳都不行的情况,我的做法是让青蛙原地不动,再次播放 i d l e idle idle动画,顺便提一下,我的动画的 l o o p loop loop选项被关闭了,所以通过代码再次播放,如果你的动画是重复播放的,那么就无需通过代码控制。综上,这种做法并不完美,但是我目前并不打算修改orz。

2.Class调用&死亡动画&继承多态

  首先来制作老鹰:

  然后制作老鹰的动画:

  接下来开始写控制老鹰移动的代码,这里用的逻辑和青蛙不一样哦,我打算指定一个上下边界,让老鹰在这个边界内上下移动:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Enemy_Eagle : MonoBehaviour
{private Rigidbody2D rb2d;private float minPositionY, maxPositionY;[SerializeField]private bool isUp = false;public float moveLength = 2.5f;public float speed = 3.5f;// Start is called before the first frame updatevoid Start(){rb2d = GetComponent<Rigidbody2D>();minPositionY = transform.position.y - moveLength;maxPositionY = transform.position.y + moveLength;}// Update is called once per framevoid Update(){Movement();}void Movement(){if (transform.position.y > maxPositionY)isUp = false;else if (transform.position.y < minPositionY)isUp = true;rb2d.velocity = new Vector2(0, isUp ? speed : -speed);}private void OnDrawGizmosSelected(){Gizmos.DrawLine(new Vector2(transform.position.x, minPositionY), new Vector2(transform.position.x, maxPositionY));}
}

  然后制作消灭青蛙的动画:

  现在来捋一下思路,我们之前是怎么消灭青蛙的?是在人物的 O n C o l l i s i o n E n t e r 2 D OnCollisionEnter2D OnCollisionEnter2D里面直接销毁了对应的游戏对象。当游戏比较简单时这么做无可厚非,但是现在青蛙死亡要播放一段动画,如果把这段逻辑也交给人物来控制的话,是不是不太合理?我们希望青蛙自己控制这段逻辑,并向外提供一个接口供人调用即可。 o k ok ok,那么还有一个问题,青蛙要先播放完动画再消灭自己,这个怎么控制呢?当然是利用我们上一节刚学过的 e v e n t s events events辣:
E n e m y F r o g . c s : Enemy_Frog.cs: EnemyF​rog.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Enemy_Frog : MonoBehaviour
{private void Death(){Destroy(gameObject);}//供player调用public void JumpOn(){animator.SetTrigger("death");}
}


P l a y e r C o n t r o l l e r . c s : PlayerController.cs: PlayerController.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class PlayerController : MonoBehaviour
{……private void OnCollisionEnter2D(Collision2D collision){if (collision.gameObject.tag == "Enemy"){if (animator.GetBool("falling"))    //掉落状态{collision.gameObject.GetComponent<Enemy_Frog>().JumpOn();……}……}}
}

  至此青蛙的死亡动画已经做好了,但是先别激动,你还有老鹰的没做23333。不过在动手之前,我想请你认真思考一下,如果再从头实现老鹰的死亡动画的话,是不是大部分代码都是重复的?如果以后还要增加新的敌人,那岂不是每个都要重写,而且在人物的代码中还要具体区分每一个敌人。想想就头痛,那有没有更好的办法呢?当然有,我们可以使用面向对象的思维,给所有的敌人写一个基类,让敌人继承这个基类。这样不仅可以提高代码的复用,还可以让程序更加灵活。接下来将涉及到继承多态等知识,大家可以先学习一波。
E n e m y . c s : Enemy.cs: Enemy.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Enemy : MonoBehaviour
{// Start is called before the first frame updateprotected Animator animator;protected virtual void Start(){animator = GetComponent<Animator>();}// Update is called once per framevoid Update(){}private void Death(){Destroy(gameObject);}//供player调用public void JumpOn(){animator.SetTrigger("death");}
}

  老鹰和青蛙需要继承这个基类,同时它们不需要自己定义 a n i m a t o r animator animator变量了, D e a t h Death Death和 J u m p O n JumpOn JumpOn两个函数也可以省去。

E n e m y F r o g . c s : Enemy_Frog.cs: EnemyF​rog.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Enemy_Frog : Enemy
{protected override void Start(){//调用基类的startbase.Start();}

P l a y e r C o n t r o l l e r . c s : PlayerController.cs: PlayerController.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class PlayerController : MonoBehaviour
{……private void OnCollisionEnter2D(Collision2D collision){if (collision.gameObject.tag == "Enemy"){if (animator.GetBool("falling"))    //掉落状态{//注意这里得到的组件是 所有敌人的基类 Enemycollision.gameObject.GetComponent<Enemy>().JumpOn();……}……}}
}

3.音效Audio


  给 P l a y e r Player Player添加背景音乐:

  给两个敌人添加爆炸的音效并修改代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Enemy : MonoBehaviour
{// Start is called before the first frame updateprotected Animator animator;protected AudioSource audioSource;protected virtual void Start(){animator = GetComponent<Animator>();audioSource = GetComponent<AudioSource>();}// Update is called once per framevoid Update(){}private void Death(){Destroy(gameObject);}//供player调用public void JumpOn(){animator.SetTrigger("death");audioSource.Play();}
}

  人物添加跳跃、受伤、拾取樱桃的音效并通过代码控制:



4.对话框Dialog&淡入动画效果

  这一节我们将创建一个对话框,用来在恰当的时机提示用户如何进入下一个关卡,那么就要用到 U I UI UI了:

  接下来设置它的位置,注意要修改锚点:

  接下来为它添加一个子物体 T e x t Text Text,并设置相关的属性:

  我想把房子的门当作下一关的入口,所以我需要一个碰撞体,并把它当作触发器使用,同时创建一个脚本用来控制对话框的显示与关闭。如果你需要多个这样的入口,那么你可以自己实现一个预制体——带有控制脚本和碰撞体的空游戏对象,这样可以不用重新写代码,只需要把它放置在合适的位置即可。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class EnterDialog : MonoBehaviour
{// Start is called before the first frame updatepublic GameObject dialog;void Start(){}// Update is called once per framevoid Update(){}private void OnTriggerEnter2D(Collider2D collision){if (collision.tag == "Player"){dialog.SetActive(true);}}private void OnTriggerExit2D(Collider2D collision){if (collision.tag == "Player"){dialog.SetActive(false);}}
}

  接下来给我们的对话框制作一段简单的动画效果吧~注意这次的动画和之前的不太一样,之前是通过多张图片来制作的,这次要录制动画。点击下图所示的红色圆圈,就可以开始录制了。

  这个时候你可以修改对应物体(动画所对应的物体)的颜色、透明度、位置、旋转等等属性,这些修改会以关键帧的形式表现出来:

  以我制作的为例,第一帧对话框的透明度为 0 0 0,第二帧背景的透明度回到之前设置的值,文字部分保持不变,第三帧文字部分的透明度回到之前设置的值。这时候点击播放就可以看到淡入效果啦。
  在开始下一章的内容之前,你需要自己搭建第二关的地形:

5.场景控制SceneManager&Invoke&BuildIndex

  首先给我们的场景底部加一条 D e a d L i n e Dead\ Line Dead Line,当玩家掉落到这条线以下时认为游戏失败,并重新加载第一个场景,我们希望这个加载可以滞后两秒执行( I n v o k e Invoke Invoke),同时停止播放背景音乐:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class PlayerController : MonoBehaviour
{private void OnTriggerEnter2D(Collider2D collision){if (collision.tag == "Collection"){pickCherryAudio.Play();Destroy(collision.gameObject);++cherry;cherryText.text = cherry.ToString();}else if (collision.tag == "DeadLine"){//注意这个只会停止播放第一个GetComponent<AudioSource>().Stop();//延迟2s后执行Invoke(nameof(Restart), 2f);}}void Restart(){SceneManager.LoadScene(SceneManager.GetActiveScene().name);}

  接下来制作第一关到第二关的跳转。还记得我们之前制作的 d i a l o g dialog dialog吗,它是用来提示玩家进入下一关卡的,那么我们可以写一个脚本并将其挂在 d i a l o g dialog dialog上,这样只有当 d i a l o g dialog dialog为活跃状态时才能响应玩家的按键:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;public class EnterHouse : MonoBehaviour
{// Update is called once per framevoid Update(){if (Input.GetKeyDown(KeyCode.E)){SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);}}
}

  上面函数的参数是场景的 b u i l d I n d e x buildIndex buildIndex,在哪可以看到呢?

6.趴下效果Crouch&Input设置

  在开始之前,我们需要设置一下趴下的按键:


  然后制作趴下的动画并设置状态机:

  控制动画的代码很好写,不多赘述。但是当人物下蹲时,我们也应该修改它的碰撞体的位置和大小,或者使用一个新的碰撞体,更进一步,我们不能无条件的信任玩家,如果他们下蹲进入了一个障碍物,然后站立起来,此时我们依然认为人物回到了 i d l e idle idle状态的话就会有问题,比如卡在障碍物里面、播放错误的动画等等。所以我们需要判断玩家的头上有没有障碍物。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class PlayerController : MonoBehaviour
{private Rigidbody2D rb2d;private Animator animator;private BoxCollider2D boxCollider2D;[SerializeField]private int cherry = 0;[SerializeField]private bool isHurt = false;private Vector2 initBoxCollider2DOffset;private Vector2 initBoxCollider2DSize;private Vector2 crouchBoxCollider2DOffset = new Vector2(0, -0.57f);private Vector2 crouchBoxCollider2DSize = new Vector2(0.92f, 0.85f);public Text cherryText;public float speed = 7f;public float jumpForce = 7f;public LayerMask ground;public AudioSource jumpAudio;public AudioSource hurtAudio;public AudioSource pickCherryAudio;// Start is called before the first frame updatevoid Start(){rb2d = GetComponent<Rigidbody2D>();animator = GetComponent<Animator>();boxCollider2D = GetComponent<BoxCollider2D>();initBoxCollider2DOffset = boxCollider2D.offset;initBoxCollider2DSize = boxCollider2D.size;}// Update is called once per framevoid Update(){if (!isHurt)//非受伤状态{Movement();}SwitchAnimation();}void Movement(){float horizontalMove = Input.GetAxis("Horizontal");int faceDirection = (int)Input.GetAxisRaw("Horizontal");rb2d.velocity = new Vector2(horizontalMove * speed, rb2d.velocity.y);animator.SetFloat("running", Mathf.Abs(horizontalMove));if (faceDirection != 0){transform.localScale = new Vector3(faceDirection, 1, 1);}if (Input.GetButtonDown("Jump") && boxCollider2D.IsTouchingLayers(ground)){rb2d.velocity = new Vector2(rb2d.velocity.x, jumpForce);animator.SetBool("jumping", true);jumpAudio.Play();}Crouch();}void Crouch(){//头顶上没有障碍物if (!Physics2D.OverlapCircle(transform.position, 0.4f, ground)){//持续按下if (Input.GetButton("Crouch")){animator.SetBool("crouching", true);boxCollider2D.offset = crouchBoxCollider2DOffset;boxCollider2D.size = crouchBoxCollider2DSize;}else{animator.SetBool("crouching", false);boxCollider2D.offset = initBoxCollider2DOffset;boxCollider2D.size = initBoxCollider2DSize;}}}void SwitchAnimation(){//animator.SetBool("idle", false);if (rb2d.velocity.y < 0 && !boxCollider2D.IsTouchingLayers(ground)) //y轴速度<0且没有接触到地面时{animator.SetBool("falling", true);}if (animator.GetBool("jumping")) //跳跃状态{if (rb2d.velocity.y < 0){animator.SetBool("jumping", false);animator.SetBool("falling", true);}}else if (animator.GetBool("falling")) //下落状态{if (boxCollider2D.IsTouchingLayers(ground)){animator.SetBool("falling", false);animator.SetBool("idle", true);}}else if (isHurt) //受伤状态{animator.SetBool("hurt", true);int sign = rb2d.velocity.x < 0 ? -1 : 1;rb2d.velocity += new Vector2(speed * Time.deltaTime, 0f) * -sign;if (Mathf.Abs(rb2d.velocity.x) < 0.1f){isHurt = false;animator.SetBool("hurt", false);}}}private void OnTriggerEnter2D(Collider2D collision){if (collision.tag == "Collection"){pickCherryAudio.Play();Destroy(collision.gameObject);++cherry;cherryText.text = cherry.ToString();}else if (collision.tag == "DeadLine"){//注意这个只会停止播放第一个GetComponent<AudioSource>().Stop();//延迟2s后执行Invoke(nameof(Restart), 2f);}}void Restart(){SceneManager.LoadScene(SceneManager.GetActiveScene().name);}private void OnCollisionEnter2D(Collision2D collision){if (collision.gameObject.tag == "Enemy"){if (animator.GetBool("falling"))    //掉落状态{//注意这里得到的组件是 所有敌人的基类 Enemycollision.gameObject.GetComponent<Enemy>().JumpOn();rb2d.velocity = new Vector2(rb2d.velocity.x, jumpForce);    //小跳效果animator.SetBool("jumping", true);}else if (transform.position.x < collision.gameObject.transform.position.x)//左侧{hurtAudio.Play();isHurt = true;rb2d.velocity = new Vector2(-7f, rb2d.velocity.y);}else if(transform.position.x > collision.gameObject.transform.position.x)//右侧{hurtAudio.Play();isHurt = true;rb2d.velocity = new Vector2(7f, rb2d.velocity.y);}}}}

7.2D光效

  这一节我们来做一些简单的 2 D 2D 2D光效。我希望第二个场景总体是暗的,只有壁火和人物身上有光源。首先修改 t i l e m a p tilemap tilemap的渲染材质:

  自己创建一个 m a t e r i a l material material,把它添加到人物和门上面:

  然后在合适的位置添加点光源吧!记得修改光源的 z z z轴:

8.优化代码Fix code

  这一节用来优化之前的代码或者实现。首先可以清除 A n i m a t o r Animator Animator中一些没用的条件,比如人物中的那个 i d l e idle idle变量。视频中提到的其他问题我暂时没有遇到(因为我的人物只有 1 1 1个碰撞体),所以不打算修改了,至于移动和跳跃的手感问题我打算放到最后说。

Unity Sunny Land开发流程(二)相关推荐

  1. Android技术分享| 视频通话开发流程(二)

    多人呼叫 多人呼叫与点对点呼叫区别在于多人呼叫是一次呼叫1个以上的人,中途也可以再呼叫邀请别人加入通话. 整个呼叫的流程跟点对点呼叫类似,但也有些区别,需要添加额外的 API 逻辑来实现功能.下面我们 ...

  2. unity HTC vive开发笔记二

    今天来介绍 HTC vive开发之操作GUI 也就是实现手柄对物体的点击 Step 1 安装好我们需要的两个插件之后 删除我们的mainCamera 加入 assets-steamvr-cameraR ...

  3. (46)HTML网页开发流程

    一.网页开发流程 二.软件开发流程 由软件定义.开发.使用.维护到报废的过程. 一般包括问题定义.可行性分析.需求分析.总体设计.详细设计.编码.测试和维护. 软件开发涉及到的部门有:运营人员-产品经 ...

  4. 走进后端开发流程 | 青训营笔记

    目录 一.走进后端开发流程 1.传统流程 2.敏捷开发 3.SAFe简介 4.字节团队的开发流程 二.开发流程详解 1.需求阶段 2.开发阶段 云原生开发 团队的分支策略 自测 3.测试阶段 4.发布 ...

  5. 数字信号处理X——MBD开发流程与自动化测试

    目录 一.MBD开发流程 二.自动化测试demo 一.MBD开发流程 需求分析Stakehold:客户需求(产品功能)能否实现与其他零配件协同工作,对应系统测试 系统设计SRS:将产品功能设计为不同的 ...

  6. Unity手机游戏开发:从搭建到发布上线全流程实战

    前言: 技术书籍是学习技术知识的重要资源之一.读技术书可以帮助我们学习新技能和知识,技术书籍提供了可靠的.全面的信息,帮助我们快速学习新技能和知识.同时技术书籍有助于保持你的竞争力,因为它们提供了最新 ...

  7. 蓝鸥Unity开发基础二——课时20 接口

    蓝鸥Unity开发基础二--课时20 接口 一.接口 使用interface关键字定义接口 接口定义一组成员单不直接实现它们 二.实现接口 实现接口的任何类都必须实现其所有的成员方法 接口不能直接实例 ...

  8. api 二次 开发 禅道_浅谈-软件开发流程

    先直接放出我对软件开发的相关人员职责和流程: 图一:软件开发的相关人员职责 以下是截屏的开发流程泳道图: 横轴是相关开发人员的工作模块:纵轴是从上至下开发时序周期. 图二:软件开发的流程图 从职责图和 ...

  9. 软件开发模型_QT开发(二十三)——软件开发流程

    一.软件开发流程简介 软件开发流程是通过一系列步骤保证软件产品的顺利完成,是软件产品在生命周期内的管理学. 软件开发流程的本质是软件开发流程与具体技术无关,是开发团队必须遵守开的规则. 二.常见软件开 ...

最新文章

  1. windows10安装docker
  2. SAP MM 明明有需求,为啥MRP RUN后没有PR单据产生?
  3. 在.NET中使用iTextSharp创建/读取PDF报告: Part I [翻译]
  4. 百度怎么进行模糊搜索_百度搜索竞价推广效果怎么样?
  5. 5G是卡位未来的重要基础设施 物联网已成为新的攻击入口
  6. 中小型企业纯开源免费工具的解决方案
  7. Linux开机启动过程详细分析
  8. Sqoop export(Hive to MySQL) 的一些 reference
  9. 月结 sap_SAP运行物料账的常见错误
  10. iptables调试的小窍门 之前没想到啊 从抚琴煮酒那看的
  11. 如何用纯 CSS 创作一只卡通鹦鹉
  12. android之Canvas绘制图片
  13. 易筋SpringBoot 2.1 | 第廿二篇:SpringBoot的Mybatis分页插件PageHelper
  14. 计算机网络第二章-----物理层
  15. 基于h a d oop的海量图片存储模型 的分析和设计
  16. mysql端口establish_PHP/MySQL Dev. Primer (1) Establish Env.
  17. 墨尔本大学 SWEN20003 Project2 课业解析
  18. 关于视频后期美白的一些事
  19. 计算机科学与技术名言,关于科学的名言(20个最值得一读的科技名言)
  20. Vmware安装Ubuntu16.0.4出现Assuming drive cache: write through和1920X1080分辨率调节问题

热门文章

  1. Unity3D-摄像机详解
  2. [linux虚拟机] 使用yum命令时,解析不了yum源,Cannot find a valid baseurl for repo: base/7/x86_6
  3. 西安电子科技大学通院811电院821考研上岸经验分享(一)
  4. 记-玩吧-一次失败的面试
  5. 个人开发者只要一行代码接入微信支付和支付宝支付
  6. monkey快速入门
  7. 汽车云智能采集服务 八爪鱼采集器在汽车行业网站的应用
  8. 以下11條小建議,幫助你們的異地戀一直保持活力
  9. lua-switch功能实现
  10. stop word理解及超全的停用词表