基于PF规则的CRPG制作尝试(十一)射箭之后箭矢回收的实现

基于PF规则的CRPG制作尝试(十一)射箭之后箭矢回收的实现

之前(第九节)进行了射箭的实现,也有说目前还有三个部分没有完成。今天我们来完成第三部分,也就是箭矢的回收。

事实上这个问题也困扰了我一段时间,最开始是打算记录箭的初始位置(在角色手上),和父级关系。然后在箭射出2秒后将箭变回记录好的位置,并恢复之前的父子关系(因为箭飞出去的时候是需要解除之前的所属关系的)。

但以上的想法是具有一定问题的,例如:箭矢的初始位置是相对于手的,由于角色一直处于微微晃动的IDLE中,想用世界坐标来记录箭矢的位置是不可能的。

在权衡利弊后,我决定使用Instantiate()函数。通过Instantiate函数复制一个箭矢gameobject。根据我的观察,通过Instantiate函数复制出来的对象的name会默认为原名称+(clone),因此我们可以使用GameObject.Find方法
来对箭进行操作。

具体步骤如下:
在攻击状态(ATTACK)时,对敌方角色点击右键,先将箭调至目前不可见的layer,然后对箭进行复制。之后播放:抽出箭——拉弓——射出动画,在抽出箭的动画中插入了一个事件(Drawarrow),在动画播放到此事件时,将复制出来的箭矢的调至可见的layer。

ActorController部分的代码:

public Animator anim;
public GameObject Weapon;
public GameObject Arrow;
public GameObject target;
public bool isshooting = false;

 void Update()
    {
            if (Input.GetMouseButtonDown(1))
            {
                //在攻击状态下进行攻击判定
                if (state == STATE.ATTACK)
                {
                    Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                    RaycastHit hit;
                    if (Physics.Raycast(ray, out hit) && hit.transform.gameObject.tag == "monster")
                    {
                        //角色方向的切换
                        ActorTrans.LookAt(hit.transform.position);
                        if (Weapon.tag == "bow" && monsterdis <= 10)
                        {
                            ChangeLayer(Arrow.transform, "Weapon");
                            //复制箭
                            Instantiate(Arrow, Arrow.transform.parent);
                            //获得目标物体
                            target = hit.transform.gameObject;             
                            anim.SetBool("attack", true);
                            GameObject.Find(Arrow.name + "(Clone)").GetComponent<ArrowData>().enabled = true;
                            int ar = Attackroll();
                            if (ar >= hit.transform.gameObject.GetComponent<MonsterData>().AC)
                            {
                                int dam = Damage();
                                print("dur攻击了" + hit.transform.name + " 攻击检定结果为" + ar + " 造成了" + dam + "点伤害");
                            }
                            else
                                print("dur攻击了" + hit.transform.name + "未破防 攻击检定结果为" + ar);
                        }
                    }
                }
            }
     }
     
      void Drawarrow()
    {
        ChangeLayer(GameObject.Find(Arrow.name + "(Clone)").transform, "Actor");
        ChangeLayer(Arrow.transform, "Weapon");
        print("Drawarrow");
        isfiring = true;
    }

      void arrowshoot()
    {
        isshooting = true;
        Invoke("arrowshootover", 2.0f);
        print("射完了");
    }
    
    void arrowshootover()
    {
        isshooting = false;
    }
    //改变layer
    void ChangeLayer(Transform trans, string targetLayer)
    {
        //遍历更改所有子物体layer
        trans.gameObject.layer = LayerMask.NameToLayer(targetLayer);
        foreach (Transform child in trans)
        {
            ChangeLayer(child, targetLayer);
        }
    }

射箭这部分也没什么值得一提的,无非是在之前的代码中加一段2秒后箭自毁的函数(Destroyarrow())。
ArrowData部分的代码如下:

