荏苒追寻个人博客

做一个有追求的青年


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 日程表

Unity官方教程1——Playground学习记录

发表于 2022-09-02 | 分类于 Unity

文章链接

  • Unity官方教程0——系列内容汇总
  • Unity官方教程1——Playground学习记录
  • Unity官方教程2——Creator Kit Puzzle学习记录
  • Unity官方教程3——Creator Kit FPS学习记录
  • Unity官方教程4——Creator Kit RPG学习记录
  • Unity官方教程5——Creator Kit Beginner Code学习记录

Unity

  • Rigidbody2D使用与优化

Unity编辑器

属性

  • AddComponentMenu,通过该属性,可以在Unity的Component菜单下添加子菜单;
  • AssemblyIsEditorAssembly,程序集级别的属性,具有该属性的程序集中的任何类都将被视为编辑器类;
  • MenuItem,通过该属性,可以在Unity的菜单栏上添加菜单项;
  • SerializeField,强制Unity对脚本的私有字段进行序列化(Unity对脚本进行序列化时,仅对公共非静态的字段进行序列化,如果需要序列化私有非静态字段,则需要用SerializeField属性来指定);
  • TooltipAttribute,通过该属性,可以在Inspector窗口中为组件的属性指定工具提示(鼠标悬停在上面会有一个工具气泡提示);
  • DisallowMultipleComponent,通过该属性,可以防止将相同类型(或子类型)的 MonoBehaviour 多次添加到 GameObject;

精灵

在2D工作控件中,精灵的实质就是2D图形对象,在3D控件中,精灵的实质就是标准纹理,精灵不同于纹理的地方在于可以通过一些特殊技巧在开发过程中组合和管理精灵纹理从而达到提高效率和方便性的目的。

刚体(RigidBody2D)的四个属性:

  • Mass,质量,物体的质量
  • Friction, 摩擦力,摩擦力越大,物体运动的阻力越大
  • Angular Friction,
  • Gravity,重力,重力为0是GameObject不会掉下来;

MonoBehaviour

Unity 脚本的基类,继承它的脚本才能被作为组件加入到GameObject中,同时它还提供了基本的事件回调。除此之外:

1. Coroutines,MonoBehaviour允许开启、停止和管理协程;
 2. Events,提供了一个事件集合,可以根据具体回调的时机选择执行相应的脚步代码
     1. Start,当GameObject开始存在于场景中,或者GameObject开始实例化时。
     2. Update,每一帧都会调用
     3. FixedUpdate,每一个物理时间段都为调用,调用频率低于Update
     4. OnBecameVisible 和 OnBecameInvisible,当游戏对象的渲染器进入或离开摄像机视图时回调
     5. OnCollisionEnter 和 OnTriggerEnter,碰撞进入或者触发器进入时回调
     6. OnDestroy,游戏对象被销毁时回调

Playground简介

Playground包含的内容:

  1. 5个完整的小游戏示例;

  2. 上面5个小游戏示例所需要的图片资源(精灵)

  3. 上面5个小游戏中用到的预制件(Prefab),包括角色预制件和粒子效果预制件;

  4. 包含了四种类型的脚本,分别是:

    1. Attributes脚本

    2. Conditions脚本

    3. GamePlay脚本

    4. MoveMent脚本

问题

  1. 问:Maze游戏新建关卡时,先添加背景图片,然后添加砖块,但砖块被背景图片遮挡住了

    答:注意场景中层的概念,图片精灵添加到场景中后,除了每个组件都会有的Transform组件,还会生成一个SpriteRender组件,同时还会多出一个Additional Setting选项,这里面可以设置它在场景中的层级,值越小,越在下面,所以只要把砖块的层级设置的比背景的大就可以了。

  2. 问:Maze游戏中,触碰到旗子后如何进行场景的切换的

    答: 采用了Condition Area组件,然后在组件中执行EndOfLevelGameplayAction

  3. 问: UserInterface(游戏界面)的UI层级是如何保证的?

    答:

  4. 问:为关卡添加背景音效?

    答:添加背景音效

什么是Condition Area组件?

即条件判定区域组件,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
using UnityEngine;
using System.Collections;
using UnityEngine.Events;

