alphabet effects!
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE codename-engine-alphabet-font>
|
||||
<alphabetFont fps="24" advance="30" lineGap="70">
|
||||
<alphabetFont fps="24" advance="30" lineGap="70" useColorOffsets="true">
|
||||
<spritesheet>menus/alphabet</spritesheet>
|
||||
|
||||
<defaultAnim casing="upper">LETTER capital</defaultAnim>
|
||||
|
||||
@@ -51,6 +51,17 @@ class CoolUtil
|
||||
return (v == null || isNaN(v)) ? defaultValue : v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the % operator, but without any negatives.
|
||||
*
|
||||
* @param dividend The intial value. The left side of the equation.
|
||||
* @param divisor What to modulo by. The right side of the equation.
|
||||
* @return A positive reminder of `dividend / divisor`.
|
||||
*/
|
||||
public static inline function positiveModulo(dividend:Float, divisor:Float) {
|
||||
return ((dividend % divisor) + divisor) % divisor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut to parse JSON from an Asset path
|
||||
* @param assetPath Path to the JSON asset.
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
package funkin.menus.ui;
|
||||
|
||||
import funkin.menus.ui.effects.RegionEffect;
|
||||
|
||||
import flixel.animation.FlxAnimation;
|
||||
import flixel.util.FlxDirectionFlags;
|
||||
import flixel.math.FlxPoint;
|
||||
|
||||
import haxe.xml.Access;
|
||||
import flixel.animation.FlxAnimation;
|
||||
|
||||
using StringTools;
|
||||
using flixel.util.FlxColorTransformUtil;
|
||||
|
||||
enum abstract AlphabetAlignment(Int) from Int to Int {
|
||||
var LEFT;
|
||||
@@ -46,6 +50,9 @@ enum abstract CaseMode(Int) from Int to Int {
|
||||
}
|
||||
|
||||
class NewAlphabet extends FlxSprite {
|
||||
public var effects:Array<RegionEffect> = [];
|
||||
var __renderData:AlphabetRenderData;
|
||||
|
||||
public var text(default, set):String = "";
|
||||
@:isVar public var textWidth(get, set):Float;
|
||||
public var textHeight(get, null):Float;
|
||||
@@ -62,6 +69,7 @@ class NewAlphabet extends FlxSprite {
|
||||
public var originOffset:FlxPoint = FlxPoint.get();
|
||||
|
||||
public var font(default, set):String;
|
||||
var transformMult:Int = 1; // 1 if multipliers (tint), 0 if offset.
|
||||
var defaultAdvance:Float = 40.0;
|
||||
var lineGap:Float = 75.0;
|
||||
var fps:Float = 24.0;
|
||||
@@ -75,6 +83,7 @@ class NewAlphabet extends FlxSprite {
|
||||
public function new(?x:Float, ?y:Float, ?font:String = "bold") {
|
||||
super(x, y);
|
||||
this.font = font;
|
||||
this.__renderData = new AlphabetRenderData(this);
|
||||
}
|
||||
|
||||
override function update(elapsed:Float) {
|
||||
@@ -97,6 +106,8 @@ class NewAlphabet extends FlxSprite {
|
||||
// FLXOBJECT UPDATE END
|
||||
|
||||
__animTime += elapsed;
|
||||
for (effect in effects)
|
||||
effect.effectTime += FlxG.elapsed * effect.speed;
|
||||
}
|
||||
|
||||
override function draw() {
|
||||
@@ -115,6 +126,7 @@ class NewAlphabet extends FlxSprite {
|
||||
if (__queueResize)
|
||||
recalcSizes();
|
||||
var curLine = 0;
|
||||
var lastLine = 0;
|
||||
var daText = switch (forceCase) {
|
||||
case UPPER: text.toUpperCase();
|
||||
case LOWER: text.toLowerCase();
|
||||
@@ -128,11 +140,22 @@ class NewAlphabet extends FlxSprite {
|
||||
frameOffset.x -= (textWidth - __laneWidths[0]) * alignmentMultiplier;
|
||||
|
||||
var isGraphicsShader = shader != null && shader is flixel.graphics.tile.FlxGraphicsShader;
|
||||
var offsetMult = (1 - transformMult) * 255;
|
||||
var ogRed:Float = colorTransform.redMultiplier;
|
||||
var ogGreen:Float = colorTransform.greenMultiplier;
|
||||
var ogBlue:Float = colorTransform.blueMultiplier;
|
||||
|
||||
for (i in 0...daText.length) {
|
||||
var letter = daText.charAt(i);
|
||||
__renderData.reset(this, daText.charAt(i));
|
||||
for (effect in effects) {
|
||||
if (effect.willModify(i, i - lastLine, __renderData))
|
||||
effect.modify(i, i - lastLine, __renderData);
|
||||
}
|
||||
|
||||
var letter = __renderData.letter;
|
||||
if (letter == "\n") {
|
||||
curLine++;
|
||||
lastLine = i + 1;
|
||||
frameOffset.x = ogOffX - (textWidth - __laneWidths[curLine]) * alignmentMultiplier;
|
||||
frameOffset.y -= lineGap;
|
||||
continue;
|
||||
@@ -147,8 +170,8 @@ class NewAlphabet extends FlxSprite {
|
||||
var frameToGet = Math.floor(__animTime * fps) % anim.numFrames;
|
||||
frame = frames.frames[anim.frames[frameToGet]];
|
||||
|
||||
var offsetX = xOffset.exists(letter) ? xOffset.get(letter) : 0;
|
||||
var offsetY = frame.sourceSize.y - lineGap + (yOffset.exists(letter) ? yOffset.get(letter) : 0);
|
||||
var offsetX = (xOffset.exists(letter) ? xOffset.get(letter) : 0) + __renderData.offsetX;
|
||||
var offsetY = frame.sourceSize.y - lineGap + (yOffset.exists(letter) ? yOffset.get(letter) : 0) + __renderData.offsetY;
|
||||
frameOffset.x += offsetX;
|
||||
frameOffset.y += offsetY;
|
||||
if (!isOnScreen(camera)) {
|
||||
@@ -160,11 +183,18 @@ class NewAlphabet extends FlxSprite {
|
||||
if (isGraphicsShader)
|
||||
shader.setCamSize(_frame.frame.x, _frame.frame.y, _frame.frame.width, _frame.frame.height);
|
||||
|
||||
setColorTransform(
|
||||
__renderData.red * transformMult, __renderData.green * transformMult, __renderData.blue * transformMult, colorTransform.alphaMultiplier,
|
||||
Math.round(__renderData.red * offsetMult), Math.round(__renderData.green * offsetMult), Math.round(__renderData.blue * offsetMult), 0
|
||||
);
|
||||
super.drawComplex(camera);
|
||||
frameOffset.y -= offsetY;
|
||||
frameOffset.x -= offsetX;
|
||||
frameOffset.x -= advance;
|
||||
}
|
||||
colorTransform.redMultiplier = ogRed;
|
||||
colorTransform.greenMultiplier = ogGreen;
|
||||
colorTransform.blueMultiplier = ogBlue;
|
||||
}
|
||||
|
||||
frameOffset.set(ogOffX, ogOffY);
|
||||
@@ -266,6 +296,7 @@ class NewAlphabet extends FlxSprite {
|
||||
lineGap = Std.parseFloat(xml.get("lineGap")).getDefault(75.0);
|
||||
fps = Std.parseFloat(xml.get("fps")).getDefault(24.0);
|
||||
forceCase = xml.get("forceCasing").getDefault("none").toLowerCase();
|
||||
transformMult = (xml.get("useColorOffsets") == "true") ? 0 : 1;
|
||||
|
||||
for (node in xml.elements()) {
|
||||
switch (node.nodeName) {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package funkin.menus.ui.effects;
|
||||
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.menus.ui.effects.RegionEffect;
|
||||
|
||||
class ColorWaveEffect extends RegionEffect {
|
||||
public var period:Float = 30;
|
||||
public var color1:FlxColor;
|
||||
public var color2:FlxColor;
|
||||
|
||||
public function new(color1:FlxColor, color2:FlxColor, ?period:Float = 30) {
|
||||
super();
|
||||
speed = 5;
|
||||
this.color1 = color1;
|
||||
this.color2 = color2;
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
override function modify(index:Int, lineIndex:Int, renderData:AlphabetRenderData) {
|
||||
renderData.color = FlxColor.interpolate(color1, color2, (-effectTime + lineIndex).positiveModulo(period) / period);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package funkin.menus.ui.effects;
|
||||
|
||||
import flixel.util.FlxColor;
|
||||
|
||||
class AlphabetRenderData {
|
||||
public var parent:NewAlphabet;
|
||||
public var letter:String;
|
||||
public var offsetX:Float = 0;
|
||||
public var offsetY:Float = 0;
|
||||
public var color(get, set):FlxColor;
|
||||
public var red:Float = 0;
|
||||
public var green:Float = 0;
|
||||
public var blue:Float = 0;
|
||||
|
||||
public function new(parent:NewAlphabet) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public function reset(parent:NewAlphabet, letter:String) {
|
||||
this.parent = parent;
|
||||
this.letter = letter;
|
||||
offsetX = 0;
|
||||
offsetY = 0;
|
||||
color = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
function get_color():FlxColor {
|
||||
return FlxColor.fromRGBFloat(red, green, blue);
|
||||
}
|
||||
function set_color(value:FlxColor):FlxColor {
|
||||
red = value.redFloat;
|
||||
green = value.greenFloat;
|
||||
blue = value.blueFloat;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
class RegionEffect {
|
||||
public var effectTime:Float = 0;
|
||||
public var speed:Float = 1;
|
||||
public var enabled:Bool = true;
|
||||
public var regionMin:Array<Int> = [];
|
||||
public var regionMax:Array<Int> = [];
|
||||
|
||||
public function new() {}
|
||||
|
||||
public function resetRegions() {
|
||||
regionMin.splice(0, regionMin.length);
|
||||
regionMax.splice(0, regionMax.length);
|
||||
}
|
||||
|
||||
public function addRegion(min:Int, max:Int) {
|
||||
regionMin.push(min);
|
||||
regionMax.push(max);
|
||||
}
|
||||
|
||||
public function willModify(index:Int, lineIndex:Int, renderData:AlphabetRenderData):Bool {
|
||||
if (!enabled) return false;
|
||||
|
||||
if (regionMin.length == 0) regionMin.push(0);
|
||||
if (regionMax.length == 0) regionMax.push(-1);
|
||||
|
||||
for (i in 0...Std.int(Math.min(regionMin.length, regionMax.length))) {
|
||||
var min = (regionMin[i] < 0) ? renderData.parent.text.length - regionMin[i] : regionMin[i];
|
||||
var max = (regionMax[i] < 0) ? renderData.parent.text.length - regionMax[i] : regionMax[i];
|
||||
if (index >= min && index <= max)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function modify(index:Int, lineIndex:Int, renderData:AlphabetRenderData):Void {}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package funkin.menus.ui.effects;
|
||||
|
||||
import funkin.menus.ui.effects.RegionEffect;
|
||||
|
||||
class ShakeEffect extends RegionEffect {
|
||||
public var intensityX:Float = 2;
|
||||
public var intensityY:Float = 2;
|
||||
|
||||
public function new(?x:Float = 2, ?y:Float = 2) {
|
||||
super();
|
||||
intensityX = x;
|
||||
intensityY = y;
|
||||
}
|
||||
|
||||
override function willModify(index:Int, lineIndex:Int, renderData:AlphabetRenderData) {
|
||||
return (intensityX != 0 || intensityY != 0) && super.willModify(index, lineIndex, renderData);
|
||||
}
|
||||
|
||||
override function modify(index:Int, lineIndex:Int, renderData:AlphabetRenderData):Void {
|
||||
renderData.offsetX += FlxG.random.float(-intensityX, intensityX);
|
||||
renderData.offsetY += FlxG.random.float(-intensityY, intensityY);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package funkin.menus.ui.effects;
|
||||
|
||||
import funkin.menus.ui.effects.RegionEffect;
|
||||
|
||||
class WaveEffect extends RegionEffect {
|
||||
public var intensityX:Float = 0;
|
||||
public var intensityY:Float = 5;
|
||||
public var period:Float = 10;
|
||||
|
||||
public function new(?x:Float = 0, ?y:Float = 5, ?p:Float = 10) {
|
||||
super();
|
||||
speed = 3;
|
||||
intensityX = x;
|
||||
intensityY = y;
|
||||
period = p;
|
||||
}
|
||||
|
||||
override function willModify(index:Int, lineIndex:Int, renderData:AlphabetRenderData) {
|
||||
return period != 0 && (intensityX != 0 || intensityY != 0) && super.willModify(index, lineIndex, renderData);
|
||||
}
|
||||
|
||||
override function modify(index:Int, lineIndex:Int, renderData:AlphabetRenderData):Void {
|
||||
renderData.offsetX += intensityX * Math.cos((effectTime + lineIndex) * Math.PI * 2 / period);
|
||||
renderData.offsetY += intensityY * Math.sin((effectTime + lineIndex) * Math.PI * 2 / period);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user