设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 617|回复: 1
打印 上一主题 下一主题

[原创发布] 【MZ插件】CRT显示器扫描线和随机故障等效果

[复制链接]

Lv3.寻梦者

梦石
0
星屑
2246
在线时间
1010 小时
注册时间
2012-4-30
帖子
1500

开拓者

跳转到指定楼层
1
发表于 2026-2-28 15:20:28 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
指挥AI写的,效果还不赖,分享出来,功能文档里写的很明白了,不过自己感觉故障效果没那么完美,勉强可以用,MV 不知道能不能用可以自行测试



本来录屏的转gif有点糊,明白我意思就好

JAVASCRIPT 代码复制下载
  1. /*:
  2.  * @target MZ
  3.  * @plugindesc CRT 显示器滤镜,包含扫描线、屏幕曲率、暗角、色差和随机故障效果。
  4.  * @author enpitsulin
  5.  *
  6.  * @param scanlineIntensity
  7.  * @text 扫描线强度
  8.  * @desc 扫描线效果的强度 (0.0 - 1.0)。
  9.  * @type number
  10.  * @decimals 2
  11.  * @min 0
  12.  * @max 1
  13.  * @default 0.35
  14.  *
  15.  * @param curvatureAmount
  16.  * @text 屏幕曲率
  17.  * @desc 桶形畸变的程度 (0.0 - 1.0)。
  18.  * @type number
  19.  * @decimals 2
  20.  * @min 0
  21.  * @max 1
  22.  * @default 0.25
  23.  *
  24.  * @param vignetteIntensity
  25.  * @text 暗角强度
  26.  * @desc 屏幕边缘暗化的程度 (0.0 - 1.0)。
  27.  * @type number
  28.  * @decimals 2
  29.  * @min 0
  30.  * @max 1
  31.  * @default 0.30
  32.  *
  33.  * @param chromaticAberration
  34.  * @text 色差强度
  35.  * @desc RGB 通道分离的程度 (0.0 - 1.0)。
  36.  * @type number
  37.  * @decimals 2
  38.  * @min 0
  39.  * @max 1
  40.  * @default 0.15
  41.  *
  42.  * @param colorBleeding
  43.  * @text 色溢强度
  44.  * @desc 红色通道水平扩散的程度 (0.0 - 1.0)。
  45.  * @type number
  46.  * @decimals 2
  47.  * @min 0
  48.  * @max 1
  49.  * @default 0.12
  50.  *
  51.  * @param glitchFrequency
  52.  * @text 故障频率
  53.  * @desc 故障效果平均间隔秒数。
  54.  * @type number
  55.  * @decimals 1
  56.  * @min 0
  57.  * @default 5.0
  58.  *
  59.  * @param glitchIntensity
  60.  * @text 故障强度
  61.  * @desc 故障效果的最大强度 (0.0 - 1.0)。
  62.  * @type number
  63.  * @decimals 2
  64.  * @min 0
  65.  * @max 1
  66.  * @default 0.60
  67.  *
  68.  * @param glitchEnabled
  69.  * @text 启用故障效果
  70.  * @desc 是否启用随机故障效果(手动触发仍然可用)。
  71.  * @type boolean
  72.  * @default true
  73.  *
  74.  * @param enabled
  75.  * @text 默认启用
  76.  * @desc 是否默认启用 CRT 滤镜效果。
  77.  * @type boolean
  78.  * @default true
  79.  *
  80.  * @command setEnabled
  81.  * @text 设置启用状态
  82.  * @desc 启用或禁用 CRT 滤镜效果。
  83.  *
  84.  * @arg enabled
  85.  * @text 启用
  86.  * @type boolean
  87.  * @default true
  88.  *
  89.  * @command setGlitchEnabled
  90.  * @text 设置故障效果启用状态
  91.  * @desc 启用或禁用随机故障效果(手动触发仍然可用)。
  92.  *
  93.  * @arg enabled
  94.  * @text 启用
  95.  * @type boolean
  96.  * @default true
  97.  *
  98.  * @command triggerGlitch
  99.  * @text 触发故障效果
  100.  * @desc 手动触发一次故障效果。
  101.  *
  102.  * @arg duration
  103.  * @text 持续时间(帧)
  104.  * @desc 故障效果的持续帧数(默认:随机 10-40)。
  105.  * @type number
  106.  * @min 1
  107.  * @default 0
  108.  *
  109.  * @command setGlitchFrequency
  110.  * @text 设置故障频率
  111.  * @desc 更改自动故障效果的平均间隔。
  112.  *
  113.  * @arg frequency
  114.  * @text 频率(秒)
  115.  * @type number
  116.  * @decimals 1
  117.  * @min 0
  118.  * @default 5.0
  119.  *
  120.  * @help
  121.  * CRTFilter.js
  122.  *
  123.  * 为游戏画面应用 CRT(阴极射线管)显示器效果,包括扫描线、桶形畸变、
  124.  * 暗角、色差和周期性故障效果。
  125.  *
  126.  * 此滤镜钩入 Spriteset_Base,因此会同时应用于地图场景和战斗场景。
  127.  *
  128.  * 插件命令:
  129.  *   setEnabled          - 开启/关闭 CRT 效果
  130.  *   setGlitchEnabled    - 开启/关闭自动故障效果
  131.  *   triggerGlitch       - 手动触发故障效果
  132.  *   setGlitchFrequency  - 更改自动故障间隔
  133.  */
  134.  
  135. void (function () {
  136.   "use strict";
  137.  
  138.   var PLUGIN_NAME = "CRTFilter";
  139.   var params = PluginManager.parameters(PLUGIN_NAME);
  140.  
  141.   var SETTINGS = {
  142.     scanlineIntensity: Number(params["scanlineIntensity"] || 0.35),
  143.     curvatureAmount: Number(params["curvatureAmount"] || 0.25),
  144.     vignetteIntensity: Number(params["vignetteIntensity"] || 0.30),
  145.     chromaticAberration: Number(params["chromaticAberration"] || 0.15),
  146.     colorBleeding: Number(params["colorBleeding"] || 0.12),
  147.     glitchFrequency: Number(params["glitchFrequency"] || 5.0),
  148.     glitchIntensity: Number(params["glitchIntensity"] || 0.60),
  149.     glitchEnabled: params["glitchEnabled"] !== "false",
  150.     enabled: params["enabled"] !== "false",
  151.   };
  152.  
  153.   // =========================================================================
  154.   // GlitchStateMachine Class - Manages glitch timing and state
  155.   // =========================================================================
  156.  
  157.   function GlitchStateMachine() {
  158.     this.initialize.apply(this, arguments);
  159.   }
  160.  
  161.   GlitchStateMachine.prototype.initialize = function (options) {
  162.     this.state = "cooldown"; // cooldown | attack | sustain | release
  163.     this.timer = 0;
  164.     this.phaseTimer = 0;
  165.     this.duration = 0;
  166.     this.maxIntensity = options.maxIntensity || 0.6;
  167.     this.frequency = options.frequency || 5.0;
  168.     this.enabled = options.glitchEnabled !== false;
  169.     this.currentIntensity = 0;
  170.     this.cooldownTarget = this._randomCooldown();
  171.   };
  172.  
  173.   GlitchStateMachine.prototype._randomCooldown = function () {
  174.     var base = this.frequency * 60;
  175.     return Math.floor(base * 0.5 + Math.random() * base);
  176.   };
  177.  
  178.   GlitchStateMachine.prototype._randomDuration = function () {
  179.     return Math.floor(10 + Math.random() * 30);
  180.   };
  181.  
  182.   GlitchStateMachine.prototype.update = function () {
  183.     switch (this.state) {
  184.       case "cooldown":
  185.         this.timer++;
  186.         if (this.enabled && this.timer >= this.cooldownTarget) {
  187.           this.trigger(0);
  188.         }
  189.         break;
  190.  
  191.       case "attack": {
  192.         this.phaseTimer++;
  193.         var attackLen = Math.max(1, Math.floor(this.duration * 0.2));
  194.         var t = this.phaseTimer / attackLen;
  195.         this.currentIntensity = t * this.maxIntensity;
  196.         if (this.phaseTimer >= attackLen) {
  197.           this.state = "sustain";
  198.           this.phaseTimer = 0;
  199.         }
  200.         break;
  201.       }
  202.  
  203.       case "sustain": {
  204.         this.phaseTimer++;
  205.         var sustainLen = Math.max(
  206.           1,
  207.           Math.floor(this.duration * 0.5)
  208.         );
  209.         this.currentIntensity = this.maxIntensity;
  210.         if (this.phaseTimer >= sustainLen) {
  211.           this.state = "release";
  212.           this.phaseTimer = 0;
  213.         }
  214.         break;
  215.       }
  216.  
  217.       case "release": {
  218.         this.phaseTimer++;
  219.         var releaseLen = Math.max(
  220.           1,
  221.           Math.floor(this.duration * 0.3)
  222.         );
  223.         var rt = 1 - this.phaseTimer / releaseLen;
  224.         this.currentIntensity = rt * this.maxIntensity;
  225.         if (this.phaseTimer >= releaseLen) {
  226.           this._end();
  227.         }
  228.         break;
  229.       }
  230.     }
  231.   };
  232.  
  233.   GlitchStateMachine.prototype.trigger = function (duration) {
  234.     this.state = "attack";
  235.     this.phaseTimer = 0;
  236.     this.duration = duration > 0 ? duration : this._randomDuration();
  237.   };
  238.  
  239.   GlitchStateMachine.prototype._end = function () {
  240.     this.state = "cooldown";
  241.     this.timer = 0;
  242.     this.phaseTimer = 0;
  243.     this.currentIntensity = 0;
  244.     this.cooldownTarget = this._randomCooldown();
  245.   };
  246.  
  247.   GlitchStateMachine.prototype.setEnabled = function (value) {
  248.     this.enabled = value;
  249.   };
  250.  
  251.   GlitchStateMachine.prototype.setFrequency = function (seconds) {
  252.     this.frequency = seconds;
  253.   };
  254.  
  255.   GlitchStateMachine.prototype.getIntensity = function () {
  256.     return this.currentIntensity;
  257.   };
  258.  
  259.   // =========================================================================
  260.   // Fragment Shader (GLSL ES 1.0)
  261.   // =========================================================================
  262.  
  263.   var FRAGMENT_SRC =
  264.     "precision mediump float;" +
  265.     "varying vec2 vTextureCoord;" +
  266.     "uniform sampler2D uSampler;" +
  267.     "uniform float uTime;" +
  268.     "uniform float uScanlineIntensity;" +
  269.     "uniform float uCurvature;" +
  270.     "uniform float uVignette;" +
  271.     "uniform float uChromatic;" +
  272.     "uniform float uBleeding;" +
  273.     "uniform float uGlitchStrength;" +
  274.     "uniform float uGlitchSeed;" +
  275.     "" +
  276.     "float rand(vec2 co) {" +
  277.     "  return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);" +
  278.     "}" +
  279.     "" +
  280.     "vec2 curveUV(vec2 uv, float amount) {" +
  281.     "  vec2 c = uv - 0.5;" +
  282.     "  float r2 = dot(c, c);" +
  283.     "  vec2 curved = uv + c * r2 * amount * 0.5;" +
  284.     "  return curved;" +
  285.     "}" +
  286.     "" +
  287.     "void main() {" +
  288.     "  vec2 uv = vTextureCoord;" +
  289.     "" +
  290.     "  uv = curveUV(uv, uCurvature);" +
  291.     "" +
  292.     "  if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) {" +
  293.     "    gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);" +
  294.     "    return;" +
  295.     "  }" +
  296.     "" +
  297.     "  float bandY = floor(uv.y * 20.0);" +
  298.     "  float bandRand = rand(vec2(bandY, uGlitchSeed));" +
  299.     "  float displacement = 0.0;" +
  300.     "  if (uGlitchStrength > 0.0 && bandRand > 0.7) {" +
  301.     "    displacement = (bandRand - 0.7) / 0.3 * 0.06 * uGlitchStrength;" +
  302.     "    displacement *= sign(rand(vec2(bandY + 1.0, uGlitchSeed)) - 0.5);" +
  303.     "  }" +
  304.     "  vec2 glitchUV = vec2(uv.x + displacement, uv.y);" +
  305.     "" +
  306.     "  float caBase = uChromatic * 0.004;" +
  307.     "  float caGlitch = uGlitchStrength * 0.012;" +
  308.     "  float caAmount = caBase + caGlitch;" +
  309.     "" +
  310.     "  float r = texture2D(uSampler, vec2(glitchUV.x + caAmount, glitchUV.y)).r;" +
  311.     "  float g = texture2D(uSampler, glitchUV).g;" +
  312.     "  float b = texture2D(uSampler, vec2(glitchUV.x - caAmount, glitchUV.y)).b;" +
  313.     "  float a = texture2D(uSampler, glitchUV).a;" +
  314.     "" +
  315.     "  float bleedOffset = uBleeding * 0.003;" +
  316.     "  float rBleed = texture2D(uSampler, vec2(glitchUV.x + bleedOffset, glitchUV.y)).r;" +
  317.     "  r = mix(r, rBleed, 0.5);" +
  318.     "" +
  319.     "  float scanline = 1.0 - uScanlineIntensity * 0.5 * (1.0 - cos(vTextureCoord.y * 1000.0 * 3.14159 * 2.0));" +
  320.     "  r *= scanline;" +
  321.     "  g *= scanline;" +
  322.     "  b *= scanline;" +
  323.     "" +
  324.     "  vec2 vig = uv - 0.5;" +
  325.     "  float vigDist = dot(vig, vig);" +
  326.     "  float vigFactor = 1.0 - vigDist * uVignette * 2.5;" +
  327.     "  vigFactor = clamp(vigFactor, 0.0, 1.0);" +
  328.     "  r *= vigFactor;" +
  329.     "  g *= vigFactor;" +
  330.     "  b *= vigFactor;" +
  331.     "" +
  332.     "  if (uGlitchStrength > 0.0) {" +
  333.     "    float flicker = 1.0 + (rand(vec2(uTime, uGlitchSeed)) - 0.5) * 0.3 * uGlitchStrength;" +
  334.     "    r *= flicker;" +
  335.     "    g *= flicker;" +
  336.     "    b *= flicker;" +
  337.     "  }" +
  338.     "" +
  339.     "  if (uGlitchStrength > 0.0) {" +
  340.     "    float noiseLine = rand(vec2(floor(uv.y * 300.0), uGlitchSeed + 7.0));" +
  341.     "    if (noiseLine > 0.97) {" +
  342.     "      float noise = rand(vec2(uv.x * 100.0, uGlitchSeed + uv.y)) * uGlitchStrength;" +
  343.     "      r = mix(r, noise, 0.4 * uGlitchStrength);" +
  344.     "      g = mix(g, noise, 0.4 * uGlitchStrength);" +
  345.     "      b = mix(b, noise, 0.4 * uGlitchStrength);" +
  346.     "    }" +
  347.     "  }" +
  348.     "" +
  349.     "  gl_FragColor = vec4(clamp(r, 0.0, 1.0), clamp(g, 0.0, 1.0), clamp(b, 0.0, 1.0), a);" +
  350.     "}";
  351.  
  352.   // =========================================================================
  353.   // CRTFilter Class
  354.   // =========================================================================
  355.  
  356.   function CRTFilter() {
  357.     this.initialize.apply(this, arguments);
  358.   }
  359.  
  360.   CRTFilter.prototype = Object.create(PIXI.Filter.prototype);
  361.   CRTFilter.prototype.constructor = CRTFilter;
  362.  
  363.   CRTFilter.prototype.initialize = function () {
  364.     PIXI.Filter.call(this, null, FRAGMENT_SRC);
  365.     this.uniforms.uTime = 0;
  366.     this.uniforms.uScanlineIntensity = SETTINGS.scanlineIntensity;
  367.     this.uniforms.uCurvature = SETTINGS.curvatureAmount;
  368.     this.uniforms.uVignette = SETTINGS.vignetteIntensity;
  369.     this.uniforms.uChromatic = SETTINGS.chromaticAberration;
  370.     this.uniforms.uBleeding = SETTINGS.colorBleeding;
  371.     this.uniforms.uGlitchStrength = 0;
  372.     this.uniforms.uGlitchSeed = 0;
  373.     this._enabled = SETTINGS.enabled;
  374.     this._time = 0;
  375.  
  376.     this._glitch = new GlitchStateMachine({
  377.       maxIntensity: SETTINGS.glitchIntensity,
  378.       frequency: SETTINGS.glitchFrequency,
  379.       glitchEnabled: SETTINGS.glitchEnabled,
  380.     });
  381.   };
  382.  
  383.   CRTFilter.prototype.update = function () {
  384.     if (!this._enabled) {
  385.       this.uniforms.uGlitchStrength = 0;
  386.       return;
  387.     }
  388.  
  389.     this._time++;
  390.     this.uniforms.uTime = this._time * 0.01;
  391.  
  392.     this._glitch.update();
  393.     this.uniforms.uGlitchStrength = this._glitch.getIntensity();
  394.     if (this.uniforms.uGlitchStrength > 0) {
  395.       this.uniforms.uGlitchSeed = Math.random() * 100;
  396.     }
  397.   };
  398.  
  399.   CRTFilter.prototype.setEnabled = function (value) {
  400.     this._enabled = value;
  401.     this.enabled = value;
  402.   };
  403.  
  404.   CRTFilter.prototype.setGlitchEnabled = function (value) {
  405.     this._glitch.setEnabled(value);
  406.   };
  407.  
  408.   CRTFilter.prototype.triggerGlitch = function (duration) {
  409.     if (this._enabled) {
  410.       this._glitch.trigger(duration || 0);
  411.     }
  412.   };
  413.  
  414.   CRTFilter.prototype.setGlitchFrequency = function (seconds) {
  415.     this._glitch.setFrequency(seconds);
  416.   };
  417.  
  418.   // Make available globally for save/load compatibility
  419.   window.CRTFilter = CRTFilter;
  420.   window.GlitchStateMachine = GlitchStateMachine;
  421.  
  422.   // =========================================================================
  423.   // Engine Hooks
  424.   // =========================================================================
  425.  
  426.   var _Spriteset_Base_createOverallFilters =
  427.     Spriteset_Base.prototype.createOverallFilters;
  428.   Spriteset_Base.prototype.createOverallFilters = function () {
  429.     _Spriteset_Base_createOverallFilters.call(this);
  430.     this._crtFilter = new CRTFilter();
  431.     if (!this._crtFilter._enabled) {
  432.       this._crtFilter.enabled = false;
  433.     }
  434.     this.filters.push(this._crtFilter);
  435.   };
  436.  
  437.   var _Spriteset_Base_update = Spriteset_Base.prototype.update;
  438.   Spriteset_Base.prototype.update = function () {
  439.     _Spriteset_Base_update.call(this);
  440.     if (this._crtFilter) {
  441.       this._crtFilter.update();
  442.     }
  443.   };
  444.  
  445.   // =========================================================================
  446.   // Plugin Commands
  447.   // =========================================================================
  448.  
  449.   PluginManager.registerCommand(PLUGIN_NAME, "setEnabled", function (args) {
  450.     var scene = SceneManager._scene;
  451.     if (scene && scene._spriteset && scene._spriteset._crtFilter) {
  452.       var enabled = args.enabled === "true";
  453.       scene._spriteset._crtFilter.setEnabled(enabled);
  454.     }
  455.   });
  456.  
  457.   PluginManager.registerCommand(PLUGIN_NAME, "setGlitchEnabled", function (args) {
  458.     var scene = SceneManager._scene;
  459.     if (scene && scene._spriteset && scene._spriteset._crtFilter) {
  460.       var enabled = args.enabled === "true";
  461.       scene._spriteset._crtFilter.setGlitchEnabled(enabled);
  462.     }
  463.   });
  464.  
  465.   PluginManager.registerCommand(
  466.     PLUGIN_NAME,
  467.     "triggerGlitch",
  468.     function (args) {
  469.       var scene = SceneManager._scene;
  470.       if (scene && scene._spriteset && scene._spriteset._crtFilter) {
  471.         var duration = Number(args.duration) || 0;
  472.         scene._spriteset._crtFilter.triggerGlitch(duration);
  473.       }
  474.     }
  475.   );
  476.  
  477.   PluginManager.registerCommand(
  478.     PLUGIN_NAME,
  479.     "setGlitchFrequency",
  480.     function (args) {
  481.       var scene = SceneManager._scene;
  482.       if (scene && scene._spriteset && scene._spriteset._crtFilter) {
  483.         var frequency = Number(args.frequency) || 5.0;
  484.         scene._spriteset._crtFilter.setGlitchFrequency(frequency);
  485.       }
  486.     }
  487.   );
  488. })();

评分

参与人数 2+2 收起 理由
714784864 + 1 塞糖
OK一个好用户名 + 1 塞糖

查看全部评分

Lv2.观梦者

梦石
0
星屑
655
在线时间
17 小时
注册时间
2025-4-3
帖子
8

RM创作大赛01参赛者

2
发表于 2026-3-31 09:04:29 | 只看该作者
感谢,刚好能用上
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2026-6-4 14:29

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表