[AddComponentMenu("Playground/Conditions/Condition Area")]
public class ConditionArea : ConditionBase
{
// the amount of times (in seconds) that this Condition will call OnTriggerStay
// i.e. if it's 1, it means that OnTriggerStay will be called every second
// i.e. if it's 4, it means that it will be called every 4 seconds
// ... and so on...
public float frequency = 1f;
//not used in case of ColliderEventTypes.Enter and ColliderEventTypes.Exit


//the type of event to check for
[Header("Type of Event")]
public ColliderEventTypes eventType = ColliderEventTypes.Enter;

private float lastTimeTriggerStayCalled;

// This function will be called at the beginning
void Start()
{
lastTimeTriggerStayCalled = -frequency;
}

//This will create a dialog window asking for which dialog to add
private void Reset()
{
Utils.Collider2DDialogWindow(this.gameObject, true);
}

//this function is called every time another collider enters this trigger
private void OnTriggerEnter2D(Collider2D otherCollider)
{
//is this the type of event we need?
if(eventType == ColliderEventTypes.Enter)
{
//check for the tag of the object which entered the area, if necessary
if(otherCollider.CompareTag(filterTag) || !filterByTag)
{
ExecuteAllActions(otherCollider.gameObject);
}
}
}

// This will be called EVERY FRAME when something stays inside the trigger collider
void OnTriggerStay2D(Collider2D otherCollider)
{
//is this the type of event we need?
if(eventType == ColliderEventTypes.StayInside
&& Time.time >= lastTimeTriggerStayCalled + frequency) //check also the frequency
{
//check for the tag of the object which entered the area, if necessary
if(otherCollider.CompareTag(filterTag) || !filterByTag)
{
ExecuteAllActions(otherCollider.gameObject);
lastTimeTriggerStayCalled = Time.time;
}
}
}

//this function is called every time another collider exits this trigger
private void OnTriggerExit2D(Collider2D otherCollider)
{
//is this the type of event we need?
if(eventType == ColliderEventTypes.Exit)
{

//check for the tag of the object which entered the area, if necessary
if(otherCollider.CompareTag(filterTag)
|| !filterByTag)
{
ExecuteAllActions(otherCollider.gameObject);
}
}
}

public enum ColliderEventTypes
{
Enter,
Exit,
StayInside
}
}

上述代码中,类开头的[AddComponentMenu("Playground/Conditions/Condition Area")]、属性上面的[Header("Type of Event")],这些类似于Java中的注解,在C#中这个叫特性,继承于System.Attribute类,通常用作限定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Events;

public abstract class ConditionBase : MonoBehaviour
{
//actionitems can be connected to GameplayAction scripts, and execute their one action (the method ExecuteAction implemented in each child class)
[SerializeField]
public List<Action> actions = new List<Action>();

//custom actions are more complicated to setup but more powerful, and appear only if useCustomActions is enabled
public bool useCustomActions = false;
public UnityEvent customActions;

//to perform the actions only once
public bool happenOnlyOnce = false;
private bool alreadyHappened = false;

public bool filterByTag = false;
public string filterTag = "Player";

//dataObject is usually the other object in the collision
public void ExecuteAllActions(GameObject dataObject)
{
//first check if the action has already been executed
if(happenOnlyOnce && alreadyHappened)
return;

//first execute the simple GameplayActions, if present
bool actionResult;
foreach(Action ga in actions)
{
if(ga != null)
{
actionResult = ga.ExecuteAction(dataObject);
if(actionResult == false)
{
Debug.LogWarning("An action failed and interrupted the chain of Actions");
return;
}
}
}

//execute the custom actions, if present and enabled
if(useCustomActions)
{
customActions.Invoke();
}

alreadyHappened = true; //will prevent re-executing the actions if happenOnlyOnce is true
}
}

什么是GameplayAction?

Playground 作业

注意:在学习如何制作游戏时,模仿 80 年代老游戏(例如小行星、打砖块、太空侵略者、青蛙等等……)的玩法一般来说是很不错的做法,因为这些游戏很简单。然后,随着你的水平不断提升,你可以添加越来越多的细节并优化互动方式。

如果你需要灵感,请打开 Examples 文件夹并启动其中一个游戏。检查游戏对象,看看我们是如何制作这些游戏对象的,然后尝试创建类似的游戏对象。

todo

打印高级概念中的PDF资料

利用瓦片地图构建关卡

  1. 瓦片地图
  2. 官网TileMap相关教程

Unity官方教程0——系列内容汇总

发表于 2022-09-01 | 分类于 Unity

文章链接

  • Unity官方教程0——系列内容汇总
  • Unity官方教程1——Playground学习记录
  • Unity官方教程2——Creator Kit Puzzle学习记录
  • Unity官方教程3——Creator Kit FPS学习记录
  • Unity官方教程4——Creator Kit RPG学习记录
  • Unity官方教程5——Creator Kit Beginner Code学习记录
  • Unity官方教程6——Creative Core Animation)
  • Unity官方教程7——平台游戏MicroGame
  • Unity Puzzle Match Kit学习记录
  • Unity官方多人游戏示例——MegacityMultiplayer
  • Unity官方教程8——塔防模版的学习与使用

