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)的余弦,其他两个方法根据三角函数和反三角函数的性质推推导一下即可得出,或是推导不出的话就直接在代码中打印实时的弧度值,再去理解。

你可能感兴趣的:(LayaBox实现2D游戏八方向虚拟摇杆)