/*---------------------------------------------------------------------*//** メニューの位置調整 **//*---------------------------------------------------------------------*/ void FocusMenu::adjustMenuPos(MenuKind mkind) { // フォローなしの場合は必要なし if(_unitFllowRef[mkind] == 0) { return; } do { MenuTreeNode* mtnode = _menu[mkind]->getCurrentMenuNode(); if(mtnode == 0L) { break; } MenuWindow* mwnd = (MenuWindow*)mtnode->getPanel(); if(mwnd == 0L) { break; } const RectF32* rectMwnd = mwnd->getRectangle(); // 対象がいなくなった if(!_unitFllowRef[mkind]->isEnable()) { break; // メニューを閉じる } // スクリーン座標に変換 Vector2F vScr; CalcUtils::calc3dPosToScreenPos(&vScr, _unitFllowRef[mkind]->getCenterPos()); f32 x = vScr.x(); f32 y = vScr.y(); // ユニット自体が画面外に出たときはメニューを閉じる if((x < 0) || (x > Game::getGame()->getLogicalWidth()) || (y < 0) || (y > Game::getGame()->getLogicalHeight())) { break; // メニューを閉じる } // 画面内に収めるように位置修正 if((x + rectMwnd->w()) > Game::getGame()->getLogicalWidth()) { x = Game::getGame()->getLogicalWidth() - rectMwnd->w(); } else if(x < 0) { x = 0; } if((y + rectMwnd->h()) > Game::getGame()->getLogicalHeight()) { y = Game::getGame()->getLogicalHeight() - rectMwnd->h(); } else if(y < 0) { y = 0; } // 修正を反映 if((x != rectMwnd->x()) || (y != rectMwnd->y())) { PointF32 pt(x, y); mwnd->move(&pt); } return; // 正常終了 } while(false); // なんらかエラーが発生したのでメニューを閉じる _menu[mkind]->closeMenu(); }
/*---------------------------------------------------------------------*//** フレーム制御 **//*---------------------------------------------------------------------*/ void MoveCursor::exec(ExecRes* res, const ExecCtx* ec) { if(TFW_IS_FLAG(_edchFlags, EDCH_EXT_MASK)) { return; } // 外部からの無効化 // 歩行処理 GameExecCtx* gec = (GameExecCtx*)ec; TouchPanel* ui = gec->getTouchPanel(); bool isEnableSelf = (!gec->isOpenedLockGui()) && (!gec->isLockOperating()); TFW_SET_FLAG(_edchFlags, EDCH_SELF, !isEnableSelf); if(isEnableSelf && !ui->isReacted()) { // 差分を求める Vector2F vDiff; do { // 最初にクリックしたとこからの差分で移動 bool isTouched = _isTouching; _isTouching = (ui->getTouchingNum() == 1); // タッチ時のポイントを得る if(!isTouched && _isTouching) // タッチした { ui->getTouchPosition(_ptTouchStart); // 開始のタッチ位置を得る ui->setDragOperating(true); _ext->onTapStart(_ptTouchStart); } else if(isTouched && !_isTouching) // 離した { // UI 反応済みフラグを立てるかどうかの判定 Vector2F vDiff( (f32)(_ptTouchLast->x() - _ptTouchStart->x()), (f32)(_ptTouchLast->y() - _ptTouchStart->y()) ); f32 lenDiffSq = vDiff.lengthSq(); if(lenDiffSq >= LEN_MIN_SQ) // 最小長さを超えている { ui->setReacted(true); // 反応済みフラグを立てる } _ptTouchStart->set(F32_PMAX, F32_PMAX); _ptTouchLast->set(F32_PMAX, F32_PMAX); _xDiff = 0; _yDiff = 0; _ext->onTapEnd(); break; // 差分計算から抜ける } if(_isTouching) { ui->getTouchPosition(_ptTouchLast); // 現在のタッチ位置を得る } // 差分を計算する vDiff.set( (f32)(_ptTouchLast->x() - _ptTouchStart->x()), (f32)(_ptTouchLast->y() - _ptTouchStart->y()) ); f32 lenDiffPw = vDiff.lengthSq(); if(lenDiffPw > LEN_MAX_SQ) // 最大長さを超えている { // 最大長さに収める vDiff.normalize(); vDiff *= LEN_MAX; // タッチ位置の補正 _ptTouchLast->x() = _ptTouchStart->x() + (s32)vDiff.x(); _ptTouchLast->y() = _ptTouchStart->y() + (s32)vDiff.y(); ui->setReacted(true); // 反応済みフラグを立てる } else if(lenDiffPw < LEN_MIN_SQ) // 最小長さ未満 { vDiff.set(0.0f, 0.0f); _xDiff = 0; _yDiff = 0; break; // 差分計算から抜ける } else { ui->setReacted(true); // 反応済みフラグを立てる } _xDiff = (s32)vDiff.x(); _yDiff = (s32)vDiff.y(); } while(false); // 描画用に角度を得ておく Calc::calcAngle(&_angle, vDiff.x(), vDiff.y()); } else if(_isTouching) { _xDiff = 0; _yDiff = 0; _isTouching = false; _ext->onTapEnd(); } // 2点間の距離を求める f32 lenPw = (f32)((_xDiff * _xDiff) + (_yDiff * _yDiff)); _length = ::sqrtf(lenPw); _rateLength = _length / LEN_MAX; // 状態を更新する if(_length < LEN_WALK) { _state = STATE_STOP; } else if(_length < LEN_RUN) { _state = STATE_WALK; } else { _state = STATE_RUN; } }
/*---------------------------------------------------------------------*//** 描画 **//*---------------------------------------------------------------------*/ void FocusCursor::draw(const RenderCtx* rc) { if(!_isEnableOut || !_isEnableSelf) { return; } // 無効化中 GameRenderCtx* grc = (GameRenderCtx*)rc; Renderer* rdr = rc->getRenderer(); RectF32 uv; // テクスチャ設定 rdr->bindTexture(_texRef); // 加算アルファ合成 rdr->setAlphaBlendFunc(Renderer::AFUNC_ADD); // 2D 解像描画比 f32 rate2dr = Env_get2drRate(); // 頂点カラーを基本色に rdr->setSolidColor(255, 255, 255, 255); // クリック対象を描画 { Tfw* tfw = Game::getGame()->getTfw(); ASSERT(tfw != 0L); View* view = tfw->getView(); ASSERT(view != 0L); SorSgm* sgm = (SorSgm*)tfw->getSgManager(); ASSERT(sgm != 0L); Camera* cam = sgm->getVisibleCamera(); if(cam != 0L) { UnitManager* unitmng = Game::getGame()->getUnitManager(); ASSERT(unitmng != 0L); for(int i = 0; i < unitmng->getUnitNum(); i++) { const Unit* unit = unitmng->getUnitFromIndex(i); ASSERT(unit != 0L); if(!unit->isEnable()) { continue; } // 無効なユニットは除外 if(!unit->isEnableFocus()) { continue; } // フォーカスされないユニットは除外 if(unit->isHidden()) { continue; } // 隠し属性ユニットは除外 if(unit->isHiddenClick()) { continue; } // クリック選択不可 if(unit->getUnitType() == UNITTYPE_EQUIPMENT_ITEM) { continue; } // 所持品は除外 if(unit->getCenterPos()->z() >= cam->getLoc()->z()) { continue; } // カメラより手前は除外 // 既にフォーカスがあるユニットは不要 bool isHadFocus = false; for(s32 j = 0; j < NUM_FOCUS_MAX; j++) { if(_focusarr->getUnit(j) == unit) { isHadFocus = true; break; } } if(isHadFocus) { continue; } // スクリーン座標に変換 Vector2F vScr; Gcalc::conv3dPosToScreenPos(&vScr, unit->getCenterPos(), cam, view); // 画面外チェック if( ((vScr.x() + W_FOCUS_CIRC) < 0) || ((vScr.x() - W_FOCUS_CIRC) >= Game::getGame()->getLogicalWidth()) || ((vScr.y() + H_FOCUS_CIRC) < 0) || ((vScr.y() - H_FOCUS_CIRC) >= Game::getGame()->getLogicalHeight()) ) { continue; } // 描画 ::glPushMatrix(); // 行列を保存 ::glTranslatef(vScr.x(), vScr.y(), 0.0f); drawQuestIcon(rdr, unit, rate2dr); // クエストアイコン表示 ::glRotatef(_dangFocusable, 0.0f, 0.0f, 1.0f); // フォーカス可能アイコン表示 RectF32 vtx(- W_FOCUS_CIRC / 2, - H_FOCUS_CIRC / 2, W_FOCUS_CIRC, H_FOCUS_CIRC); RendererUtils::draw2dTextureRect(rdr, &vtx, Gcalc::calcTexUv(&uv, UV_FOCUSABLE, W_TEX, H_TEX, rate2dr)); ::glPopMatrix(); // 行列を戻す } } } // フォーカスカーソル表示 drawFocusCursor(rdr, _focusarr, 1.0f, rate2dr); // マジッククラスターのフォーカスを表示 MagicSys* mgsys = Game::getGame()->getMagicSys(); for(int i = 0; i < mgsys->getMaxClusterNum(); i++) { MagicCluster* mc = mgsys->getClusterFromIndex(i); if(mc == 0L) { continue; } if(!mc->isValid()) { continue; } if(!TFW_IS_FLAG(mc->getConfFlags(), MagicCluster::CONFF_SHOW_FC)) { continue; } rdr->setSolidColor(63, 0, 255, 255); drawFocusCursor(rdr, mc->getFocusArray(), 0.5f, rate2dr); } // 通常アルファ合成 rdr->setAlphaBlendFunc(Renderer::AFUNC_NORMAL); // フォーカスゲージ表示 for(s32 i = 0; i < NUM_FOCUS_MAX; i++) { const Unit* unitFocused = _focusarr->getUnit(i); if(unitFocused == 0L) { continue; } // フォーカスがある場合のみ以下を処理する const Vector2F* posScr = _focusarr->getScreenPos(i); f32 x = posScr->x() + W_FOCUS_CIRC * 0.5f; f32 y = posScr->y(); // ゲージ表示 if(unitFocused->isCategory(Unit::UNITCAT_CHAR)) { const CharUnit* cunit = (CharUnit*)unitFocused; const CharStat* cstat = cunit->getCharStat(); if(cstat != 0L) { StatusDrawer::drawCharStat(rc, _texRef, cstat, x, y, StatusDrawer::W_GAUGE_DEFAULT, StatusDrawer::H_GAUGE_DEFAULT, false, false); } } else if(unitFocused->getUnitType() == UNITTYPE_EQUIPMENT_ITEM) { const EquipmentItemUnit* iunit = (EquipmentItemUnit*)unitFocused; const Item* item = iunit->getItem(); if(item != 0L) { // 名前表示 const VcString* name = item->getItemDef()->getName(Env_getLangId()); if(name != 0L) { rdr->setSolidColor(255, 255, 255, 255); Font* fontJp = grc->getFontSet()->getFont(GameFontSet::JP); EasyStringDrawer::draw(fontJp, name, x, y, 8, rc); y += 8.0f; } const EleneStat* eestat = item->getEleneStat(); if(eestat != 0L) { StatusDrawer::drawEleneStat(rc, _texRef, eestat, x, y, 60.0f, StatusDrawer::H_ENEGAUGE_DEFAULT, false); } } } else if(unitFocused->getUnitType() == UNITTYPE_PUT_ITEM) { const PutItemUnit* diunit = (PutItemUnit*)unitFocused; const ItemDef* itmdf = diunit->getItemDef(); if(itmdf != 0L) { // 名前表示 const VcString* name = itmdf->getName(Env_getLangId()); if(name != 0L) { rdr->setSolidColor(255, 255, 255, 255); Font* fontJp = grc->getFontSet()->getFont(GameFontSet::JP); EasyStringDrawer::draw(fontJp, name, x, y, 8, rc); y += 8.0f; } } const EleneStat* eestat = diunit->getEleneStat(); if(eestat != 0L) { StatusDrawer::drawEleneStat(rc, _texRef, eestat, x, y, 60.0f, StatusDrawer::H_ENEGAUGE_DEFAULT, false); } } } }
/*---------------------------------------------------------------------*//** フレーム制御 **//*---------------------------------------------------------------------*/ void FocusCursor::exec(ExecRes* res, const ExecCtx* ec) { if(!_isEnableOut) { return; } // 外部からの無効化 GameExecCtx* gec = (GameExecCtx*)ec; TouchPanel* ui = gec->getTouchPanel(); // フォーカスの有効性更新 _focusarr->updateValidity(); // フォーカスの座標値をリセット for(s32 i = 0; i < NUM_FOCUS_MAX; i++) { _focusarr->invalidateScreenPos(i); } // 有効性判定 _isEnableSelf = !gec->isLockOperating(); bool isEnableUiReact = _isEnableSelf && !gec->isOpenedLockGui() && !ui->isReacted() && (_fcntPreventTap == 0.0f); // タッチ操作による処理 if(isEnableUiReact) { PointF32 ptTouch, ptStart; bool isTap = false; bool isDblTapRel = false; if(!ui->isReacted()) { const f32 DIFF_TAP_RANGE = 20.0f; if(ui->isTapRelease(&ptTouch, &ptStart)) { isTap = ptTouch.isNear(&ptStart, DIFF_TAP_RANGE, DIFF_TAP_RANGE); } // 面積が狭いので、isClickRelease だとストレスに感じる if(ui->isDoubleClickRelease(&ptTouch)) { isDblTapRel = true; } } if(isTap || isDblTapRel) { Tfw* tfw = Game::getGame()->getTfw(); ASSERT(tfw != 0L); View* view = tfw->getView(); ASSERT(view != 0L); SorSgm* sgm = (SorSgm*)tfw->getSgManager(); ASSERT(sgm != 0L); Camera* cam = sgm->getVisibleCamera(); ASSERT(cam != 0L); UnitManager* unitmng = Game::getGame()->getUnitManager(); ASSERT(unitmng != 0L); for(int i = 0; i < unitmng->getUnitNum(); i++) { Unit* unit = unitmng->getUnitFromIndex(i); ASSERT(unit != 0L); if(!unit->isEnable()) { continue; } // 無効なユニットは除外 if(!unit->isEnableFocus()) { continue; } // フォーカスされないユニットは除外 if(unit->isHidden()) { continue; } // 隠し属性ユニットは除外 if(unit->getUnitType() == UNITTYPE_EQUIPMENT_ITEM) { continue; } // 所持品は除外 if(unit->getCenterPos()->z() >= cam->getLoc()->z()) { continue; } // カメラより手前は除外 // スクリーン座標に変換 Vector2F vScr; Gcalc::conv3dPosToScreenPos(&vScr, unit->getCenterPos(), cam, view); if(isDblTapRel) // ダブルクリック時は直接フォーカスをセットする { // 一度フォーカスをリセット for(int j = 0; j < NUM_FOCUS_MAX; j++) { setFocus(j, 0L, 0L); } // 範囲内かどうか判定して、範囲内だったらフォーカス設定する if(TFW_IS_NEAR(vScr.x(), ptTouch.x(), RANGE_TOTRG) && TFW_IS_NEAR(vScr.y(), ptTouch.y(), RANGE_TOTRG)) { // フォーカスをセット(上部でリセットしているので、[0] 決めうち) setFocus(0, unit, &vScr); // UI に反応済みフラグを立てる ui->setReacted(true); break; } } else if(isTap) // タップ時はメニューを表示 { // 範囲内かどうか判定して、範囲内だったらメニューを表示する TRACELN("{FocusCursor::exec} unit touch?; scr_x=%f, scr_y=%f, click_x=%d, click_y=%d", vScr.x(), vScr.y(), ptTouch.x(), ptTouch.y()); if(TFW_IS_NEAR(vScr.x(), ptTouch.x(), RANGE_TOTRG) && TFW_IS_NEAR(vScr.y(), ptTouch.y(), RANGE_TOTRG)) { showFocusMenu(unit, &vScr); // フォーカスメニュー表示 ui->setReacted(true); // UI に反応済みフラグを立てる } } } } } // フォーカスカーソルの画面位置を計算 for(s32 i = 0; i < NUM_FOCUS_MAX; i++) { // 無効になったユニットは外す const Unit* unitFocused = _focusarr->getUnit(i); if(unitFocused == 0L) { continue; } if(!unitFocused->isEnable()) { setFocus(i, 0L, 0L); } // スクリーン座標値が未計算の場合、計算する if(!_focusarr->isValidScreenPos(i)) { _focusarr->calcScreenPos(i); } } // マジッククラスターのフォーカスの画面位置を計算 MagicSys* mgsys = Game::getGame()->getMagicSys(); for(int i = 0; i < mgsys->getMaxClusterNum(); i++) { MagicCluster* mc = mgsys->getClusterFromIndex(i); if(mc == 0L) { continue; } if(!mc->isValid()) { continue; } mc->focusArray()->calcScreenPosAll(); } // タップ防止カウンタの更新 if(_fcntPreventTap > 0.0f) { _fcntPreventTap -= ec->getDeltaFrame(); if(_fcntPreventTap < 0.0f) { _fcntPreventTap = 0.0f; } } // カーソル回転角度の更新 _dangFocus += DANG_FOCUS_DELTA; if(_dangFocus > 180.0f) { _dangFocus -= 360.0f; } _dangFocusable += DANG_FOCUSABLE_DELTA; if(_dangFocusable > 180.0f) { _dangFocusable -= 360.0f; } }