脚本触发方式分为Touch和Click,上一节实现了Touch,接下来实现Click。由于本游戏使用的是鼠标/手指来操纵人物,不存在什么虚拟摇杆,因此如果想要实现Click的话,就需要点击NPC,之后角色根据A星算法得到的路径行走,在NPC面前停下,然后对应NPC调用execute(),来调用对应的脚本。不过我们发现,目前的碰撞检测中是不包含NPC在内的,即无论NPC是否是PRIORITY_SAME,角色都会从NPC身上穿过,这显然不合理。因此,需要修改isPassing函数,来让它判断在一定范围内是否存在优先级为PRIORITY_SAME的NPC。

bool GameScene::isPassing(const Point& tilePos)
{auto tiledMap = m_pMapLayer->getTiledMap();auto mapSize = tiledMap->getMapSize();//不可超出地图if (tilePos.x < 0 || tilePos.x > (mapSize.width - 1)|| tilePos.y > (mapSize.height - 1) || tilePos.y < 0){return false;}auto layer = m_pMapLayer->getCollisionLayer();auto gid = layer->getTileGIDAt(tilePos);    bool ret = m_pMapLayer->isPassing(gid);//可通过则检查是否存在NPCif (ret){auto tileSize = tiledMap->getTileSize();//获取矩形Rect r;r.origin = Point(tileSize.width * (tilePos.x + 0.5f), tileSize.height * (tilePos.y + 0.5f));r.size = Size(1.f, 1.f);auto npc = m_pScriptLayer->getClickedNPC(r, PRIORITY_SAME);ret = ( npc == nullptr ? true : false);}
return ret;
}    bool ret = m_pMapLayer->isPassing(gid);//可通过则检查是否存在NPCif (ret){auto tileSize = tiledMap->getTileSize();//获取矩形Rect r;r.origin = Point(tileSize.width * (tilePos.x + 0.5f), tileSize.height * (tilePos.y + 0.5f));r.size = Size(1.f, 1.f);auto npc = m_pScriptLayer->getClickedNPC(r, PRIORITY_SAME);ret = ( npc == nullptr ? true : false);}
return ret;
}

isPassing函数额外添加了一个判断,在对应图块可通过的情况下,会对当前的矩形来判断是否存在NPC,如果存在,则表示不可穿过。

NonPlayerCharacter* ScriptLayer::getClickedNPC(const Rect& r, int priority)
{NonPlayerCharacter* npc = nullptr;auto it = find_if(m_npcList.begin(), m_npcList.end(), [&r, &priority](NonPlayerCharacter* npc){return npc->getPriority() == priority && npc->intersectRect(r);});if (it != m_npcList.end())npc = *it;return npc;
}

getClickedNPC()函数返回优先级相同并且矩阵发生碰撞的NPC,如果没有则返回nullptr。

接下来运行程序会发现,当直接点击优先级为PRIORITY_SAME的NPC时,人物没有动作。原因是GameScene::onTouchBegan()函数中检测到目的点不可通过,而应该认为该点可通过(前面的A星算法中默认目的点可到达就是为了当前这种情况)。

bool GameScene::onTouchBegan(Touch* touch,SDL_Event* event)
{auto location = touch->getLocation();auto tiledMap = m_pMapLayer->getTiledMap();auto nodePos = tiledMap->convertToNodeSpace(location);auto tilePos = m_pMapLayer->convertToTileCoordinate(nodePos);auto player = m_pPlayerLayer->getPlayer();(!this->isPassing(tilePos))//目标不可达return false;//主角运动player->moveToward(tilePos);return true;
}

接下来就应该修改onTouchBegan();先判断目的点是否有NPC,如果有,则认为可通过(不清楚是否能到达),直接调用主角的moveToward()函数即可。

