Floating text : Would you use Nifty or BitmapText ? [Solved]

I’ve found my problem :slight_smile: ( For the positioning of the message )



I wasn’t watching the correct part of the code :



The problem came from the difference between Nifty origin and JME screen origin.


  • In Nifty the origin is in the Top-Left of the screen.
  • In JME screen, the origin is in the Bottom Left.



    The elements are now correctly setted.

Glad you could find it! :slight_smile:

Thanks everyone, the task is COMPLETE !



Here is a summary for those who don’t want to read all the episodes.


  • I’ve chosen the Nifty solution. It was not the only one possible. Like Momoko Fan said, the criteria you should take into account when chosin how to do it are :

1) Do you want the text to remain the same size regardless of how far away the battle is going on, and use niftygui effects on it? Use the niftygui text placed at a getScreenCoordinates() location
2) You want the text to be blocked by walls, and change size depending on how far away you are from it? Use BitmapText with BillboardControl


- My solution consist of adding in an overlay panel a custom control for each floating text during the game.
[java]
String id = "battleInfo-battleNotif_" + increment;
increment++;

ControlBuilder builder = new ControlBuilder( id, "battleNotif" );
builder.build( nifty, screen, notifPanel );
Element notif = screen.findElementByName( id );
[/java]

- Those 'battleNotif' controls are panel taking all the screen with an absolute layout.
[java]
<controlDefinition name="battleNotif" controller="com.didigame.acariaempire.gui.controls.BattleNotifControl">
<panel width="100%" height="100%" childLayout="absolute" >
<text id="#notif" font="textDialog.fnt" textHAlign="center" textVAlign="top" wrap="true" >
<effect>
<onCustom customKey="damage" name="battleNotif" post="true" length="5000" />
<onCustom customKey="damage" name="move" mode="out" direction="top" length="4000" startDelay="1000" />
<onCustom customKey="damage" name="textSize" startSize="0.1" endSize="1.5" length="700" neverStopRendering="true" />

<onCustom customKey="critical" name="battleNotif" post="true" length="5000" />
<onCustom customKey="critical" name="move" mode="out" direction="top" length="7000" startDelay="1000" />
<onCustom customKey="critical" name="textSize" startSize="0.1" endSize="3.0" length="1000" neverStopRendering="true" />

<onCustom customKey="shout" name="battleNotif" post="true" length="5000" />
<onCustom customKey="shout" name="move" mode="out" direction="top" length="50000" startDelay="1500" />
<onCustom customKey="shout" name="textSize" startSize="0.1" endSize="1.0" length="500" />
</effect>
</text>
</panel>
</controlDefinition>
[/java]
Like you can see, the control contains some customEffects on the text element. We will se what they do later.

- Once the control is created, we still need to define what we want to display in it. For that, I've created some methods inside the control : createDamageNotif, createShoutNotif, createMissNotif
Here is an example :
[java]
public void createMissNotif(SceneCharacter target)
{
this.color = new Color( 0.0f, 0.0f, 1.0f, 1.0f );
this.text = "Miss !";
this.customKey = "damage";

linkCharacter( sceneChar );
}
[/java]

- Once the character is linked, the custom effetcs are triggered.
One of them is really important :
[java]
<onCustom customKey="xxxx" name="battleNotif" post="true" length="5000" />
[/java]
This one will move the #notif element to the correct position on each frame end destroy the element when desactivating
Here is the JAVA class for this effect :
[java]
//
// This element can only be used inside a BattleNotifControl
//

public class BattleNotifEffect implements EffectImpl
{
private Alpha start = Alpha.FULL;
private Alpha end = Alpha.ZERO;

private BattleNotifControl control;

@Override
public void activate(Nifty nifty, Element element, EffectProperties parameter) {

// The effect if on the notifElt, inside the control
// We need to retrieve the parent, which contains the control
Element parent = element.getParent();
if( parent == null )
return;

//Retrieve the control
control = parent.getControl( BattleNotifControl.class );
if( control != null )
{
moveNotif();
TextRenderer notifTxt = control.getNotifText();
notifTxt.setColor( control.getColor() );
notifTxt.setText( control.getText() );
}
}

@Override
public void execute(Element element, float effectTime, Falloff falloff, NiftyRenderEngine r)
{
moveNotif();

if( effectTime > 0.9f )
element.markForRemoval();

// Based on FadeEffect
Alpha a = start.linear(end, effectTime );
r.setColorAlpha(a.getAlpha());
}

@Override
public void deactivate() {
}

private void moveNotif()
{
if( control == null )
return;

// Element position
Vector3f position = CameraManager.getCharacterPositionOnScreen( control.getSceneChar() );
if( position == null )
{
control.getElement().markForRemoval();
return;
}
// In Nifty the origin is in the Top Left corner ( And not Bottom Left )
position.setY( (float) CameraManager.getScreenHeight() - position.y );

int x, y, w;

// X Management
float fX = position.getX() * control.getCoeffWidth();
if( fX < 50.0f )
fX = 50.0f;
if( fX < control.getNiftyScreenWidth() / 2.0f )
{
x = 0;
w = (int) ( 2.0f * fX );
}
else
{
fX = control.getNiftyScreenWidth() - fX;
fX *= 2.0f;
x = (int) ( control.getNiftyScreenWidth() - fX );
w = (int) fX;
}

// Y management
float fY = position.getY() * control.getCoeffHeight();
y = (int) fY;

// Move the element
control.getNotifElt().setConstraintX( new SizeValue( x + "px" ) );
control.getNotifElt().setConstraintY( new SizeValue( y +"px" ) );
control.getNotifElt().setConstraintWidth( new SizeValue( w + "px" ) );

// Update parent
control.getElement().layoutElements();
}

}
[/java]


