// --- \EmoteIconParticleAnimator.hs --- class EmoteIconParticleAnimator{ // GUI情報 string _layerName; string _guiName; GUIElement _animGUI; float _timeCounter; // イージングアニメーションスピード const float PARTICLE_ANIM_SPEED = 2; // アニメーションの簡易ステート const int ANIMSTATE_IDLE = 0; const int ANIMSTATE_APPEAR = 1; const int ANIMSTATE_SHOW = 2; const int ANIMSTATE_DISAPPEAR = 3; const int ANIMSTATE_DELETE = 4; int _currentState; // パーティクルのサイズ const int PARTICLE_SIZE_LAND = 50; const int PARTICLE_SIZE_PORT = 150; int particleSize; bool _isAnimEnd; public EmoteIconParticleAnimator(){ _timeCounter = 0; _currentState = -1; particleSize = PARTICLE_SIZE_LAND; _layerName = ""; _guiName = ""; _isAnimEnd = false; ChangeAction(ANIMSTATE_IDLE); } public void FindGUIElement(string layerName, string isPortrait, string guiName){ if(isPortrait == "true"){ _animGUI = hsLayerGetPortrait(layerName).GetGUIElement(guiName); particleSize = PARTICLE_SIZE_PORT; }else{ _animGUI = hsLayerGetLandscape(layerName).GetGUIElement(guiName); particleSize = PARTICLE_SIZE_LAND; } if(_animGUI !== null){ _layerName = layerName; _guiName = guiName; } } public bool IsAnimEnd(){ return _isAnimEnd; } public void ParticleAnimation(){ if(_animGUI === null) { return; } if(_isAnimEnd) { return; } switch(_currentState){ case ANIMSTATE_IDLE:{ IdleAction(); break; } case ANIMSTATE_APPEAR:{ AppearAction(); break; } case ANIMSTATE_SHOW:{ ShowAction(); break; } case ANIMSTATE_DISAPPEAR:{ DisappearAction(); break; } case ANIMSTATE_DELETE:{ DeleteAction(); break; } default:{ break; } } } private void IdleAction(){ if(_animGUI !== null) { ChangeAction(ANIMSTATE_APPEAR); } } private void AppearAction(){ if(_animGUI === null) { return; } _timeCounter += hsSystemGetDeltaTime() * PARTICLE_ANIM_SPEED; float animScale = particleSize * easeOutBack(_timeCounter); _animGUI.SetSize(animScale, animScale); MoveYaxis(1); if(_timeCounter > 1){ ChangeAction(ANIMSTATE_SHOW); } } private void ShowAction(){ ChangeAction(ANIMSTATE_DISAPPEAR); } private void DisappearAction(){ if(_animGUI === null) { return; } _timeCounter += hsSystemGetDeltaTime() * PARTICLE_ANIM_SPEED; float animScale = particleSize * (easeOutBack(1 - _timeCounter)); _animGUI.SetSize(animScale, animScale); MoveYaxis(1); if(_timeCounter > 1){ ChangeAction(ANIMSTATE_DELETE); } } private void DeleteAction(){ hsReleaseGUI(_layerName, false, _guiName); _isAnimEnd = true; } private void MoveYaxis(int moveSpeed){ float posX, posY = 0; _animGUI.GetPos(posX, posY); _animGUI.SetPos(posX, posY - moveSpeed); } private void ChangeAction(int nextStateID){ if(_currentState == nextStateID) { return; } _currentState = nextStateID; _timeCounter = 0; } private float easeOutBack(float _time){ float t = GetMin(1, GetMax(0, _time)); float c1 = 1.70158; float c3 = c1 + 1; return 1 + c3 * MathPow(t - 1, 3) + c1 * MathPow(t - 1, 2); } private float easeOutElastic(float _time){ float t = GetMin(1, GetMax(0, _time)); float c4 = (2 * PI) / 3; float val = 0; val = MathPow(2, -10 * t) * hsMathSin((t * 10 - 0.75) * c4) + 1; if(t == 0 ){ val = 0; } if(t == 1 ){ val = 1; } return val; } private float MathPow(float _bace, float _exponent){ float operationResult = _bace; int i; for(i = 1; i < _exponent; i++){ operationResult *= _bace; } return operationResult; } private float GetMin(float a, float b){ float returnVal = a; if(a > b){ returnVal = b; } return returnVal; } private float GetMax(float a, float b){ float returnVal = a; if(a < b){ returnVal = b; } return returnVal; } } // --- \EmoteIconParticleController.hs --- component EmoteIconParticleController{ public EmoteIconParticleController(){ } } // --- \EmoteIconParticleView.hs --- class EmoteIconParticleView{ int createEmoteCounter; const bool USE_PORTRAIT_FLAG = true; const bool USE_LANDSCAPE_FLAG = false; public EmoteIconParticleView(){ createEmoteCounter = 0; } public void CreateEmoteIcon(string emoteIconURL){ string layerName = "HUD"; string guiName = "emoteIcon_%d" % createEmoteCounter; HSImageModel imageModel = MakeHSImageModel(emoteIconURL); GUIElement laGUIDefaultPos = hsLayerGetLandscape(layerName).GetGUIElement("preview_chat_bg"); float laPosX, laPosY = 0; laGUIDefaultPos.GetPos(laPosX, laPosY); float laSizeW, laSizeH = 0; laGUIDefaultPos.GetSize(laSizeW, laSizeH); laPosX -= hsMathRandom(laSizeW); // 横画面 HSGUIModel laGuiModel = MakeCommonHSGUIMoel(guiName, "image"); laGuiModel.SetImageModel(imageModel); laGuiModel.SetSize(MakeHS2DI(0, 0)); laGuiModel.SetPos(MakeHS2DI(laPosX, laPosY)); laGuiModel.SetZ(2); GUIElement poGUIDefaultPos = hsLayerGetPortrait(layerName).GetGUIElement("preview_chat_bg"); float poPosX, poPosY = 0; poGUIDefaultPos.GetPos(poPosX, poPosY); float poSizeW, poSizeH = 0; poGUIDefaultPos.GetSize(poSizeW, poSizeH); poPosX += poSizeW/2; // po版のpreview_chat_bgのpivotが0.5,1なので生成座標を調整 poPosX -= hsMathRandom(poSizeW); // 縦画面 HSGUIModel poGuiModel = MakeCommonHSGUIMoel(guiName, "image"); poGuiModel.SetImageModel(imageModel); poGuiModel.SetSize(MakeHS2DI(0, 0)); poGuiModel.SetPos(MakeHS2DI(poPosX, poPosY)); poGuiModel.SetZ(2); // 登録 hsCanvasAddGUI("HUD", USE_LANDSCAPE_FLAG, laGuiModel); hsCanvasAddGUI("HUD", USE_PORTRAIT_FLAG, poGuiModel); hsDispatchEvent("addEmoteIcon", "%s:%b:%s" % layerName % USE_LANDSCAPE_FLAG % guiName); hsDispatchEvent("addEmoteIcon", "%s:%b:%s" % layerName % USE_PORTRAIT_FLAG % guiName); ++createEmoteCounter; } // ImageModelの生成 private HSImageModel MakeHSImageModel(string imageFilePath){ HSImageModel imageModel = new HSImageModel(); imageModel.SetURI(imageFilePath); return imageModel; } // TextModelの生成 private HSTextModel MakeHSTextModel(string text, int fontSize){ HSTextModel textModel = new HSTextModel(); textModel.SetFontSize(fontSize); textModel.SetText(text); textModel.SetFontFamily("BIZUDPGothic"); textModel.SetAlignment("CM"); textModel.SetOverflowWrap(true); HSColor fontColor = MakeHSColor(0.9, 0.9, 0.9 ,1); textModel.SetColor(fontColor); return textModel; } // ButtonModelの生成 public HSButtonModel MakeButtonGUIModel(string imageFilePath){ HSButtonModel buttonModel = new HSButtonModel(); buttonModel.SetFileName(imageFilePath); return buttonModel; } // どのタイプの要素でも共通するセットアップ private HSGUIModel MakeCommonHSGUIMoel(string modelName, string modelType){ HSGUIModel model = new HSGUIModel(); model.SetName(modelName); model.SetShow(true); model.SetType(modelType); model.SetRaycastTarget(false); int defaultZ = 1; model.SetZ(defaultZ); HS2D pivot = new HS2D(); pivot.SetXY(0.5, 1.0); model.SetPivot(pivot); model.SetAnchor("CB"); return model; } private HSRectLTRB MakeRectLTRB(int l,int t,int r,int b){ HSRectLTRB ltrb = new HSRectLTRB(); ltrb.SetLTRB(l, t, r, b); return ltrb; } // 座標、サイズ管理用 HS2DI生成関数 private HS2DI MakeHS2DI(int x, int y){ HS2DI hs2di = new HS2DI(); hs2di.SetXY(x, y); return hs2di; } // GUIの色指定用 HSColor生成関数 private HSColor MakeHSColor(float r, float g, float b, float a){ HSColor hsColor = new HSColor(); hsColor.SetRGBA(r, g, b, a); return hsColor; } // UVエリア用 HSRect生成関数 private HSRect MakeHSRect(int x, int y, int w, int h){ HSRect hsrect = new HSRect(); hsrect.SetXYWH(x, y, w, h); return hsrect; } } // --- \EmoteIconParticleViewModel.hs --- component EmoteIconParticleViewModel{ EmoteIconParticleView eView; list particleAnimList; public EmoteIconParticleViewModel(){ particleAnimList = new list(); eView = new EmoteIconParticleView(); hsAddEventListener("emoteIcon", eView.CreateEmoteIcon); hsAddEventListener("addEmoteIcon", AddParticleAnim); } public void Update(){ for(int i = particleAnimList.Count()-1; i >= 0; i--){ particleAnimList[i].ParticleAnimation(); if(particleAnimList[i].IsAnimEnd()){ particleAnimList.RemoveAt(i); } } } public void AddParticleAnim(string param){ EmoteIconParticleAnimator anim = new EmoteIconParticleAnimator(); list paramData = param.Split(":"); int layerIndex = 0; int portraitFlagIndex = 1; int guiNameIndex = 2; anim.FindGUIElement(paramData[layerIndex], paramData[portraitFlagIndex], paramData[guiNameIndex]); particleAnimList.Add(anim); } }