[Unity Demo]从零开始制作空洞骑士Hollow Knight第十六集(上篇):制作更多地图,更多敌人,更多可交互对象

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、第一个代表性场景
    • 1.制作敌人僵尸跳跳虫更多敌人
    • 2.制作敌人阿斯匹德更多可交互对象
    • 3.制作敌人孵化虫和它的孩子
  • 二、第二个代表性场景
    • 1.制作更多敌人
    • 2.制作更多可交互对象
  • 总结


前言

         hello大家好久没见,之所以隔了这么久才更新并不是因为我又放弃了这个项目,而是接下来要制作的工作太忙碌了,每次我都花了很长的时间解决完一个部分,然后就没力气打开CSDN写文章就直接睡觉去了,现在终于有时间整理下我这半个月都做了什么内容。

        废话少说,接下来我将继续介绍我做的几个代表性场景,,可能你会说:“怎么标题还和上期一模一样”,那当然是没办法的事情,毕竟一期讲完这么多场景,敌人,可交互对象你没看睡着我都快写睡着了,OK我们接着来制作更多地图,更多敌人,更多可交互对象

        另外,我的Github已经更新了,想要查看最新的内容话请到我的Github主页下载工程吧:

GitHub - ForestDango/Hollow-Knight-Demo: A new Hollow Knight Demo after 2 years!


一、第一个代表性场景

1.制作敌人僵尸跳跳虫更多敌人

我突然找到一个有四个新类型敌人的场景,让我们先来介绍这四少吧,但首先还是先搭建好场景

可能看到这里你还不知道这对应的是游戏里的哪个场景,但只要我加上场景景色一切将豁然开朗

往上走去鹿角站,往右走去打苍蝇之母因此记得添加好对应的TransitionPoint。

我们先来制作最简单的僵尸跳跳虫:做好相对应的tk2dsprite和tk2dspriteAnimator。

 

添加相对应的脚本:

 

 老朋友Attack Range攻击距离:

落地状态下的灰尘粒子系统Dust:

创建一个名字为“Zombie Swipe”的playmakerFSM,然后老规矩贴出事件和变量:

逐个讲状态:

初始化阶段:

准备阶段:逐帧判断攻击距离和可视范围内:

判断玩家位置:

攻击准备阶段:

起飞阶段 

落地阶段:

冷却阶段:

回到空闲阶段:

重置Walker脚本的行为:

        这样一个简单跳跳僵尸虫就完成了。

2.制作敌人阿斯匹德更多可交互对象

        然后是制作敌人阿斯匹德,注意,这个不是折磨玩家的原始阿斯匹德,而是只会喷一个方向的:

首先添加好tk2dsprite和tk2dSpriteAnimator:

长开火和短开火的动画:

添加好相应的脚本:

除此之外,我们还要制作攻击用的子弹

我们先来制作玩家离开攻击距离的playmakerFSM:

这里会设置Spitter的playmakerFSM里面的bool变量unalert Range        以及设置bool变量Can See Hero

 

 

回到阿斯匹德spitter中,我们首先创建一个之前讲过的playmakerFSM叫flyer_receive_direction_msg。这个我之前讲蚊子那期用过,就是接收不同方向信息的,

然后才是我们的重点“spitter” FSM:

初始化状态:播放音效和动画,确认初始时的朝向,空闲状态漫无目的的IdleBuzz,通过Alert Range New来判断是否在攻击距离里,并check Can See Hero.

如果满足上述两个条件直接进入Alert状态: 

 

径直向玩家飞去:

判断位置并射线检测:

 

再飞行一小段距离,朝向玩家:

准备开火阶段:

设置发射的子弹朝向玩家,设置好速度

当玩家离开攻击距离后,回到Unalert Frame状态,下一帧再回到Idle状态

 这里我们来创建子弹预制体:

新建一个脚本名字叫EnemyBullet.cs
 

