unity 有打击感的图片,怎么做动画,可以表现出良好的打击效果
完整实现脚本:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;[RequireComponent(typeof(Image))]
public class HitEffectController : MonoBehaviour
{[Header("基础设置")]public float hitDuration = 0.5f; // 打击效果总时长[Header("缩放效果")]public float maxScale = 1.3f; // 最大缩放值public float scaleInDuration = 0.05f; // 缩放进入时间public float scaleOutDuration = 0.2f; // 缩放恢复时间public AnimationCurve scaleCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);[Header("震动效果")]public float shakeIntensity = 10f; // 震动强度public float shakeFrequency = 25f; // 震动频率public AnimationCurve shakeCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);[Header("闪光效果")]public Color flashColor = Color.white; // 闪光颜色public float flashDuration = 0.1f; // 闪光持续时间public float flashIntensity = 5f; // 闪光强度[Header("运动模糊")]public bool useMotionBlur = true;public float stretchAmount = 0.3f; // 拉伸量public float stretchDuration = 0.08f; // 拉伸持续时间[Header("粒子效果")]public ParticleSystem hitParticles;public int particleCount = 15; // 粒子数量[Header("时间效果")]public float freezeDuration = 0.05f; // 时间冻结时长private Image targetImage;private RectTransform rectTransform;private Vector3 originalScale;private Color originalColor;private Material originalMaterial;private Coroutine currentEffect;void Awake(){targetImage = GetComponent<Image>();rectTransform = GetComponent<RectTransform>();originalScale = rectTransform.localScale;originalColor = targetImage.color;originalMaterial = targetImage.material;}// 触发打击效果public void TriggerHitEffect(){if (currentEffect != null) StopCoroutine(currentEffect);currentEffect = StartCoroutine(HitEffectRoutine());}private IEnumerator HitEffectRoutine(){// 1. 时间冻结(强调击中瞬间)Time.timeScale = 0f;yield return new WaitForSecondsRealtime(freezeDuration);Time.timeScale = 1f;// 2. 初始缩放(表现冲击)float scaleTimer = 0f;while (scaleTimer < scaleInDuration){scaleTimer += Time.deltaTime;float t = scaleCurve.Evaluate(scaleTimer / scaleInDuration);float scale = Mathf.Lerp(1f, maxScale, t);rectTransform.localScale = originalScale * scale;yield return null;}// 3. 同时触发闪光和粒子效果StartCoroutine(FlashEffect());EmitParticles();// 4. 运动模糊(可选)if (useMotionBlur){StartCoroutine(StretchEffect());}// 5. 缩放恢复+震动效果float shakeTimer = 0f;Vector3 originalPosition = rectTransform.localPosition;while (shakeTimer < hitDuration){shakeTimer += Time.deltaTime;// 缩放恢复if (shakeTimer < scaleOutDuration){float scaleT = scaleCurve.Evaluate(shakeTimer / scaleOutDuration);float scale = Mathf.Lerp(maxScale, 1f, scaleT);rectTransform.localScale = originalScale * scale;}// 震动效果float shakeT = shakeCurve.Evaluate(shakeTimer / hitDuration);float shakeMagnitude = shakeIntensity * (1f - shakeT);float offsetX = Mathf.Sin(Time.time * shakeFrequency) * shakeMagnitude;float offsetY = Mathf.Cos(Time.time * shakeFrequency) * shakeMagnitude;rectTransform.localPosition = originalPosition + new Vector3(offsetX, offsetY, 0);yield return null;}// 恢复原始状态rectTransform.localScale = originalScale;rectTransform.localPosition = originalPosition;}// 闪光效果协程private IEnumerator FlashEffect(){// 创建临时材质实现闪光Material flashMaterial = new Material(Shader.Find("UI/Unlit/Transparent"));targetImage.material = flashMaterial;float timer = 0f;while (timer < flashDuration){timer += Time.deltaTime;float t = Mathf.Clamp01(timer / flashDuration);// 强度曲线:快速达到峰值然后衰减float intensity = flashIntensity * Mathf.Sin(t * Mathf.PI);// 混合原始颜色和闪光颜色Color blendedColor = Color.Lerp(originalColor, flashColor, intensity);flashMaterial.color = blendedColor;yield return null;}// 恢复原始材质targetImage.material = originalMaterial;Destroy(flashMaterial);}// 运动模糊拉伸效果private IEnumerator StretchEffect(){Vector3 originalScale = rectTransform.localScale;Vector3 stretchedScale = new Vector3(originalScale.x * (1f + stretchAmount),originalScale.y * (1f - stretchAmount * 0.5f),originalScale.z);float timer = 0f;while (timer < stretchDuration){timer += Time.deltaTime;float t = timer / stretchDuration;// 使用缓动函数实现快速拉伸然后恢复float stretchT = Mathf.Sin(t * Mathf.PI * 0.5f);rectTransform.localScale = Vector3.Lerp(originalScale, stretchedScale, stretchT);yield return null;}rectTransform.localScale = originalScale;}// 发射粒子private void EmitParticles(){if (hitParticles != null){// 在图片位置发射粒子hitParticles.transform.position = rectTransform.position;hitParticles.Emit(particleCount);}}
}
参数优化建议
缩放效果
csharp
maxScale = 1.2f - 1.5f; // 根据图片大小调整
scaleInDuration = 0.03f - 0.07f; // 快速冲击
scaleOutDuration = 0.15f - 0.3f; // 缓慢恢复
震动效果
csharp
shakeIntensity = 5f - 20f; // 小图片用小值,大图片用大值
shakeFrequency = 20f - 30f; // 高频震动更真实
闪光效果
csharp
// 根据图片主色调选择对比色
flashColor = ComplementaryColor(originalColor);
flashIntensity = 3f - 8f; // 强度根据场景亮度调整
高级效果增强技巧
1. 材质与着色器效果
冲击波着色器:
// 简化的冲击波着色器
Shader "Custom/HitWave"
{Properties{_MainTex ("Texture", 2D) = "white" {}_WaveCenter ("Wave Center", Vector) = (0.5, 0.5, 0, 0)_WaveAmount ("Wave Amount", Range(0, 1)) = 0_WaveIntensity ("Wave Intensity", Float) = 10}SubShader{// 着色器代码...float2 waveOffset = (distance(i.uv, _WaveCenter.xy) * _WaveIntensity * _WaveAmount;float2 distortedUV = i.uv + waveOffset;fixed4 col = tex2D(_MainTex, distortedUV);// 增加边缘发光col.rgb += _WaveAmount * _WaveIntensity * 0.1 * (1 - smoothstep(0, 0.2, distance(i.uv, _WaveCenter.xy)));}
}
2. 屏幕空间效果
全局屏幕震动:
public class ScreenShake : MonoBehaviour
{public float duration = 0.5f;public float intensity = 0.1f;private Vector3 originalPos;private float currentShakeTime;void Start(){originalPos = transform.localPosition;}public void Shake(){currentShakeTime = duration;}void Update(){if (currentShakeTime > 0){float percent = currentShakeTime / duration;Vector2 offset = UnityEngine.Random.insideUnitCircle * intensity * percent;transform.localPosition = originalPos + new Vector3(offset.x, offset.y, 0);currentShakeTime -= Time.deltaTime;}else{transform.localPosition = originalPos;}}
}
3. 音效同步
[Header("音效设置")]
public AudioClip hitSound;
public AudioClip impactSound;
public float soundDelay = 0.02f;private AudioSource audioSource;void Start()
{audioSource = gameObject.AddComponent<AudioSource>();
}private IEnumerator PlayHitSounds()
{audioSource.PlayOneShot(hitSound);yield return new WaitForSeconds(soundDelay);audioSource.PlayOneShot(impactSound);
}
4. 物理模拟碎片
[Header("碎片效果")]
public GameObject fragmentPrefab;
public int fragmentCount = 10;
public float explosionForce = 300f;private void CreateFragments()
{for (int i = 0; i < fragmentCount; i++){GameObject fragment = Instantiate(fragmentPrefab, transform.position, Quaternion.identity);Rigidbody2D rb = fragment.GetComponent<Rigidbody2D>();if (rb != null){Vector2 direction = Random.insideUnitCircle.normalized;rb.AddForce(direction * explosionForce);rb.AddTorque(Random.Range(-100f, 100f));}Destroy(fragment, Random.Range(0.5f, 1.5f));}
}
参数组合方案
参数组合方案
轻度打击效果
csharp
hitDuration = 0.3f;
maxScale = 1.15f;
shakeIntensity = 5f;
flashIntensity = 3f;
freezeDuration = 0.02f;
中度打击效果
csharp
hitDuration = 0.5f;
maxScale = 1.25f;
shakeIntensity = 10f;
flashIntensity = 5f;
freezeDuration = 0.05f;
useMotionBlur = true;
重度打击效果
csharp
hitDuration = 0.7f;
maxScale = 1.4f;
shakeIntensity = 15f;
flashIntensity = 8f;
freezeDuration = 0.08f;
useMotionBlur = true;
// 启用碎片效果
CreateFragments();
其他:
性能优化建议
对象池管理:csharp
public class FragmentPool : MonoBehaviour
{public GameObject fragmentPrefab;public int poolSize = 20;private Queue<GameObject> fragmentPool = new Queue<GameObject>();void Start(){for (int i = 0; i < poolSize; i++){GameObject fragment = Instantiate(fragmentPrefab);fragment.SetActive(false);fragmentPool.Enqueue(fragment);}}public GameObject GetFragment(){if (fragmentPool.Count > 0){GameObject fragment = fragmentPool.Dequeue();fragment.SetActive(true);return fragment;}return Instantiate(fragmentPrefab);}public void ReturnFragment(GameObject fragment){fragment.SetActive(false);fragmentPool.Enqueue(fragment);}
}
材质共享:csharp
private static Material flashMaterial;void Awake()
{if (flashMaterial == null){flashMaterial = new Material(Shader.Find("UI/Unlit/Transparent"));}// 使用共享材质
}
按需启用:csharp
void OnEnable()
{// 初始化
}void OnDisable()
{// 清理资源
}
使用示例
csharp
// 在UI按钮上添加点击效果
public class HitButton : MonoBehaviour
{public HitEffectController hitEffect;void Start(){Button button = GetComponent<Button>();button.onClick.AddListener(OnButtonClick);}void OnButtonClick(){hitEffect.TriggerHitEffect();}
}// 在游戏角色受击时
public class CharacterHealth : MonoBehaviour
{public HitEffectController hitEffect;public ScreenShake screenShake;public void TakeDamage(){hitEffect.TriggerHitEffect();screenShake.Shake();// 其他伤害处理...}
}
效果组合策略
轻重攻击区分:轻攻击:缩放+轻微震动重攻击:缩放+震动+闪光+屏幕震动+粒子元素类型反馈:物理攻击:灰色粒子+屏幕震动火焰攻击:红色闪光+火焰粒子冰霜攻击:蓝色闪光+冰晶粒子命中部位差异:头部命中:加强屏幕震动身体命中:标准效果四肢命中:减弱效果总结
要创建具有强烈打击感的图片动画,关键在于多种效果的组合运用:时间控制:通过时间冻结强调击中瞬间空间变形:缩放、拉伸和震动表现物理冲击视觉特效:闪光和粒子增加细节反馈辅助效果:屏幕震动和音效增强沉浸感参数优化:根据不同场景调整效果强度通过调整上述脚本中的参数和组合不同的效果模块,可以为各种游戏场景创建出令人满意的打击效果。记得在实际应用中根据游戏风格和性能要求进行适当调整。