基于egret的点光源光线效果的实现

先上效果图

基于egret的点光源光线效果的实现_第1张图片基于egret的点光源光线效果的实现_第2张图片

白色区域为光线区域,黑色区域为阴影区域,光源可以自定义坐标,同时可以添加位图作为光源样式。

代码实现主要包含两个函数,一个是计算光源产生的射线与个图形相交的坐标,一个用于绘制图形

getIntersection(ray, segment) {//计算交点
            var r_px = ray.a.x;
            var r_py = ray.a.y;
            var r_dx = ray.b.x - ray.a.x;
            var r_dy = ray.b.y - ray.a.y;

            var s_px = segment.a.x;
            var s_py = segment.a.y;
            var s_dx = segment.b.x - segment.a.x;
            var s_dy = segment.b.y - segment.a.y;

            var r_mag = Math.sqrt(r_dx * r_dx + r_dy * r_dy);
            var s_mag = Math.sqrt(s_dx * s_dx + s_dy * s_dy);
            if (r_dx / r_mag == s_dx / s_mag && r_dy / r_mag == s_dy / s_mag) { 
                return null;
            }

            var T2 = (r_dx * (s_py - r_py) + r_dy * (r_px - s_px)) / (s_dx * r_dy - s_dy * r_dx);
            var T1 = (s_px + s_dx * T2 - r_px) / r_dx;

            if (T1 < 0) return null;
            if (T2 < 0 || T2 > 1) return null;

            return {
                x: r_px + r_dx * T1,
                y: r_py + r_dy * T1,
                param: T1
            };

        }


draw(x, y) {
            this.ctx.clear();
            for (var i = 0; i < this.segments.length; i++) {
                var seg = this.segments[i];
                this.ctx.lineStyle(2, 0xffffff);
                this.ctx.moveTo(seg.a.x, seg.a.y);
                this.ctx.lineTo(seg.b.x, seg.b.y);
            }

            var points = (function (args) {
                var a = [];
                args.forEach(function (seg) {
                    a.push(seg.a, seg.b);
                });
                return a;
            })(this.segments);
            var uniquePoints = (function (points) {
                var set = {};
                return points.filter(function (p) {
                    var key = p.x + "," + p.y;
                    if (key in set) {
                        return false;
                    } else {
                        set[key] = true;
                        return true;
                    }
                });
            })(points);
            var uniqueAngles = [];
            for (var j = 0; j < uniquePoints.length; j++) {
                var uniquePoint = uniquePoints[j];
                var angles = Math.atan2(uniquePoint.y - y, uniquePoint.x - x);
                uniquePoint.angle = angles;
                uniqueAngles.push(angles - 0.00001, angles, angles + 0.00001);
            }

            var insert = [];
            for (var j = 0; j < uniqueAngles.length; j++) {
                var angle = uniqueAngles[j];
                var dx = Math.cos(angle);
                var dy = Math.sin(angle);
                var ray = {
                    a: { x: x, y: y },
                    b: { x: x + dx, y: y + dy }
                };

                var closestIntersect = null;
                for (var i = 0; i < this.segments.length; i++) {
                    var intersect = this.getIntersection(ray, this.segments[i]);
                    if (!intersect) continue;
                    if (!closestIntersect || intersect.param < closestIntersect.param) {
                        closestIntersect = intersect;
                    }
                }
                if (!closestIntersect) continue;
                closestIntersect.angle = angle;
                insert.push(closestIntersect);
            }
            insert = insert.sort(function (a, b) {
                return a.angle - b.angle;
            });

            this.ctx.beginFill( 0xffffff,1);
            this.ctx.moveTo(insert[0].x, insert[0].y);
            for (var i = 0; i < insert.length; i++) {
                var _insert = insert[i];
                this.ctx.lineTo(_insert.x, _insert.y);
            }
            this.ctx.endFill();
        }
        segments = [//图形顶点坐标

            { a: { x: 0, y: 0 }, b: { x: 640, y: 0 } },
            { a: { x: 640, y: 0 }, b: { x: 640, y: 360 } },
            { a: { x: 640, y: 360 }, b: { x: 0, y: 360 } },
            { a: { x: 0, y: 360 }, b: { x: 0, y: 0 } },

            { a: { x: 100, y: 150 }, b: { x: 120, y: 50 } },
            { a: { x: 120, y: 50 }, b: { x: 200, y: 80 } },
            { a: { x: 200, y: 80 }, b: { x: 140, y: 210 } },
            { a: { x: 140, y: 210 }, b: { x: 100, y: 150 } },

            { a: { x: 100, y: 200 }, b: { x: 120, y: 250 } },
            { a: { x: 120, y: 250 }, b: { x: 60, y: 300 } },
            { a: { x: 60, y: 300 }, b: { x: 100, y: 200 } },

            { a: { x: 200, y: 260 }, b: { x: 220, y: 150 } },
            { a: { x: 220, y: 150 }, b: { x: 300, y: 200 } },
            { a: { x: 300, y: 200 }, b: { x: 350, y: 320 } },
            { a: { x: 350, y: 320 }, b: { x: 200, y: 260 } },

            { a: { x: 340, y: 60 }, b: { x: 360, y: 40 } },
            { a: { x: 360, y: 40 }, b: { x: 370, y: 70 } },
            { a: { x: 370, y: 70 }, b: { x: 340, y: 60 } },

            { a: { x: 450, y: 190 }, b: { x: 560, y: 170 } },
            { a: { x: 560, y: 170 }, b: { x: 540, y: 270 } },
            { a: { x: 540, y: 270 }, b: { x: 430, y: 290 } },
            { a: { x: 430, y: 290 }, b: { x: 450, y: 190 } },

            { a: { x: 400, y: 95 }, b: { x: 580, y: 50 } },
            { a: { x: 580, y: 50 }, b: { x: 480, y: 150 } },
            { a: { x: 480, y: 150 }, b: { x: 400, y: 95 } }
        ];


draw()函数传入光源点坐标。后期可以根据游戏需要,通过遮罩实现光源的形式变化(如锥形光),同时结合地图障碍物制作动态光源,实现动态光影效果。


你可能感兴趣的:(egret)