And for those who are curious, here is my BattleNotifControl class :
[java]
public class BattleNotifControl implements Controller
{
private Element mainElement;
private Element notifElt;
private TextRenderer notifText;
private SceneCharacter sceneChar;

private String text;
private String customKey;
private Color color;
private float niftyScreenWidth, niftyScreenHeight, coeffWidth, coeffHeight;

private boolean init, characterLinked;

public BattleNotifControl() {
text = "???";
customKey = "";
color = Color.WHITE;
init = characterLinked = false;
}

public void bind ( final Nifty nifty,
final Screen screenParam,
final Element element,
final Properties parameter,
final Attributes controlDefinitionAttributes )
{
this.niftyScreenWidth = nifty.getRenderEngine().getWidth();
this.niftyScreenHeight = nifty.getRenderEngine().getHeight();
this.coeffWidth = niftyScreenWidth / (float) CameraManager.getScreenWidth();
this.coeffHeight = niftyScreenHeight / (float) CameraManager.getScreenHeight();

this.mainElement = element;
mainElement.setFocusable( false );

// Element
this.notifElt = mainElement.findElementByName("#notif");
this.notifText = notifElt.getRenderer( TextRenderer.class );
}

public void createDamageNotif( SceneCharacter sceneChar, int dmg, boolean critical )
{
if( critical )
this.customKey = "critical";
else
this.customKey = "damage";
if( dmg < 0 )
{
this.color = new Color( 1.0f, 0.0f, 0.0f, 1.0f );
this.text = String.valueOf( dmg );
}
else
{
this.color = new Color( 0.0f, 1.0f, 0.0f, 1.0f );
this.text = "+" + String.valueOf( dmg );
}

linkCharacter( sceneChar );
}

public void createMissNotif(SceneCharacter target)
{
this.color = new Color( 0.0f, 0.0f, 1.0f, 1.0f );
this.text = "Miss !";
this.customKey = "damage";

linkCharacter( sceneChar );
}

public void createShoutNotif( SceneCharacter sceneChar, String text )
{
this.color = Color.WHITE;
this.text = text;
this.customKey = "shout";

linkCharacter( sceneChar );
}

private void linkCharacter(SceneCharacter sceneChar)
{
this.sceneChar = sceneChar;
this.characterLinked = true;
if( init )
startCustomEffect();
}


private void startCustomEffect() {
//Effect
notifElt.startEffect( EffectEventId.onCustom, null, customKey );
}

@Override
public void init(Properties arg0, Attributes arg1) {
init = true;
if( characterLinked )
startCustomEffect();
}

@Override
public void onStartScreen() {}

@Override
public void onFocus(final boolean getFocus) {}

@Override
public boolean inputEvent(final NiftyInputEvent inputEvent) { return false; }



public Element getElement() {
return mainElement;
}

public Element getNotifElt() {
return notifElt;
}

public TextRenderer getNotifText() {
return notifText;
}

public String getCustomKey() {
return customKey;
}

public Color getColor() {
return color;
}

public String getText() {
return text;
}

public float getNiftyScreenWidth() {
return niftyScreenWidth;
}

public float getNiftyScreenHeight() {
return niftyScreenHeight;
}

public float getCoeffWidth() {
return coeffWidth;
}

public float getCoeffHeight() {
return coeffHeight;
}

public SceneCharacter getSceneChar() {
return sceneChar;
}

}
[/java]
2 Likes

awesome work didialchichi! congratulations! :smiley:



@Momoko_Fan

maybe we should find a place inside the jme3 jar for special jme related nifty things? Something like special nifty controls like this one in here … what do you think?

Sure … If you can find a place for it :slight_smile:

This is very interesting , good work @didialchichi

I created a code snippet from your post in the snippet section

http://hub.jmonkeyengine.org/groups/contribution-depot-jme3/snippets/single/17/



Thanks