最早實現這個效果,是2011年用Objective-C在iOS裡實現的。原倉庫地址:https://code.google.com/archive/p/ccjoystick/downloads
在Vue裡實現這個東西沒啥用處,畢竟Vue也不是一個遊戲框架,但是誰叫Vue這個話題的熱度最高呢😁,寫文章還是希望被更多人看到嘛...
印象裡我在不同時期曾經用三種語言分別實現過這個案例。所以無論用什麼框架、語言,只要你了解背後的原理,都很容易實現。
當然沒有第二層和第三層是不影響搖杆功能的,但誰叫我是一個擬物流的前端偏執狂呢?
搖杆嘛,圓形的洞裡有根杆(不要汙呀),所以我們必須把拖拽限制在一個圓形區域裡。
onTouchMove(e){
代碼中比較核心的部分是:我們先通過所在點和原點位置求出半徑distance,以及之間的夾角角度angle。然後通過限定半徑和夾角角度還原出x,y的坐標。就可以達到控制拖動在圓形區域內的效果了。
var curTouch=e.touches[0];
var tleft=curTouch.clientX-startLeft;
var ttop=curTouch.clientY-startTop;
//獲取點擊位置和起點的直線距離,也就是半徑
var distance = getDistance(tleft,ttop,0,0);
//如果這個距離是否大於圓形可移動區域的半徑,則強行變更
if(distance>=this.ballMoveRadius)distance = this.ballMoveRadius;
//最後通過夾角,正弦,餘弦,半徑還原x,y坐標
var angle = Math.atan2((ttop-0), (tleft-0));
this.left=Math.cos(angle)*distance;
this.top=Math.sin(angle)*distance;
}//獲取兩點間直線距離的算法
var getDistance=function(x1, y1, x2, y2) {
var _x = Math.abs(x1 - x2);
var _y = Math.abs(y1 - y2);
return Math.sqrt(_x * _x + _y * _y);
}
03 羞澀的杆體杆體是這裡面最麻煩的一塊,需要通過搖杆的拖拽的距離變化長度,同時根據搖杆的位置旋轉角度。<view class='stick' :class="{animation:inDraging===false&&transition}" :style="{height: stickHeight+'px',transform:'translateX(-50%)'}">
<view :style="{transform:'rotate('+(angle/(3.14159/180)-90)+'deg)'}" style="transform-origin: 50% 0%;width: 100%;height: 100%;">
<slot name="stick">
</slot>
</view>
</view>這裡我用了兩層dom來完成這個杆體,一層用height進行高度變化,一層用transfrom設置旋轉角度和旋轉中心點。大家有更好的實現方法嗎,在評論區告訴我吧。
夾角轉為旋轉角度算法angle/(3.14159/180),減去90是為了讓度數起點在12點鐘的位置。
onTouchMove(e){
現在搖杆UE基本就完成了,接下來我們要輸出一些數值,畢竟搖杆不能光自己搖,得用來控制其他的元素進行運動。 04 搖杆數值
var curTouch=e.touches[0];
var tleft=curTouch.clientX-startLeft;
var ttop=curTouch.clientY-startTop;
var distance = getDistance(tleft,ttop,0,0);
if(distance>=this.ballMoveRadius)distance = this.ballMoveRadius;
var angle = Math.atan2((ttop-0), (tleft-0));
this.left=Math.cos(angle)*distance;
this.top=Math.sin(angle)*distance;
//同步杆體的高度,旋轉角度
this.stickHeight = distance;
this.angle = angle;
}方向我們在杆體運動的時候,已經寫完了,就是那個角度angle。
power = 當前半徑/最大半徑;
搖杆力度這件事在拳皇裡是不存在的,但是在很多遊戲中分輕推和重推(其實就是搖杆當前距離和最大距離的比),比如輕推是走,重推是跑。gif有點掉幀,大家能看出來運動的快慢嗎?
05 組件化
現在把上面的成果封裝成一個vue組件,方便復用。
<ezjoystick
:touchRadius="100"
:ballMoveRadius="50"
:transition="true"
@onJoyStickUpdate="onBeetleJoystickUpdate"
>
<view slot="ball">
</view>
<view slot="stick">
</view>
<view slot="bottom">
</view>
</ezjoystick>
ballMoveRadius 桿頭的最大移動範圍半徑三個slot
三個slot都是非必須的,不填的話,該部分就是空dom。具體可參考源碼。
onJoystickUpdate 有數值變化就會觸發
06 實現經典UI組件封裝好了,接下來用咱們這個組件實現幾個經典的界面吧
模擬十字鍵,核心是把角度轉成4個方向,這裡我隨手寫了一下,應該有更優雅的實現。
onCrossJoyStickUpdate(obj){
this.crossupPressed=false;
this.crossrightPressed=false;
this.crossdownPressed=false;
this.crossleftPressed=false;
if(obj.angle>-2.35&&obj.angle<-0.75){
this.crossupPressed=true;
}else if(obj.angle>-0.75&&obj.angle<0.75){
this.crossrightPressed=true;
}else if(obj.angle>0.75&&obj.angle<2.35){
this.crossdownPressed=true;
}else{
this.crossleftPressed=true;
}
}
07 源碼倉庫https://github.com/ezshine/ezjoystickclone源碼後使用HBuilerX打開可以快速看到實例,或將components複製到vuecli項目中導入使用。數位化人才教育平臺開課吧已獲5.5億美元獨立融資,領跑新職業教育賽道,累積累積文獻超過500萬。我們整合了全球知名度IT和網際網路企業一線師資,提供Java,Web前端,數據分析,Python ,人工智慧,產品運營,智能物聯等技術課程。您將與國內外知名院校的畢業生及各大廠的職場精英,共同探索計算機科學帶來的世界變革。