bool GameScene::onTouchBegan(Touch* touch,SDL_Event* event)
{auto location = touch->getLocation();auto tiledMap = m_pMapLayer->getTiledMap();auto nodePos = tiledMap->convertToNodeSpace(location);auto tilePos = m_pMapLayer->convertToTileCoordinate(nodePos);auto player = m_pPlayerLayer->getPlayer();
    //是否点击了相同优先级的NPCauto npc = m_pScriptLayer->getClickedNPC(Rect(nodePos, Size(1.f, 1.f)), PRIORITY_SAME);player->setTriggerNPC(npc);//TODOif (npc != nullptr);else if (!this->isPassing(tilePos))//目标不可达return false;//主角运动player->moveToward(tilePos);//显示点击特效auto collisionLayer = m_pMapLayer->getCollisionLayer();auto tileSize = tiledMap->getTileSize();Point pos((tilePos.x + 0.5f) * tileSize.width, (tilePos.y + 0.3f) * tileSize.height);m_pEffectLayer->showAnimationEffect("click_path", pos, collisionLayer);return true;
}    //是否点击了相同优先级的NPCauto npc = m_pScriptLayer->getClickedNPC(Rect(nodePos, Size(1.f, 1.f)), PRIORITY_SAME);player->setTriggerNPC(npc);//TODOif (npc != nullptr);else if (!this->isPassing(tilePos))//目标不可达return false;//主角运动player->moveToward(tilePos);//显示点击特效auto collisionLayer = m_pMapLayer->getCollisionLayer();auto tileSize = tiledMap->getTileSize();Point pos((tilePos.x + 0.5f) * tileSize.width, (tilePos.y + 0.3f) * tileSize.height);m_pEffectLayer->showAnimationEffect("click_path", pos, collisionLayer);return true;
}

之后还需要修改Character类,来支持我们的操作。

NonPlayerCharacter* m_pTriggerNPC;
//设置npcvoid setTriggerNPC(NonPlayerCharacter* npc);

Character类中添加一个NPC指针,在onTouchBegan()中,如果点击了NPC,则会把该NPC传送给主角。

void Character::popStepAndAnimate()
{m_bMoving = false;//存在待到达目的点,转入if (m_bHavePendingMove){m_bHavePendingMove = false;this->clearShortestPath();//滞后改变this->moveToward(m_pendingMove);return ;}//运动结束else if (m_nStepIndex >= m_shortestPath.size()){this->clearShortestPath();//站立动画this->changeState(State::Idle);return ;
    }//点击了NPC,且将要到达else if (m_pTriggerNPC != nullptr && m_nStepIndex == m_shortestPath.size() - 1){auto delta = m_shortestPath.back()->getTilePos() - m_lastStep->getTilePos();auto newDir = this->getDirection(delta);//改变方向if (newDir != m_dir){m_bDirty = true;m_dir = newDir;}this->clearShortestPath();this->changeState(State::Idle);m_pTriggerNPC->execute(this->getUniqueID());m_pTriggerNPC = nullptr;return ;}//...
}    }//点击了NPC,且将要到达else if (m_pTriggerNPC != nullptr && m_nStepIndex == m_shortestPath.size() - 1){auto delta = m_shortestPath.back()->getTilePos() - m_lastStep->getTilePos();auto newDir = this->getDirection(delta);//改变方向if (newDir != m_dir){m_bDirty = true;m_dir = newDir;}this->clearShortestPath();this->changeState(State::Idle);m_pTriggerNPC->execute(this->getUniqueID());m_pTriggerNPC = nullptr;return ;}//...
}

在这里判断下主角是否走到了对应NPC的面前,如果是的话,先判断主角朝向是否需要改变,然后停止运动,之后触发NPC的函数。

