LayaBox实现2D游戏八方向虚拟摇杆

在使用Laya引擎制作自己的小游戏时,需要用到虚拟摇杆来控制人物移动,在百度搜素了许多案例之后,结合自己的情况记录如下Demo。
先看看效果:


运行效果

1.实现思路

图1

如上图“图1”所示,在数学直角坐标系中,将一个圆平分成8块,每一块对应一个方向,即 1->左、2->左上、3->上、4->右上、5->右、6->右下、7->下、8->左下,以x轴正方为起始点,逆时针旋转,即各个方向对应的角度分别为 1->左->[337.5°~22.5°)、2->左上->[22.5°~67.5°)、3->上->[67.5°~112.5°)、4->右上->[112.5°~157.5°)、5->右->[157.5°~202.5°)、6->右下->[202.5°~247.5°)、7->下->[247.5°~292.5°)、8->左下->[292.5°~337.5°)



那么如何计算出移动的方向呢?这就需要用到反三角函数(acos、asin、atan...)了,如下图“图2”所示:

图2

通过反三角函数计算出α对应的弧度,在将弧度转换成角度即可。

2.使用LayaAirIDE编辑场景
说明:我是用的是LayaAir_2_01版本以及ActionScript3.0语言
在编辑模式先新建一个场景,在场景中添加虚拟摇杆所需要用到的两张图片,并分别为其命名,如下图“图3”所示:

图3

然后发布,我是用 分离模式 发布该资源,该模式会生成一个场景类以及json文件。之后再src下新建一个名为script的文件夹用于放置脚本类文件,在该文件夹下新建一个名为 StartScene 脚本并继承 TestSceneUI 类,作为场景的 runTime 脚本,如下图“图4”、“图5”所示:


图4

图5

然后切回编辑模式,将 StartScene 脚本设置为场景的runTime 脚本。如下图“图6”所示:


图6

3.编写代码
接下来就正在进入正题啦,废话已经说过了,直接先给出代码,再看后面的说明内容:

package script {
    import laya.components.Script;
    import ui.TestSceneUI;
    import laya.display.Stage;
    import laya.display.Sprite;
    import laya.events.Event;
    import laya.display.Text;
    import laya.utils.Tween;
    import laya.utils.Ease;
    
    public class StartScene extends TestSceneUI {
        // 小圆被拉动的最远半径
        private const RADIUS:Number = 80;

        // 小圆组件
        private var smallCircle:Sprite;
        
        // 大圆组件
        private var bigCircle:Sprite;
        
        // 用于显示角度的文本
        private var text:Text;

        /**
         * 构造函数
         * 需加载父类的构造函数
         */
        public function StartScene():void {
            super();
        }

        override public function onEnable():void {
            Laya.init(1000, 800);
            Laya.stage.scaleMode = Stage.SCALE_FULL;

            // 获取两个圆组件
            smallCircle = this.getChildByName("smallCircle") as Sprite;
            bigCircle = this.getChildByName("bigCircle") as Sprite;
            
            // 用于显示文字
            text = new Text();
            text.pos(Laya.stage.width / 2, Laya.stage.height / 2);
            text.color = '#ffffff';
            text.fontSize = 20;
            this.addChild(text);
            
            // 给小圆添加鼠标按下侦听事件
            smallCircle.on(Event.MOUSE_DOWN, this, onSmallClickDown);
            
            // 鼠标抬起时
            Laya.stage.on(Event.MOUSE_UP, this, onSmallClickUp);
        }
        

        /**
         * 鼠标按下小圆侦听事件
         */
        private function onSmallClickDown():void {
            // 点击时为小圆注册
            Laya.stage.on(Event.MOUSE_MOVE, this, onSmallClickMove);
        }

        /**
         * 鼠标抬起侦听事件
         */
        private function onSmallClickUp():void {
            // 取消鼠标移动事件
            Laya.stage.off(Event.MOUSE_MOVE, this, onSmallClickMove);
            // 小圆返回中心位置
            Tween.to(smallCircle, {x:bigCircle.x, y:bigCircle.y}, 300, Ease.backIn);
        }

        private function onSmallClickMove():void {
            // 鼠标与大圆中心x、y轴的距离
            var xx:Number = Laya.stage.mouseX - bigCircle.x;
            var yy:Number = Laya.stage.mouseY - bigCircle.y;
            // 勾股定理求斜边
            var obl:Number = Math.sqrt(Math.pow(xx, 2) + Math.pow(yy, 2));
            // 求弧度
            var rad:Number = getRad(xx, yy, obl);
            // 弧度转角度
            var angle:Number = 180 / Math.PI * rad;
            // 在文本框中显示角度
            text.text = angle + "度";
            // 限制小圆移动范围
            if (obl > RADIUS) {
                // 当鼠标与大圆中心超过移动半径 RADIUS 时,停止小圆继续往外移动
                // 通过三角形边与边的比例计算出小圆应该处于的位置
                var smallCircleX:Number = (RADIUS * xx) / obl + bigCircle.x;
                var smallCircleY:Number = (RADIUS * yy) / obl + bigCircle.y;
                smallCircle.pos(smallCircleX, smallCircleY);
            } else {
                // 小圆处于大圆之中时,与鼠标同一位置
                smallCircle.pos(Laya.stage.mouseX, Laya.stage.mouseY);  
            }
        }


        /**
         * 求弧度函数
         * @param xx : x轴距离
         * @param yy : y轴距离
         * @param obl : 斜边
         */
        private function getRad(xx:Number, yy:Number, obl:Number):Number {
            // 方法一:asin()
            // var rad:Number = xx > 0 ? ((Math.PI * 3)/2  + Math.asin(-yy/obl)) : (Math.PI / 2 -  Math.asin(-yy/obl));
            
            // 方法二:acos()
            var rad:Number = yy < 0 ? Math.acos(xx / obl) : (Math.PI * 2- Math.acos(xx / obl));
            
            // 方法三:atan2()
            // var rad:Number = yy < 0 ? Math.atan2(-yy, xx) : Math.PI * 2 + Math.atan2(-yy, xx);
            return rad;
        }

        override public function onDisable():void {
        }
    }
}

注意:
 1.在Laya坐标系中,与数学直角坐标系不同的是Laya坐标系y轴向下为正放,数学直角坐标系y轴向上为正方。
 2.如果使用方法一,则起始点为y轴的上方,也就是y轴的负方向。
 3.当a大于180度时候,a的余弦值等于(360-a)的余弦,其他两个方法根据三角函数和反三角函数的性质推推导一下即可得出,或是推导不出的话就直接在代码中打印实时的弧度值,再去理解。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343