陜西企業(yè)電腦網(wǎng)站制作aso安卓優(yōu)化公司
最近學(xué)習(xí)unity2D,想實(shí)現(xiàn)一個(gè)回旋鏢武器,發(fā)出后就可以在角色周圍回旋。
一、目標(biāo)
1.不是一次性的,扔出去、返回、沒有了;而是扔出去,返回到角色后方相同距離,再次返回;再次返回,永遠(yuǎn)不停止。
2.銷毀的時(shí)機(jī),是這個(gè)武器與角色再次重合的時(shí)候,相當(dāng)于回收回旋鏢;如果不回收(例如跳躍躲開),那就一直轉(zhuǎn)。
3.角色的位置會(huì)移動(dòng),回旋鏢得多次判斷下一個(gè)目標(biāo)點(diǎn)的位置。
4.回旋鏢的速度,需要從最大速度開始,到接近目標(biāo)點(diǎn)的時(shí)候逐漸減速;返回時(shí)也要從最大速度開始,到接近目標(biāo)點(diǎn)的時(shí)候減速。
總的來說,就是類似《忍者龍劍傳3》里,那個(gè)十字回旋鏢武器的效果,如果跳躍躲開,就會(huì)一直在身邊轉(zhuǎn)。
二、問題
實(shí)際寫代碼實(shí)現(xiàn)的時(shí)候,才發(fā)現(xiàn)有一堆坑。
1.回旋鏢的坐標(biāo),不能完全到達(dá)目標(biāo)點(diǎn),因?yàn)閡nity是按幀算的,每幀移動(dòng)多少速度的話,可能會(huì)超過目標(biāo)點(diǎn),或者沒有到達(dá)目標(biāo)點(diǎn),有誤差。
2.如果只以接近目標(biāo)點(diǎn)判斷的話,會(huì)丟失距離,每次回旋的距離逐漸變近,最后停留原地不動(dòng)了。
3.如果角色坐標(biāo)移動(dòng),回旋鏢計(jì)算目標(biāo)點(diǎn)并重新移動(dòng)時(shí),經(jīng)常速度變?yōu)?,卡在原地不動(dòng)(不確定哪里出bug了)。
三、代碼部分
//這部分代碼,在武器代碼cs部分float weaponRange = 3;float weaponSpeed = 15;//當(dāng)前已飛行的距離float distanceTravelled = 0f;//當(dāng)前武器位置到目標(biāo)點(diǎn)的總距離float distanceToTarget;//目標(biāo)點(diǎn)在哪邊bool targetIsRight = false;[SerializeField] Transform weaponPos;Func<Vector2> weaponPosFunc;Vector2 targetPos;Vector2 nowSpeed;Animator animator;Rigidbody2D rb2d;SpriteRenderer sprite;CircleCollider2D cc2d;void Awake(){animator = GetComponent<Animator>();cc2d = GetComponent<CircleCollider2D>();rb2d = GetComponent<Rigidbody2D>();sprite = GetComponent<SpriteRenderer>();}//發(fā)射武器方法,其他類調(diào)用public void Shoot(bool isFaceingRight) {Vector2 newTarget;//其他類傳來的,一開始武器起點(diǎn)坐標(biāo)Vector2 v = weaponPosFunc();//bool類型,武器圖片,如果角色面朝右邊就是true,就翻轉(zhuǎn)圖片,否則不翻轉(zhuǎn)sprite.flipX = isFaceingRight;//bool類型,武器的目標(biāo)點(diǎn)方向,后面會(huì)用targetIsRight = isFaceingRight;//賦值,剛開始武器到目標(biāo)點(diǎn)的距離distanceToTarget = Vector2.Distance(weaponPos.position, targetPos);//首次武器目標(biāo)點(diǎn),直線,看是角色面前還是背后//targetPos就是武器目標(biāo)點(diǎn)if (!isFaceingRight) { newTarget = new Vector2(v.x - weaponRange, v.y);targetPos = newTarget;}else{newTarget = new Vector2(v.x + weaponRange, v.y);targetPos = newTarget;}}//更新方法,系統(tǒng)會(huì)每幀調(diào)用void Update(){// 向目標(biāo)位置飛行,并逐步減速,到達(dá)目標(biāo)點(diǎn)要掉頭,反復(fù)重復(fù)MoveTowardsTarget();}void MoveTowardsTarget(){//已經(jīng)走過的距離/物體到目標(biāo)的距離float dPercent = distanceTravelled / distanceToTarget;if(dPercent < 0){dPercent = -dPercent;}if(dPercent > 1){dPercent = 1;}// 計(jì)算當(dāng)前的速度因子,使物體從快到慢;weaponSpeed是初始武器速度//Lerp方法,就是dPercent為0時(shí),返回第一個(gè)參數(shù);為1時(shí)返回第二個(gè)參數(shù);0-1之間時(shí)就返回第一個(gè)參數(shù)到第二個(gè)參數(shù)之間的值float speedFactor = Mathf.Lerp(weaponSpeed, 0f, dPercent);//確定一個(gè)最慢速度,否則速度因子接近0,越來越慢,很難到目標(biāo)if(speedFactor < 2f){speedFactor = 2f;}// 計(jì)算朝目標(biāo)位置的方向,方向向量Vector2 direction = (targetPos - (Vector2)weaponPos.position).normalized;//如果方向向量變?yōu)?,就沒辦法移動(dòng)了,此時(shí)要指定一個(gè)默認(rèn)方向向量if(direction.x == 0 && direction.y == 0){//如果目標(biāo)點(diǎn)在右邊,方向向量就是右邊;否則左邊if (targetIsRight){direction = new Vector2(1,0);}else{direction = new Vector2(-1, 0);}}//設(shè)置物體的速度,方向向量*速度因子//設(shè)置了這個(gè),武器就會(huì)開始移動(dòng)rb2d.velocity = direction*speedFactor;//保存當(dāng)前速度,后續(xù)可能用nowSpeed = direction * speedFactor;// 更新已飛行的距離,剛開始是0;每一幀移動(dòng)速度*每一幀時(shí)間=路程,然后累加distanceTravelled += rb2d.velocity.magnitude * Time.deltaTime;//打印日志,武器到目標(biāo)點(diǎn)的距離//Debug.Log("distanceToTarget"+ distanceToTarget);// 如果 (超過目標(biāo)點(diǎn) 或者 接近目標(biāo)點(diǎn)) 并且 至少走夠了武器路程//需要分左右,才能知道是沒到目標(biāo)點(diǎn)還是超過目標(biāo)點(diǎn),需要超過目標(biāo)點(diǎn);是否超過目標(biāo)點(diǎn)就先用x判斷了;y又復(fù)雜了,還得分上下//防止沒到目標(biāo)點(diǎn)就卡住,又加了接近目標(biāo)點(diǎn)if (targetIsRight){if ( ((targetPos.x <= weaponPos.position.x) || distanceToTarget<=0.1) && distanceTravelled >= weaponRange){//重置目標(biāo)點(diǎn)FreshTargetPos();}}else{if ( ((targetPos.x >= weaponPos.position.x) || distanceToTarget<=0.1) && distanceTravelled >= weaponRange){//重置目標(biāo)點(diǎn)FreshTargetPos();}}}void FreshTargetPos() {//玩家當(dāng)前坐標(biāo),實(shí)時(shí)獲取(玩家的武器發(fā)射點(diǎn)的坐標(biāo))Vector2 p = weaponPosFunc();//武器當(dāng)前坐標(biāo)Vector2 w = weaponPos.position;//w點(diǎn)關(guān)于p點(diǎn)的對(duì)稱點(diǎn)//targetPos = new Vector2( 2*p.x -w.x , 2*p.y -w.y );// 計(jì)算朝目標(biāo)位置的方向,方向向量,擴(kuò)大武器范圍倍數(shù)Vector2 direction = (p - (Vector2)w).normalized * weaponRange;//算出下一個(gè)目標(biāo)點(diǎn)targetPos = new Vector2(direction.x+p.x, direction.y+p.y);//看目標(biāo)點(diǎn)到底在哪里,然后判斷有沒有超過目標(biāo)點(diǎn)if (targetPos.x > weaponPos.position.x){targetIsRight = true;}else{targetIsRight = false;}//已走過的路程歸零distanceTravelled = 0;// 重新計(jì)算物體到目標(biāo)的距離,weaponPos是當(dāng)前武器坐標(biāo),targetPos是目標(biāo)點(diǎn)坐標(biāo);得到的是距離distanceToTarget = Vector2.Distance(weaponPos.position, targetPos);}
四、備注
unity代碼比較多,就貼重要部分了,關(guān)于坐標(biāo)的計(jì)算;
目前代碼就是這個(gè)版本了,大概實(shí)現(xiàn)了需求;
武器當(dāng)前速度處理還可能有些問題,但是可以在玩家周圍回旋了;
如果玩家靜止或者直線移動(dòng),武器就在x軸上回旋;
如果玩家跳躍,武器就會(huì)斜方向回旋到玩家背后;
感覺情況有些復(fù)雜,可能哪里還有bug,歡迎留言指正。
五、效果圖片
如圖,可以在角色周圍水平回旋,斜方向也可以。