RPG游戏制作-06-与NPC的交互相关推荐

  1. 转载一个手机RPG游戏制作工具,仿造RPGXP写的

    转载一个手机RPG游戏制作工具,仿造RPGXP写的 有朋友问有没有脚本编辑功能,大家注意啦: 有脚本编辑功能,可视化界面编辑脚本,和RMXP一样 经过一年的开发,手机RPG游戏制作工具--MobieG ...

  2. 简单的RPG游戏制作教程

    □企划部份 ◎第一步:决定资料格式 在进入游戏制作的初期,由于有许多和程式有关的资料需要编整,因此担任企划的人员常会忙得乱七八糟.在这个阶段,企划人员必需要和程式商量游戏中资料的格式.举个例子来说,在 ...

  3. Unity学习笔记3 简易2D横版RPG游戏制作(三)

    这一篇本来应该是在上一篇后面直接补进去的.不过因为排版的问题.所以我就另开一篇来整理了,好了,废话不多说,马上整理: 十八.关卡的锁定与解锁 前面我们已经解决了在游戏开始时可以选择关卡的问题,接下来我 ...

  4. RPG游戏制作-02-游戏世界主角的诞生

    在RPG游戏中,有着各种各样的NPC(Non-Player Control),玩家可以操作主角与NPC进行交互,来获得情报,道具,装备等等.而NPC的概念比较广泛,从各种商人到宝箱再到空气墙,都可以认 ...

  5. 《从零开始的RPG游戏制作教程》第二期:让勇者和怪物登场

    目录 1. 前言 2. 第一期:制作基础场景 在[第一期:制作基础场景]中,我们教学了如何下载魔兽地图编辑器,并制作了一个非常基础的小村子场景. 本期我们会简单地在场景中放入魔兽争霸3自带的英雄,使得 ...

  6. 《从零开始的 RPG 游戏制作教程》第九期:信息反馈(上)

    目录 1. 前言 2. 第一期:制作基础场景 3. 第二期:让勇者和怪物登场 4. 第三期:基础的数值设计 5.第四期:从理论的角度简单聊聊关卡 6.第五期:制作物品和技能 7.第六期:设置怪物掉落物 ...

  7. Unity学习笔记2 简易2D横版RPG游戏制作(二)

    十二.敌人受攻击时的闪烁和Player的生命值的修正 上一篇中,我们利用Controller2D中的IEnumerator TakenDamage接口,使得我们的Player受到攻击时会进行闪烁,我们 ...

  8. RPG游戏制作-04-接入脚本前的准备

    在RPG的开发中,一般情况下都会使用脚本,脚本在游戏开发中也很重要,在RPG游戏中,脚本就像剧本,来控制整个RPG游戏的流程. 本游戏使用lua脚本语言,版本为5.3,没使用额外的库,这点和cocos ...

  9. 《从零开始的RPG游戏制作教程》第三期:基础的数值设计

    目录 1. 前言 2. 第一期:制作基础场景 2. 第二期:让勇者和怪物登场 上期回顾 在[第二期:让勇者和怪物登场]中,我们已经制作了一个自定义的勇者克里夫. 很显然,相比我们先前所放置的怪物,我们 ...

  10. 《从零开始的RPG游戏制作教程》第四期:从理论的角度简单聊聊关卡

    目录 1. 前言 2. 第一期:制作基础场景 3. 第二期:让勇者和怪物登场 4. 第三期:基础的数值设计 到目前为止,我们已经接触了如何制作简单的游戏场景,如何放置装饰物.单位,如何修改单位属性,并 ...

最新文章

  1. PyTorch 可视化特征
  2. 51nod 1278 相离的圆
  3. git bash上传大文件到github
  4. mysql中文乱码 go_Mysql binlog乱码问题研究-Go语言中文社区
  5. 怎么检测声音频率和幅值_【电缆小课堂】国网天津电缆公司电缆带电检测团队介绍及典型案例分析...
  6. 火狐浏览器 模拟人工重复操作_火狐浏览器下载手机版-火狐浏览器下载安装到手机v68.6.0...
  7. Java程序低手之关于泛型(Generic)
  8. 【二叉树的迭代版后序遍历】LeetCode 145. Binary Tree Postorder Traversal
  9. 昌邑机器人_昌邑四轴CNC加工齿模长沙四轴CNC加工精鑫精密
  10. Android基础之图片的压缩算法
  11. Windows上优质精选的最佳应用程序及工具列表(附下载链接)
  12. VSS 2005使用
  13. 雷达威力图绘制matlab,科学网—matlab绘雷达图 - 张凌的博文
  14. canvas实现星星闪烁特效
  15. python、pygame开发的太空大战游戏源代码,供学习参考
  16. 从fit文件中提取lick指数的matlab程序
  17. 计算机学院考勤管理办法,学生考勤管理规定
  18. 对php课程的建议,万紫千红总是春——对新课程语文教学、复习的建议与采饶措施a href=http://www.ruiwen.com/friend/list.php(教师中心专稿)/a...
  19. AD19 网络标签 无法连接
  20. c语言:已知斐波那契数列定义:f(0) = 0; f(1) = 1;f(n) = f(n-1) + f(n-2);请计算并输出数列的前n(n<=30)项。

热门文章

  1. 【数据仓库】1.数据模型
  2. 1、异常值(outliers)检测综述:定义、检测方法、影响、修正
  3. 计算机系统——处理器体系结构
  4. 如何制作流程图?流程图制作软件哪个好
  5. IC-二进制, 自然数, 有符号数
  6. gif软件(ShareX)
  7. sql server返回是星期几的函数
  8. 报错:Unhandled exception
  9. (二)使用selenium爬取拉钩招聘网信息并存入csv文件
  10. 不同网段实现全网互通