跳跳涂鸦跳跳涂鸦——向上跳动游戏(学习笔记)
一、需求分析
(一)、游戏的主要玩法
1、是一款2D向上跳动游戏
主要玩法:player向上跳动,然后有五种类型的砖块,每个砖块有不同的属性、砖块上面有怪物,也有相应的道具,吃了道具有不同的效果。附加玩法:通过吃金币来购买皮肤拓展玩法:死亡后花钱复活,可以花钱买道具、总之可以在核心晚上的基础上加上其他的类型。还可以添加双人模式等…2、 五种砖块的属性
第一种:普通的,就是站上去向上跳第二种、跳不上去第三种:跳上去之后让主角向上跳一次,然后就下落第四种:跳上去之后高度是第一种的1.5倍第五种:在第一种的基础之上添加左右移动,和上下移动。3、游戏物体
砖块、敌人、主角、各类UI面板二、知识点
(一)、原理知识
1、添加专门的背景相机
因为游戏人物要向上移动,所以背景会离开相机的照射范围解决方案有两个,一、添加两个相机。二、背景跟随相机移动使用添加两个相机来解决,先让背景能正常的在主相机上面显示,然后新建一个相机,位置信息跟主摄像机位置保持一直,然后设置背景的渲染层级(layer)为water,然后背景相机的culling Mask 只勾选water照射层级跟背景一样,然后再设置主相机的模式为Depth only。Culling Mask 不勾选water.2、设置底部图片跟随相机的变动而变动长度
原理:图片的宽高能转化成相机照射的宽高,然后窗口的宽高跟相机照射宽高一样,在图片不能适应屏幕比例或者相机照射窗口的时候,可以通过比例调节图片的宽高以达到跟相机照射宽高一样。
这里实际上是固定了屏幕比例,然后让图片适应相机照射范围。让相机照射范围的比例,跟图片转化到屏幕比例的大小一致。通过改变图片的宽高来达到一致。
(二)、插件知识
1、使用了iTween来控制MainUI中的player跳动
换装界面的动画也是使用iTween来设置的
GameOver面板的弹出也是通过iTween来设置的
iTween.MoveBy(gameObject, iTween.Hash("y", offsetY,"easeType", iTween.EaseType.easeInOutQuad,"loopType", iTween.LoopType.pingPong,"time", time));
(三)、操作知识
1、UI面板的搭建
根据需求来制定游戏面板UI面板主要有Main、InGame、Pause、GameOver、Skin五个五个之间的切换有两种方式 第一种:通过删除在穿件的方式来确定,和通过setactive来设置第二种:通过CanvasGroup里面的alpha来设置2、通过简单的UI框架来控制UI之间的切换
设置GUIManager来控制,通过一个List和Stack来装UI面板。通过出栈和如栈来控制显示。(四)、代码相关
1、设置Player的弹跳跟左右移动
跳弹的原理主要是用刚体里面的方法来实现,需要注意的是每次跳完之后要从小设置加速度为0
通过Tag来判断是不是Player进入,是Player进入才进行弹跳
private void OnTriggerEnter2D(Collider2D collision){if(collision.tag == "Platform")Jump(1);}public void Jump(float x){GetComponent<Rigidbody2D>().velocity = Vector2.zero;GetComponent<Rigidbody2D>().AddForce(new Vector2(0, 12 * x), ForceMode2D.Impulse);}
左右移动:主要是通过按键的按下来控制位移来解决,通过Player身上的位置信息来进行移动
移动的时候要注意Player转向的问题,通过一个三维值来转向
Vector3 acc = Vector3.zero;Vector3 diff;if (Input.GetKey(KeyCode.LeftArrow)){acc.x = -0.1f;transform.localScale = new Vector3(-1, 1, 1);}if (Input.GetKey(KeyCode.RightArrow)){transform.localScale = new Vector3(1, 1, 1);acc.x = 0.1f;}diff = Vector3.MoveTowards(transform.localPosition, transform.localPosition + acc, 0.5f * Time.time);diff.y = transform.localPosition.y;diff.z = 0;
2、控制Player移动到边界的问题
Player跳到左边界的时候让其回到右边界,同理右边也一样设置两个标志位来记录左边和右边,两个标志位的位置获得通过相机的世界坐标来确定通过跳到位置信息和两个表示为来进行判断得到是否越界float rightBorder;float leftBorder;void Start () {leftBorder = Camera.main.ViewportToWorldPoint(new Vector3(0, 0)).x;rightBorder = Camera.main.ViewportToWorldPoint(new Vector3(1, 0)).x; }if (diff.x < leftBorder){diff.x = rightBorder;}if (diff.x > rightBorder){diff.x = leftBorder;}transform.localPosition = diff;
3、设置Tile的类型和参数
设置砖块类型的变换,碰撞效果等。需要添加刚体和碰撞体。通过Sprite数组来进行图片的变化,然后每个图片都是一样的效果。通过switch来进行不同砖块属性的变换4、 控制相机跟随主角
正常情况下主角移动相机跟随,但是这样个人的感觉不太好,所以设置为主角超过屏幕中间的之后相机才跟随移动
//当前位置public Transform target;//目标位置的初始位置private Vector3 velocity = Vector3.zero;private float dampTime = 0.5f;public void Update(){if (target){//使用pos来标记相机当前查看的位置为主角的当前位置Vector3 pos = Camera.main.WorldToScreenPoint(target.position);//需要移动的位置Vector3 delta = target.position - Camera.main.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, pos.z));//设置目标位置的初始位置Vector3 destination = transform.position + delta;destination.x = 0; //默认x为0if (destination.y > transform.position.y){//SmoothDown方法 参数一:当前位置,参数二:移动距离,参数三:目标的初始位置,参数四:时间间隔transform.position = Vector3.SmoothDamp(transform.position, destination, ref velocity, dampTime);}}}
5、单例模板
使用单例模板来控制所以代码的单例模式public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoBehaviour{private static T m_instance;public static T Instance{get { return m_instance; }}protected virtual void Awake(){m_instance = this as T;}}
6、随机生成砖块(GameSetting类)
使用一个类来控制砖块的各种高宽属性,用编辑器拓展来进行手动赋值设置,值根据需求来变动使用对象池来管理所以的砖块生成和回收。使用权值来控制不同砖块生成的比例问题。7、砖块的左右移动和上下移动
使用一个变量来统一控制,当左右移动和上下移动的砖块达到一定位置的时候就向反方向移动。然后通过OnTriggerOnenter来设置移动。8、对象池的设置
所以的游戏物体都用对象池来生成,这里没有用到对象池模板,而是简单的设置了一下生成和回收
所以游戏物体都一个自己的随机生成方法和对象池
生成参数有,最大高度、最小高度、生成数量、和其他不同东西之间需要的参数
/// <summary>/// 从池子取物体/// </summary>/// <param name="type">类型</param>/// <returns></returns>public GameObject GetInactiveObject(ObjectType type){switch (type){case ObjectType.Tile:return tilePool.Dequeue(); case ObjectType.Item:return itemPool.Dequeue(); case ObjectType.Coin:return coinPool.Dequeue();case ObjectType.Enemy:return enemyPool.Dequeue();case ObjectType.Bullet:GameObject go = bulletPool.Dequeue();go.transform.position = bulletSpawnPos.position;go.SetActive(true);return go; default:return null;}}/// <summary>/// 回收物体/// </summary>/// <param name="go">游戏物体</param>/// <param name="type">游戏物体类型</param>public void AddInActiveObjectToPool(GameObject go, ObjectType type){go.SetActive(false);switch (type){case ObjectType.Tile:tilePool.Enqueue(go);CreateTile();break;case ObjectType.Item:itemPool.Enqueue(go);break;case ObjectType.Coin:coinPool.Enqueue(go);break;case ObjectType.Enemy:enemyPool.Enqueue(go);break;case ObjectType.Bullet:bulletPool.Enqueue(go);break;default:break;}}
9、物体的生成和单个物体的对象池
比较多,而且都类似,所以只放一个上来
void GenerateTilePool(){for (int i = 0; i < initialSize; i++){GameObject go = Instantiate(tilePrefab, transform);go.SetActive(false);go.name = i.ToString();tilePool.Enqueue(go);}}GameObject go = GetInactiveObject(ObjectType.Tile);float rand = Random.Range(0, totalsum);int randNumber = SetTileByRandomNumber(rand); Vector2 pos = new Vector2(Random.Range(-3.5f,3.5f),currentY);
根据不同游戏物体的需求来具体生成,如果同一个游戏物体有几个类型就用枚举类型加witch来解决
生成主要通过随机数的位置。