跳跳涂鸦跳跳涂鸦——向上跳动游戏(学习笔记)

一、需求分析

(一)、游戏的主要玩法

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来解决

  • 生成主要通过随机数的位置。

10、难度曲线的变化

  • 主要是增加怪物的生成数量,当然达到一定程度之后就一直保持一个参数不变化了。

11、游戏物体权值的设置

  • 游戏不同之间物体的生成比例不一样,所以使用权值来确定哪些物体生成的多哪些少
  • 每个物体都有一个权值,然后加起来是总权值,生成多的个数就多设置一些。

12、换装

  • 通过改变player身上的Sprite Renderer来控制
  • 在开始界面保存游戏物体身上的sprite Renderer信息,购买了相应的皮肤之后把购买的信息赋值给开始界面。主要通过给每一个皮肤设置一个ID来控制,然后保存该ID值来进行改变。

13、游戏音乐和音效

  • 通过两个脚本来控制。
  • 背景音乐(music manager),获取游戏物体身上的AudioScenes来进行控制
  • 游戏音效(soundManager)通过一个列表装好所有的音效,在不同的点击效果来设置播放效果。

三、遇到的问题

(一)、老师错误

1、具体的

(二)、自己的错误

1、设置相机错误

  • 描述:设置两个相机是时候不能实现效果,原本主相机和背景相机相互不干扰的,但是没有该效果,背景相机移动主相机还是能看到,但是自己设置的不行
  • 原因:是从主摄像机复制一个出来进行拍摄背景的,但是自己是新建的一个相机,所以不能达到背景相机移动不影响主相机的效果。刚开设置的时候背景相机的位置跟主相机的位置不一样,所以设置了跟随以后没有跟上。如果是新建一个相机的位置跟主相机一样的话,还是能正常显示该效果的。
  • 解决:从主相机复制来制作背景相机
  • 注意:可能是位置的问题,因为位置不一样所以不能拍摄

2、测试不同的砖块的时候没有出现图片的替换

  • 描述:同上
  • 原因:设计的时候代码多了一行,但是后面没有执行,所以没有执行数组的索引替换
  • 解决:注释多写的代码
  • 注意:有时候有些参数设置了,但是后面没有处理,于是带代码上面也使用了后面没有处理的转换,于是不能达到自己想要的效果,

3、对象池生成物体的时候转换名字的时候报错,提示类型不能转换

  • 描述:同上
  • 原因:对象池回收的时候要设置为不可见状态,而代码设置了可见状态,所以不能进行同时转换
  • 解决:把代码改回来
  • 注意:写逻辑的时候对待什么时候是false什么时候是true要判断清楚。

4、砖块上下移动的时候一直向下移动

  • 描述:同上
  • 原因:在设置参数的时候,一个是y方向的移动,变成了x方向,所以砖块一直向下移动
  • 解决:把参数改回来
  • 注意:一个是在设置的时候仔细查看值,第二个是发现错误的时候定位要准确,知道是不能向上移动,肯定是x或者y的值不对。

5、floor不能跟player发生碰撞

  • 描述:
  • 原因:使用boxcollider的时候用错了,本来要使用boxcollide2D的,自己用了boxCollider
  • 解决:修改boxCollider
  • 注意:发生碰撞检测的时候,如果达不到想要的结果,先查看rigidbody,和Collider的状态,比如Collider的is Trigger勾选等。

四、最后总结

1、总结概括

  • 该游戏主要是一款2D向上跳跃游戏,主要运用技术有对象池、使用不同的对象池和随机生成方法来控制游戏物体的产生和回收、通过简单的UI框架来控制UI的显示、通过一个UI控制类添加List和栈来控制显示和隐藏,主要是给每个面板一个ID值,需要的时候出栈不需要的时候出栈、开发过程中还有很多地方运用到了List比如不同主角、方块之间的变化也是通过改变sprite Renderer来改变的。还学习了简单的换装原理。和声音管理组件的使用。

2、制作思路扩展

  • 其实不同之间的方块也可以通过面向对象的思维来制作,给方块添加一个父类。
  • 在对象池的使用过程中,也可以使用面向对象的思想,来进行写一个对象池和生成模板来进行不同的生成。

3、反思

  • 虽然看完和制作完之后,基本原理都弄清楚了,知识点也知道了,扩展思路也有,但是如果是自己写代码的话还是写不出来。
  • 一些内置方法自己也不是很清楚用法。看来编程能力还有待提高。
  • 还有就是开发的时候,有些错误可以避免的但是还是粗心没有看清楚。
  • 还有一些知识点有点懒也没有具体的写笔记,知识笼统的概括了一下而已。代码也没有贴上来。

