25731人加入学习
(149人评价)
Unity2D 初级案例 - 坦克大战(Unity2017.1)

制作于2017年12月23日

价格 免费

将敌人v初始值是负的,一出生往下走

将旋转计时器一开始设为0

玩家状态的管理

创建一个空 PlayerManager

再挂一个同名脚本

属性值 生命值 得再写单例 静态

右键圈住 按住ctrl不松 然后按住re

游戏一开始便在Awake方法里

Instance = this;

玩家复活的方法

public bool isDead;

private void Recover()

先判断一下生命值 小于0与--,生命值未归为0,则重新出生

再拿一下born的引用 公共变量法

再在else中 用一个GameObject'变量接收一下born(共用的born)

再拿脚本 将createPlayer = true;

isDead = false;

再在update里判断一下如果死亡 则调用Recover方法

再在玩家的死亡方法里  加上调用

PlayerManager.Intance.isDead = true;

得分

再在敌人的死亡方法里

PlayerManager.Instance.PlayerScore++;

 

 

[展开全文]

我用的是2017.4.2f2的版本

上面显示说Instance有保护级别,不可调用

 

[展开全文]

1.代码提示问题

打开preferences→extemal tools

2.在window中可以打开自己想要的面板

可以自由拖放自己的面板,然后在layout保存自己喜欢的布局

一般用tall,然后调整一下project

3.后期导入的模型跟音效都会保存在Assets里

4.创建项目后项目名称带*,说明项目没有保存

5.快捷键

复制 :ctrl+D

聚焦物体 :F

环绕查看:Alt+鼠标左键

步移工具:ctrl

修改名称:F2

注释:Ctrl+K

取消注释:Ctrl+U

自动吸附顶点:V

在视野的模式下:按Q键向下,E向上,W向前

6.旋转

Local围绕自身轴旋转

Gobal围绕空间轴旋转

(Local自身坐标系,Gobal全局坐标系)

Transform中的Rotation表示旋转度数,Scale表示缩放

7.pivot建模原点;center中心

8.使用步移工具,必须要切换到Global状态

9.每个游戏角色都有自己名字,F2修改名称

10.smoothness光滑程度

11.mesh网格;Mesh Runderer在网格上渲染

12.建模一般建两种,一种精细化用来渲染,一种是简模,用来做碰撞检测

13.发生碰撞效果,添加“刚体组件Rigidbody”

script创建脚本(脚本也是一种组件,可以通过创建/删除组件来控制)

14.C#script中,如"public class Player"中的Player,后期就算修改要记得跟运动物体保持一致

15.注释:Ctrl+K、Ctrl+C

取消注释:Ctrl+K、Ctrl+U

16.如何使刚体组件与具体的一个运动物体连接,有两种方法:

1.在代码中更改,=在算法中相当于赋值:如rd=GetComponent<什么类型的组件如Rigidbody>();刚体是模拟物理效果,我们要给他施加力才能运作起来,在update中给施加持续的力,如:

rd.AddForce(力的大小跟方向如Vector3.right);

2.拖拽的方式 :将Player拖拽到组件rd的位置,但拖拽容易出现引用丢失的情况。如果有两个刚体组件的话,会以代码指定的为准。

17.代码中的public/private:组件中的属性可以是公开的,也可以是私有的,一般只把必要的属性设置为公有的。如果设置为私有的就没办法通过拖拽设置值了。

18.向量:forward、Left、back、right

19.监听键盘按下:float h = Input输入,GetAxis得到轴("Horizontal"水平轴) ,h是一个小数的意思。点击播放按钮,小球落下,点击图形界面,按键A,看到Consale里从0→-1的变化。Debug.Log(h);→rd.Addforce(new Vector3(h,0,0))l;注:vector中的h如果赋不上值,可以复制前面的内容。键的控制快捷键可以通过Project Settings→Axes中修改;player的运动速度可以通过rd.AddForce(new Vector3(h, 0, v)*1);*1代表速度

20.控制相机跟随小球移动:在Camer中添加脚本→计算两个位置的差→Vector3 offset(偏移)=transform.position(自身的位置)-(小球的位置)playerTransform.position;

小球的位置怎样获得?输入属性:public Transform playerTransform;然后回到界面,打开Camer,把player拖拽到Camer中的Script

