void FloorMapLayer::confirm_attack_impl(const npc_t& npc) { auto life = get_tile_prop(npc.gid, "life").asInt(); auto hun = get_tile_prop(npc.gid, "hun").asInt(); auto gold = get_tile_prop(npc.gid, "gold").asInt(); auto defence = get_tile_prop(npc.gid, "defence").asInt(); auto attack = get_tile_prop(npc.gid, "attack").asInt(); auto player_info = Player::GetInstance()->get_player_info(); auto attack_damage = std::max(0, player_info.attack - defence); auto damage = std::max(0, attack - player_info.defence); if (attack_damage == 0 || (life + attack_damage - 1) / attack_damage * damage >= player_info.hp) // 只要攻击不够无论防御多高都打不过 { auto dict = FileUtils::getInstance()->getValueMapFromFile("chinese.xml"); auto text = dict["txt7_2"].asString(); PromptDialog::show(text); stop_and_clear(); return; } auto blood = (life + attack_damage - 1) / attack_damage * damage; auto target_pos = this->convertToNodeSpace(_info_panel->get_node_position_in_world(WarriorInfoPanel::hun)); target_pos -= Vec2(26.0f, 0); pick_up_item_impl(npc, target_pos, [blood, gold, hun]() { PlayerDelegate::add_hp(-blood); PlayerDelegate::add_gold_hun(gold, hun); }); auto end_pos = Vec2((npc.x + 0.5f) * 75.0f - 50.0f, (npc.y + 0.5f) * 75.0f - 50.0f); _warrior->move_to(end_pos, CC_CALLBACK_0(FloorMapLayer::step, this)); _paths.erase(_paths.begin()); }
void FloorMapLayer::confirm_open(OKCancelDialog::RETURN_TYPE type, const npc_t& npc) { if (type == OKCancelDialog::CANCEL) { stop_and_clear(); } else { _warrior->stand_auto(); auto npc_layer = _tiled_map->getLayer("npc"); auto door = npc_layer->getTileAt(Vec2(npc.x, 11 - npc.y)); npc_layer->setupTileSprite(door, Vec2(npc.x, 11 - npc.y), npc.gid); door->runAction(CCSequence::create(FadeOut::create(0.5f), RemoveSelf::create(), CCCallFunc::create(std::bind(&FloorMapLayer::confirm_open_impl, this, npc)), nullptr)); // 如果是竖门需要将其上方的附加节点一并去除 auto uplink = get_tile_prop(npc.gid, "uplink").asInt(); if (1 == uplink) { auto npc_iter = find(_npcs.begin(), _npcs.end(), npc_t(npc.x, npc.y + 1, 0)); if (npc_iter != _npcs.end()) { const auto& npc_up = *npc_iter; auto door_up = npc_layer->getTileAt(Vec2(npc_up.x, 11 - npc_up.y)); npc_layer->setupTileSprite(door_up, Vec2(npc_up.x, 11 - npc_up.y), npc_up.gid); door_up->runAction(CCSequence::create(FadeOut::create(0.5f), RemoveSelf::create(), nullptr)); } } } }
void FloorMapLayer::confirm_open(OKCancelDialog::RETURN_TYPE type, const Floor::npc_t& npc) { if (type == OKCancelDialog::CANCEL) { stop_and_clear(); } else { _warrior->stand_auto(); _warrior->set_lock(true); // 设置等待开门的过程中不可重新寻路,以免出现计算混乱 auto npc_layer = _tiled_map->getLayer("npc"); auto door = npc_layer->getTileAt(Vec2(npc.pos.x, 11 - npc.pos.y)); npc_layer->setupTileSprite(door, Vec2(npc.pos.x, 11 - npc.pos.y), npc.gid); const float OPEN_DURATION = 0.5f; door->runAction(CCSequence::create(FadeOut::create(OPEN_DURATION), RemoveSelf::create(), CCCallFunc::create(std::bind(&FloorMapLayer::confirm_open_impl, this, npc)), nullptr)); // 如果是竖门需要将其上方的附加节点一并去除 auto uplink = get_tile_prop(npc.gid, "uplink").asInt(); if (1 == uplink) { auto npc_up = Floor::GetInstance()->get_floor_info(_floor).find_npc_by_pos(Floor::position_t(npc.pos.x, npc.pos.y + 1)); if (nullptr != npc_up) { auto door_up = npc_layer->getTileAt(Vec2(npc_up->pos.x, 11 - npc_up->pos.y)); npc_layer->setupTileSprite(door_up, Vec2(npc_up->pos.x, 11 - npc_up->pos.y), npc_up->gid); door_up->runAction(CCSequence::create(FadeOut::create(OPEN_DURATION), RemoveSelf::create(), nullptr)); } } } }
void FloorMapLayer::confirm_open_impl(const npc_t& npc) { auto color = get_tile_prop(npc.gid, "color").asInt(); PlayerDelegate::add_key(1 == color ? -1 : 0, 2 == color ? -1 : 0, 3 == color ? -1 : 0); auto end_pos = Vec2((npc.x + 0.5f) * 75.0f - 50.0f, (npc.y + 0.5f) * 75.0f - 50.0f); _warrior->move_to(end_pos, CC_CALLBACK_0(FloorMapLayer::step, this)); _paths.erase(_paths.begin()); }
bool FloorMapLayer::interact_item(const npc_t& npc) { bool walk_pause = false; auto style = get_tile_prop(npc.gid, "style").asInt(); switch (style) { case 1: // 怪物 { walk_pause = true; auto end_pos = Vec2((npc.x + 0.5f) * 75.0f - 50.0f, (npc.y + 0.5f) * 75.0f - 50.0f); _warrior->turn_to(end_pos); if (_paths.size() > 2) // 怪物为行走路径的最后一个节点,不提示对话框,直接开打 { auto dict = FileUtils::getInstance()->getValueMapFromFile("chinese.xml"); auto text = dict["isAttack"].asString(); auto name = dict[get_tile_prop(npc.gid, "name").asString()].asString(); auto info = text + " " + name; auto dialog = OKCancelDialog::create("", info); dialog->setCallback(std::bind(&FloorMapLayer::confirm_attack, this, std::placeholders::_1, npc)); ModalDialogManager::GetInstance()->pushDialog(dialog); } else { assert(_paths.size() == 2); // 和npc交互时路径肯定还有至少两个节点,一个自己的,一个对方的 if (_paths.size() == 2) confirm_attack(OKCancelDialog::OK, npc); } } break; case 3: // 门 { walk_pause = true; auto end_pos = Vec2((npc.x + 0.5f) * 75.0f - 50.0f, (npc.y + 0.5f) * 75.0f - 50.0f); _warrior->turn_to(end_pos); auto color = get_tile_prop(npc.gid, "color").asInt(); const auto& player = Player::GetInstance()->get_player_info(); if (1 == color && player.key_red < 1 || 2 == color && player.key_blue < 1 || 3 == color && player.key_yellow < 1) { auto dict = FileUtils::getInstance()->getValueMapFromFile("chinese.xml"); auto text = dict["buyKeyTip"].asString(); PromptDialog::show(text); stop_and_clear(); break; } auto dict = FileUtils::getInstance()->getValueMapFromFile("chinese.xml"); auto prefix = dict["open_msg1"].asString(); auto sufix = dict["open_msg2"].asString(); auto textkey = 1 == color ? "rKey" : (2 == color ? "bKey" : "yKey"); auto info = prefix + dict[textkey].asString() + sufix; auto dialog = OKCancelDialog::create("", info); dialog->setCallback(std::bind(&FloorMapLayer::confirm_open, this, std::placeholders::_1, npc)); ModalDialogManager::GetInstance()->pushDialog(dialog); } break; case 6: // 楼梯 { walk_pause = false; // 无需停下来,直接切换楼层,切换场景的持续时间的一半让勇士正好走入下一个楼梯格子 auto next_scene = PromptLayer::scene(_floor == 1 ? 2 : 1); auto transition = TransitionFade::create(0.5f, next_scene); Director::getInstance()->replaceScene(transition); } break; default: break; } return walk_pause; }
void FloorMapLayer::pick_up_item(const npc_t& npc) { std::function<void()> callback; WarriorInfoPanel::node_type type; bool need_pick = true; auto style = get_tile_prop(npc.gid, "style").asInt(); switch (style) { case 2: // 钥匙 { auto color = get_tile_prop(npc.gid, "color").asInt(); if (0 == color) // 钥匙串 { type = WarriorInfoPanel::key_blue; callback = std::bind(&PlayerDelegate::add_key, 1, 1, 1); } else if (1 == color) // 红钥匙 { type = WarriorInfoPanel::key_red; callback = std::bind(&PlayerDelegate::add_key, 1, 0, 0); } else if (2 == color) // 蓝钥匙 { type = WarriorInfoPanel::key_blue; callback = std::bind(&PlayerDelegate::add_key, 0, 1, 0); } else if (3 == color) // 黄钥匙 { type = WarriorInfoPanel::key_yellow; callback = std::bind(&PlayerDelegate::add_key, 0, 0, 1); } } break; case 4: // 宝石 { auto color = get_tile_prop(npc.gid, "color").asInt(); auto value = get_tile_prop(npc.gid, "value").asInt(); if (1 == color) // 红宝石,攻击 { type = WarriorInfoPanel::attack; callback = std::bind(&PlayerDelegate::add_attack, value); } else if (2 == color) // 蓝宝石,防御 { type = WarriorInfoPanel::defend; callback = std::bind(&PlayerDelegate::add_defence, value); } } break; case 5: // 血瓶 { auto value = get_tile_prop(npc.gid, "value").asInt(); type = WarriorInfoPanel::hp; callback = std::bind(&PlayerDelegate::add_hp, value); } break; default: need_pick = false; break; } if (need_pick) { auto target_pos = this->convertToNodeSpace(_info_panel->get_node_position_in_world(type)); target_pos -= Vec2(26.0f, 0); pick_up_item_impl(npc, target_pos, callback); } }
void FloorMapLayer::onTouchEnded(Touch *touch, Event *e) { // bugfix: 如果对话框已弹出,就不再执行以下代码,这种情况是在对话框弹出前,touchbegan就已经触发的情况下发生 // 重现方法: 控制勇士经过怪物,然后鼠标按下等待勇士到达怪物处,弹出提示对话框后,松开鼠标继续弹出 if (ModalDialogManager::GetInstance()->isShown()) { return; } // 正在战斗中则不允许重新走动,以免计算混乱 if (_warrior->is_fighting()) { return; } // 获取起始点 auto end_vec2 = _tiled_map->convertTouchToNodeSpace(touch) / 75.0f; auto end_pt = node_t(end_vec2.x, end_vec2.y); if (!_paths.empty() && _paths.back() == end_pt) { return; } auto start_vec2 = _tiled_map->convertToNodeSpace(_warrior->getPosition()) / 75.0f; auto start_pt = node_t(start_vec2.x, start_vec2.y); if (start_pt == end_pt) { return; } // 获取阻碍点 auto wall_layer = _tiled_map->getLayer("wall"); auto wall_layer_size = wall_layer->getLayerSize(); auto pos = touch->getLocation(); auto tiles = wall_layer->getTiles(); std::vector<node_t> blocks; for (uint32_t i = 0; i < (uint32_t)(wall_layer_size.height); ++i) { for (uint32_t j = 0; j < (uint32_t)(wall_layer_size.width); ++j) { if (tiles[i * (uint32_t)(wall_layer_size.width) + j] != 0) { blocks.push_back(node_t(j, (uint32_t)(wall_layer_size.height) - 1 - i)); } } } if (std::find(blocks.begin(), blocks.end(), end_pt) != blocks.end() || end_pt.x >= 10 || end_pt.y >= 12) { return; } // npc列表 npc_t stair_up, stair_down; auto npc_layer = _tiled_map->getLayer("npc"); auto npc_layer_size = npc_layer->getLayerSize(); auto npc_tiles = npc_layer->getTiles(); _npcs.clear(); for (uint32_t i = 0; i < (uint32_t)(npc_layer_size.height); ++i) { for (uint32_t j = 0; j < (uint32_t)(npc_layer_size.width); ++j) { int32_t gid = (int32_t)(npc_tiles[i * (uint32_t)(npc_layer_size.width) + j]); if (gid != 0) { _npcs.push_back(npc_t(j, npc_layer_size.height - 1 - i, gid)); if (get_tile_prop(gid, "style").asInt() == 6) { if (get_tile_prop(gid, "type").asInt() == 1) stair_up = _npcs.back(); else stair_down = _npcs.back(); } } } } // A星路径 AStar astar(10, 12); astar.set_start_and_end(start_pt, end_pt); astar.set_blocks(blocks); _paths = astar.get_path(); auto iter = std::find_if(_paths.begin(), _paths.end(), [&](node_t node) { // 找到除了首节点的第一个楼梯节点 return (node.x != start_pt.x || node.y != start_pt.y) && (node.x == stair_up.x && node.y == stair_up.y || node.x == stair_down.x && node.y == stair_down.y); }); if (iter != _paths.end()) _paths.erase(++iter, _paths.end()); // 箭头 _arrow_node->setVisible(true); _arrow_node->setPosition(Vec2((end_pt.x + 0.5f) * 75.0f - 50.0f, (end_pt.y + 0.5f) * 75.0f - 50.0f)); // 路线 uint32_t index = 0; _road_node->removeAllChildren(); for (auto node : _paths) { if (index == _paths.size() - 1) break; auto pos = Vec2((node.x + 0.5f) * 75.0f - 50.0f, (node.y + 0.5f) * 75.0f - 50.0f); auto res = "Images/diban" + String::createWithFormat("%d", index % 22)->_string + ".png"; auto sprite = Sprite::create(res); sprite->setPosition(pos); _road_node->addChild(sprite); ++index; } // 勇士 _warrior->stopAllActions(); step(); }
bool FloorMapLayer::init(int floor, bool up) { _floor = floor; // 由于直接继承自node,需要做一些处理,现在layer的功能全被废弃了,无意义 setContentSize(Director::getInstance()->getWinSize()); auto listener = EventListenerTouchOneByOne::create(); listener->setSwallowTouches(true); listener->onTouchBegan = CC_CALLBACK_2(FloorMapLayer::onTouchBegan, this); listener->onTouchEnded = CC_CALLBACK_2(FloorMapLayer::onTouchEnded, this); _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this); // 加载地图编辑器文件 auto res = "TileMaps/floor00" + String::createWithFormat("%d", floor)->_string + ".tmx"; _tiled_map = cocos2d::experimental::TMXTiledMap::create(res); if (nullptr != _tiled_map) { _tiled_map->setPosition(Vec2(-50.0f, -50.0f)); this->addChild(_tiled_map); } auto npc_layer = _tiled_map->getLayer("npc"); auto npc_layer_size = npc_layer->getLayerSize(); auto npc_tiles = npc_layer->getTiles(); std::vector<Floor::npc_t> npcs; for (uint32_t i = 0; i < (uint32_t)(npc_layer_size.height); ++i) { for (uint32_t j = 0; j < (uint32_t)(npc_layer_size.width); ++j) { int32_t gid = (int32_t)(npc_tiles[i * (uint32_t)(npc_layer_size.width) + j]); if (gid != 0) { const Floor::floor_t& floor = Floor::GetInstance()->get_floor_info(_floor); Floor::npc_t npc(j, npc_layer_size.height - 1 - i, gid); if (floor.is_valid()) { auto iter = std::find(floor.npcs.begin(), floor.npcs.end(), npc); if (iter == floor.npcs.end()) { npc_layer->setTileGID(999, Vec2(j, i)); } } npcs.push_back(npc); if (get_tile_prop(gid, "style").asInt() == 6) { if (get_tile_prop(gid, "type").asInt() == 2) _stair_up = npcs.back(); else _stair_down = npcs.back(); } } } } Floor::GetInstance()->auto_init_floor(_floor, npcs); // 路径节点 _road_node = Node::create(); if (nullptr != _road_node) { _road_node->setPosition(Vec2::ZERO); this->addChild(_road_node); } // 勇士骨骼动画节点 _warrior = WarriorNode::create(); /*cocostudio::CCBone* bone = _warrior->getBone("sheild1"); int index = bone->getDisplayManager()->getCurrentDisplayIndex(); bone->removeDisplay(1); bone->changeDisplayByIndex(-1, true); cocostudio::CCBone* bone2 = _warrior->getBone("sheild2"); index = bone2->getDisplayManager()->getCurrentDisplayIndex(); bone2->removeDisplay(1); bone2->changeDisplayByIndex(-1, true);*/ Floor::position_t pos = up ? _stair_down.pos : _stair_up.pos; _warrior->setPosition(Vec2((pos.x + 0.5f) * 75.0f - 50.0f, (pos.y + 0.5f) * 75.0f - 50.0f)); this->addChild(_warrior); // 上方背景 auto inside_bg = Sprite::create("Images/bg_top2.png"); auto outside_bg = Sprite::create("Images/bg_top_1.png"); if (nullptr != outside_bg && nullptr != inside_bg) { auto win_size = Director::getInstance()->getWinSize(); outside_bg->setScale(inside_bg->getContentSize().width / outside_bg->getContentSize().width); outside_bg->setPosition(Vec2(win_size.width / 2, 1092.0f)); this->addChild(outside_bg); inside_bg->setPosition(Vec2(win_size.width / 2, 1076.0f)); this->addChild(inside_bg); } // 点击箭头节点 _arrow_node = ArrowNode::create(); if (nullptr != _arrow_node) { _arrow_node->setPosition(Vec2::ZERO); _arrow_node->setVisible(false); this->addChild(_arrow_node); } // 勇士属性面板 _info_panel = WarriorInfoPanel::create(); if (nullptr != _info_panel) { _info_panel->setPosition(Vec2(-10.0f, 825.0f)); this->addChild(_info_panel); } return true; }