跳跳涂鸦——向上跳动游戏(学习笔记)相关推荐

  1. 涂鸦LZ201-CN开发板学习笔记(一)

    涂鸦LZ201-CN开发板学习笔记(一) 前言 一.引出 二.准备流程 1.购买开发板 2.创建产品 (1)创建产品 (2)功能定义 (3)设备交互 (4)硬件开发 3.检查开发板 第一步: 第二步: ...

  2. 字节跳动 MySQL 学习笔记火了,完整版开放下载!

    最近很多小伙伴找我要一些 MySQL 基础资料,于是我翻箱倒柜,把这份阿里大牛总结的 MySQL 归纳笔记找出来,免费共享给大家! 据说有小伙伴靠这份笔记顺利进入 BAT 哦,所以一定要好好学习这份资 ...

  3. Unity 2D 游戏学习笔记(1)

    在学习了一段时间的C#后,终于开始学习unity啦,按照unity官方的教程一步一步的来开始学习unity的各种操作. 首先,先用2D Game Kit 来简单熟悉2D游戏的制作,因为是外网打开的比较 ...

  4. python求数列的积_python小游戏学习笔记4-2(列表【】,数列矩阵排列)

    x数值的单列写法: xlist = [1,2,3,4,5] for x in xlist: print(x) 关于len(长度)的用法:(结果为:5)(lens的作用就是把list 化为单个数字(内容 ...

  5. Mutli-SG游戏 ——学习笔记

    还是先给出Mutli-SG的定义: Multi-SG 游戏规定,在符合拓扑原则的前提下,一个单一游戏的后继可以为多个单一游戏. Multi-SG 其他规则与 SG 游戏相同. 关于这种游戏,Jia Z ...

  6. Java小游戏学习笔记

    图片的插入图片的插入之前的方法太过于繁琐,所以我们可以在对象中直接打印图片在测试类里缩减代码量代码如下: //人物图片public static Image image= CommonUtils.ge ...

  7. 学习笔记Java小游戏学习笔记

    [尚学堂]Java300集零基础适合初学者视频教程_Java300集零基础教程_Java初学入门视频基础巩固教程_Java语言入门到精通_哔哩哔哩_bilibili 图片的插入图片的插入之前的方法太过 ...

  8. 博弈论·公平组合游戏 学习笔记

    文章目录 公平组合游戏ICG N状态和P状态 游戏图 Sprague-Grundy SG函数 Nim游戏 游戏的和 SG定理 写在前面:发现是好久之前存在草稿里的,偶然间翻出来了,稍微完善了一下. 公 ...

  9. Unity-3DRPG游戏 学习笔记(1)--使用URP渲染管线

    教程地址: Unity2020 3DRPG游戏开发教程|Core核心功能01:Create Project 创建项目导入素材|Unity中文课堂_哔哩哔哩_bilibili 创建URP通用渲染管线(2 ...

最新文章

  1. 基于jQuery图片自适应排列显示代码
  2. 词向量, BERT, ALBERT, XLNet全面解析(ALBERT第一作者亲自讲解)
  3. springframework引入不进来_啥?你不知道JWT
  4. Android:ListView常见错位之CheckBox错位
  5. go在方法中修改结构体的值_golang修改结构体中的切片值方法
  6. Vue.js not detected 解决办法
  7. skype for business 无法共享桌面、无法传输图片
  8. php7 有参数类型,PHP7中的可空返回类型
  9. 单库单服解决方案terraform部署实践
  10. python脚本修改深度学习标签类别
  11. Google去广告——Adblock插件使用
  12. 服务器与客户端的简单实现
  13. iOS-成为或取消第一响应者
  14. 时间加减计算器_考前急救!2019年注册会计师计算器使用技巧,不会你就out了...
  15. c语言指数部分尾数部分,C语言中 float double在内存中的存储
  16. c语言调用json编程,c语言开发JSON - wangxuwei的个人空间 - OSCHINA - 中文开源技术交流社区...
  17. 四种电子取证软件的比较
  18. 线性代数(三十一) : 特征值与行列式以及迹的关系
  19. 基于DirectShow和FFmpeg的USB摄像头监控软件
  20. 数据分析师+前途无忧爬虫分析

热门文章

  1. 我的世界网易怎么调成java,网易版我的世界如何将单机地图改为联机地图
  2. 【Spring系列】- Spring循环依赖
  3. 测试工程师各类工具介绍
  4. Beyond Compare解决java文件对比中文乱码问题
  5. Vmware16安装(详细)
  6. html页面打印成a4的尺寸,我如何将我的html div调整为A4打印页面中的整页?
  7. Filter过滤器导致CSS样式失效
  8. 8除以2表示什么意思_8除以2等于4表示什么
  9. 本科科研经历(技术干货篇-论文发表流程)
  10. 梦想世界 2014年8月14日服务器维护公告,《命运之轮》停止运营公告