设置主相机的位置:transform.position=playerTransform.position+offset;(注:offset下方有波浪线,因为offset是在start方法里面定义的,所以在update里面是没有办法使用的,解决方法:输入private Vector3 offset;

21:添加墙:创建Cube→positon设置Y:0.5

Scale中的Z为20。创建材质、附材质。复制墙Ctrl+D,将四周都围上墙。

22.预制体:地面等都属于环境:创建一个空物体命名为Env,将环境相关的物体都拖到Env下面。创建预制体:预制体相当于一个模板,在Assets下创建一个模板文件Prefabs,如:创建一个方体作为Food,将方体放入Prefabs文件中作为一个预制体,可以直接Ctrl+D复制,例如Food(1)作为Food的孩子,修改预制体Food其他孩子也会变化,如果修改Food(1)想让Food发生变化的话,将Food中的Overrides修改为Apply all,这样母亲Food连同其他孩子都会被修改。(注:当一个物体被旋转后再使用移动工具,坐标轴会跟物体坐标轴一致,这时可以打开Gobal模式,就可以跟世界坐标轴一致了。)

Prefab 预制体

Instance 实例

Class 类

Instance (对象-Object)实例

23.控制小球旋转:给Food预制体创建一个脚本→tansform.Rotate旋转(Vector3.up);

24.查文档:在Help:Unity Manual,Scripting API→Class类(文档当作字典查阅的)(UnityEngine→Class)

25.碰撞检测:在player写一个系统事件(如start、Update都是系统事件),写oncollisionEnter,会自动给出系统事件,输出(Debug.Log("发生碰撞了")),碰撞一共有三个阶段,oncollisionEnter,oncollisionExit,

oncollisionStay,如果物体碰撞之后player会把food吃掉,就不需要执行Exit、Stay方法了。

区分Food的方法:名字/标签,但是名字跟标签都可以重复,给它添加标签Add Tags,修改Prefabs里的标签,所有的Food都有标签了。

collision.gameObject.tag(碰撞到游戏物体的标签)

条件编程语句:用来判断碰撞物体条件if(collision.gameObject.tag=="Food")→

Destroy(collision.gameObject);

(解释:是先通过collision再到gameObject,然后再找到标签的)(注意:赋值时用的是==而不是=)

标签获得:可以通过游戏物体获得标签,也可以通过组件获得标签。即一个为collision.gameObject.tag

collision.collision.tag

26.通过触发检测,吃东西:触发检测是可以不发生碰撞效果就可以吃东西,只要进入触发检测的范围内。

创建一个Cube,然后给一个标签test,将Cube里Box Collder中的is Trigger勾选。触发检测也有三个过程,OnTriggerEnter;OnTriggerExit;OnTriggerStay;

If(other.tag=="Food")

Destory(other.gameObject);

然后将Food的碰撞器修改为触发器。

27.通过UI显示得分:

1.首先给定义一个整数变量:public int score=0;(int:整数 score:变量)

score++:++是自增运算符。

2.创建UI:Button按钮,Text文本,Image图片;创建一个Text,切换到2D模式,双击Canvas(画布,Evensystem事件系统),调整text组件(1.调整字在框中的位置及,居中 2.调整小框在大框中的位置,按着Alt+右上角的键,可以自动对齐右上角3.调整字体大小.)

3.将数字计算(score)与UI关联:

引入UI的命名空间:using UnityEngine. UI

定义一个组件:public text scoreText;

将Text拖拽到Score Text下面,这样Player就可以有访问UI组件的权限了。

分数发生变化时要更新UI显示:

scoreText.text="sdfaesd";(字符串的含义是,把sdfaesd给UI,即UI显示sdfaesd,如果是显示分数的话,应改为scoreText="分数"+score;

28.显示游戏胜利:创建一个UI,text,(为防止后期text混乱,给每个text重新命名,ScoreText,WinText),把wintext禁掉,等游戏胜利了再激活wintext。

1.首先给一个游戏物体的引用:

public GameObject wintext;

在if(other.tag=="Food")下面给If(score==12)

{ winText.SetActive(true);(解释:true/false,SetActive激活,是否激活)

29.游戏打包:File→BuildSetting→addopensence

然后在unity Hub中安装程序用来打开游戏

如果是PC端导出,选PC,点击Build,创建

默认是全屏状态下运行,如果改成窗口状态下运行:Player Setting→resolution(分辨率)

→window(窗口模式)→创建

 

 

案例2:打砖块

1.创建地面、墙体:创建MineScen→创建Plane→reset使地面位于中心部分→改名ground→创建Material→附材质;建墙体Cube→Y0.5重命名Brick→创建Prefab文件夹→将Brick拖到Prefab里→复制墙体→步移(按着Ctrl移动,就会根据步长,移动步长是可以设置的,在左上角Scene窗口里)→选择复制6排高→选中墙块 右键创建Empty parent

2.控制相机移动:给相机加一个Script→

movement→transform组件用来控制自身的位置、旋转、大小→Transform.translate(变换的方法)(Vector3.Left);

(注意:我们在使用某个组件的时候,是先使用某个组件如Transform,再使用这个组件上的某种方法如Translate的)

用wasd来控制相机方法:首先给相机一个水平轴:float h=Input.GetAxis("Horizontal");

transform.Translate(new Vector3(h,0,0));

相机移动过快解决:update的更新次数→创建一个Script命名为LearnUpdate→Debug.Log(Time.deltatime);

Debug.Log(1/Time.deltaTime);

(FPS:每秒可以执行多少帧,成为延迟)

∵运动距离=速度*时间

∴Transform.Translate(new Vector3(h,0,0)*Time.deltaTime);(这里的Vector3代表着在x轴运行的一个速度)

如果想以两倍的速度移动相机:

Public int speed=1;

∴Transform.Translate(new Vector3(h,0,0)*speed*Time.deltaTime)

再给相机一个y轴方向的移动

float v=Input.GetAxis("Vertical");

(注:写代码习惯性将方法首字母大写,属性首字母小写)

Update更新次数是不确定的,但FixedUpdate更新次数是固定的,也可以设置,在ProjectSetting中可以设置执行间隔时间

3.发射小球:创建一个球体,Bullet,将其放在Prefab里→在Camer身上添加一个新的脚本Shoot:定义一个Prefab:

Public gameObject bulletPrefab

(可以是场景中的某个物体,也可以是个Prefab)

//根据Prefab创建实例=实例化Prefab

GameObject.Instantiate实例化(bulletPrefab.transform.position,

transform.rotation);(position,rotation代表相机的位置)

当我们按下鼠标左键的时候再去实例化,怎样检测按键?如下:

跟按键有关的都是通过Input输入的

Input输入.GetMouseButtonDown(0)

(0代表左键,1代表右键)

if(Input.GetMouseButtonDown(0))

{GameObject.Instantiate(bulletPrefab.transform.position,

transform.rotation)};

如果想让物体有物理效果要添加刚体组件

在bullet下添加Rigidbody,方法:

1.获取刚体组件2.给它施加力

if(Input.GetMouseButtonDown(0))

{GameObject bullet=GameObject.Instantiate(bulletPrefab.transform.position,

transform.rotation)};

rigidbodyrd=bullet.getcomponent<Rigidbody>();

rd.AddForce(Vector3.forward*100);

(100代表100N的力)

(GetMouseButtonDown,代表鼠标按下)

∵当通过力的方式给它速度,没办法直观看到给的力的大小及转化成的速度

∴这里可以通过给速度的方式

rd.velocity=Vector3.forward*30;

(forward向前的力)

给墙一个物理效果rigidbody

 

Unity中资源的导入方式:

Asset Store资源商店里有→下载好资源→拖拽到unity中/右键import package

unity自带的资源导入:打开unity安装文件→unityDownloadAssitant→standard Assets→安装在unity的目录下

添加窗口:在菜单栏的空白处右键,addTab

Layer可以控制层:锁定、隐藏

maximize;最大化游戏窗口

聚焦某个物体:1.双击物体2.按F键

Transform组件:position.rotation.scale;reset重置值

V工具可以吸附顶点:方便顶点对齐

预制体属性:创建一个Cube→拖到Assest里变成一个预制体→Ctrl+D复制两个,修改其中一个的属性,其余两个不变→如果想让其变回最原始状态可以选择reset,变成预制体的状态可以选revert;

 

案例3:古迹探险

古迹地形设计:创建Terrain:地形设计

Terrain Height:最大高度

创建一个Terrain的文件夹,将TerrainDate放入

笔刷:1.刷到最大高度就不会再变大了

2.地形还原:按shift+笔刷,Opacity可以控制笔刷的程度。

3.添加贴图:在笔刷选项下→rise or lower Terrain→paint Texture

4.导入树:Tree→speedtree→可以导入树

5.刚体组件:选择相机→Align with view相机跟当前视野保持一致→小球→rigidbody

Drag:摩擦力(既会增加下落的阻力,也会增加在地面的阻力)

Angular Drag:旋转时候的摩擦力

Use Gravite:是否使用重力

Freeze Position:冻结坐标轴

Freeze Rotation:冻结旋转轴

Mass:物体的质量:影响物体运动的惯性

 

碰撞器:

Terrain Collider:如果地形碰撞器容易出现错误,我们给添加一个Box Collider,调节至跟地面贴合

Mash Collider:会比较费面,耗性能,碰撞更精准,根据面的多少来看

Mash Renderer:针对不太精准的碰撞,且面比较多的情况,这个碰撞器就可以

 

碰撞检测:如果选sphere,就是检测在shpere身上发生的碰撞,如果选cube就是检测在cube身上发生的碰撞

创建Script→指定给Sphere

oncollsionEnter、OncollsionExit、OncollsionStay

(注意:两个物体发生碰撞的前提是有碰撞器collider,其中一个或两个都有刚体rigidbody)

经过测试: OnCollisionEnter方法被触发要符合以下条件

1 碰撞双方必须是碰撞体

2 碰撞的主动方必须是刚体,注意我的用词是主动方,而不是被动方

3 刚体不能勾选IsKinematic

4 碰撞体不能够勾选IsTigger

 

触发检测:小球可以穿过检测物体,不发生碰撞。创建Cube中BoxCollider中的Is Trigger,取消勾选Mesh Render或者将其移除

OnTriggerEnter、OnTriggerExit、OnTriggerStay

print("OnTriggerEnter:"+other);

(other会直接输出触发器的名字)

print("OnTriggerEnter:"+other.name);

(.name可以获取触发器所在游戏物体的名字)

print("OnTriggerEnter:"+other.tag);

(.tag可以获取触发器所在游戏物体的标签)

 

要注意ontriggerEnter方法写的位置,不要写在大括号内部

 

灯光:右键创建PointLight、arealight区域光

火焰:windows→Lighting→Settings

烘焙:将含有地形的Env文件选择Static,Light也勾选Static,Terrain也勾选

再去lighting中,点击General Lighting生成光照贴图Generate Light生成光照贴图→禁用灯光检查是否烘焙上(场景变得无灯光效果就是没有烘焙上)→没有烘焙上,选择灯光→Mode选择Baked→再把灯光启用→再进行烘焙→再把灯光禁用后依旧有灯光的效果

在火光的灯光效果中:Mode选择Mixed,因为火光需要一闪一闪的效果,因此需要计算

 

火光:(在这之前创建灯光时将灯光放入Perfab文件,方便后期Apply all)创建Particle systerm→调整速度→粒子样式open Editor→可以选择导入的fire

shape:调整火焰形状

Start Lifetime:火焰大小控制

Start speed:可以调整为Random between two contents两个数值控制速度

size overLifetime:修改火焰大小渐变

Rate over Time:火焰数量

Radius:火焰聚拢

粒子样式:找到火焰贴图所在的位置→创建Material→命名为flame→如下图创建好材质后→导入Rander中作为贴图

 

(1)Renderer模块

设置其Material,将火焰粒子贴图放入其中。

(2)Texture Sheet Animation模块

由于火焰贴图共有4帧,因此需要将其水平和垂直方向的平铺数量划分成2,设置Tiles的x和y为2。

(3)shape模块

radius设置为0,使得粒子产生的位置固定。

Force over Lifetime模块

粒子受到的力作用,起初可以将三个方向都设置为0。之后当模拟火焰受到风的影响而偏移时,可以调整x的值。

Color over Lifetime模块

设置粒子随时间而产生的颜色变化。上面的标记控制透明度的变化,下面的标记控制颜色的变化,火焰的底部偏蓝色,从底部往上,火焰会由蓝变橙红,并且粒子生命将要结束时,将会逐渐变透明。

(4)main(主模块)的设置

Duration:发射器喷粒子的时间长度

Looping:重复持续发射粒子

Start Lifetime:单个粒子的生命周期,这里设置为0.3到0.5之间的随机值。

Start Speed:粒子的初始速度。

Start Size:粒子大小,由于火焰会忽大忽小,因此设置为0.6到1之间的随机值。

Start Rotation:粒子旋转的弧度

Gravity Modifier:粒子所受重力,由于火焰是向上窜的,因此设置为-1.

 

灯光闪烁效果:选中火焰,window→Animation→保存至Animation→选中Animation中的Bonfire→AddProperty→Intensity

火苗播放的很同步调整:Animation→Transform→Position

 

导航系统:window中nevigation →注意要将跟地形有关的物体static勾选,才能烘焙

Agent Rudius:调整可视范围

想穿过草,要将草的nevigation static关掉。然后回到nevigation重新烘焙

如果不想让人物行走在石头上面:可以选中石头。再点击一下会生成Mesh render→再回到nevigation 里Object→nevigation area→notwalkable→重新烘焙

选择人物→添加Nev Mesh Agent组件→redius、Height

给英雄添加导航组件:创建脚本hero→

if(Input.GetMouseButtonDown(0)){}

当鼠标按下左键的时候触发射线检测

{ Ray ray=Camera.main.ScreenPointToRay

(Input.mousePosition);

RaycastHit hit;

if(Physics.Raycast(ray,out hit))

{ //print(hit.point);

agent.SetDestination(nit.point);

}

}

获取射线=主相机里有ScreenPointToRay用来把屏幕坐标转化为射线,屏幕坐标获取=鼠标位置获取(Input.mousePosition);RaycastHit

hit用来保存碰撞信息;Physics.Raycast(ray,out hit);

Physics里有Raycast射线检测,Raycast里有ray射线,out hit参数;如果发生碰撞,可以检测到点击地面的哪个位置,print(hit .point);输出点的位置

要人物沿着鼠标点击的路线运动:

即Nev mesh agent沿着鼠标运动

首先引入Nev mesh命名空间Using UnityEngine.AI,然后就可以定义Nev mesh agent组件public NavMeshAgent agent,agent可以直接通过拖拽的方式赋值,

agent.SetDestination(hit.point);

有了agent 就可以通过agent里的Destination用来设置目标位置,这时候就不需要前面的print(hit.point)了

设置hero转向:在Nav Mesh Agent里设置Augular speed

 

 

控制摄像机的跟随:首先确定相机跟hero之间的偏移→用update使hero与hero保持偏移

创建相机脚本:首先定义一个Transform组件,public Transform hero,用Transform找到hero的位置,取得位置偏移

private Vector3 offset;

offset=transform.position-hero.positon;

偏移=当前位置-hero的位置

transform.position=offset+hero.positon;

相机跟主角的偏移=

 

控制英雄的动画播放:创建一个动画状态机,在Animation里创建Animator Controller,用来控制hero的动画播放,赋值,打开Animator,

-idle是默认状态,(控制hero的原理是通过控制其速度来控制状态),创建float参数,命名为speed,将idle与walk状态链接,箭头指向walk,设置其最大速度Greater,speed>0时,由idle切换至walk,设置其最小速度less,speed<0.1时,由walk切换至idle,

由walk切换至run时,当最大速度>2时,由run切换至walk,当最小速度<2时;这时这个动画还不太发生变化,需要给其赋值:

去代码中,获取animator 组件,public Animator anim;赋值给hero中的anim组件

anim.setfloat("speed",agent.velocity,magnitude);

状态机里 参数需要animator来设置,velocity速度,magnitude速度大小

 

案例4

通过案例驱动学习UGUI:

canvas中的pixcl periect:使字更柔和,如果想让字体清晰,勾选pixcl periect

图片空间:创建3D场景→保存至scene里,命名为image.字体文件命名为Text

导入图片(新建文件夹Texture),修改TextureType→Sprite(2D)→应用

应用图片:右键UI→image:

→Source Image选择需要的图片

Raycast Target:检测鼠标跟图面发不发生关系,比如图面上发生点击等事件,默认是勾选的,通过碰撞检测检测到的

等比例放大:按shift放大;setNative Size恢复原本大小

Button组件里:Hightlight Color高亮状态;

Target Graphic:修改某个图片的状态,也可以修改别的状态,只要把别的物体的Button组件赋值过来就好

Pressed Color:鼠标按下时的状态;

select color:被选中时的状态

Interactable:没办法触发点击

创建一个自己喜欢样式的Button:创建image→创建一个喜欢的样式→给一个Button组件→如果没有文字的话,可以创建子文件text

给任何一个游戏物体创建Button Manager脚本如main Camera:

添加一个方法:

public void onButtonClick()

{print("ButtonClick");}

可以添加一个带参数的方法:

public void OnButtonClick(int i)

{print("ButtonClick+"+i)}

把Button节点拖动到onClick列表的“None”那里(注意一定是节点,不能是脚本!),下拉箭头ButtonManager→OnButtonClick(int)

 

 

锚点:创建一个新场景,命名为Anchor,创建一个UI,button,一般情况下右上角的UI以右上角为锚点,左上角的UI以左上角为锚点,这样在不同屏幕里显示,UI不会被移除屏幕

在Rect Transform里修改锚点的位置

pivot:中心点

 

登录UI开发:

创建场景,005-Login,Canvas→UI→image

如果使图片跟屏幕分辨率保持一致,跟着画布发生变化,在Rect Transform里修改锚点的位置,按Alt选最右下角的模式,使图片与其附体保持一致→用户名、密码Text,向右对齐→创建输入框,右键InputField→修改其Content Type→Password输入密码时变为密码格式***

→Placeholder是提示信息,当真正输入时Placeholder被禁用Text是输入的信息

登录按钮设置:右键UI→Button→登录→在mineCamera 添加脚本“LoginController”→定义一个方法“public void OnloginButtonClick(){ }→找到LoginButton的OnClick,给runtime赋mineCamera的值,方法选择LogController→

OnLoginButtonClick()

输入框设置:选usernameInput选项→创建

InputField 组件,在LoginController中定义方法:先给一个命名空间using UnityEngine.UI;

public InputField usernameInput;public InputField passwordInput;→赋值→

public void OnloginButtonClick”{

string username=usernameInput.text;

string password=passwordInput.text;

if(username=="admin"&&password=="admin"){//场景跳转 sceneManager.LoadScene("001-text");

场景跳转到001-text场景

}

→选择主界面file箭头BuildSetting→把当前场景及001场景拖拽进去(这样才可以跳转成功)

(注意:在创建每个Text时记得命名

用户名:usenameLable密码:passwordLable

输入用户名:UsenameInput密码:PasswordInput登录:LoginButton)

(注意:有些名称需要引用命名空间“Using UnityEngine....”可以从左边错误提示下拉按钮找到)

密码填错时警告信息:创建一个Text→messageable(可以把整个物体禁掉,或只把Text组件禁掉)→在LoginController中添加方法“public void onLoginButtonClick()

else{messageText.text="用户名或密码错误,请重新输入”;messageText.enable=true;}

警告信息只显示一分钟:添加一个携程IEnumerator HideMessage(){yield return new WaidForSeconds(1);messageText.enable=false;}→回到else调用这个携程:StartCoroutine(HideMessage);

 

UI中的控件:

单选和多选按钮:

Toggle:单选按钮

男女勾选多选案例:设置两个Toggle,建立一个空物体GameObject,将两个物体放入空物体中,方便分组,在空物体中建立一个组件Toggle Group组件,将GameObject的值赋分别给男女Toggle赋值,

这时候这两个为一组,这是两个选项只有一个is on是勾选上的

 

Slider:控制血量、音量大小:

File就是控制进度时需要显示的部分

Image Type:是单独控制图片分割的形式的,使用其中的Solid功能时需要给图片指定一个边框:

给图片指定边框:导入图片,点击图片把Texture type更改为sprite(2D),通过Sprite Editor给图片编辑一个边框,如何下载Sprite Editor:在paceage那里右键,打开view in package Manager:unity registy是unity网络包还未导入可以下载安装,选2Dsprite;可以形成一个边框,运行时尺寸会有变化,因为image type中的slide选项,在变换图片时,不会成比例变换,上边框只会左右拉伸,左右边框只会上下拉伸。(例:一个有四角边框的图片,如果给其设置边框,再变化边框时,边框线不会发生变化)。在image type中的simple选项中放大缩小边框会被等比例拉伸的,边框线也会等比例拉伸,影响像素。

Flie Center:显示中间部分

image type中的Tild选项:平铺

(导入图片→创建一个Button→给按钮图片样式source image中导入→调节图片的边框范围)

 

UI中的控件:

Scrolbar:拖拽条,进度条。direction可以调节滚动条方向

Dropdown:下拉菜单

在Canvas中有panel选项,可以将控件放在同一个面板中,如果不想保留面板图片,可以勾掉image就只保留面板线框了

 

 

开发开始界面:创建新场景:009-StartScene→image→填充方式“四角填充”

声音按钮:创建UI,(导入的UI的TextureType改为Sprite2D&UI)image找到对应图片,命名为"BGM",按shift缩放到适当的大小;在此image下再创建一个image,找到相应的按钮图片SetNativeSize然后再等比例放缩,在此之下再创建一个imgae,放一个声音按钮,重复以上步骤。把以上命名为“AudioButton”,并添加一个Button组件,

添加叶子:image,shift+Alt等比例放大,命名为leaf

复制AudioButton,再做一个EmailButton

Play按钮:创建Text,调整Font Style,

Effect Distance阴影影响面积

创建shadow组建,命名为StartButton,

 

创建新场景,命名为010-PlayScene:

人物状态,Text:“LV50”,将此image命名为“Head”

进度条(血量值):Slider(如果不需要跟用户交互的话可以将Interactable勾选掉),在设计中往往需要的是Slider组件

创建一个image,在此之下再创建一个image用来做血量值背景“BlackBgm”,再创建一个血量值image命名为"GreenBar",添加一个Slider组件,将GreenBar添加到Fill Rect里,在GreenBar中,ImageType修改为Fill,Fill method修改为horizontal,然后就可以回到上层image中通过修改vaule来修改血量值了。Disable降低透明度变为正常状态。

给进度条加上小叶子、创建按钮+图标

设置图标,命名为“SettingButton”创建一个Button组件,复制一个做对话框图标,命名为

“DialogButton”

技能图标开发:命名为“skill”外边框,setnegativesize,在此image下面添加一个技能image,再复制一个作为这个图片的遮罩:将这图片变为黑色或者深灰色,命名为coldMask,Fill Amount可以调节。叶子、Text,给字体添加边框,即添加Outline组件,调整边框的粗细,边框的颜色。添加一个Button:

开发机能冷却效果:

添加脚本组件命名为“Skillitem":首先提供一个方法:public void OnskillClick()当技能被点击时会触发的

技能需要冷却时间的,定义一个:

public float coldTime=2;

计时器:用来计时冷却

private float timer=0;

是否处于冷却期

private bool isColding=false;

private Image coldMask;

在start中

{coldMask=transform.Find("coldMask").

GetComponent<Image>();

if (isColding){

timer+=Time.deltaTime;

coldMask.fillAmount=(coldTime-timer)/coldTime;剩余时间比例

if(timer>coldTime){isColding=false;FillAmount=0;timer=0;

}}

public void OnskillClick()

{if(isColding=false){isColding=true;timer=0;

coldMask.fillAmount=1;}

写好以上代码后,在skill的Button组件中,添加一个点击事件,OnClick→SkillitemOnSk

 

 

(注:在C#中,Tab引入系统自动给的提示命令)

 

按下键的时候也可以触发技能:见笔记

 

Panel面板:

Image→设置边框→命名为Panel→标题背景板:添加文字→字描边

面板内部边框:选择边框,调整大小→如果外边框变动,内边框也跟着变动→将内边框的锚点放在面板的四个角上,标题的锚点,设置在panel上面。

 

决策场景:012-Character-Knapskack

Image→重复上次Panel动作→关闭按钮“CloseButton”→导入线框→头像“Head”→人物属性:Text、Image等几个创建成一个Empty

Parent(注:全部选中子物体,让它们跟父物体的中心保持一致,这样比较好调整)

背包:Image→命名为“Knapsack"→标签的Image需要一个父image 一个子image ,标签命名为”item“→父物体上添加一个控件Toggle,复制三个,将选择变为单选:

将这三个标签再创建一个父类,命名为“itemGroup”,将三个标签先移出,调整itemGroup的位置高宽设置为100,按住ALT

拉伸一下→在itemGroup下添加组件ToggleGroup,将这三个指定给TG ,并把最后一个设置为选中状态,ison勾选,还有文字未选中情况下的遮罩状态

创建Panel1、Panel2、3

找到item1,的on vaule changed,将Panel1赋予,setactive,当选择Panel1的时候会激活,选panel的时候会禁用→设置初始状态,两个装备隐藏

物品栏:在panel3 下创建一个空物体→在其下面创建组建GridLayout Group(网格布局),命名为Grid。创建一个image,命名“item”,找一个背景,在其下方再创建一个image,找一个图标。如果直接将item拖到Grid下方,复制多了就会发现每个图标的距离很小,因此,创建一个空物体,item放在空物体下面,中心点一致。这时可以将其放在Grid下方,设置其间距

→设置分页,给每一个Panel都设置一个分页

,然后给每一个Panel做item

在UI文件里,创建一个prefabs,吧charactorPanel拖拽进去,

 

关卡选择:

013-LevelSelect:首先创建画布Canvas,给一个背景,再把上面的charactorPanel的预制体放入此文件夹,在charactorPanel右键prefab里有Unpack,这样就可以断开连接了,删除用不到的东西。TitleBgm,CloseButton,创建边框,做item(有上锁效果),Grid,排序方式,StartAxis,Vertical,两行两行填充。

(注意:Grid原点放在中心的时候,修改wide时向两边延伸,Grid原点放在右边,再修改wide,是从右向左延伸)

做一个锁着的状态“Levelitem-lock"放进预制体里,修改后Apply all。这样需要上锁效果的,直接拖拽预制体填充就好。

列表滚动:创建一个空物体,命名为ScrollRect,其大小跟每一页的大小是一致的如800*400,将Grid放置其下,新增组件ScrollRect,将Grid给Content、viewport赋值,∵滚动是受超出范围来,只有有图片的时候才能检测到滚动,∴在ScrollRect里添加一个image,image里有一个Raycast Padding是可以检测的。如果垂直滑动跟水平滑动都可以的话,把Scroll里的Vertical关闭,把超出界限的部分隐藏,创建一个Mask,要将之前image的颜色透明度调回正常,之前是透明,将show Mask Graphic取消掉

分页滚动:在ScrollRect里添加脚本“LevelScrollRectangle”,脚本思路见笔记

(注意:以上内容都做完但是还是滚动不了的原因,出现在刚开始的步骤,Grid的宽度设置600*350,这是一个页面的宽度,需要4个页面,2400*350,要注意Grid的中心点调至左边,调中心点还有看工具栏的选项是中心点还是轴心点,选中心点然后才能移动中心点的位置,后面移动不了,都是因为这个步骤错了)

 

按页滚动:创建空物体“PageButton”→在其下创建image“圆点”再其下创建image“叶子”→在image添加一个Toggle,给其赋值,这样勾选ison,可以使叶子显示或隐藏,Ctrl+D,复制,这样四个圆点就做好了,在PageButton设置ToggleGroup,赋值,这样点击圆点,叶子就能显示了,回到脚本监听OnvauleChange方法,见笔记

 

任务栏:创建场景014-Taxtlist→将ChatacterPanel→先取消连接,然后删除不用的内容,可以按住Alt调整画布的宽度,创建任务条,给其边框使其拖拽不变形,创建“完成”按钮,给这个Text一个outline,给这个按钮添加一个Button,命名为DownButton,将以上内容放在一个文件下面,命名为“item”

任务列表布局:创建一个空物体“Verticallist”,在其身上创建一个VerticalLayoutGroup,将item做成预制体,然后放入垂直列表内,然后可以复制多份,然后设置其滚动区域image、Mask、然后上下滑动(取消horizontal勾选)设置面板,

声音大小滑动器:新场景015-Settings,Text声音→slider→设置slider背景、音量条、拖动按钮样式, 开关样式:创建image做打开模式下的开关“on",再创建关闭样式“off",添加组件“Toggle”,由于Toggle只能显示图片的开关,不能连接到游戏上,所以创建代码:"Mytoggle",代码逻辑见笔记

登陆面板:016-Login:按住ALT键对称缩放,用户名、密码,对于密码,content type要改为password。

 

 

坦克大战:

1.场景搭建:main Camera:设置Camera的大小为8.5,颜色调为黑色,注:信息显示面板Console,在window里打开,可以看报错信息,

切割素材:用sprite editor→Grid by Cell Size(以固定大小来切割),调整到合适的尺寸,切好图集→保存场景→创建文件夹Scence

创建玩家,玩家比对着Cube更改尺寸,创建一个文件夹,Prefabs,将玩家创建为预制体。再做墙,障碍向右拖拽Barrier,再做Grass,再做一个Heart(老窝),动画命名为“Bom”,将以上的预制体全部拖到预制体文件夹里,在预制体文件夹里创建一个Effect文件夹,存放特效。把爆炸特效的控制器放在一个文件夹里

玩家出生时会有一个屏障效果:shield,

玩家游戏时动作转换:创建一个脚本:见笔记,创建数组后,将需要用的图片赋予public sprite

碰撞检测:创建2D碰撞器,(在预制体上添加碰撞器是无法添加到同样的克隆体上的,因此)

给player添加一个刚体组件,(注:是rigibody2D),运行起来会发现player很快运动,这时将Gravity Scale重力,调整为0,给map里的其他物体添加碰撞器,草坪不需要交互,所以取消Grass的碰撞器

player运动时图片方向斜着,解决方法:在

rigidbody→constrains→Freeze Rotation Z

player在碰撞到物体时会有点鬼畜,解决办法:用代码:生命周期函数,见笔记

控制player的运动方向:脚本笔记

让特效覆盖在玩家的上面:精灵渲染器Sprite Renderer里,有sorting layer,order layer,sorting layer是层级,order in layer层级顺序。如,将order in layer设置为1,层级越大越后渲染,也就是说,最不想让谁被覆盖掉,就把谁设置为大,这样可以最后被渲染。

将子弹拖入场景,拖入坦克文件夹,order in Layer,设置为1

写玩家的攻击方法:写脚本 →将子弹的预制体赋给Tank里的Bullect Prefab,然后在脚本里调用一下方法

子弹旋转角度:见脚本

攻击CD的加入,触发器与碰撞器:在子弹预制体身上加一个脚本,“Bullect”,在脚本中控制方向

触发检测:给子弹添加一个触发器,(因为子弹不需要碰撞效果,所以只要一个触发器)BoxCollider2D,两方都有碰撞器组件,一方的is Trigger勾选上的,最好碰撞的那方有刚体,即在Bullet里加上Rigidbody2D。在脚本里给子弹加上触发检测的方法→给物体添加标签,add Tag,然后在脚本里编写触发检测的语句。→→做个空气墙:在界面复制一个墙体,把其中的渲染器删掉,即把sprite Renderer删掉,命名为“Air Barrier”,然后把它拖入Map文件夹做预制体

玩家无敌方法与死亡方法:见脚本。

死亡方法:坦克在break之前需要爆炸特效及生命力减1等效果。需要用到爆炸特效→产生爆炸特效:给爆炸特效一个脚本:“Explosion”,然后在player调用一下Explosion脚本至explosion Prefab.

无敌方法:被保护状态,如果玩家处于被保护状态,让玩家不会销毁。见脚本。然后,由于不能一直让特效产生,所以,找到玩家,把“shield”放在玩家下方然后reset一下,这样当玩家处于无敌状态时显示一下,之后不是无敌状态时就关闭。见脚本修改。

判断玩家子弹还是敌人子弹:见脚本

注意:写完脚本,记得修改frefabs上的标签,改成各自的名称。

如果子弹射击没有反应:有可能是Order in Layer的渲染层级跟被碰撞物体的渲染层级不在一个层级,所以要想使两个物体发生作用,要将其渲染层级调至一起。

区分玩家子弹与敌人子弹:将玩家子弹重命名,为playerBullect,并勾选 is player Bullect,然后再复制一个playerBullect,命名为EnemyBullect,勾选掉is player Bullect.

敌人制作:复制玩家,然后把无敌状态删除。更换图标,删除玩家脚本,重新添加新的脚本。

将玩家脚本复制到敌人脚本里:见脚本

老窝的爆炸效果:找到heart脚本,

爆炸重生脚本:Bron脚本,private woid BornTank()→调用一个延时特效Invoke("BornTank",0.8f)→引用一下玩家→延时销毁

设置第二个玩家:SmallEnemy→把图片的切换添加一下,精灵数组里添加→敌人不需要保护状态,把Explosion跟Bullet添加好就好。smallEnemy的移动速度改为4,打开Born脚本:见笔记。记得把enemy挂载的脚本改为enemy的脚本。

 

初始化地图工具: 1.测试场景大小:选中一个敌人,拖动敌人拖到左下角的位置,例坐标为-10,-8,0,拖到中间位置为0,-8,0,所以地图的大小大约是长20,宽18。所以创建一个GameObject→命名为MapCreation→新添加脚本“MapCreation”,见脚本。→赋值后只留一个小坦克来测试。→实例化老家,在(0,-8,0)的位置来实例化→见脚本→墙中间有缝隙,可能是墙有点小,可以缩放为3.2

 

游戏运行起来后,在界面会有罗列,我们想让罗列的内容在一个物体下,如MapCreation,面板看起来不会很混乱,因此添加一个方法→在MapCreation脚本里,见脚本→让它随机产生敌人,而且不在一个地方产生两个物体,见脚本。

 

实例化地图:见脚本。把草的渲染参数调为1。

玩家管理:设置一个GameObject→然后更名为“PlayerManager”→增加一个脚本

UI设计:给main Camera设置为灰色,拖黑色背景,放大至跟原先屏幕即5:4的大小差不多,然后把main Camera调整为16:10→BackGround的渲染层级设为-2

Img-PlayerScore:找到相应的图片,调整至居右对其,设置Text,字写20,字体颜色为白色,

在PlayerManager的脚本里设置一下,见脚本

  1. 游戏结束UI:创建一个UI,找到相应图片,然后去脚本修改。
[展开全文]

//坦克死亡的方法

private void Die()

{

if(isDefended)

{

return;

}

PlayerManger.Instance.isDead=trus;

//产生爆炸音效

Instantiate(explosionPrefab,transform.position,transform.rotation);

//死亡

Destroy(gameObject);

}

[展开全文]

生命值,

得分,

单利模式

 

[展开全文]

授课教师

SiKi学院老师

课程特色

图文(1)
视频(32)
下载资料(1)