官方教程资源链接

  • Playground,入门小示例,包括了各种已经编写好的的脚本;
  • Creator Kit Puzzle,解迷游戏示例
  • Creator Kit FPS,第一人称射击游戏示例
  • Creator Kit RPG,角色扮演游戏示例
  • Creator Kit Beginner Code
    • Creator Kit Beginner Code 中文版
    • Creator Kit Beginner Code 英文版
  • 3D Game Kit

Unity基础系列文章

  • Unity基础——音频
  • Unity基础——视频概述
  • Unity基础——物理系统
  • Unity基础——动画
  • Unity基础——Create User Interface

Unity发布

  • Unity与Android原生的通信
  • Unity与iOS原生的通信

Tanks 教程官网地址

Angry Bots2教程地址

教程PDF文件地址

知乎

Unity有哪些适合拿来练手的游戏项目?

Unity技术交流

官方入门教程

其他优质项目

  1. 月光跑酷3D版

  2. 我的世界

  3. 水果忍者

    1. Unity3DTraining,上面3个项目都在这个里面;
  4. 2048

  5. 赛车游戏

  6. 天天萌泡泡,这个是三消游戏,需要了解其核心的算法逻辑

  7. 愤怒的小鸟

  8. FishMaster

  9. 甜品消消乐

  10. DrawLines

  11. 贪吃蛇

  12. 吃豆人游戏

  13. 炸弹人

优质博客内容参考

  • 林新发CSDN博客,浏览了下相关专栏的文章,觉得很有技术含量,照着学应该能学到不少东西;
  • 水果消消乐开发实践
  • 呆呆敲代码的小Y,这个码龄只有两年的小伙伴,却在CSDN上有如此至多的产出,非常值得尊重与学习;
  • 向宇it ,博客有许多游戏示例实现的实现,虽然源码是付费的,但是核心代码都在文章中贴出来了,非常值得学习。

知乎

Unity有哪些适合拿来练手的游戏项目?

Unity技术交流

官方入门教程

sketchFab,用Google账号登录

库

UniTask, UniTask 是一种用于异步编程的 C# 库,它扩展了 .NET 中的 Task 和 await/async 模式。

Android OpenGL基础4——变换

发表于 2022-08-10 | 分类于 Android , OpenGL

