时间:2025-03-15 21:34
人气:
作者:admin
unity方法
关于transform组件的使用
直接使用transform组件
transform.Translate()
用于当前脚本挂载组件的移动
player = this.gameObject;
用于挂载当前实体对象
关于c#面向对象
Public ObjState{
Move,
Stop,
Lockmove
}
表示ObjState只有3个状态
If(ObjState == move){
Num++;
}
Static 一般的变量要在实例化类后才能访问,加了static后不实例化也可以访问
Materials 材质包
关于unity的生命周期
Void Start(){} 在游戏开始时运行
Void update(){} 每一帧重复执行的函数,一般来说一个游戏每秒60帧
关于unity的控制台
用debug.log(“”)输出
Vector3
是unity中的一种向量类,用于表示位置,方向和运动等概念
// 给rd施加一个向右的力,默认为1牛的力
rd.AddForce(Vector3.right);
// 施加2牛的力
rd.AddForce(new Vector3(2,0,0));
Input.getAxis(“Horizontal”) 获取当前键盘键入字符,水平
Input.getAxis(“Vertical”) 获取当前键盘键入字符,垂直
碰撞发生的三个事件:碰撞、碰撞中、碰撞后
private void OnCollisionEnter(Collision collision) {
Debug.Log("碰撞检测.");
}
private void OnCollisionExit(Collision collision) {
Debug.Log("碰撞检测.");
}
private void OnCollisionStay(Collision collision) {
Debug.Log("碰撞检测.");
}
今天学习游戏碰撞检测
当前模型碰撞检测:
Private void OnCollisionEnter(Collision collisio){
If(collisio.gameObject.tag == “food”){
}
}
Destory(collision.gameObject) 摧毁模块
触发检测:跟碰撞检测差不多,区别是触发检测没有实物碰撞
private void OnTriggerEnter(Collider other) {
if (other.gameObject.tag == "food")
{
Destroy(other.gameObject);
}
}
触发检测
碰到物体后销毁及增加分数
引入命名空间
using UnityEngine.UI;
获取分数组件
定义分数变量
Int score = 0
Public Text scoreText;
更新分数
Score++
scoreText.text = XXXXX
游戏胜利后显示胜利文本
winText.SetActive(true);
完成
Time.deltatime 每一帧之间执行的时间
1/deltatime 则是每秒执行的帧数
void Update()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
transform.Translate(new Vector3(h,v,0) * speed * Time.deltaTime);
}
使用算法实现模块每秒执行速度
也可以用生命周期FixedUpdate
private void FixedUpdate() {
}
修正执行速度,大多数用算法
public GameObject bulletPrefab;
void Start()
{
GameObject.Instantiate(bulletPrefab,transform.position,transform.rotation);
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
GameObject.Instantiate(bulletPrefab,transform.position,transform.rotation);
}
}
检测鼠标是否按下后创建子弹
void Update()
{
if (Input.GetMouseButtonDown(0))
{
GameObject bullet = GameObject.Instantiate(bulletPrefab,transform.position,transform.rotation);
Rigidbody rd = bullet.GetComponent<Rigidbody>();
// rd.AddForce(Vector3.forward*100);
rd.velocity = Vector3.forward*30;
}
}
获取刚体组件并且施加前进的力
Rd.velocity = vector3.forward
学习GUI
今日主要重点:查找组件find方法
关卡选择的制作:
设置背包面板为预制体,实例化预制体,然后与预制体断开链接,删除背包内元素
设置超宽的关卡选择,然后使用scroll组件再使用mask组件进行滑动管理
public class levelScroll : MonoBehaviour,IBeginDragHandler,IEndDragHandler
{
public void OnBeginDrag(PointerEventData eventData)
{
throw new System.NotImplementedException();
}
public void OnEndDrag(PointerEventData eventData)
{
throw new System.NotImplementedException();
}
}
public void OnEndDrag(PointerEventData eventData)
{
float currentPosition = scroll.horizontalNormalizedPosition;
if (currentPosition<0.25)
{
index= 0;
}
if (currentPosition>0.25 && currentPosition<0.75)
{
index = 1;
}
if (currentPosition>0.75)
{
index = 2;
}
// 指定页
// scroll.horizontalNormalizedPosition = pagePosition[index];
isMoving = true;
}
void Update()
{
// 如果正在移动,则使用线性插值函数移动
// 线性函数用法:Mathf.Lerp(起始值,目标值,速度)
if (isMoving)
{
scroll.horizontalNormalizedPosition = Mathf.Lerp(scroll.horizontalNormalizedPosition,pagePosition[index],Time.deltaTime*speed);
if (Math.Abs(scroll.horizontalNormalizedPosition-pagePosition[index])<0.001f)
{
isMoving = false;
scroll.horizontalNormalizedPosition = pagePosition[index];
}
}
}
切换按钮
使用togle group的组件实现
Togle按钮下有onvaluechanged方法。分别给三个按钮绑定方法
public void moveToPage1(bool isOn){
if (isOn)
{
isMoving =true;
index = 0;
}
}
public void moveToPage2(bool isOn){
}
public void moveToPage3(bool isOn){
}
相应的,srcoll拉到相应位置选中的按钮也随之变化
public Toggle[] toggleArray;
toggleArray[index].isOn = true;
滚动scroll+mask的制作:新建一个image添加scrollrect和mask组件然后showmaskgraphic取消选择然后将grid或者layoutgroup拖到content内
使用toggle控件onvaluechanged方法控制,开和关两个选项显示
使用inputfield组件
文件夹分类
Animation动画
AnimationController动画控制器
Prefab预制体下
Effect特效
Map地图
依旧用wasd水平垂直轴移动
void Update()
{
float h = Input.GetAxisRaw("Horizontal");
float v = Input.GetAxisRaw("Vertical");
transform.Translate(Vector3.right*h*Time.deltaTime*speed);
transform.Translate(Vector3.up*v*Time.deltaTime*speed);
}
还要控制玩家贴图的旋转
引入sprite render组件和新建一个sprite数组,放入上下左右四张贴图
H<0则为向左
H>0为向右
V<0==down
V>0==up
使用awake生命函数初始化时获取渲染组件sprite render
Boxclider和rigbody
if (h!=0)
{
return;
}
private void Move(){}
Order in layer = 1
子弹的层级也是1
instantiate方法:
Instantiate(预制体,位置,自旋转)
给子弹组件施加一个向前的力,往朝向方向移动
transform.Translate(transform.up*bulletSpeed*Time.deltaTime,Space.World);
设置子弹速度和射击间隔
void Update()
{
// 设置子弹射击间隔0.4s
if (timeVal>=0.4f)
{
Shoot();
timeVal = 0;
}else{
timeVal+=Time.deltaTime;
}
}
void Update()
{
transform.Translate(transform.up*bulletSpeed*Time.deltaTime,Space.World);
}
给子弹添加触发器boxcolider和刚体rigidbody -完成
物体添加tag --完成
射击检测和空气墙 --完成
编写玩家被击中-销毁状态
private void Die(){
if (isDefend)
{
return;
}
// 生成爆炸特效
Instantiate(deathAnimation,transform.position,transform.rotation);
// 摧毁组件
Destroy(gameObject);
}
在子弹脚本中调用死亡函数
private void OnTriggerEnter2D(Collider2D collision) {
switch (collision.tag)
{
case "wall":
break;
case "enemy":
break;
case "obst":
break;
case "airObst":
break;
case "tank":
// 使用玩家组件下的die方法
collision.SendMessage("Die");
break;
}
Destroy(gameObject);
}
在子弹脚本中定义是否为玩家子弹的变量
If(!isTankBullet)collision.SendMessage("Die")
编写heart被摧毁脚本
Destory(collision.gameobject)
Destory(gameobject)
除了子弹,其他组件不需要勾选is trigger
今天就纠结这个istrigger了,学了个锤子
喝了酒,犯困,什么都没学
敌人的制作,家爆炸特效以及出生特效
前两个没什么好说的,敌人的脚本跟玩家的差不多
家爆炸特效是在heart变更特效图后生成爆炸特效
延时出生和延时销毁出生特效
void Start()
{
// 延时生成和延时销毁
Invoke("Generate",0.7f);
Destroy(gameObject,0.7f);
}
private void Generate(){
Instantiate(tankPrefab,transform.position,Quaternion.identity);
}
int num = Random.Range(0,8) //不包括8
修bug:包括敌人tag,子弹tag,子弹脚本-击中敌人
新建一个空组件createMap
先生成家
注意:awake函数执行在start函数之前,所以生成地图使用awake函数
组件生成后设置父组件
GameObject itemGo = Instantiate(obj,position,rotation);
itemGo.transform.SetParent(gameObject.transform);
定义一个已有位置数组
一般来说,墙生成60个其他物体生成20个
生成born特效,设isPlayer为true
最开始顶上3个位置生成3个敌人
然后每隔5秒生成1个敌人
InvokeRepeating("createEnemy",4,5);
设置敌人碰撞检测:让敌人碰到后跳过移动间隔,设置一开始敌人向下走,减少碰撞
敌人脚本-死亡得分
玩家脚本-死亡就调用 状态管理death = true
把玩家状态创建为一个全局单例--即不用引入到其他脚本中就可以使用
private static status instance;
public static status Instance
{
get
{
return instance;
}
set
{
instance = value;
}
}
private void Awake() {
instance = this;
}
//固定写法
状态管理中玩家有3条血,死亡一次--
Heart--die--status--isDefeat = true
Player--fixedupdate--status.isdefeat
要在UI里面新建组件
有首页的光标选择
w切换光标位置1,s切换光标位置2
Flag为1时切换scene1
然后就是切换场景sceneManager
视频里用的是3秒后自动返回主界面,我们可以设置空格键返回
Heart引入音效组件
public AudioClip dieAudio;
直接播放音效
AudioSource.PlayClipAtPoint(dieAudio,transform.position);
坦克死亡:直接在爆炸特效上添加一个音频组件,生命周期开始时只播放一次
打到障碍物:在子弹脚本上调用障碍物的播放音效方法
直接在子弹上添加音效组件
当一个组件上有多个音效:先在脚本内定义音效数组,然后添加音效组件,控制组件的播放切换
if (Math.Abs(h)<0.05f)
{
currAudio.clip = playerAudio[0];
if (!currAudio.isPlaying)
{
currAudio.Play();
}
}
1.主页面渐入效果
可以用animation组件也可以用脚本做
2.玩家2功能-在edit-projectsetting-input中新增玩家2按键
3.其他坦克的扩展,奖励品功能
Scenes-canvasScaler-scalermode-scaleWithScreenSize
做2d游戏cameraMode一般为camera,然后把camera拖到canvas中
3d游戏一般为overlay
贪吃蛇
继续贪吃蛇
在四周做一个隐藏的边界,创建一个空组件然后设置10高度满长度添加碰撞检测
Boxcolider设置size XY值
蛇头的移动,这里视频把蛇的移动间隔用循环定时器,监听键盘用update
每隔(velTime)秒移动x step y step
上为x = 0,y为+step,下为x=0,y为-step类推
lastPos = gameObject.transform.localPosition;
gameObject.transform.localPosition = new Vector3(lastPos.x+x,lastPos.y+y,lastPos.z);
2d组件的旋转必须是四元数:
Quaternion.euler(0,0,0)
Transform.localrotation = Quaternion.Euler(0,0,0)
If(keycode.w && x!=-step)
停止循环定时器,并修改移动延时,然后重启定时器
食物生成器food
后面的生成视频中采用的是食物销毁后生成食物,但是也可以用食物上限检测的方法来做
单例化createFood脚本
注意:要setparent,不然生成的食物没有位置锚点,生成不知道哪里去
确定当前要增加的是奇数身段还是偶数,设置父组件
生成的身段添加到bodyList数组中
吃食物-蛇身数组+1-蛇头每帧移动时将蛇身最后一节放到蛇头上一个位置,就有移动的视觉错句,弊端是蛇身颜色每一帧是变化的
Bug:
将尾部移动到头部只能适用于单色的,蛇身是两个颜色就会造成颜色不停变换
要将蛇身每个部位向前移动
for (int i = body.Count-1; i < 0; i--)
{
body[i].localPosition = body[i-1].localPosition;
}
body[0].localPosition = headPos;
死亡
Tag-body
Ontrigger if (collision.tag == tag)
注意修改边界尺寸也要把碰撞尺寸一起修改!不然没办法触发碰撞器!!!
自由模式
主要是根据蛇头碰到gameobject.name为上边界时则将y轴转换正负数
然后左右边界有偏移量所以转换的时候要加上偏移量
直接转没有效果是因为直接转会反复触发上下边界的判定,所以由上边界转换到下边界时要步数+1
就是生成食物有一个传参,是否为奖励品
吃掉食物时有20%几率为真
UIcontroller依旧实例化
三个文本:长度文本,分数文本,阶段文本
切换背景颜色并设置透明度的方法,但是我并没有用,只是用普通的color.red
Image image = GetComponent<Image>();
// 设置颜色为红色,透明度为55%
image.color = new Color(1, 0, 0, 0.55f); // R, G, B, A (红, 绿, 蓝, 透明度)
引入菜单按钮和暂停按钮
使用Time.scale(0)控制时间暂停
同时暂停的图片也要切换,用sprite数组引入图片
将快捷键中的提交submit空格键取消
Edit-projectsetting-input
并且加速的时候还要有一个当前是否暂停游戏的判断
主菜单:将两个场景在scene setting中设置
结束循环定时器,并且用系统自带的得分记录功能储存得分
死亡调用
这个是类似html的本地储存,用法playerprefabs.setInt(键,值);
PlayerPrefs.SetInt("lastl",mainUI.Instance.length);
PlayerPrefs.SetInt("lasts",mainUI.Instance.score);
//判断是否是最高得分
if (PlayerPrefs.GetInt("bests",0)<mainUI.Instance.length)
{
PlayerPrefs.SetInt("bestl",mainUI.Instance.length);
PlayerPrefs.SetInt("bests",mainUI.Instance.score);
}
}
然后用一个协成做游戏等待后重开
StartCoroutine(gameOver(1.5f));
}
IEnumerator gameOver(float t){
yield return new WaitForSeconds(t);
SceneManager.LoadScene(1);
}
//等待1.5秒后重载游戏场景
上次得分和最后得分在组件加载时就调用脚本
用户选择皮肤和模式
在按钮组件中绑定方法,并传入isOn参数
并且游戏进入时读取上一次的用户选择
新建Resoures文件夹并把所有皮肤放进去
游戏开始时蛇头awake函数直接替换资源
if (PlayerPrefs.GetString("sb") == "sb01")
{
gameObject.GetComponent<Image>().sprite = Resources.Load<Sprite>("sh01");
bodySprite[0] = Resources.Load<Sprite>("sb0101");
bodySprite[1] = Resources.Load<Sprite>("sb0102");
}
else
{
gameObject.GetComponent<Image>().sprite = Resources.Load<Sprite>("sh02");
bodySprite[0] = Resources.Load<Sprite>("sb0201");
bodySprite[1] = Resources.Load<Sprite>("sb0202");
}
边界的话就是mainUI脚本中判断是否为自由模式
是的话直接遍历bg下的边界组件enable为false
在蛇头中也要判断后撞到边界直接死亡
void Start()
{
if (PlayerPrefs.GetString("mode") == "free")
{
isFree = true;
foreach (Transform t in bg.gameObject.transform)
{
t.gameObject.SetActive(true);
}
}else{
isFree = false;
foreach (Transform t in bg.gameObject.transform)
{
t.gameObject.SetActive(false);
}
}
}
//遍历组件
public AudioClip eataudio;
AudioSource.PlayClipAtPoint(eataudio,Vector3.zero);
在做贪吃蛇的复盘,计划明天学愤怒小鸟
PVZ也可以,whatever
RPG游戏也可以
出去玩了
完成贪吃蛇复盘,进度太慢了,要加快了