public ActorController ac;
    public const float g = 9.8f;

    public GameObject target;
    public float speed = 10;
    private float verticalSpeed;
    private Vector3 moveDirection;

    private float angleSpeed;
    private float angle;
    public GameObject clone;
    private float time;
     
    void Start()
    {
        clone = GameObject.Find(ac.Arrow.name + "(Clone)");
        target = ac.target;

        float tmepDistance = Vector3.Distance(clone.transform.position, target.transform.position);
        float tempTime = tmepDistance / speed;
        float riseTime, downTime;
        riseTime = downTime = tempTime / 2;
        verticalSpeed = g * riseTime;


        float tempTan = verticalSpeed / speed;
        double hu = Math.Atan(tempTan);
        angle = (float)(180 / Math.PI * hu);
        clone.transform.eulerAngles = new Vector3(-angle, clone.transform.eulerAngles.y, clone.transform.eulerAngles.z);
        angleSpeed = angle / riseTime;

        moveDirection = target.transform.position - clone.transform.position;
    }

    void Update()
    {
        print("运行了arrowdata");
        if ((transform.name == (ac.Arrow.name + "(Clone)")) && ac.isshooting == true)
        {
            clone.GetComponent<ArrowData>().enabled = true;
            clone.transform.parent = null;
            clone.transform.LookAt(target.transform.position);
            if (clone.transform.position.y < target.transform.position.y)
            {
                //finish
                return;
            }
            time += Time.deltaTime;
            float test = verticalSpeed - g * time;
            clone.transform.Translate(moveDirection.normalized * speed * Time.deltaTime, Space.World);
            clone.transform.Translate(Vector3.up * test * Time.deltaTime, Space.World);
            float testAngle = -angle + angleSpeed * time;
            clone.transform.eulerAngles = new Vector3(testAngle, clone.transform.eulerAngles.y, clone.transform.eulerAngles.z);

            Invoke("Destroyarrow", 2.0f);
        }
    }
    void Destroyarrow()
    {
        gameObject.GetComponent<ArrowData>().enabled = false;
        Destroy(clone);
        print("destroy");
    }

以上

写一个简易 CRPG 是一项很复杂的任务,需要设计游戏世界、角色、道具、怪物等众多要素,并编写相关的代码来实现游戏逻辑。下面是一个简单的示例,只包含了一些基本的游戏元素和逻辑: ```c++ #include <iostream> #include <cstdlib> #include <ctime> using namespace std; // 定义角色结构体 struct Player { string name; int hp; int mp; int level; int exp; int gold; }; // 定义怪物结构体 struct Monster { string name; int hp; int attack; int defense; int exp; int gold; }; // 初始化角色 void initPlayer(Player& player) { player.name = "Hero"; player.hp = 100; player.mp = 50; player.level = 1; player.exp = 0; player.gold = 0; } // 显示角色状态 void showPlayer(Player& player) { cout << "Name: " << player.name << endl; cout << "Level: " << player.level << endl; cout << "HP: " << player.hp << endl; cout << "MP: " << player.mp << endl; cout << "Exp: " << player.exp << endl; cout << "Gold: " << player.gold << endl; } // 初始化怪物 void initMonster(Monster& monster) { monster.name = "Slime"; monster.hp = 50; monster.attack = 10; monster.defense = 5; monster.exp = 20; monster.gold = 10; } // 显示怪物状态 void showMonster(Monster& monster) { cout << "Name: " << monster.name << endl; cout << "HP: " << monster.hp << endl; cout << "Attack: " << monster.attack << endl; cout << "Defense: " << monster.defense << endl; cout << "Exp: " << monster.exp << endl; cout << "Gold: " << monster.gold << endl; } // 角色攻击怪物 void playerAttack(Player& player, Monster& monster) { int damage = player.level * 10 + rand() % 10 - monster.defense; if (damage < 0) damage = 0; monster.hp -= damage; cout << player.name << " deals " << damage << " damage to " << monster.name << endl; if (monster.hp <= 0) { cout << monster.name << " is defeated!" << endl; player.exp += monster.exp; player.gold += monster.gold; if (player.exp >= player.level * 100) { player.exp -= player.level * 100; player.level++; cout << player.name << " levels up!" << endl; } initMonster(monster); } } // 怪物攻击角色 void monsterAttack(Player& player, Monster& monster) { int damage = monster.attack - player.level * 2; if (damage < 0) damage = 0; player.hp -= damage; cout << monster.name << " deals " << damage << " damage to " << player.name << endl; if (player.hp <= 0) { cout << player.name << " is defeated!" << endl; exit(0); } } // 主函数 int main() { srand(time(NULL)); Player player; Monster monster; initPlayer(player); initMonster(monster); while (true) { showPlayer(player); showMonster(monster); cout << "1. Attack" << endl; cout << "2. Run away" << endl; int choice; cin >> choice; if (choice == 1) { playerAttack(player, monster); monsterAttack(player, monster); } else if (choice == 2) { cout << "You run away!" << endl; initMonster(monster); } } return 0; } ``` 这个简易 CRPG 的逻辑很简单,玩家需要与怪物战斗,获得经验和金币,提升自己的等级。玩家每次攻击怪物或者被怪物攻击时,都会有一定的随机因素,使得游戏更加有趣。这只是一个简单的示例,实际上一个完整的 CRPG 需要更加复杂的设计和实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值