前面的三篇文章中讲述了OpenGL中的一些基本概念、物体的创建、着色及纹理的应用,使物体的细节表现的更丰富,但是它始终还是一个静态物体,那么如何使物体动起来了,一种方案是在每一帧中改变物体的顶点属性值,重新渲染,这个可以实现功能,但每次都要重新想GPU传递数据,这个性能上会有很大的浪费,于是就催生了一种新的方案,通过一定方式(通常是数学中的矩阵运算来动态变换一个物体。这就是本篇的主题——变换。这里主要介绍变换时长用到的一些数学概念及这些概念涉及到的数学运算,主要就是向量和矩阵。

阅读全文 »

Android OpenGL基础3——纹理的使用

发表于 2022-08-05 | 分类于 Android , OpenGL

系列文章

  • Android OpenGL基础1——常用概念及方法解释
  • Android OpenGL基础2——Shader的使用流程
  • Android OpenGL基础3——纹理的使用
  • Android OpenGL基础4——变换
  • Android OpenGL——Android Studio OpenGL开发的简单示例

纹理概念

纹理是一个2D图片(甚至也有1D和3D的纹理),它可以用来添加物体的细节。为了能让纹理映射到物体(通常是物体某个面)上,我们需要指定这个面分别对应纹理的哪个部分,这样面的每个顶点就关联这一个纹理坐标,用来标明从纹理的那个部分采样(片段着色器采集片段颜色),然后在其他片段上惊醒片段插值。

纹理坐标在x和y轴上,范围为0到1之间(注意我们使用的是2D纹理图像)。使用纹理坐标获取纹理颜色叫做采样(Sampling)。纹理坐标起始于(0, 0),也就是纹理图片的左下角,终始于(1, 1),即纹理图片的右上角。

阅读全文 »

Android OpenGL基础1——常用概念及方法解释

发表于 2022-08-02 | 分类于 Android , OpenGL

OpenGL 对象

在顶点数据定义好了之后,通常这些属性会作为输入发送给图形渲染管线的第一个处理阶段:顶点着色器。它会在GPU上创建内存用于存储顶点数据,同时还要告诉OpenGL如何去解释内存中的这些数据,并且指定如何发送到显卡。顶点着色器接下来会处理内存中指定数量的顶点。通常会采用VBO对象来管理这个GPU上分配的内存。

VBO对象

VBO,即顶点缓冲对象(Vertex Buffer Object),主要作用就是可以一次性发送大批顶点数据到显卡上,而不是每个顶点发送一次。原因是CPU传送数据给GPU其实是比较耗时的,所以尽可能的一次性把需要的顶点数据全部传给GPU,这样顶点着色器几乎能立即访问到顶点,有助于加快顶点着色器效率。

阅读全文 »

Android OpenGL——使用OpenGL绘制立方体

发表于 2022-08-01 | 分类于 Android , OpenGL

目标

在Android的GLSurfaceView基础上,采用OpenGL的Api绘制一个带文理贴图的立方体。

步骤

小结

疑惑

  1. Shader中顶点输入的规则到底是什么?

  2. mpvMatrix指的是什么?

  3. glVertexAttribPointer和glEnableVertexAttribArray的作用

Android 好文

发表于 2022-07-29 | 分类于 Android

编译构建

刚学会Transform,你告诉我就要被移除了

Android NDK开发—— ndkBuild与cmake两种Native Build的详解

发表于 2022-07-14 | 分类于 Android , NDK开发

项目中Native编译配置时,有下面一段代码配置在主module下的build.gradle文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
android {
if (BUILD_ENV == 'ndk') {// 如果是ndk编译环境的话,需要编译Native Code
externalNativeBuild {
if (PROP_BUILD_TYPE == 'ndk-build') {// 编译Native Code 采用ndkBuild的方式编译
ndkBuild {
path "jni/Android.mk"
}
} else if (PROP_BUILD_TYPE == 'cmake') {// 编译Native Code 采用 cmake的方式编译
cmake {
path "../../KaDa-Cocos2d/CMakeLists.txt"
}
}
}
}
}

这里涉及到两种Native Code 的编译方式,分别是GNU make(对应于ndk-build命令)和CMake(对应于cmake命令),本文就主要介绍这两种方式的详细使用说明。之前的文章里面也有简单的说明:

音视频基础6——交叉编译动态库

GNU Make(ndkBuild)

CMake(cmake)

  • cmake官网
  • cmake官方文档

Android RecyclerView 分析

发表于 2022-04-18 | 分类于 Android , 控件

比较好的RecyclerView效果

  • 五行代码实现 炫动滑动 卡片层叠布局,仿探探、人人影视订阅界面 简单&优雅:LayoutManager+ItemTouchHelper

比较好的RecyclerView分析文章

  • RecyclerView 源码分析(一) - RecyclerView的三大流程
  • RecyclerView 源码分析(二) - RecyclerView的滑动机制
  • RecyclerView 源码分析(三) - RecyclerView的缓存机制
  • RecyclerView 源码分析(四) - RecyclerView的动画机制
  • RecyclerView 源码分析(五) - Adapter的源码分析
  • RecyclerView 源码分析(六) - DiffUtil的差量算法分析
  • RecyclerView 源码分析(七) - 自定义LayoutManager及其相关组件的源码分析
  • RecyclerView 源码分析(八) - ItemAnimator的源码分析(源码分析系列终篇)

自己的理解与分析

LinearLayoutManager

LayoutChunkResult

记录了四个值:

  • public int mConsumed,一次 layoutChunk 消费的宽度或高度;
  • public boolean mFinished,layoutChunk是否完成,当Recycler的next得到的View为空时 mFinished 为 true;
  • public boolean mIgnoreConsumed;
  • public boolean mFocusable;

Android 杂谈——Activity与Fragment恢复的那些事儿

发表于 2022-03-30 | 分类于 Android

最近项目测试同学反馈,App在进入二级页面后,然后退出到后台,过一段时间后,将App拉回到前台,会发现首页空白的情况。我们的App首页是ViewPager+Fragment的结构,所以怀疑肯定是长期在后台Activity和Fragment在被系统回收,在回到前台Activity和Fragment采用默认的恢复机制导致界面恢复逻辑异常导致的问题,如实就有了这篇文章,旨在记录解决问题的过程,同时研究一下系统自动恢复机制的原理。

本文代码对应API版本为: API 30
本文链接:https://rainmonth.github.io/posts/A220330.html

阅读全文 »
<i class="fa fa-angle-left" aria-label="上一页"></i>1…789…22<i class="fa fa-angle-right" aria-label="下一页"></i>

216 日志
43 分类
43 标签
GitHub
© 2025 Randy Zhang
由 Hexo 强力驱动
|
主题 — NexT.Gemini v6.1.0