前言
说是基于unity的2D横版游戏,实际上只是一个初学unity与C#新人的练手Demo,目前还处于半成状态。美术资源方面全部出自unity免费资源,经过自己的小修,大致拼出了一个游戏。代码方面,仅仅初识C#语法,此前从未接触过面向对象编程的我,显然写出来的东西显然不堪入目,问题包括但不限于:1.未遵守命名规范。2.未领会面向对象编程的思想,代码复用随处可见。3.代码思路及其不清晰,动画状态转换判断一半靠动画机参数,一半靠代码里的if else(再三确认.jpg)。4.总体架构没想好,想到哪写哪,beAttackBox满足不了要求写个beAttackBoxOfEnemy,还不行就beAttackBoxOfBoss,看架势如果写完整个游戏,要写上千个脚本。5.维护性极差,脚本功能纵横交错,出了问题现在的我能解决,过一个月就只有上帝能解决了。
总而言之,这段小结仅出于记录自己黑历史的目的,冒着荣登知乎“你见过最烂的代码是怎样的”这一问题榜首的风险发布,不敢劳烦各位大佬斧正,只希望大伙就看个乐呵,尽量不要进行人身攻击,以下是展示部分。
分割线
游戏展示
由于还有有关游戏导出分辨率的问题尚未解决,展示仅在编译器中进行。
1.近战敌人演示
2.远程敌人演示
3.boss战(自己写的boss都能过不了?)
部分代码展示
boss1AI
//bossAI形式不同于小怪enemyAI,不具有普适性。
//boss1行动模式用自然语言描述如下:
//在场景中,boss一直处于战斗状态,以若干秒为一个周期,根据所设计的概率随机选择一个符合条件(与玩家的距离、自身血量所决定的阶段、技能冷却情况)的
//行动(发动某攻击,接近玩家,远离玩家),在完成行动后,进入后摇时间,后摇结束后进入下一周期,在受击动画完成后若干秒,立刻进入下一个周期。
//行动并不仅限于一个动画,可以考虑两个动画进行组合以实现连招。boss子物体包含若干个范围盒,按由外到内的顺序排列,每进入一个范围盒,可随机选择的动作增加。
//由外到内,增加的可选择动作为:
//1.接近玩家。
//2.远离玩家、发动技能跳斩attack5(仅在该范围盒)、发动技能突刺attack2(二阶段新增技能旋转攻击attack4,隐身突袭attack3)。
//3.普通攻击attack1、击退踢腿attack6(后接突刺或跳斩)。
//具体数值见boss1Const
/*其余说明:1.boss面向改变不属于行动,于等待阶段进行。
* 2.当血量低于50时,进入二阶段,立即进行三次隐身突袭attack3,并减少单个周期的时间以实现行动后摇减少,加速敌人攻击。
* 3.一定时间内受击超过一定次数时,boss会踢腿击退接突刺或跳斩的连招
*
*
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class boss1AI : MonoBehaviour
{
static public float HP;
public enum BossState { range1, range2, range3 };//
public BossState bossState = BossState.range1;
public AnimationCurve jump;
public AudioSource attack2;
private Animator ani;
private SpriteRenderer spr;
private Rigidbody2D rid;
private GameObject player;
private bool isIdle;
private float animationLength;
private int[] moving=new int[10000];//用于记录boss行动的数组
private int i = 0;
private float waitingTime = 0;//后摇计时器
private float movingTime = 0;//行动计时器
private float attack3CD = 0;//特殊技能attack3计时器
private int movingNumble = 0;//随机数,用于决定boss的下一步行动
private int attack3Times = 3;//attack3技能单词释放次数
private float jumpTime=0;
// Start is called before the first frame update
void Start()
{
ani = gameObject.GetComponent<Animator>();
spr = gameObject.GetComponent<SpriteRenderer>();
rid = gameObject.GetComponent<Rigidbody2D>();
player = GameObject.FindGameObjectWithTag("Player");
//判断动画状态机播放的动画是否为Idle
//引用组件
HP = boss1Const.maxHP;
}
// Update is called once per frame
private void FixedUpdate()
{
animationLength = ani.GetCurrentAnimatorStateInfo(0).length;//获取当前播放动画长度
if (waitingTime >= boss1Const.waitingTime)
{
if (ani.GetBool("isIdle") == true)
{
roll:
switch (bossState)
{
case BossState.range1:
movingNumble = Random.Range(0, 15);//生成一个0到14之间的随机数(包含),数字大小决定了移动距离
break;
case BossState.range2:
movingNumble = Random.Range(0, 60);//生成一个0到59之间的随机数(包含)15~34为跳斩,35-59为突刺,进入2阶段后,单数正常判定,双数为旋转攻击,隐身突袭为特殊技能,进入2阶段每5个循环释放一次
break;
case BossState.range3:
movingNumble = Random.Range(35, 120);//生成一个0到119之间的随机数(包含)60~104为普攻,105~119为击退接突刺(或跳斩)
break;
}
//处于待机状态且不处于后摇时间中时,roll点决定boss下一步行动
if (attack3CD <= 0 && (ani.GetInteger("attackingNumber") == 0 || ani.GetInteger("attackingNumber") == 3) && HP <= 0.5 * boss1Const.maxHP)
{
moving[++i] = 3;
}
else if (movingNumble >= 0 && movingNumble < 15)//接近玩家
{
moving[++i] = 0;
}
else if (movingNumble >= 15 && movingNumble < 35)
{
if (HP <= boss1Const.maxHP * 0.5 && movingNumble % 2 == 0)//旋转攻击(二阶段时)
{
moving[++i] = 4;
}
else//跳斩
{
moving[++i] = 5;
}
}
else if (movingNumble >= 35 && movingNumble < 60)
{
if (HP <= boss1Const.maxHP * 0.5 && movingNumble % 2 == 0)//旋转攻击(二阶段时)
{
moving[++i] = 4;
}
else//突刺
{
moving[++i] = 2;
}
}
else if (movingNumble >= 60 && movingNumble < 105)//普通攻击
{
moving[++i] = 1;
}
else if (movingNumble >= 105 && movingNumble <= 120)
{
moving[++i] = 6;
}
//根据movingNumble确定下一步行动
if(moving[i-1]==6)
{
if(i%2==0)
{
moving[i] = 2;
}
else
{
moving[i] = 5;
}
}
//查看上一步行动,若为踢腿,则根据随机数指定下一步行动为突刺或跳斩
if (i >= 2)
{
if (moving[i] == moving[i - 1] && moving[i] == moving[i - 2] && moving[i] != 3)
{
i--;
goto roll;
}
}
//查看即将进行的行动,若重复两次以上,重新roll点决定行动
}
if (HP <= 0.5 * boss1Const.maxHP)
{
attack3CD -= Time.deltaTime;
}
//特殊技能冷却时间改变
switch(moving[i])
{
case 0:
doWalk(movingNumble);
break;
case 1:
doAttack1();
break;
case 2:
doAttack2();
break;
case 3:
doAttack3();
break;
case 4:
doAttack4();
break;
case 5:
doAttack5();
break;
case 6:
doAttack6();
break;
}
}
else if(HP>0)
{
doWait();
}
else
{
doDestroy();
}
//
}
void doWait()
{
waitingTime += Time.fixedDeltaTime;
//累加后摇计时器
doChangeFacing();
//旋转面向
}
void doWalk(float velocity)
{
ani.SetBool("isIdle", false);
ani.SetBool("isWalking", true);
movingTime += Time.fixedDeltaTime;
if (movingTime > animationLength)
{
waitingTime = boss1Const.waitingTime-boss1Const.waitingTimeAfterWalk;
movingTime = 0;
ani.SetBool("isWalking", false);
ani.SetBool("isIdle", true);
}
transform.Translate(Vector2.right * Time.fixedDeltaTime * (velocity / 60 + 0.25f) * boss1Const.walkSpeed, Space.Self);
//接近玩家一段距离
}
void doAttack1()
{
ani.SetBool("isIdle", false);
ani.SetInteger("attackingNumber", 1);
movingTime += Time.fixedDeltaTime;
if (spr.sprite.name == "attack-A5" || spr.sprite.name == "attack-A6" || spr.sprite.name == "attack-A7")
{
doMove(1.5f);
}
//根据动画播放进度进行相匹配的位移
if (movingTime > animationLength)
{
waitingTime = boss1Const.waitingTime - boss1Const.waitingTimeAfterAttack1;
movingTime = 0;
ani.SetInteger("attackingNumber", 0);
ani.SetBool("isIdle", true);
}
}
//普攻
void doAttack2()
{
ani.SetBool("isIdle", false);
ani.SetInteger("attackingNumber", 2);
movingTime += Time.fixedDeltaTime;
if(spr.sprite.name=="attack-B4"&& attack2.isPlaying == false)
{
attack2.Play();
}
if(spr.sprite.name=="attack-B3")
{
doChangeFacing();
}
if (spr.sprite.name == "attack-B4"||spr.sprite.name=="attack-B5" )
{
doMove(4f);
}
//根据动画播放进度进行相匹配的位移
if (movingTime > animationLength)
{
waitingTime = boss1Const.waitingTime - boss1Const.waitingTimeAfterAttack2;
movingTime = 0;
ani.SetInteger("attackingNumber", 0);
ani.SetBool("isIdle", true);
}
}
//突刺
void doAttack3()
{
ani.SetInteger("attackingNumber", 3);
ani.SetBool("isIdle", false);
ani.SetBool("isWalking", false);
movingTime += Time.fixedDeltaTime;
if (spr.sprite.name == "attack-C1")
{
spr.color = Color.Lerp(new Color(1, 1, 1, 1), new Color(1, 1, 1, 0), movingTime / animationLength * 3f);
}
else if(spr.sprite.name!="attack-C1"&&spr.sprite.name!="attack-C2")
{
spr.color = Color.Lerp(new Color(1, 1, 1, 0), new Color(1, 1, 1, 1), (movingTime - 0.5f * animationLength) * 3f);
}
//实现隐身效果
if (spr.sprite.name=="attack-C2")
{
doFlash(player.transform.position - (Vector3.right + Random.Range(-1, 1) * Vector3.right*2) * 0.5f + Vector3.up * 0.5f);
doChangeFacing();
//随机瞬移至玩家身边并调整面向
}
if(spr.sprite.name=="attack-C7"||spr.sprite.name=="attack-C8")
{
doJump(boss1Const.jumpHeight*0.5f);
}
if (movingTime > animationLength)
{
if(attack3Times>1)
{
attack3Times--;
movingTime = 0;
waitingTime = boss1Const.waitingTime - boss1Const.waitingTimeAfterAttack3;
ani.SetInteger("attackingNumber", 0);
ani.SetBool("isIdle", true);
}
else
{
attack3Times = 3;
movingTime = 0;
waitingTime = boss1Const.waitingTime - boss1Const.waitingTimeAfterAttack3;
attack3CD = boss1Const.attack3CD;
ani.SetInteger("attackingNumber", 0);
ani.SetBool("isIdle", true);
}
}
}
//隐身突袭
void doAttack4()
{
ani.SetInteger("attackingNumber", 4);
ani.SetBool("isIdle", false);
movingTime += Time.fixedDeltaTime;
if(spr.sprite.name!="attack-D1"&&spr.sprite.name!="attack-D2"&&spr.sprite.name!="attack-D12"&&spr.sprite.name!="attack-D7")
{
doMove(4f);
}
if(spr.sprite.name=="attack-D7")
{
doChangeFacing();
}
if (movingTime > animationLength)
{
waitingTime = boss1Const.waitingTime - boss1Const.waitingTimeAfterAttack4;
movingTime = 0;
ani.SetInteger("attackingNumber", 0);
ani.SetBool("isIdle", true);
}
}
//旋转攻击
void doAttack5()
{
ani.SetInteger("attackingNumber", 5);
ani.SetBool("isIdle", false);
movingTime += Time.fixedDeltaTime;
if(spr.sprite.name == "jump-attack-1" || spr.sprite.name== "jump-attack-2"||spr.sprite.name== "jump-attack-3")
{
doJump(boss1Const.jumpHeight);
}
if (spr.sprite.name != "jump-attack-8")
{
doMove(Random.Range(2.5f, 2.8f));
}
//根据动画播放进度进行相匹配的位移
if (movingTime > animationLength)
{
waitingTime = boss1Const.waitingTime - boss1Const.waitingTimeAfterAttack5;
movingTime = 0;
ani.SetInteger("attackingNumber", 0);
ani.SetBool("isIdle", true);
}
}
//跳斩
void doAttack6()
{
ani.SetInteger("attackingNumber", 6);
ani.SetBool("isIdle", false);
movingTime += Time.fixedDeltaTime;
if (spr.sprite.name == "kick-3" || spr.sprite.name == "kick-4")
{
doMove(4f);
}
if (movingTime >= animationLength)
{
movingTime = 0;
waitingTime = boss1Const.waitingTime - boss1Const.waitingTimeAfterAttack6;
ani.SetInteger("attackingNumber", 0);
ani.SetBool("isIdle", true);
}
}
//踢腿
void doMove(float velocity)
{
transform.Translate(Vector2.right * Time.fixedDeltaTime*velocity , Space.Self);
}
//位移
void doChangeFacing()
{
if (player.transform.position.x <= transform.position.x)
{
transform.rotation = Quaternion.Euler(0, 180, 0);
}
else
{
transform.rotation = Quaternion.Euler(0, 0, 0);
}
}
//改变面向
void doJump(float jumpHeight)
{
jumpTime += Time.fixedDeltaTime;
transform.Translate(new Vector3(0, jump.Evaluate(jumpTime) - jump.Evaluate(jumpTime - Time.fixedDeltaTime)) * jumpHeight, Space.World);
if(jumpTime>=0.5f)
{
jumpTime = 0;
}
}
//跳跃
void doFlash(Vector3 Position)
{
transform.position = Position;
}
//闪烁
void doDestroy()
{
ani.SetBool("isDead", true);
movingTime += Time.deltaTime;
if (movingTime >= animationLength)
{
StartCoroutine(reStart());
}
}
IEnumerator reStart()
{
yield return new WaitForSecondsRealtime(3.0f);
SceneManager.LoadScene("title");
}
}
enemy1AI
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class enemy1AI : MonoBehaviour
{
private Animator ani;
private SpriteRenderer spr;
private Rigidbody2D rid;
private GameObject attackBox;
private GameObject beAttackBox;
private GameObject isGroundBox;
private BoxCollider2D attackBoxCollider;
private GameObject player;
private enemyState enemyState;
private enemyConst enemyConst;
//组件引用
//状态
private float attackTime = 0;
private float wanderTime = 0;
private float readyAttackTime = 0;
private float velocity = 0;
private float waitingTime= 0;
private float hitTime = 0;
//计时器
// Start is called before the first frame update
void Start()
{
ani = gameObject.GetComponent<Animator>();
spr = gameObject.GetComponent<SpriteRenderer>();
rid = gameObject.GetComponent<Rigidbody2D>();
enemyConst = GetComponent<enemyConst>();
player = GameObject.FindGameObjectWithTag("Player");
//读取组件
for (int i = 0; i < transform.childCount; i++)
{
switch (transform.GetChild(i).name)
{
case "attackBox":
attackBox = transform.GetChild(i).gameObject;
break;
case "beAttackBox":
beAttackBox = transform.GetChild(i).gameObject;
break;
case "isGroundBox":
isGroundBox = transform.GetChild(i).gameObject;
break;
}
}
//读取子物体
attackBoxCollider = attackBox.GetComponent<BoxCollider2D>();
//读取子物体组件
enemyState = GetComponent<enemyState>();
}
// Update is called once per frame
private void FixedUpdate()
{
if(ani.GetBool("isDead")==false)
{
setGrativy();
//根据敌人状态设置重力
doWander();
//警戒范围内无玩家时进行巡逻
doChase();
//玩家进入警戒范围后进行追击,并在脱离追击范围前持续追击
doAttack();
//玩家进入攻击范围内进行攻击
doBeHit();
//受击时播放受击动画
}
doDestroy();
//死亡时播放死亡动画
}
void Update()
{
ani.SetFloat("attackSpeed", enemyConst.attackSpeed);
}
void doMove(float velocity,float speed)
{
if (velocity > 0)
{
transform.rotation = Quaternion.Euler(0, 0, 0);
}
else if (velocity < 0)
{
transform.rotation = Quaternion.Euler(0, 180, 0);
}
//判断是否需要旋转enemy1
ani.SetFloat("velocity", velocity);
transform.Translate(Vector2.right * Time.fixedDeltaTime * velocity * speed, Space.World);
//左右移动enemy1
}
//移动enemy1
void doWander()
{
if (enemyState.state == enemyState.State.wander && ani.GetBool("isBeingHit") == false)
{
waitingTime = 0;
float velocity = 0;
wanderTime += Time.fixedDeltaTime;
if (wanderTime <= 0.25 * enemyConst.wanderLength)
{
velocity = 1;
}
else if (wanderTime >= 0.25 * enemyConst.wanderLength && wanderTime <= enemyConst.wanderLength * 0.5)
{
velocity = 0;
}
else if (wanderTime >= 0.5 * enemyConst.wanderLength && wanderTime <= enemyConst.wanderLength * 0.75)
{
velocity = -1;
}
else if (wanderTime >= 0.75 * enemyConst.wanderLength && wanderTime <= enemyConst.wanderLength)
{
velocity = 0;
}
else
{
wanderTime = 0;
}
//根据计时器设定velocity方向以实现巡逻,单次巡逻时长为enemy1Const.wanderLength,巡逻模式为右走-停止-左走-停止
doMove(velocity,enemyConst.walkSpeed);
//移动enemy1
}
}
void doChase()
{
if (enemyState.state == enemyState.State.chase && ani.GetBool("isAttacking1") == false && ani.GetBool("isAttacking2") == false && ani.GetBool("isBeingHit") == false)
{
ani.SetFloat("velocity", 0);
waitingTime += Time.fixedDeltaTime;
if (waitingTime >= enemyConst.baseChangeTime)
{
if (transform.position.x - player.transform.position.x >= 0)
{
velocity = -1;
}
else if (player.transform.position.x - transform.position.x >= 0)
{
velocity = 1;
}
doMove(velocity, enemyConst.chaseSpeed);
}
}
}
void doAttack()
{
readyAttackTime += Time.fixedDeltaTime;
if (enemyState.state == enemyState.State.attack || ani.GetBool("isAttacking1") == true || ani.GetBool("isAttacking2") == true) //确保攻击动画播放完毕
{
if (ani.GetBool("isGrounded") == true && ani.GetBool("isBeingHit") == false && ani.GetBool("isAttacking1") == false && ani.GetBool("isAttacking2") == false && enemyState.state == enemyState.State.attack && readyAttackTime >= enemyConst.baseAttackTime)
{
attackTime = 0;
ani.SetFloat("velocity", 0);//站定进行攻击
if (Random.Range(1,3)==1)
{
ani.SetBool("isAttacking1", true);
}
else
{
ani.SetBool("isAttacking2", true);
}
}
//随机发起一种形式的新攻击
if (ani.GetBool("isAttacking1") == true)
{
attackTime += Time.fixedDeltaTime;
if (attackTime >= 1 / enemyConst.attackSpeed * enemyConst.attackAnimation1Length)
{
ani.SetBool("isAttacking1", false);
waitingTime = 0;
readyAttackTime = 0;
}
}
else if(ani.GetBool("isAttacking2")==true)
{
attackTime += Time.fixedDeltaTime;
if (attackTime >= 1 / enemyConst.attackSpeed * enemyConst.attackAnimation2Length)
{
ani.SetBool("isAttacking2", false);
waitingTime = 0;
readyAttackTime = 0;
}
}
//攻击计时,以转化动画状态
}
}
void doBeHit()
{
if (ani.GetBool("isBeingHit") == true)
{
hitTime += Time.fixedDeltaTime;
if (hitTime >= enemyConst.hitAnimationLength)
{
hitTime = 0;
ani.SetBool("isBeingHit", false);
}
}
}
void doDestroy()
{
if(enemyState.HP<=0)
{
ani.SetBool("isDead", true);
Destroy(gameObject, enemyConst.deadAnimationLength);
}
}
private void setGrativy()
{
if (ani.GetBool("isBeingHit") == true)
{
rid.gravityScale = 0;
}
else
{
rid.gravityScale = 10;
}
//受击状态下重力设置为0以实现受击时的僵直;
}
}
enemy2AI
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class enemy2AI : MonoBehaviour
{
public GameObject arrow;
private Animator ani;
private SpriteRenderer spr;
private Rigidbody2D rid;
private GameObject attackBox;
private GameObject beAttackBox;
private GameObject isGroundBox;
private BoxCollider2D attackBoxCollider;
private GameObject player;
private enemyState enemyState;
private enemyConst enemyConst;
private GameObject shootPoint;
private GameObject shootPoint2;
//组件引用
//状态
private float attackTime = 0;
private float wanderTime = 0;
private float readyAttackTime = 0;
private float velocity = 0;
private float waitingTime = 0;
private float hitTime = 0;
private bool havingInstantiateArrow = false;
//计时器
// Start is called before the first frame update
void Start()
{
ani = gameObject.GetComponent<Animator>();
spr = gameObject.GetComponent<SpriteRenderer>();
rid = gameObject.GetComponent<Rigidbody2D>();
enemyConst = GetComponent<enemyConst>();
player = GameObject.FindGameObjectWithTag("Player");
//读取组件
for (int i = 0; i < transform.childCount; i++)
{
switch (transform.GetChild(i).name)
{
case "attackBox":
attackBox = transform.GetChild(i).gameObject;
break;
case "beAttackBox":
beAttackBox = transform.GetChild(i).gameObject;
break;
case "isGroundBox":
isGroundBox = transform.GetChild(i).gameObject;
break;
case "shootPoint":
shootPoint = transform.GetChild(i).gameObject;
break;
case "shootPoint2":
shootPoint2 = transform.GetChild(i).gameObject;
break;
}
}
//读取子物体
attackBoxCollider = attackBox.GetComponent<BoxCollider2D>();
//读取子物体组件
enemyState = GetComponent<enemyState>();
}
// Update is called once per frame
private void FixedUpdate()
{
if (ani.GetBool("isDead") == false)
{
setGrativy();
//根据敌人状态设置重力
doWander();
//警戒范围内无玩家时进行巡逻
doChase();
//玩家进入警戒范围后进行追击,并在脱离追击范围前持续追击
doAttack();
//玩家进入攻击范围内进行攻击
doBeHit();
//受击时播放受击动画
}
doDestroy();
//死亡时播放死亡动画
}
void Update()
{
ani.SetFloat("attackSpeed", enemyConst.attackSpeed);
}
void doMove(float velocity, float speed)
{
if (velocity > 0)
{
transform.rotation = Quaternion.Euler(0, 0, 0);
}
else if (velocity < 0)
{
transform.rotation = Quaternion.Euler(0, 180, 0);
}
//判断是否需要旋转enemy1
ani.SetFloat("velocity", velocity);
transform.Translate(Vector2.right * Time.fixedDeltaTime * velocity * speed, Space.World);
//左右移动enemy1
}
//移动enemy1
void doWander()
{
if (enemyState.state == enemyState.State.wander && ani.GetBool("isBeingHit") == false)
{
waitingTime = 0;
float velocity = 0;
wanderTime += Time.fixedDeltaTime;
if (wanderTime <= 0.25 * enemyConst.wanderLength)
{
velocity = 1;
}
else if (wanderTime >= 0.25 * enemyConst.wanderLength && wanderTime <= enemyConst.wanderLength * 0.5)
{
velocity = 0;
}
else if (wanderTime >= 0.5 * enemyConst.wanderLength && wanderTime <= enemyConst.wanderLength * 0.75)
{
velocity = -1;
}
else if (wanderTime >= 0.75 * enemyConst.wanderLength && wanderTime <= enemyConst.wanderLength)
{
velocity = 0;
}
else
{
wanderTime = 0;
}
//根据计时器设定velocity方向以实现巡逻,单次巡逻时长为enemy1Const.wanderLength,巡逻模式为右走-停止-左走-停止
doMove(velocity, enemyConst.walkSpeed);
//移动enemy1
}
}
void doChase()
{
if (enemyState.state == enemyState.State.chase && ani.GetBool("isAttacking1") == false && ani.GetBool("isAttacking2") == false && ani.GetBool("isBeingHit") == false)
{
ani.SetFloat("velocity", 0);
waitingTime += Time.fixedDeltaTime;
if (waitingTime >= enemyConst.baseChangeTime)
{
if (transform.position.x - player.transform.position.x >= 0)
{
velocity = -1;
}
else if (player.transform.position.x - transform.position.x >= 0)
{
velocity = 1;
}
doMove(velocity, enemyConst.chaseSpeed);
}
}
}
void doAttack()
{
readyAttackTime += Time.fixedDeltaTime;
if (enemyState.state == enemyState.State.attack || ani.GetBool("isAttacking1") == true || ani.GetBool("isAttacking2") == true) //确保攻击动画播放完毕
{
if (ani.GetBool("isGrounded") == true && ani.GetBool("isBeingHit") == false && ani.GetBool("isAttacking1") == false && ani.GetBool("isAttacking2") == false && enemyState.state == enemyState.State.attack && readyAttackTime >= enemyConst.baseAttackTime)
{
attackTime = 0;
ani.SetFloat("velocity", 0);//站定进行攻击
if (player.transform.position.y + 1 >= transform.position.y) //判断是否需要向下射箭
{
ani.SetBool("isAttacking1", true);
}
else
{
ani.SetBool("isAttacking2", true);
}
}
//根据玩家位置发动攻击
if (ani.GetBool("isAttacking1") == true)
{
attackTime += Time.fixedDeltaTime;
if (spr.sprite.name == "attack-A4"&&havingInstantiateArrow==false)
{
havingInstantiateArrow = true;
Instantiate(arrow, shootPoint.transform.position, transform.rotation);
}
//生成水平的箭
if (attackTime >= 1 / enemyConst.attackSpeed * enemyConst.attackAnimation1Length)
{
ani.SetBool("isAttacking1", false);
havingInstantiateArrow = false;
waitingTime = 0;
readyAttackTime = 0;
}
//结束动画
}
else if (ani.GetBool("isAttacking2") == true)
{
attackTime += Time.fixedDeltaTime;
if (spr.sprite.name == "attack-B4" && havingInstantiateArrow == false)
{
havingInstantiateArrow = true;
Instantiate(arrow, shootPoint2.transform.position, Quaternion.Euler(0, transform.rotation.y*180, 315));
}
//生成斜向下的箭
if (attackTime >= 1 / enemyConst.attackSpeed * enemyConst.attackAnimation2Length)
{
ani.SetBool("isAttacking2", false);
havingInstantiateArrow = false;
waitingTime = 0;
readyAttackTime = 0;
}
//结束动画
}
//攻击计时,以转化动画状态
}
}
void doBeHit()
{
if (ani.GetBool("isBeingHit") == true)
{
hitTime += Time.fixedDeltaTime;
if (hitTime >= enemyConst.hitAnimationLength)
{
hitTime = 0;
ani.SetBool("isBeingHit", false);
}
}
}
void doDestroy()
{
if (enemyState.HP <= 0)
{
ani.SetBool("isDead", true);
Destroy(gameObject, enemyConst.deadAnimationLength);
}
}
private void setGrativy()
{
if (ani.GetBool("isBeingHit") == true)
{
rid.gravityScale = 0;
}
else
{
rid.gravityScale = 10;
}
//受击状态下重力设置为0以实现受击时的僵直;
}
}
总结
历经二十天的努力,我的第一款游戏demo的制作算是告一段落了,尽管还有数不清的不足之处,但是起码是一个可以运行的游戏了。我不敢说自己已经尽全力去把它做到最好了,不过我想下一次,我会做的更好。