本文乃Siliphen原创,转载请注明出处:http://blog.csdn.net/stevenkylelee

前言

最近开始学习unity。学习最好的方法是动手实践。

因为游戏2048画面简单,可以自己搞定,于是选择2048作为练手对象。

在动手练习的过程中,自己积累了实践经验,也加深了对unity的理解。

写下此文,作为学习总结。希望和大家交流,彼此促进进步。

我的2048游戏可执行文件在本文的末尾可以下载到。

做出来的效果如下:

2048玩法

2048是一个益智游戏。规则是:

在 4 × 4 大小的棋盘上,玩家可以选择向“上,下,左,右”四个方向滑动方块,每次滑动成功,所有方块向滑动的方向靠拢。

相邻的且数字相同的方块会合并成一个新的方块,这个方块的数字是原先2个方块的和。

每次滑动成功,或合并成功,都会在棋盘空白区域随机位置生成一个数字是2或4的新方块。

游戏初始时,棋盘上会出现2个方块。

输的条件:棋盘填满方块,且没有方块能够合并成新的方块。

赢的条件:棋盘上出现数字为2048的方块。

游戏玩法示意图如下:

玩法细节:方块的结合律

在动手实现游戏之前,需要把核心玩法的细节都确定好。

方块水平序列( 2 2 2 )向左滑动的结合结果是:(4 2)

方块水平序列( 2 2 2 )向右滑动的结合结果是:(2 4)

方块优先向滑动的方向结合。

方块水平序列 (2 2 2 2) 向左、向右滑动的结合结果是:(4 4)

每次滑动方块,方块之间只能结合一次。

若要使上述情况结合成8,需要滑动2次。

垂直序列以此类推。

总体设计

基本流程

核心玩法类图

资源文件组织

清晰的、有规律的文件组织,能够提高开发效率,降低维护成本。

“scenes”文件夹用于放置unity的场景文件。如下图:

“scripts”文件夹用于放置脚本文件。

“scripts/scenes”文件夹以场景为单位来分类代码,每个场景文件夹下有3个文件夹,分别是:

“controller”,放置控制器代码。

“model” , 放置模型代码。

“view”,放置和用户UI界面有关的代码。

代码分类结构如下图:

其中,game_play 表示核心玩法场景。home 表示首页场景。

场景代码入口函数

很多语言和框架,都有一个程序入口函数,例如C,C#的main,

而 Unity 并没有类似这样一个所谓的“代码入口”,代码都是作为组建挂载到 GameObject 上才能执行。

为了清晰,本项目每个场景都设置一个入口脚本,这个脚本是这个场景运行的第一个脚本,其他脚本通过这个脚本进行初始化和挂载。

核心玩法的入口脚本:

