现在正在自制小游戏的冲刺以及残影效果,记录一下自己的学习经历
在开始学习之前,我们首先要对对象池设计模式有一个概念: 对象池(Object Pool)就是在一个池子里存放着许多的物体,当我们需要的时候就拿出来一个,将他做成我想要的样子,用完之后在存入池子里
为什么要有对象池?
因为系统中经常会出现需要频繁出现然后消失的物体,比如说我们的子弹,一个地图里出现的敌人,如果我们经常用Instantiate 和 Destroy 来生成后销毁,会比较吃内存,所以需要用对象池设计模式概念,在游戏一开始就创建若干数量的物体,先隐藏起来,在需要用到的时候再显示出来,以此循环.
我们制作残影, 是通过创建多个图像在玩家身后 然后随着时间逐渐降低它的不透明度,到达指定时间返回对象池,下面是代码.
挂在每个残影上的ShadowPrefab脚本
using UnityEngine;
public class ShadowSprite : MonoBehaviour
{
private Transform player;
private SpriteRenderer thisSprite;
private SpriteRenderer playerSprite;
private Color color;
[Header("时间控制参数")]
public float activeTime;//显示时间
public float activeStart;//开始显示的时间点
[Header("不透明度控制")]
private float alpha;
public float alphaSet;//初始值
public float alphaMultiplier;
private void OnEnable()
{
player = GameObject.FindGameObjectWithTag("Player").transform;
thisSprite = GetComponent();
playerSprite = player.GetComponent();
alpha = alphaSet;
thisSprite.sprite = playerSprite.sprite;
transform.position = player.position;
transform.localScale = player.localScale;
transform.rotation = player.rotation;
activeStart = Time.time;
}
void Update()
{
alpha *= alphaMultiplier;
color = new Color(0.5f, 0.5f, 1, alpha);//Color(1,1,1,1)代表100%显示各通道颜色,请查看Api手册
thisSprite.color = color;
if (Time.time >= activeStart + activeTime)
{
//返回对象池
ShadowPool.instance.ReturnPool(this.gameObject);
}
}
}
挂在对象池上面的ShadowPool脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ShadowPool : MonoBehaviour
{
public static ShadowPool instance;
public GameObject shadowPrefab;
public int shadowCount;
private Queue availableObjects = new Queue();
void Awake()
{
instance = this;
//初始化对象池
FillPool();
}
public void FillPool()
{
for (int i = 0; i < shadowCount; i++)
{
var newShadow = Instantiate(shadowPrefab);
newShadow.transform.SetParent(transform);
//取消启用,返回对象池
ReturnPool(newShadow);
}
}
public void ReturnPool(GameObject gameObject)
{
gameObject.SetActive(false);
availableObjects.Enqueue(gameObject);
}
public GameObject GetFormPool()
{
if (availableObjects.Count == 0)
{
FillPool();
}
var outShadow = availableObjects.Dequeue();
outShadow.SetActive(true);
return outShadow;
}
}
在我们的PlayerController上需要添加一些代码,下面是添加的变量代码
[Header("CD的UI组件")]
public Image cdImage;
[Header("Dash参数")]
public float dashTime;//dash时长
private float dashTimeLeft;//冲锋剩余时间
private float lastDash = -10f;//上一次dash时间点
public float dashCoolDown;
public float dashSpeed;
public bool isGround, isJump, isDashing;
在Update中要获得按键反馈的代码
void Update()
{
if (Input.GetKeyDown(KeyCode.J))
{
if (Time.time >= (lastDash + dashCoolDown))
{
//可以执行dash
ReadyToDash();
}
}
}
void ReadyToDash()
{
isDashing = true;
dashTimeLeft = dashTime;
lastDash = Time.time;
}
执行冲刺的动作代码,需要放到FixedUpdate中执行
void Dash()
{
if (isDashing)
{
if (dashTimeLeft > 0)
{
if (rb.velocity.y > 0 && !isGround)
{
rb.velocity = new Vector2(dashSpeed * horizontalMove, jumpForce);//在空中Dash向上
}
rb.velocity = new Vector2(dashSpeed * horizontalMove, rb.velocity.y);//地面Dash
dashTimeLeft -= Time.deltaTime;
ShadowPool.instance.GetFormPool();
}
if (dashTimeLeft <= 0)
{
isDashing = false;
if (!isGround)
{
//目的为了在空中结束 Dash 的时候可以接一个小跳跃。根据自己需要随意删减调整
rb.velocity = new Vector2(dashSpeed * horizontalMove, jumpForce);
}
}
}
}