using System.Collections;
using UnityEngine;[RequireComponent(typeof(Rigidbody2D))]
public class EnemyBullet : MonoBehaviour
{public float scaleMin = 1.15f;public float scaleMax = 1.45f;private float scale;[Space]public float stretchFactor = 1.2f;public float stretchMinX = 0.75f;public float stretchMaxY = 1.75f;[Space]public AudioSource audioSourcePrefab;public AudioEvent impactSound;private bool active;private Rigidbody2D body;private tk2dSpriteAnimator anim;private Collider2D col;private void Awake(){body = GetComponent<Rigidbody2D>();anim = GetComponent<tk2dSpriteAnimator>();col = GetComponent<Collider2D>();}private void OnEnable(){active = true;scale = Random.Range(scaleMin, scaleMax);col.enabled = true;body.isKinematic = false;body.velocity = Vector2.zero;body.angularVelocity = 0f;anim.Play("Idle");}private void Update(){if (active){float rotation = Random.Range(body.velocity.y,body.velocity.x) * 57.295776f;transform.SetRotation2D(rotation);float num = 1f - body.velocity.magnitude * stretchFactor * 0.01f;float num2 = 1f + body.velocity.magnitude * stretchFactor * 0.01f;if (num2 < stretchMinX){num2 = stretchMinX;}if (num > stretchMaxY){num = stretchMaxY;}num *= scale;num2 *= scale;transform.localScale = new Vector3(num2, num, transform.localScale.z);}}private void OnCollisionEnter2D(Collision2D collision){if (active){active = false;StartCoroutine(Collision(collision.GetSafeContact().Normal, true));}}private void OnTriggerEnter2D(Collider2D collision){if(active && collision.tag == "HeroBox"){active = false;StartCoroutine(Collision(Vector2.zero, false));}}public void OrbitShieldHit(Transform shield){if (active){active = false;Vector2 normal = transform.position - shield.position;normal.Normalize();StartCoroutine(Collision(normal, true));}}private IEnumerator Collision(Vector2 normal, bool doRotation){transform.localScale = new Vector3(scale, scale, transform.localScale.z);body.isKinematic = true;body.velocity = Vector2.zero;body.angularVelocity = 0f;tk2dSpriteAnimationClip impactAnim = anim.GetClipByName("Impact");anim.Play(impactAnim);if (!doRotation || (normal.y >= 0.75f && Mathf.Abs(normal.x) < 0.5f)){transform.SetRotation2D(0f);}else if (normal.y <= 0.75f && Mathf.Abs(normal.x) < 0.5f){transform.SetRotation2D(180f);}else if (normal.x >= 0.75f && Mathf.Abs(normal.y) < 0.5f){transform.SetRotation2D(270f);}else if (normal.x <= 0.75f && Mathf.Abs(normal.y) < 0.5f){transform.SetRotation2D(90f);}impactSound.SpawnAndPlayOneShot(audioSourcePrefab, transform.position);yield return null;col.enabled = false;yield return new WaitForSeconds((impactAnim.frames.Length - 1) / impactAnim.fps);Destroy(gameObject);//TODO:}}

回到Unity编辑器添加好对应的参数,

最后再添加一个子对象,一个小小的亮灯:

3.制作敌人孵化虫和它的孩子

这个敌人我忘了叫什么名字了,暂且叫它孵化虫吧,先添加上tk2dsprite和tk2dspriteanimator:

它的攻击方式只有一种,那就是生下小虫子,然后小虫子来攻击玩家,子对象只需要一个Alert Range New

上面的playmakerFSM除了之前讲过的flyer_receive_direction_msg,还有就是“Hatcher”

这里给它最多生五个孩子

在开始前,我们可以在场景中偏离核心区域的地方预生成它的孩子,并把它们关在笼子里面别到处乱跑,

注意添加好tag,这里我先预生成了15只虫子宝宝并让它们待在这个隐形笼子里面。 

 

如上面阿斯匹德一样Idle状态:

 

 

 检查是否已经生够了到达最大可生成数量:

 来点生下来的音效,设置好生下来的位置,为宝宝的playmakerFSM发送事件SPAWN:

 

 这里有几个自定义playmakerFSM行为脚本我好像忘记说了:

using System;
using UnityEngine;namespace HutongGames.PlayMaker.Actions
{[ActionCategory(ActionCategory.Audio)][Tooltip("Instantiate an Audio Player object and play a oneshot sound via its Audio Source.")]public class AudioPlayerOneShot : FsmStateAction{[RequiredField][CheckForComponent(typeof(AudioSource))][Tooltip("The object to spawn. Select Audio Player prefab.")]public FsmGameObject audioPlayer;[RequiredField][Tooltip("Object to use as the spawn point of Audio Player")]public FsmGameObject spawnPoint;[CompoundArray("Audio Clips", "Audio Clip", "Weight")]public AudioClip[] audioClips;[HasFloatSlider(0f, 1f)]public FsmFloat[] weights;public FsmFloat pitchMin;public FsmFloat pitchMax;public FsmFloat volume;public FsmFloat delay;public FsmGameObject storePlayer;private AudioSource audio;private float timer;public override void Reset(){spawnPoint = null;audioClips = new AudioClip[3];weights = new FsmFloat[]{1f,1f,1f};pitchMin = 1f;pitchMax = 1f;volume = 1f;timer = 0f;}public override void OnEnter(){timer = 0f;if(delay.Value == 0f){DoPlayRandomClip();Finish();}}public override void OnUpdate(){if(delay.Value > 0f){if(timer < delay.Value){timer += Time.deltaTime;return;}DoPlayRandomClip();Finish();}	}private void DoPlayRandomClip(){if (audioClips.Length == 0)return;GameObject value = audioPlayer.Value;Vector3 position = spawnPoint.Value.transform.position;Vector3 up = Vector3.up;//TODO:这行记得要改,因为我还没做对象池GameObject gameObject = UnityEngine.Object.Instantiate(audioPlayer.Value, position, Quaternion.Euler(up));audio = gameObject.GetComponent<AudioSource>();int randomWeightIndex = ActionHelpers.GetRandomWeightedIndex(weights);if(randomWeightIndex != -1){AudioClip audioClip = audioClips[randomWeightIndex];if(audioClip != null){float pitch = UnityEngine.Random.Range(pitchMin.Value, pitchMax.Value);audio.pitch = pitch;audio.PlayOneShot(audioClip);}}audio.volume = volume.Value;}public AudioPlayerOneShot(){pitchMin = 1f;pitchMax = 2f;}}}
using UnityEngine;namespace HutongGames.PlayMaker.Actions
{[ActionCategory(ActionCategory.GameObject)][Tooltip("Spawns a random amount of chosen GameObject from global pool and fires them off in random directions.")]public class FlingObjectsFromGlobalPool : RigidBody2dActionBase{[RequiredField][Tooltip("GameObject to spawn.")]public FsmGameObject gameObject;[Tooltip("GameObject to spawn at (optional).")]public FsmGameObject spawnPoint;[Tooltip("Position. If a Spawn Point is defined, this is used as a local offset from the Spawn Point position.")]public FsmVector3 position;[Tooltip("Minimum amount of objects to be spawned.")]public FsmInt spawnMin;[Tooltip("Maximum amount of objects to be spawned.")]public FsmInt spawnMax;[Tooltip("Minimum speed objects are fired at.")]public FsmFloat speedMin;[Tooltip("Maximum speed objects are fired at.")]public FsmFloat speedMax;[Tooltip("Minimum angle objects are fired at.")]public FsmFloat angleMin;[Tooltip("Maximum angle objects are fired at.")]public FsmFloat angleMax;[Tooltip("Randomises spawn points of objects within this range. Leave as 0 and all objects will spawn at same point.")]public FsmFloat originVariationX;public FsmFloat originVariationY;[Tooltip("Optional: Name of FSM on object you want to send an event to after spawn")]public FsmString FSM;[Tooltip("Optional: Event you want to send to object after spawn")]public FsmString FSMEvent;private float vectorX;private float vectorY;private bool originAdjusted;public override void Reset(){gameObject = null;spawnPoint = null;position = new FsmVector3{UseVariable = true};spawnMin = null;spawnMax = null;speedMin = null;speedMax = null;angleMin = null;angleMax = null;originVariationX = null;originVariationY = null;FSM = new FsmString{UseVariable = true};FSMEvent = new FsmString{UseVariable = true};}public override void OnEnter(){if (gameObject.Value != null){Vector3 a = Vector3.zero;Vector3 zero = Vector3.zero;if (spawnPoint.Value != null){a = spawnPoint.Value.transform.position;if (!position.IsNone){a += position.Value;}}else if (!position.IsNone){a = position.Value;}int num = Random.Range(spawnMin.Value, spawnMax.Value + 1);for (int i = 1; i <= num; i++){//TODO:以后创造完对象池后记得替换掉GameObject gameObject = GameObject.Instantiate(this.gameObject.Value, a, Quaternion.Euler(zero));float x = gameObject.transform.position.x;float y = gameObject.transform.position.y;float z = gameObject.transform.position.z;if (originVariationX != null){x = gameObject.transform.position.x + Random.Range(-originVariationX.Value, originVariationX.Value);originAdjusted = true;}if (originVariationY != null){y = gameObject.transform.position.y + Random.Range(-originVariationY.Value, originVariationY.Value);originAdjusted = true;}if (originAdjusted){gameObject.transform.position = new Vector3(x, y, z);}base.CacheRigidBody2d(gameObject);float num2 = Random.Range(speedMin.Value, speedMax.Value);float num3 = Random.Range(angleMin.Value, angleMax.Value);vectorX = num2 * Mathf.Cos(num3 * 0.017453292f);vectorY = num2 * Mathf.Sin(num3 * 0.017453292f);Vector2 velocity;velocity.x = vectorX;velocity.y = vectorY;rb2d.velocity = velocity;if (!FSM.IsNone){FSMUtility.LocateFSM(gameObject, FSM.Value).SendEvent(FSMEvent.Value);}}}Finish();}}}

二、第二个代表性场景

1.制作敌人沃姆Worm

说起来你看到这名字可能想不起来这是啥怪物,其实就是遗忘十字路中恶心玩家的那个路障

首先是灰尘粒子系统:

这个石头也是粒子系统:

这个也是粒子系统石头,区别在于,上面那个是Idle状态下播放的粒子系统,而这个是在Burst状态下播放的:

 

这个虫子属于是既能伤害玩家又能伤害敌人的,因此添加上DamageHero和DamageEnemy两个脚本: 

这里我们把将骨钉攻击那期的Nail Slash里面的playmakerfsm“damages_enemy”也给它安排上:

还有自己的Worm Control:

 向上中:

缩回去: 

 已经缩回地里:

是否开启burst rocks的particlesystem:

Burst的时候就在这里开启伤害和Collider: 

自定义行为脚本如下:

using UnityEngine;namespace HutongGames.PlayMaker.Actions
{[ActionCategory("Particle System")][Tooltip("Set particle emission on or off on an object with a particle emitter")]public class SetParticleEmission : FsmStateAction{[RequiredField][Tooltip("The particle emitting GameObject")]public FsmOwnerDefault gameObject;public FsmBool emission;public override void Reset(){gameObject = null;emission = false;}public override void OnEnter(){if (gameObject != null){GameObject ownerDefaultTarget = Fsm.GetOwnerDefaultTarget(gameObject);if (ownerDefaultTarget != null){ownerDefaultTarget.GetComponent<ParticleSystem>().enableEmission = emission.Value;}}Finish();}}
}
using HutongGames.PlayMaker;
using UnityEngine;[ActionCategory("Hollow Knight")]
public class SetDamageHeroAmount : FsmStateAction
{[UIHint(UIHint.Variable)]public FsmOwnerDefault target;public FsmInt damageDealt;public override void Reset(){target = new FsmOwnerDefault();damageDealt = null;}public override void OnEnter(){GameObject safe = target.GetSafe(this);if(safe != null){DamageHero component = safe.GetComponent<DamageHero>();if(component != null && !damageDealt.IsNone){component.damageDealt = damageDealt.Value;}}base.Finish();}}

至此我们制作了一个流动的循环。 

2.制作可交互对象

其实主要就是这些杆子,我们用脚本breakable.cs来制作

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Breakable : MonoBehaviour,IHitResponder
{private Collider2D bodyCollider;[Tooltip("Renderer which presents the undestroyed object.")][SerializeField] private Renderer wholeRenderer;[Tooltip("List of child game objects which also represent the whole object.")][SerializeField] public  GameObject[] wholeParts;[Tooltip("List of child game objects which represent remnants that remain static after destruction.")][SerializeField] private GameObject[] remnantParts;[SerializeField] private List<GameObject> debrisParts;[SerializeField] private float angleOffset = -60f;[Tooltip("Breakables behind this threshold are inert.")][SerializeField] private float inertBackgroundThreshold;[Tooltip("Breakables in front of this threshold are inert.")][SerializeField] private float inertForegroundThreshold;[Tooltip("Breakable effects are spawned at this offset.")][SerializeField] private Vector3 effectOffset;[Tooltip("Prefab to spawn for audio.")][SerializeField] private AudioSource audioSourcePrefab;[Tooltip("Table of audio clips to play upon break.")][SerializeField] private AudioEvent breakAudioEvent;[Tooltip("Table of audio clips to play upon break.")][SerializeField] private RandomAudioClipTable breakAudioClipTable;[Tooltip("Prefab to spawn when hit from a non-down angle.")][SerializeField] private Transform dustHitRegularPrefab;[Tooltip("Prefab to spawn when hit from a down angle.")][SerializeField] private Transform dustHitDownPrefab;[Tooltip("Prefab to spawn when hit from a down angle.")][SerializeField] private float flingSpeedMin;[Tooltip("Prefab to spawn when hit from a down angle.")][SerializeField] private float flingSpeedMax;[Tooltip("Strike effect prefab to spawn.")][SerializeField] private Transform strikeEffectPrefab;[Tooltip("Nail hit prefab to spawn.")][SerializeField] private Transform nailHitEffectPrefab;[Tooltip("Spell hit effect prefab to spawn.")][SerializeField] private Transform spellHitEffectPrefab;[Tooltip("Object to send HIT event to.")][SerializeField] private GameObject hitEventReciever;[Tooltip("Forward break effect to sibling FSMs.")][SerializeField] private bool forwardBreakEvent;[Space]public Probability.ProbabilityGameObject[] containingParticles;public FlingObject[] flingObjectRegister;private bool isBroken;private void Awake(){bodyCollider = GetComponent<Collider2D>();}protected void Reset(){inertBackgroundThreshold = 1f;inertForegroundThreshold = -1f;effectOffset = new Vector3(0f, 0.5f, 0f);flingSpeedMin = 10f;flingSpeedMax = 17f;}protected void Start(){CreateAdditionalDebrisParts(debrisParts);float z = transform.position.z;if(z > inertBackgroundThreshold || z < inertForegroundThreshold){BoxCollider2D component = GetComponent<BoxCollider2D>();if(component != null){component.enabled = false;}Destroy(this);return;}for (int i = 0; i < remnantParts.Length; i++){GameObject gameObject = remnantParts[i];if(gameObject != null && gameObject.activeSelf){gameObject.SetActive(false);}}angleOffset *= Mathf.Sign(transform.localScale.x);}protected virtual void CreateAdditionalDebrisParts(List<GameObject> debrisParts){}public void Hit(HitInstance damageInstance){if (isBroken){return;}Debug.LogFormat("Breakable Take Hit");float impactAngle = damageInstance.Direction;float num = damageInstance.MagnitudeMultiplier;if(damageInstance.AttackType == AttackTypes.Spell){Instantiate(spellHitEffectPrefab, base.transform.position, Quaternion.identity).SetPositionZ(0.0031f);}else{if (damageInstance.AttackType != AttackTypes.Nail && damageInstance.AttackType != AttackTypes.Generic){impactAngle = 90f;num = 1f;}Instantiate(strikeEffectPrefab, base.transform.position,Quaternion.identity);Vector3 position = (damageInstance.Source.transform.position + base.transform.position) * 0.5f;SpawnNailHitEffect(nailHitEffectPrefab, position, impactAngle);}int cardinalDirection = DirectionUtils.GetCardinalDirection(damageInstance.Direction);Transform transform = dustHitRegularPrefab;float flingAngleMin;float flingAngleMax;Vector3 euler;if (cardinalDirection == 2){angleOffset *= -1f;flingAngleMin = 120f;flingAngleMax = 160f;euler = new Vector3(180f, 90f, 270f);}else if (cardinalDirection == 0){flingAngleMin = 30f;flingAngleMax = 70f;euler = new Vector3(0f, 90f, 270f);}else if (cardinalDirection == 1){angleOffset = 0f;flingAngleMin = 70f;flingAngleMax = 110f;num *= 1.5f;euler = new Vector3(270f, 90f, 270f);}else{angleOffset = 0f;flingAngleMin = 160f;flingAngleMax = 380f;transform = dustHitDownPrefab;euler = new Vector3(-72.5f, -180f, -180f);}if(transform != null){Instantiate(transform, transform.position + effectOffset, Quaternion.Euler(euler));}Break(flingAngleMin, flingAngleMax, num);}private static Transform SpawnNailHitEffect(Transform nailHitEffectPrefab, Vector3 position, float impactAngle){if (nailHitEffectPrefab == null)return null;int cardinalDirection = DirectionUtils.GetCardinalDirection(impactAngle);float y = 1.5f;float minInclusive;float maxInclusive;if (cardinalDirection == 3){minInclusive = 270f;maxInclusive = 290f;}else if (cardinalDirection == 1){minInclusive = 70f;maxInclusive = 110f;}else{minInclusive = 340f;maxInclusive = 380f;}float x = (cardinalDirection == 2) ? -1.5f : 1.5f;Transform transform = Instantiate(nailHitEffectPrefab,position,Quaternion.identity);Vector3 eulerAngles = transform.eulerAngles;eulerAngles.z = Random.Range(minInclusive, maxInclusive);transform.eulerAngles = eulerAngles;Vector3 localScale = transform.localScale;localScale.x = x;localScale.y = y;transform.localScale = localScale;return transform;}public void Break(float flingAngleMin, float flingAngleMax, float impactMultiplier){if (isBroken)return;SetStaticPartsActivation(true);for (int i = 0; i < debrisParts.Count; i++){GameObject gameObject = debrisParts[i];if (gameObject == null){Debug.LogErrorFormat(this, "Unassigned debris part in {0}", new object[]{this});}else{gameObject.SetActive(true);gameObject.transform.SetRotationZ(gameObject.transform.localEulerAngles.z + angleOffset);Rigidbody2D component = gameObject.GetComponent<Rigidbody2D>();if (component != null){float num = Random.Range(flingAngleMin, flingAngleMax);Vector2 a = new Vector2(Mathf.Cos(num * 0.017453292f), Mathf.Sin(num * 0.017453292f));float d = Random.Range(flingSpeedMin, flingSpeedMax) * impactMultiplier;component.velocity = a * d;}}}if (containingParticles.Length != 0){GameObject gameObject2 = Probability.GetRandomGameObjectByProbability(containingParticles);if (gameObject2){if (gameObject2.transform.parent != transform){FlingObject flingObject = null;foreach (FlingObject flingObject2 in flingObjectRegister){if (flingObject2.referenceObject == gameObject2){flingObject = flingObject2;break;}}if (flingObject != null){flingObject.Fling(transform.position);}else{gameObject2 = Instantiate(gameObject2, transform.position, Quaternion.identity);}}gameObject2.SetActive(true);}}breakAudioEvent.SpawnAndPlayOneShot(audioSourcePrefab, transform.position);breakAudioClipTable.SpawnAndPlayOneShot(audioSourcePrefab, transform.position);if (hitEventReciever != null){FSMUtility.SendEventToGameObject(hitEventReciever, "HIT", false);}if (forwardBreakEvent){FSMUtility.SendEventToGameObject(gameObject, "BREAK", false);}GameObject gameObject3 = GameObject.FindGameObjectWithTag("CameraParent");if (gameObject3 != null){PlayMakerFSM playMakerFSM = PlayMakerFSM.FindFsmOnGameObject(gameObject3, "CameraShake");if(playMakerFSM != null){playMakerFSM.SendEvent("EnemyKillShake");}}wholeRenderer.enabled = false;bodyCollider.enabled = false;isBroken = true;}private void SetStaticPartsActivation(bool v){}[System.Serializable]public class FlingObject{public GameObject referenceObject;[Space]public int spawnMin;public int spawnMax;public float speedMin;public float speedMax;public float angleMin;public float angleMax;public Vector2 originVariation;public FlingObject(){spawnMin = 25;spawnMax = 35;speedMin = 9f;speedMax = 20f;angleMin = 20f;angleMax = 160f;originVariation = new Vector2(0.5f, 0.5f);}public void Fling(Vector3 origin){if (!referenceObject){return;}int num = Random.Range(spawnMin, spawnMax + 1);for (int i = 0; i < num; i++){//TODO:Object PoolGameObject gameObject = Instantiate(referenceObject);if (gameObject){gameObject.transform.position = origin + new Vector3(Random.Range(-originVariation.x, originVariation.x), Random.Range(-originVariation.y, originVariation.y), 0f);float num2 = Random.Range(speedMin, speedMax);float num3 = Random.Range(angleMin, angleMax);float x = num2 * Mathf.Cos(num3 * 0.017453292f);float y = num2 * Mathf.Sin(num3 * 0.017453292f);Vector2 force = new Vector2(x, y);Rigidbody2D component = gameObject.GetComponent<Rigidbody2D>();if (component){component.AddForce(force, ForceMode2D.Impulse);}}}}}
}

 其三个子对象,一个是杆的顶部top,一个是杆的底部base,最后一个是破坏后蹦出来的石头particlesystem:

制作好一个后,我们就可以照此制作更多的这种可破坏的杆子Pole了,

还有这种可破坏的雕塑,原理都是一样的,只不过这个没有头部只有底部,而且有两个粒子系统:

 

 三、第三个代表性场景

            这个夭折了因为CSDN提示我上传的图片到达上限了,这我是没想到的,没办法这一集只能分为上下两期来讲了,而且下期我将讲述一个非常劲爆的敌人,感兴趣的话就等我一两个小时把内容整理完成发出来吧。

        想看效果的请移步到下一篇文章!!!

        md,我没想到CSDN有规矩24小时内只能上传300张图片,喜提一天冷却时间,大伙只能等我明天再来把这篇和下一篇文章写完了。

总结

        想看效果的请移步到下一篇文章!!!

        想看效果的请移步到下一篇文章!!!

        想看效果的请移步到下一篇文章!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/451276.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

0x2E service

0x2E service 1. 概念2. Request message 数据格式3. Respone message 数据格式3.1 正响应格式3.2 negative respone codes(NRC)4. 示例4.1 正响应示例:4.2 NRC 示例1. 概念 UDS(Unified Diagnostic Services)中的0x2E服务,也称为WriteDataByIdentifier(通过标识符写入数据…

spring-boot学习(2)

上次学习截止到拦截器 1.构建RESfun服务 PathVariable通过url路径获取url传递过来的信息 2.MyBatisPlus 第三行的mydb要改为自己的数据库名 第四&#xff0c;五行的账号密码改成自己的 MaooerScan告诉项目自己的这个MyBatisPlus是使用在哪里的&#xff0c;包名 实体类的定义…

专家系统简介

本文对基于规则的专家系统进行简介&#xff0c;举例专家系统的结构类似 MYCIN 系统&#xff0c;同时串联介绍专家系统的各种思想。需要注意的是&#xff0c;本文所述仅是专家系统的一种实现途径&#xff0c;其依赖规则进行知识表示和推理&#xff0c;另外还有基于语义网络、框架…

穿越沙漠问题

题目&#xff1a;一辆吉普车穿越1000km的沙漠。吉普车的总装油量为500L&#xff0c;耗油率为1L/km。由于沙漠中没有油库&#xff0c;必须先用这辆车在沙漠中建立临时油库。若吉普车用最少的耗油量穿越沙漠&#xff0c;应在哪些地方建立油库&#xff0c;以及各处存储的油量是多少…

链动2+1芸众商城421+全插件独立版源码

芸众商城最新全插件421个&#xff0c;去授权 源码全开源链动21商城小程序 这套版本插件全部都是新版本&#xff0c;并非外面那种老版本 老插件全部都不能用的&#xff0c;一堆bug问题&#xff0c;我们插件源码是直接打官方授权源码所以都是最新的&#xff0c;还有很多小程序前…

Parameter-Efficient Fine-Tuning for Large Models: A Comprehensive Survey阅读笔记

Parameter-Efficient Fine-Tuning for Large Models: A Comprehensive Survey 综述阅读笔记 仅记录个人比较感兴趣的部分 基本知识 PEFT的三种分类&#xff1a;additive, selective, reparameterized, and hybrid fine-tuning selective fine-tuning 不需要任何额外的参数&am…

计算机毕业设计Hadoop+Hive+Spark+Flink广告推荐系统 广告预测 广告数据分析可视化 广告爬虫 大数据毕业设计 深度学习 机器学习

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 专业 小四号宋体 班级 小…

《环境感知方案:探索未来智能世界的关键技术》

《环境感知方案&#xff1a;探索未来智能世界的关键技术》 一、环境感知方案的研究现状&#xff08;一&#xff09;机器人领域的环境感知&#xff08;二&#xff09;农业领域的环境感知&#xff08;三&#xff09;智能网联汽车领域的环境感知 二、先进的环境感知技术&#xff0…

A Multi-Head Reconstruction Network For Image Anomaly Detection创新点总结

创新点解析&#xff1a;Multi-Head Reconstruction Network (MRN) 与 Multi-Feature Aggregation (MFA) 1. Multi-Head Reconstruction Network (MRN) 传统重建方法的过程&#xff1a; 训练自动编码器或生成模型来重建正常样本的图像。通过比较原始图像和重建图像来检测异常…

数据结构与算法 - 树 #数的概念 #二叉树 #堆 - 堆的实现/堆排序/TOP-K问题

文章目录 前言 一、树 (一)、概念 1、树的定义 (二)、树的定义 1、树为什么是递归定义的&#xff1f; 2、如何定义树(如何表达一棵树) 解决方案一&#xff1a;假设我们得知该树的度 解决方案二&#xff1a;顺序表 解决方案三&#xff1a;左孩子右兄弟表示法 二、二叉…

Linux Ubuntu dbus CAPI ---- #include<dbus.h>出现“无法打开源文件dbus/xxx.h“的问题

一、确保已安装dbus库和CAPI sudo apt-get install libdbus-1-dev 二、在c_cpp_properties.json的includePath中是否配置了dbus库依赖文件所在的路径 三、编译一个简单的dbus代码&#xff0c;在编译过程中只要出现.h文件找不到的情况&#xff0c;就使用下列命令找到.h文件路径…

Java集合常见知识总结(中)

Set Comparable 和 Comparator 的区别 Comparable 接口和 Comparator 接口都是 Java 中用于排序的接口&#xff0c;它们在实现类对象之间比较大小、排序等方面发挥了重要作用&#xff1a; Comparable 接口实际上是出自java.lang包 它有一个 compareTo(Object obj)方法用来排序…

【web】JDBC

项目连接数据库 右侧导航栏找到databsae 如果没有驱动&#xff0c;先下载驱动 填写数据库用户名密码 勾选对应的表即可 JDBC代码流程 1,配置信息 2,加载驱动 从MySQL Connector/J 5.1版本开始&#xff0c;推荐使用com.mysql.cj.jdbc.Driver这个新的驱动类。 3,链接数据库…

初识Linux · 重定向和缓冲区

目录 前言&#xff1a; 预备知识 缓冲区 重定向 前言&#xff1a; 其实有了文件2的预备知识&#xff0c;我们已经初步了解了文件描述符fd是什么&#xff0c;底层是如何运作的了&#xff0c;那么本文&#xff0c;我们通过文件描述符对重定向和缓冲区有一个更深层次的理解&a…

JVM(HotSpot):GC之垃圾标记阶段

文章目录 前言一、标记阶段算法1、引用计数法2、可达性分析算法&#xff08;JVM使用&#xff09; 二、4种引用1、 强引用2、软引用(SoftReference)3、弱引用(WeakHashMap)4、虚引用(PhantomReference) 三、代码案例1、 强引用2、软引用(SoftReference)3、弱引用(WeakHashMap) 前…

AI-Talk开发板之shell_xtts

一、说明 运行duomotai_ap sdk下的shell_xtts例程&#xff0c;测试语音合成以及SPK功能。 操作说明&#xff1a;开发指南 | 聆思文档中心 (listenai.com) 与处理器的信号连接&#xff1a; 二、工程 1、设备树 由于AI-Talk开发板与CSK6-MIX开发板有些管脚不一样&#xff0c;所…

主机加固是什么?又该如何实施呢?

MCK主机加固&#xff1a;企业数据安全的守护神 内核级安全加固&#xff1a;MCK主机加固采用基于操作系统内核级的安全加固技术&#xff0c;从根本上阻断了病毒和恶意软件的入侵路径&#xff0c;确保企业核心数据的安全。 智能防御机制&#xff1a;智能识别并预警潜在的安全威胁…

纯血鸿蒙!

纯血鸿蒙&#xff0c;这是哪个营销大师给起的名字啊&#xff01; 纯血&#xff01;象征着高贵、自信、自主、血性、英雄气概&#xff0c;都融入这纯血鸿蒙了&#xff01; 鸿蒙本就是开天辟地&#xff0c;加上纯血&#xff0c;真是荡气回肠&#xff01; 鸿蒙的推出背景 我们前…

数据结构(JAVA)包装类泛型

文章目录 包装类基本数据类型和对应的包装类装箱和拆箱面试题 泛型什么是泛型泛型的语法泛型类的使用泛型的使用裸类型(Raw Type) &#xff08;仅需了解&#xff09;擦除机制泛型的上界泛型方法 包装类 基本数据类型和对应的包装类 注意&#xff0c;除了int基本数据类型的包装…

机器学习核心:监督学习与无监督学习

个人主页&#xff1a;chian-ocean 文章专栏 监督学习与无监督学习&#xff1a;深度解析 机器学习是现代人工智能的核心支柱&#xff0c;已广泛应用于从数据挖掘到计算机视觉再到自然语言处理的诸多领域。作为机器学习最主要的两大类型&#xff0c;监督学习&#xff08;Super…