using UnityEngine;
using System.Collections;public class SceneEntryGameplay : MonoBehaviour
{// Use this for initializationvoid Start (){// 加上其他的脚本gameObject.AddComponent<CtrlGameplay>();gameObject.AddComponent<UserInput>();}// Update is called once per framevoid Update (){}}

这个入口脚本挂载到场景中的一个叫“Entry”的空GameObject上,

节点 Entry 和脚本 SceneEntryGameplay 就是这个场景所有代码来龙去脉的起点。

项目设置

因为做的游戏是2D的,所以,创建项目时,选择2D项目。

摄像机属性【Projection】选择【 orthographic】,【size】设置为“6.4”。如下图所示:

为什么【size】是6.4呢。这个是通过适配分辨率算出来的,

假设要做的游戏的分辨率是 720 * 1280 ,那么 size =  6.4 = 720 / 2 / 100 ,

unity会在任何分辨率的手机上,锁定高度,扩展宽度。

几乎所有的2D游戏的分辨率适配都是通过设置摄像机的size。

核心玩法之基础搭建

获取用户输入

在unity中接收PC鼠标的输入和接收手机触摸的输入,分别用不同的方法。

为了调试方便,我们要同时支持PC和手机的输入。

我们定义:PC的鼠标按下左键 等同于 手机触屏的按下手指。PC的鼠标按下左键滑动 等同于 手机触屏的手指滑动。

脚本“UserInput”用来接收用户的输入。路径:“scripts/scenes/game_play/view/input”

简化的框架代码如下:

using UnityEngine;
using System.Collections;
using System;
using UnityEngine.UI;/*获取用户输入
*/
public class UserInput : MonoBehaviour
{// Use this for initializationvoid Start(){}// Update is called once per framevoid Update(){Mouse();Touch();}// 处理鼠标的输入void Mouse(){if( Input.GetMouseButtonDown( 0 ) ){   // 按下m_MouseMove = true;}else if( Input.GetMouseButtonUp( 0 ) ){m_MouseMove = false;}if( m_MouseMove == true ){   // 滑动}}// 处理移动设备的输入void Touch(){if( Input.touchCount == 0 ){return;}var touch = Input.GetTouch( 0 );if( touch.phase == TouchPhase.Began ){   // 按下}else if( touch.phase == TouchPhase.Moved ){   // 滑动}}// 标示鼠标是否是按下的移动bool m_MouseMove = false;}

UserInput类同时支持PC鼠标和移动设备的输入,其中PC鼠标的输入需要一个变量 m_MouseMove 来标示是否是按下鼠标键的滑动,

按下鼠标左键时, m_MouseMove = true 。抬起鼠标左键时, m_MouseMove = false。

通过 m_MouseMove 变量,在按下鼠标左键和抬起左键之间的鼠标运动,都认为是按下左键的滑动,

这样就在PC上用鼠标模拟了移动设备的手指滑动。

UserInput类需要挂载到GameObject上才能运行,

代码入口类“SceneEntryGameplay”负责挂载这个脚本。

手势识别

手势识别的作用是确定用户的操作意图。

2048的手势规则是:

手指快速向左滑动一段距离,认为是向左滑动的操作。类推向右,上,下。

手指按下后滑动速度超过某个时间长度,操作无效。

滑动操作成功后,不松手再滑动,操作无效。

每次有效滑动操作需要经历:

1.手指按下。2.朝某个方向,在指定时间内,滑动指定长度距离。

在“UserInput”类中,我们已经兼容了PC和手机的操作,

现在需要一个手势识别类,可复用在PC和手机的操作上。

脚本“Direction”用来定义滑动方向。路径:“scripts/scenes/game_play/controller”。

public enum Direction
{Left,Right,Up,Down,}

脚本“CtrlInput”是手势识别类。路径:“scripts/scenes/game_play/view/input”

代码如下:

using UnityEngine;
using System;/*处理用户输入
*/
public class CtrlInput
{public class EventArgsCtrlInput : EventArgs{public Direction Direction { get; set; }}public event EventHandler<EventArgsCtrlInput> Move;// 开始接收输入public void Start( Vector3 pt ){// 记录原点位置m_ptStart = pt;// 记录触摸开始时间m_TimeStart = Time.fixedTime;// 本次操作有效m_Flag = true;}// 检查输入public void Check( Vector3 pt ){if( m_Flag == false ){return;}if( Time.fixedTime - m_TimeStart > 3 ){   // 滑动超时return;}var v = pt - m_ptStart;// 相对于起始点的距离。var len = v.magnitude;if( len < m_Len ){return;}var degree = Mathf.Rad2Deg * Mathf.Atan2( v.x , v.y );if( -45 >= degree && degree >= -135 ){   // 左m_Flag = false;Move( this , new EventArgsCtrlInput() { Direction = Direction.Left } );}else if( 45 <= degree && degree <= 135 ){   // 右m_Flag = false;Move( this , new EventArgsCtrlInput() { Direction = Direction.Right } );}else if( -45 <= degree && degree <= 45 ){   // 上m_Flag = false;Move( this , new EventArgsCtrlInput() { Direction = Direction.Up } );}else if( 135 <= degree || degree <= 135 ){   // 下m_Flag = false;Move( this , new EventArgsCtrlInput() { Direction = Direction.Down } );}}// 触摸起点Vector3 m_ptStart;// 滑动的有效长度int m_Len = 30;// 时间起点float m_TimeStart;// 用于控制操作识别完成后,不松手再滑动,操作无效。bool m_Flag = true;}

class CtrlInput 识别出手势后会发出“Move”事件。

手势识别的原理是,逻辑上,以原点为中心把滑动空间分成4部分,上,下,左,右,每个部分90度,判断用户手指滑动的方向。

示意图如下:

Start 函数在手指按下时调用,用来定位原点在屏幕上的位置,也就是初始化原点。

Check 函数用来检查手指移动到的点是否符合手势条件,做滑动方向判断。

通过原点和手指滑动到的点算出来的角度来确定用户是往哪个方向滑动。

例如:(45)到(-45)这个范围表示向上滑动。以此类推左,右,下方向。

class CtrlInput需要被 class UserInput 调用,

class UserInput 实际代码如下:

using UnityEngine;
using UnityEngine.UI;/*获取用户输入
*/
public class UserInput : MonoBehaviour
{// Use this for initializationvoid Start(){m_Text = GameObject.Find( "txtInfo" ).GetComponent< Text >();m_CtrlGameplay = GetComponent< CtrlGameplay >();m_CtrlInput.Move += OnMove;}// Update is called once per framevoid Update(){Mouse();Touch();}// 处理鼠标的输入void Mouse(){if( Input.GetMouseButtonDown( 0 ) ){   // 按下m_MouseMove = true;m_CtrlInput.Start( Input.mousePosition );}else if( Input.GetMouseButtonUp( 0 ) ){m_MouseMove = false;}if( m_MouseMove == true ){   // 滑动m_CtrlInput.Check( Input.mousePosition );}}// 处理移动设备的输入void Touch(){if( Input.touchCount == 0 ){return;}var touch = Input.GetTouch( 0 );if( touch.phase == TouchPhase.Began ){   // 按下m_CtrlInput.Start( touch.position );}else if( touch.phase == TouchPhase.Moved ){   // 滑动m_CtrlInput.Check( touch.position );}}void OnMove( object sender , CtrlInput.EventArgsCtrlInput e ){// 在UI上显示移动方向m_Text.text = e.Direction.ToString();// 主控制器尝试用户的合并操作。m_CtrlGameplay.Merge( e.Direction );}// 标示鼠标是否是按下的移动bool m_MouseMove = false;// 处理输入CtrlInput m_CtrlInput = new CtrlInput();// 核心玩法主控制器CtrlGameplay m_CtrlGameplay;// 用于调试信息显示的文本控件public UnityEngine.UI.Text m_Text = null;}

class UserInput的事件处理器 OnMove 用来响应处理合法的用户手势操作,

这里会给游戏逻辑控制器 CtrlGameplay 发送控制指令。

棋盘地图

游戏是在 4 * 4 的矩阵中进行。可以用二维数组 List< List< Cell > > 来表示棋盘的逻辑结构。

其中Cell表示的是棋盘的每个单元格。

这里,我们直接用GameObject来定位棋盘的每个单元格。

在 Hierarchy 面板中创建一个叫“Map”的GameObject作为地图的根节点,

在“Map”下建立 4 * 4 = 16 个GameObject作为地图的每个单元格,单元格GameObject的命名规则是:“tile_行索引_列索引”。

如下图所示:

棋盘的背景可以自己发挥,这里是直接帖了一张图。

脚本“Map”用于表示整个棋盘。路径:“scripts/scenes/game_play/model”

代码如下:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;public class Map
{List<List<Cell>> m_Cells;static readonly Map m_Ins = new Map();public static Map Instance{get{return m_Ins;}}// 初始化。解析场景,生成棋盘地图逻辑结构。public void Init(){m_Cells = new List<List<Cell>>();for( int i = 0 ; i < 4 ; ++i ){var row = new List<Cell>();m_Cells.Add( row );for( int x = 0 ; x < 4 ; ++x ){row.Add( new Cell() );}}for( int y = 0 ; y < 4 ; ++y ){for( int x = 0 ; x < 4 ; ++x ){var name = string.Format( "tile_{0}_{1}" , y , x );var tile = GameObject.Find( name );var theCell = m_Cells[ y ][ x ];theCell.Position = tile.transform.position;theCell.Coord = new Vector3( x , y , 0 );}}}public List<List<Cell>> Cells{get{return m_Cells;}}}public class Cell
{// 单元格在棋盘中的逻辑坐标。public Vector3 Coord{get; set;}// 单元格在世界空间中的坐标。public Vector3 Position{get; set;}// 单元格绑定方块实体。public GameObject Entity{get;set;}}

class Map 的 Init方法解析场景的棋盘数据,生成棋盘地图逻辑结构。

游戏实体

实体"Entity"的定义比较广泛,在游戏中一般表示一个游戏体。

本项目中,游戏实体“Entity”的定义是:在游戏中出现的方块。

方块需要一些属性用来进行计算。比如:方块所代表的分值。

Unity是组件式编程,GameObject基本上就相当于表示游戏实体了。

要为游戏实体增加属性和行为,只能用为GameObject增加脚本组件的方式。

脚本“EntityProperty”用于表示游戏实体属性。路径:“scripts/scenes/game_play/model”

代码如下:

using UnityEngine;public class EntityProperty : MonoBehaviour
{// Use this for initializationvoid Start (){}// Update is called once per framevoid Update (){}// 分值public int Score{get; set;}// 关联的单元格public Cell AssociatedCell{get; set;}// 是否可以合并public bool MergeEnabled{get; set;}}

路径:“Resources/prefabs/entities”下,创建表示”2,4,8,16,32,64,128,256,512,1024,2048“分值的几个游戏实体预制,如下图:

为了方便地创建出方块实体,可以写一个方块工厂类,一句话生成方块实体。

“FactoryEntity”游戏实体工厂类。路径:“scripts/scenes/game_play/controller”。

代码:

class FactoryEntity
{static public GameObject Create( int Score ){var path = "prefabs/entities/entity_" + Score;var prefab = Resources.Load( path ) as GameObject;var theEntity = GameObject.Instantiate( prefab );// 设置分值var theEntityProperty = theEntity.GetComponent<EntityProperty>();theEntityProperty.Score = Score;theEntityProperty.MergeEnabled = true ;return theEntity;}}

核心玩法之控制器

到了这里,游戏手势识别,地图,方块实体都已经准备好了。
现在还缺一组控制器用来实现游戏流程的行为控制。

主控制器

主控制的责任是容纳和管理其他的几个子控制器,做最顶层控制流程管理。

而子控制一般只负责单一控制功能。
主控制和子控制器的关系如下:
脚本“CtrlGameplay”作为游戏核心玩法的主控制器。路径:“scripts\scenes\game_play\controller”。代码如下:
using UnityEngine;
using System;public class CtrlGameplay : MonoBehaviour
{public void Merge( Direction dir ){m_CtrlMerge.Merge( dir );if( m_CtrlMerge.HasMerged == true ){Audio.Instance.Play( "merge" );}if( m_CtrlMerge.HasMoved == true ){Audio.Instance.Play( "move" );}m_State = 1;}// Use this for initializationvoid Start (){// 初始化地图Map.Instance.Init();// 初始化实体生成器m_EntityGenerator.Init();// 开始游戏时生成的实体m_EntityGenerator.GenerateFirst();// 初始化合并控制器m_CtrlMerge.Finish += OnFinishMerge;m_CtrlMerge.CreateEntity += Tracker.Instance.OnCreateEntity ;// 初始化UIUiGameplay.Instance.Init();UiGameplay.Instance.Refresh();}void Update(){if( m_State == 1 ){m_CtrlMerge.CheckFinish();}}// 完成一轮行动void Finish(){m_State = 0;m_EntityGenerator.Generate();var JudgeRet = m_Judgement.Judge();if( JudgeRet == Judgement.JudgeRet.Lose ){int a = 1;}else if( JudgeRet == Judgement.JudgeRet.Win ){int a = 1;}}void OnFinishMerge( object sender , EventArgs e )  {if( m_CtrlMerge.HasMoved == true ){Finish();}}#region Private Fields// 实体生成EntityGenerator m_EntityGenerator = new EntityGenerator() ;// 合并CtrlMerge m_CtrlMerge = new CtrlMerge();// 判断Judgement m_Judgement = new Judgement();int m_State = 0;#endregion}
之前说过,核心玩法的场景只有一个入口函数类“SceneEntryGameplay”,这个类负责加载其他的组件代码。
脚本CtrlGameplay也是在SceneEntryGameplay中被挂载上的。
游戏核心玩法主控制器“CtrlGameplay”只有一个公共方法“Merge”。
Merge方法方法由类UserInput调用,当类UserInput检测到玩家输入了一个合法的指令(例如向左滑动)时,就调用该方法。
CtrlGameplay.Merge内部是通过调用子控制器来完成功能。

方块实体生成控制器

类EntityGenerator是方块实体生成控制器。路径:“scripts/scenes/game_play/controller”

它的作用是,移动或者合并完成后,在棋盘空余的地方生成新的方块。

代码如下:

using UnityEngine;
using System.Collections.Generic;// 实体生成器
public class EntityGenerator
{public void Init(){}// 游戏初始时的生成逻辑。public void GenerateFirst(){for( int i = 0 ; i < 2 ; ++i ){Generate();}}// 生成实体public bool Generate(){// 选出空余的位置List<Cell> EmptyCells = new List<Cell>();var Cells = Map.Instance.Cells;for( int y = 0 ; y < Cells.Count ; ++y ){for( int x = 0 ; x < Cells[ y ].Count ; ++x ){if( Cells[ y ][ x ].Entity == null ){EmptyCells.Add( Cells[ y ][ x ] );}}}if( EmptyCells.Count == 0 ){return false;}int idx = Random.Range( 0 , EmptyCells.Count - 1 );var theCell = EmptyCells[ idx ];// 生成实体var entity1 = FactoryEntity.Create( 2 );entity1.transform.position = theCell.Position;theCell.Entity = entity1;return true;}}

方块实体合并控制器

实体合并控制器只完成一个工作:朝指定方向滑动方向,合并方块。

合并与滑动方块的算法用向左滑动为例来说明:

* 遍历地图的每一行,对于每行从左向右扫描单元格。

* 如果当前扫描到的地图单元格有方块的话,向左查找一个最近的方块。最近的方法的定义是,没有被其他方块阻隔。

* 找到了最近的方块,判断是否可以合并,如果可以合并,就销毁这2个方块,在左边的方块的位置上生成一个新合并后的方块。

* 如果没有找到可以合并的方块,就向左查找一个最左的空的位置,看是否可以移动到空的位置上。

算法图示如下:

向右,向上,向下的算法以此类推。

最终的效果如下所示:

代码有400行之多,这里就不贴了。

方块实体移动控制

cocos2d 对于物体的移动,缩放等有很好的支持,动作 MoveTo 一句话就可以执行运动。

而unity的物体运动,需要自己在Update函数中写代码。

如果是用位置不断加速度的做法,很容易会造成“穿越”目的点,而不是刚好停在目标点上。

这里,模仿cocos2d的Action MoveTo,设计一个移动控制器来控制方块实体的移动。

该控制器需要2个参数:时间长度,目的点。

功能:在指定的时间内达到指定的目的点。

代码如下:

using UnityEngine;
using System.Collections;
using System;public class MoveTo : MonoBehaviour
{public EventHandler Finish;// Use this for initializationvoid Start (){}// Update is called once per framevoid Update (){m_Elapsed += Time.deltaTime;var f = m_Elapsed / m_Duration;if( f >= 1 ){gameObject.transform.position = m_Src + m_v;enabled = false;if( Finish != null ) Finish( this , null );return;}var pt = m_Src + m_v * f;gameObject.transform.position = pt ;}public void Start( float Duration , Vector3 dst ){this.m_Duration = Duration;this.m_Dst = dst;m_Src = gameObject.transform.position;m_v = dst - m_Src;m_Elapsed = 0;enabled = true;}float m_Duration;Vector3 m_Dst;float m_Elapsed = 0;Vector3 m_Src;Vector3 m_v;}

MoveTo.Start 函数用于启动运动,启动运动时,记录当前位置,算出当前位置和目标位置的向量。

然后 Update 函数,计算当前流逝的时间和目标时间的百分比,确定在当前时间点,应该朝向目标位置移动多少距离。

使用原位置不断执行偏移量加法的方法,可以避免计算误差,最后精确地落在目标点上。

判断游戏输赢

判定游戏输赢依次执行以下步骤:

* 如果出现了2048数字的方块,判赢。

* 如果棋盘还有空位,游戏继续。

* 如果棋盘没有空位,但有可以合并的方块,游戏继续。

* 判输。

下载本文的游戏demo

本文章的2048游戏demo下载地址(包含 PC ,Android 平台):

http://download.csdn.net/detail/stevenkylelee/9579545

Unity 游戏2048:制作总结相关推荐

  1. 天上的街市Unity游戏场景制作案例(一)

    目录 Downtown Street of Heaven 场景 Unity实现过程 新建项目 场景布置 场景制作参考 移动媒介的添加 Downtown Street of Heaven 场景 Unit ...

  2. Unity 游戏Demo制作 地下城 二

    这篇大致是优化了一下房间门和墙壁的逻辑,接着增加了人物逻辑,然后增加了切换房间的同时切换摄像机位置.部分逻辑也参考了其他前辈的资料. 首先是房间门,因为免费素材比较难找,游戏本身也是致敬以撒的,因此就 ...

  3. Unity 游戏Demo制作——地下城 一

    想做一个类似以撒的肉鸽游戏,然后记录一下进度,也做个学习的总结笔记吧,目前想到的要素:随机地图生成,敌人AI,角色控制和攻击,一些动画,还有随机掉落物品,商店. using System.Collec ...

  4. Unity游戏快速制作特效

    专家进阶教学之一 先立个flag吧,反正我也还不懂 估计也很难完成,先定亿个小目标

  5. Unity游戏排行榜的制作与优化

    前言 游戏排行榜是一个很重要的功能,在弱联网的单机游戏与网络游戏中排行榜都是非常重要的,今天我们来详细的讲解游戏排行榜的制作方案,主要有4个点: 对啦!这里有个游戏开发交流小组 里面聚集了一帮热爱学习 ...

  6. Unity常用模块设计 : Unity游戏排行榜的制作与优化

    游戏排行榜是一个很重要的功能,在弱联网的单机游戏与网络游戏中排行榜都是非常重要的,今天我们来详细的讲解游戏排行榜的制作方案,主要有4个点: 对惹,这里有一个游戏开发交流小组,希望大家可以点击进来一起交 ...

  7. Unity小地图Minimap制作全面功能介绍篇

    本系列文章将讲述如何制作小地图. 功能如下: 小地图制作和美化       https://blog.csdn.net/alayeshi/article/details/115914212 小地图展示 ...

  8. ​Unity 游戏开发技巧集锦之制作一个望远镜与查看器摄像机

    ​Unity 游戏开发技巧集锦之制作一个望远镜与查看器摄像机 Unity中制作一个望远镜 本节制作的望远镜,在鼠标左键按下时,看到的视图会变大:当不再按下的时候,会慢慢缩小成原来的视图.游戏中时常出现 ...

  9. Unity 4 3 制作一个2D横版射击游戏 2

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 在上一篇 ...

最新文章

  1. ipvsadm的命令参考
  2. 作用域安全的构造函数
  3. 第十一回:琴房外度曲生慕意 书店里软语救阿四[林大帅作品集]
  4. python 虚拟环境 django.db 报错_jumpserver一体化安装
  5. 【渝粤题库】陕西师范大学201371 国际法学作业
  6. axios发送post数据后台收不到_使用axios post 提交数据,后台获取不到
  7. 单交换机VLAN 配置和结果验证(51cto-o8)
  8. linux下字体怎么安装方法,linux安装字体方法
  9. angular cli_使用Angular CLI连接到服务器的最佳方法
  10. C#基础5:字符串操作
  11. WebDevHelper -- RESTful服务和Ajax开发时的利器
  12. ios系统软件迁移到安卓_IPHONE数据迁移到安卓系统操作分析:
  13. 删除亚马逊Kindle电子书的DRM,将AZW转为PDF格式文档
  14. 读书笔记——晶体管电路设计
  15. Android 国内集成使用谷歌地图
  16. 一个海底隧道中只有一个车道,规定同一个方向的可以连续过隧道。某方向有列车过隧道时,另一个方向的列车就要等待, 现在东岸和西岸都有列车要过隧道,如果把每个过隧道的列车看作一个进程,使用P、V操作
  17. echarts 3 无法显示和弦图chord解决办法
  18. 什么是哈希冲突,怎么解决哈希冲突的问题?
  19. html怎么链接ftp地址,在浏览器的地址栏中输入xxxyftp.abc.com.cn,该URL中()是要访 - 信管网...
  20. Speedoffice(Excel)中如何标记重复内容

热门文章

  1. mybatisplus 分页组件
  2. 计算机一级 文档计算总和,江苏省计算机一级选择题总和.docx
  3. Ubuntu10.04下build OpenJDK7 的过程
  4. 2018 CocoaPods安装详解
  5. 小马哥---高仿小米4 主板型号H71T 刷机拆机主板图与开机识别图 v009标贴 15年版本
  6. HTML绘制齿轮,如何用CAD绘制三维立体齿轮??
  7. bzoj 1001狼抓兔子
  8. 淘宝天猫最本质的区别是什么呢?
  9. 荣耀v8升级android 8,荣耀逆向升级?简单谈谈荣耀V8升级荣耀8X感受
  10. 算法 - 粒子群(PSO)算法