如何使用 Slick2D 渲染最后一个字符字形的一部分
How do I render a portion of the last character glyph using Slick2D
我目前正在使用 Slick 在游戏中呈现自定义聊天。
我想做的是,我希望能够为聊天创建自定义 "fading" 效果,平滑地 从右向左淡化.我不太擅长用文字解释事情,所以我会展示一个我想要的例子。
示例:
我想渲染文本 bernhardkiv: hello world!
,运行 我的常规字体渲染器,结果如下:
而我希望能够做到的,就是顺畅的截断文字,如下;
而且我不知道该怎么做!我相信使用 glScissoring 可以做到这一点,但我一直在尝试使用它,但似乎没有任何效果(什么也没有发生,一切都保持不变)。
我将不胜感激任何人的帮助,我本质上希望能够,而不是在 x、y 处渲染,我希望能够在 x、y 处以宽度 string_width 渲染 - smooth_cut, 能做一点渐变效果
免责声明:
这对我来说是一个新领域,但由于似乎没有其他人回答,我会尝试一下,因为这个问题对我来说似乎很有趣。我还没有彻底测试这些代码修改,所以可能 bugs/side-effects 我不知道。使用风险自负。 :-)
Slick2D 库中的 org.newdawn.slick.Font
实现 类(并支持 类)似乎对扩展不友好(私有成员和方法) .据我所知,为了达到预期的效果,需要对这些内部 Slick2D 类 中的一些进行更改。 (另一种方法是复制整个 类 和包。)据我从提问者的评论中理解,Slick2D 源代码包含在提问者的项目中,因此对内部 Slick2D 类 进行更改应该是在这种情况下可行。
可以说,上述 类 的扩展不友好是有原因的,并且可能有更好的方法来进行必要的更改以使其可扩展。如果有一个实际的项目和更多的时间,我什至可能会以不同的方式自己去做。 然而,这个答案的目的是向提问者展示我如何通过对内部 Slick2D 进行最少的代码更改来达到预期效果的本质 类。 提问者可以his/her 自己决定如何处理将这些更改应用到 his/her 项目的细节。
此代码使用 Slick build 237。
您可以在此 github repo 查看完整的代码更改。下面我只显示与实现所需淡入淡出效果最相关的代码更改。
将每个字符想象成 GL_QUAD 中绘制的每个字符,每个角都有一个 RGBA 值(如所描述的 here 此图片的来源):
(x,x,x,1) (x,x,x,0)
-----------------
| |
| |
| |
| |
| |
| |
-----------------
(x,x,x,1) (x,x,x,0)
我们正在做的是保持左上角和左下角的颜色不变,并将右上角和右下角的颜色更改为 alpha 为 0(透明)。 OpenGL 会逐渐为我们淡化透明度。为此,我们扩展 org.newdawn.slick.Image
以使用以下方法创建 FadableImage
(这与 Image
的 drawEmbedded
方法非常相似,但不会覆盖它):
public class FadableImage extends Image {
//.....
public void drawEmbeddedFaded(float x,float y,float width,float height, Color color, float fadePercentWidth) {
init();
//if percent width is set to an invalid amount, default it to 1.
if(fadePercentWidth < 0.0f || fadePercentWidth > 1.0f)
fadePercentWidth = 1.0f;
if (corners == null) {
GL.glTexCoord2f(textureOffsetX, textureOffsetY);
GL.glVertex3f(x, y, 0);
GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight);
GL.glVertex3f(x, y + height, 0);
//set the color of x2 and y2 of the quad to 0 alpha
GL.glColor4f(color.r, color.g, color.b, 0.0f);
GL.glTexCoord2f(textureOffsetX + textureWidth*fadePercentWidth, textureOffsetY
+ textureHeight);
GL.glVertex3f(x + width*fadePercentWidth, y + height, 0);
GL.glTexCoord2f(textureOffsetX + textureWidth*fadePercentWidth, textureOffsetY);
GL.glVertex3f(x + width*fadePercentWidth, y, 0);
//reset the color
GL.glColor4f(color.r, color.g, color.b, color.a);
} else {
corners[TOP_LEFT].bind();
GL.glTexCoord2f(textureOffsetX, textureOffsetY);
GL.glVertex3f(x, y, 0);
corners[BOTTOM_LEFT].bind();
GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight);
GL.glVertex3f(x, y + height, 0);
//set the color of x2 and y2 of the quad to 0 alpha
GL.glColor4f(color.r, color.g, color.b, 0.0f);
//corners[BOTTOM_RIGHT].bind();
GL.glTexCoord2f(textureOffsetX + textureWidth*fadePercentWidth, textureOffsetY
+ textureHeight);
GL.glVertex3f(x + width*fadePercentWidth, y + height, 0);
//corners[TOP_RIGHT].bind();
GL.glTexCoord2f(textureOffsetX + textureWidth*fadePercentWidth, textureOffsetY);
GL.glVertex3f(x + width*fadePercentWidth, y, 0);
//reset the color
GL.glColor4f(color.r, color.g, color.b, color.a);
}
}
}
你可以看到我要描述的diff
为了使用FadableImage
,我们还需要扩展org.newdawn.slick.font.GlyphPage
来创建FadableGlyphPage
。为了支持 FadableGlyphPage
我们需要修改 org.newdawn.slick.font.GlyphPage
的构造函数并添加一个新的。
然后我们需要修改 org.newdawn.slick.UnicodeFont
以在 UnicodeFont
加载 loadGlyphs
中的字形时使用我们的 FadableGlyphPage
。
我们更改 UnicodeFont
的 drawDisplayList(...)
方法来调用我们 FadableImage
的特殊 drawEmbeddedFaded(...)
方法来获取给定字符串的指定结束索引处的字符。我们还必须进行修改,以便正确处理 DisplayList
缓存。
我们向 UnicodeFont
添加了一个方便的方法来绘制一个字符串,其中 endIndex-1 处的字符淡入淡出并绘制到由 fadePercentWidth:
指定的宽度百分比
public void drawString(float x, float y, String text, int endIndex, float fadePercentWidth) {
drawDisplayList(x, y, text, Color.white, 0, endIndex, fadePercentWidth);
}
所以想法是最后呈现的字符将是 endIndex-1 处的字符。渐变宽度百分比是包含 endIndex-1 处字符的四边形的宽度百分比。所以您可以使用该参数来微调您想要的效果(0.0f
到 1.0f
)。将渐变宽度百分比设置为 0.5f
,将绘制四边形总宽度的 50%。淡入淡出将达到 50% 的宽度:
(x,x,x,1) (x,x,x,0)
------------|------------
| | |
| drawn | not |
| | drawn |
| | |
| | |
| | |
------------|------------
(x,x,x,1) (x,x,x,0)
现在让我们用这段代码来测试它:
import java.awt.Font;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.UnicodeFont;
import org.newdawn.slick.font.effects.ColorEffect;
public class TextFadeTest extends BasicGame {
private final int Y_OFFSET = 50;
private final org.newdawn.slick.Color bgColor = new org.newdawn.slick.Color(126, 166, 240);
private UnicodeFont unicodeFont;
public TextFadeTest(String gamename) {
super(gamename);
}
@Override
public void init(GameContainer gc) throws SlickException {
gc.setShowFPS(false);
gc.getGraphics().setBackground(bgColor);
Font awtFont = new Font(Font.SERIF, Font.PLAIN, 36);
unicodeFont = new UnicodeFont(awtFont);
unicodeFont.getEffects().add(new ColorEffect(java.awt.Color.WHITE));
unicodeFont.addAsciiGlyphs();
unicodeFont.loadGlyphs();
}
@Override
public void update(GameContainer gc, int i) throws SlickException {}
@Override
public void render(GameContainer gc, Graphics g) throws SlickException {
String str = "bernhardkiv: hello world!";
int y = 0;
unicodeFont.drawString(10, y, str);
unicodeFont.drawString(10, y+=Y_OFFSET, str, Color.white, 0, 22);
unicodeFont.drawString(10, y+=Y_OFFSET, str, 22, 0f);
unicodeFont.drawString(10, y+=Y_OFFSET, str, 22, 0.10f);
unicodeFont.drawString(10, y+=Y_OFFSET, str, 22, 0.25f);
unicodeFont.drawString(10, y+=Y_OFFSET, str, 22, 0.50f);
unicodeFont.drawString(10, y+=Y_OFFSET, str, 22, 0.75f);
unicodeFont.drawString(10, y+=Y_OFFSET, str, 22, 0.90f);
unicodeFont.drawString(10, y+=Y_OFFSET, str, 22, 1.0f);
}
public static void main(String[] args) {
try {
AppGameContainer appgc;
appgc = new AppGameContainer(new TextFadeTest("TextFadeTest"));
appgc.setDisplayMode(640, 480, false);
appgc.start();
}
catch(SlickException ex) {
Logger.getLogger(TextFadeTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
结果如下:
我目前正在使用 Slick 在游戏中呈现自定义聊天。
我想做的是,我希望能够为聊天创建自定义 "fading" 效果,平滑地 从右向左淡化.我不太擅长用文字解释事情,所以我会展示一个我想要的例子。
示例:
我想渲染文本 bernhardkiv: hello world!
,运行 我的常规字体渲染器,结果如下:
而我希望能够做到的,就是顺畅的截断文字,如下;
而且我不知道该怎么做!我相信使用 glScissoring 可以做到这一点,但我一直在尝试使用它,但似乎没有任何效果(什么也没有发生,一切都保持不变)。
我将不胜感激任何人的帮助,我本质上希望能够,而不是在 x、y 处渲染,我希望能够在 x、y 处以宽度 string_width 渲染 - smooth_cut, 能做一点渐变效果
免责声明:
这对我来说是一个新领域,但由于似乎没有其他人回答,我会尝试一下,因为这个问题对我来说似乎很有趣。我还没有彻底测试这些代码修改,所以可能 bugs/side-effects 我不知道。使用风险自负。 :-)
Slick2D 库中的
org.newdawn.slick.Font
实现 类(并支持 类)似乎对扩展不友好(私有成员和方法) .据我所知,为了达到预期的效果,需要对这些内部 Slick2D 类 中的一些进行更改。 (另一种方法是复制整个 类 和包。)据我从提问者的评论中理解,Slick2D 源代码包含在提问者的项目中,因此对内部 Slick2D 类 进行更改应该是在这种情况下可行。可以说,上述 类 的扩展不友好是有原因的,并且可能有更好的方法来进行必要的更改以使其可扩展。如果有一个实际的项目和更多的时间,我什至可能会以不同的方式自己去做。 然而,这个答案的目的是向提问者展示我如何通过对内部 Slick2D 进行最少的代码更改来达到预期效果的本质 类。 提问者可以his/her 自己决定如何处理将这些更改应用到 his/her 项目的细节。
此代码使用 Slick build 237。
您可以在此 github repo 查看完整的代码更改。下面我只显示与实现所需淡入淡出效果最相关的代码更改。
将每个字符想象成 GL_QUAD 中绘制的每个字符,每个角都有一个 RGBA 值(如所描述的 here 此图片的来源):
(x,x,x,1) (x,x,x,0)
-----------------
| |
| |
| |
| |
| |
| |
-----------------
(x,x,x,1) (x,x,x,0)
我们正在做的是保持左上角和左下角的颜色不变,并将右上角和右下角的颜色更改为 alpha 为 0(透明)。 OpenGL 会逐渐为我们淡化透明度。为此,我们扩展 org.newdawn.slick.Image
以使用以下方法创建 FadableImage
(这与 Image
的 drawEmbedded
方法非常相似,但不会覆盖它):
public class FadableImage extends Image {
//.....
public void drawEmbeddedFaded(float x,float y,float width,float height, Color color, float fadePercentWidth) {
init();
//if percent width is set to an invalid amount, default it to 1.
if(fadePercentWidth < 0.0f || fadePercentWidth > 1.0f)
fadePercentWidth = 1.0f;
if (corners == null) {
GL.glTexCoord2f(textureOffsetX, textureOffsetY);
GL.glVertex3f(x, y, 0);
GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight);
GL.glVertex3f(x, y + height, 0);
//set the color of x2 and y2 of the quad to 0 alpha
GL.glColor4f(color.r, color.g, color.b, 0.0f);
GL.glTexCoord2f(textureOffsetX + textureWidth*fadePercentWidth, textureOffsetY
+ textureHeight);
GL.glVertex3f(x + width*fadePercentWidth, y + height, 0);
GL.glTexCoord2f(textureOffsetX + textureWidth*fadePercentWidth, textureOffsetY);
GL.glVertex3f(x + width*fadePercentWidth, y, 0);
//reset the color
GL.glColor4f(color.r, color.g, color.b, color.a);
} else {
corners[TOP_LEFT].bind();
GL.glTexCoord2f(textureOffsetX, textureOffsetY);
GL.glVertex3f(x, y, 0);
corners[BOTTOM_LEFT].bind();
GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight);
GL.glVertex3f(x, y + height, 0);
//set the color of x2 and y2 of the quad to 0 alpha
GL.glColor4f(color.r, color.g, color.b, 0.0f);
//corners[BOTTOM_RIGHT].bind();
GL.glTexCoord2f(textureOffsetX + textureWidth*fadePercentWidth, textureOffsetY
+ textureHeight);
GL.glVertex3f(x + width*fadePercentWidth, y + height, 0);
//corners[TOP_RIGHT].bind();
GL.glTexCoord2f(textureOffsetX + textureWidth*fadePercentWidth, textureOffsetY);
GL.glVertex3f(x + width*fadePercentWidth, y, 0);
//reset the color
GL.glColor4f(color.r, color.g, color.b, color.a);
}
}
}
你可以看到我要描述的diff
为了使用FadableImage
,我们还需要扩展org.newdawn.slick.font.GlyphPage
来创建FadableGlyphPage
。为了支持 FadableGlyphPage
我们需要修改 org.newdawn.slick.font.GlyphPage
的构造函数并添加一个新的。
然后我们需要修改 org.newdawn.slick.UnicodeFont
以在 UnicodeFont
加载 loadGlyphs
中的字形时使用我们的 FadableGlyphPage
。
我们更改 UnicodeFont
的 drawDisplayList(...)
方法来调用我们 FadableImage
的特殊 drawEmbeddedFaded(...)
方法来获取给定字符串的指定结束索引处的字符。我们还必须进行修改,以便正确处理 DisplayList
缓存。
我们向 UnicodeFont
添加了一个方便的方法来绘制一个字符串,其中 endIndex-1 处的字符淡入淡出并绘制到由 fadePercentWidth:
public void drawString(float x, float y, String text, int endIndex, float fadePercentWidth) {
drawDisplayList(x, y, text, Color.white, 0, endIndex, fadePercentWidth);
}
所以想法是最后呈现的字符将是 endIndex-1 处的字符。渐变宽度百分比是包含 endIndex-1 处字符的四边形的宽度百分比。所以您可以使用该参数来微调您想要的效果(0.0f
到 1.0f
)。将渐变宽度百分比设置为 0.5f
,将绘制四边形总宽度的 50%。淡入淡出将达到 50% 的宽度:
(x,x,x,1) (x,x,x,0)
------------|------------
| | |
| drawn | not |
| | drawn |
| | |
| | |
| | |
------------|------------
(x,x,x,1) (x,x,x,0)
现在让我们用这段代码来测试它:
import java.awt.Font;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.UnicodeFont;
import org.newdawn.slick.font.effects.ColorEffect;
public class TextFadeTest extends BasicGame {
private final int Y_OFFSET = 50;
private final org.newdawn.slick.Color bgColor = new org.newdawn.slick.Color(126, 166, 240);
private UnicodeFont unicodeFont;
public TextFadeTest(String gamename) {
super(gamename);
}
@Override
public void init(GameContainer gc) throws SlickException {
gc.setShowFPS(false);
gc.getGraphics().setBackground(bgColor);
Font awtFont = new Font(Font.SERIF, Font.PLAIN, 36);
unicodeFont = new UnicodeFont(awtFont);
unicodeFont.getEffects().add(new ColorEffect(java.awt.Color.WHITE));
unicodeFont.addAsciiGlyphs();
unicodeFont.loadGlyphs();
}
@Override
public void update(GameContainer gc, int i) throws SlickException {}
@Override
public void render(GameContainer gc, Graphics g) throws SlickException {
String str = "bernhardkiv: hello world!";
int y = 0;
unicodeFont.drawString(10, y, str);
unicodeFont.drawString(10, y+=Y_OFFSET, str, Color.white, 0, 22);
unicodeFont.drawString(10, y+=Y_OFFSET, str, 22, 0f);
unicodeFont.drawString(10, y+=Y_OFFSET, str, 22, 0.10f);
unicodeFont.drawString(10, y+=Y_OFFSET, str, 22, 0.25f);
unicodeFont.drawString(10, y+=Y_OFFSET, str, 22, 0.50f);
unicodeFont.drawString(10, y+=Y_OFFSET, str, 22, 0.75f);
unicodeFont.drawString(10, y+=Y_OFFSET, str, 22, 0.90f);
unicodeFont.drawString(10, y+=Y_OFFSET, str, 22, 1.0f);
}
public static void main(String[] args) {
try {
AppGameContainer appgc;
appgc = new AppGameContainer(new TextFadeTest("TextFadeTest"));
appgc.setDisplayMode(640, 480, false);
appgc.start();
}
catch(SlickException ex) {
Logger.getLogger(TextFadeTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
结果如下: