How to tween alpha of a BitmapFontCache in libgdx? - libgdx

I am animating some text in my libgdx application and would like a label text to fade-in and move (e.g. similar to this jsfiddle).
I can move, and change alpha of other objects (e.g. Sprites) and can move BitmapFontCaches. However I can't get alpha of the BitmapFontChage to change.
Declaration:
message = new BitmapFontCache(messageFont, true);
message.setWrappedText("some text", 10.0f, 10.0f, 10.0f);
message.setAlphas(0.0f);
In my screen class, I override the render method, and call .draw() on a renderer class, which is (among other things) essentially just a message.draw(batch); call.
#Override
public void render(float delta) {
...
try{
batch.begin();
feedbackRenderer.draw(batch);
tweenManager.update(delta);}
finally{
batch.end();
}
}
Then as a part of a timeline I call these two Tweens. (yes, they are wrapped in .push( ) and I do start my tweenManager:)
Tween.to(message, BitmapFontCacheAccessor.POSITION_X, animationDuration)
.target(35.0f)
Tween.to(message, BitmapFontCacheAccessor.ALPHA, animationDuration)
.target(1.0f)
The BitmapFontCacheAccessor tries to setAlphas() of the BitmapFontCache as such:
public class BitmapFontCacheAccessor implements TweenAccessor<BitmapFontCache> {
public static final int POSITION_X = 1;
public static final int ALPHA = 2;
#Override
public void setValues(BitmapFontCache target, int tweenType, float[] newValues) {
switch (tweenType) {
case POSITION_X:
float y = target.getY();
target.setPosition(newValues[0], y);
break;
case ALPHA:
target.setAlphas(newValues[0]);
break;}
}...
It moves the label (==> .setPosition(x, y) works!), but does not even touch the alpha. This exact same approach works for Sprites, which fade in nicely.
Is there perhaps some catch when tweening alpha for the BitmapFontCache? Is it possible?
Many thanks!

After a good hour of debugging I have found the reason for this funny behavior.
Libgdx's BitmapFontCache does not have a getAlphas() method
Therefore, to get the alpha channel I used getColor().a
However, these two are not always synced. The behavior is quite random, I myself am not quite sure when it syncs and when it doesn't (f.ex. in the question above, the fade-outs would work, but fade-ins wouldn't)
The solution is to change and declare BOTH alpha channels.
Definition of BitmapFontCache:
message = new BitmapFontCache(messageFont, true);
message.setColor(1,1,1,0);
message.setAlphas(0);
and inside TweenAccessor:
case ALPHA:
//first alpha channel
target.setAlphas(newValues[0]);
//second alpha channel
Color c = target.getColor();
c.a = newValues[0];
target.setColor(c);
break;
To you, hopeless SO wanderer, I address this answer so that you can spend some of the finite number of minutes of your life better than I did.

Related

Libgdx- Resetting a Vector3 to use it multiple times in different situations

OK guys I need your help,
I'm trying to figure out how to reset a Vector3, to use it on multiple situations,...
For example I got a code where for testing purpose I have several buttons,
Where the first one uses a Matrix4 that refers to a Vector3 to translate a player,
How would I go to do so:
Button 1 pressed
Vector3: 1,2,3
Button 2 pressed
Vector3: reset, new values 2,4,6
Pseudo code for comprehension..
Can't seem to find a correct way to do so,
Not behind the computer right now,
Code will come in time,
Maybe if else if can do the trick but not sure :3
Any hint?
for reference, edited qn:
stage.addActor(tpS);
ghost = new Matrix4();
tpIleApprentis.addListener((new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
TpS.hide();
translation = new Vector3(86.83f,96f,63.5f);
ghost.getTranslation(translation);
translation.set(0,0,0);
PlayerSystem.characterComponent.ghostObject.setWorldTransform(ghost);
return false;
}
}));
Ok so,
as I was working with Ashley ECS and Bullet System,
I finally ended up using such method that basically remove the player and recreate the player,
Yes the solution isn't optimal, but it works,
Actually it's plenty sufficient:
tpIleApprentis0.addListener(new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
gameWorld.remove(gameWorld.character);
gameWorld.remove(gameWorld.characterHair);
gameWorld.remove(gameWorld.characterEar);
gameWorld.remove(gameWorld.characterScar);
gameWorld.remove(gameWorld.characterMouth);
System.out.println("Teleportation Ville des Apprentis");
gameWorld.createPlayer(86.8f,64.4f,-96.6f);
return false;
}
});
Ashley engine is created and located in gameworld class;
remove method is part of ashley ecs system and involves bullet component
for the create method it's the same:
public void remove(Entity entity)
{
engine.removeEntity(entity);
bulletSystem.removeBody(entity);
}
public void createPlayer(float x, float y, float z)
{
character = playerFactory.createMaleCharacter(bulletSystem, x, y, z);
characterHair = playerFactory.createMaleHair(x, y, z);
characterEar = playerFactory.createMaleEar(x, y, z);
characterMouth = playerFactory.createMaleMouth(x, y, z);
characterScar = playerFactory.createMaleScar(x, y, z);
engine.addEntity(character);
engine.addEntity(characterHair);
engine.addEntity(characterEar);
engine.addEntity(characterMouth);
engine.addEntity(characterScar);
...
if anybody got a better solution?
but as said, actually this solution fits my needs
You don't need to "reset" the Vector3 before reusing it, you can simply override it with new values using one of the set methods.
https://libgdx.badlogicgames.com/ci/nightlies/docs/api/com/badlogic/gdx/math/Vector3.html#set-float-float-float-
Vector3 vector = new Vector3(1, 2, 3);
...
vector.set(2, 4, 6); // reuse

Explanation to why two constructors are required

Unfortunately, I do not feel confident with my understanding of default constructors.
I have searched extensively to find a resource that provides an explanation to adhere to my personal learning curve of the Java language. However, upon completing an assignment, I feel I may not be meeting the assignment criteria due to my own feeling of redundancy to need for a default constructor. This is why i feel like i am misinterpreting the concept of different types of constructors all together.
I have created two constructors as the assignment requires. One that takes in no parameters and initializes instance variables to a default value. And another that takes in parameters to give values to the object variables when the new object is created in the main method.
Why am I creating a default constructor for the object if the default is never used in the main method? Below is a sample of my code:
public class Circle {
private double x; // declaring variable to hold value of x coordinate
private double y; // Variable to hold value of y coordinate
private double r; // Variable to hold value of the radius of a circle
/* default constructor */
Circle() {
x = 0.0;
y = 0.0;
r = 0.0;
}
/* constructor takes in three parameters and sets values for variables x, y, and r */
public Circle(double x, double y, double r) {
this.x = x;
this.y = y;
this.r = r;
}
// test class created for main method
public class TestCircle {
public static void main (String[] args){
Circle c1 = new Circle(2.0,3.0,9.0);
System.out.println();
System.out.println(" A circle object has been created with the following attributes:");
c1.printAttributes();
System.out.println();
System.out.println("The circle is tested for the maximum radius of 8.0...");
c1.setRadius(8.0);
System.out.println();
System.out.println("... since the radius is more than the allowable maximum, the new attributes for the Circle are:");
c1.printAttributes();
System.out.println();
System.out.println("The area of the Circle is " + c1.area());
System.out.println("The Circumference of the circle is " + c1.circumference());
System.out.println();
System.out.println("The origin of the circle is now moved by a specified amount...");
c1.move(6,-7);
System.out.println();
System.out.println("The new attributes of the circle are:");
c1.printAttributes();
System.out.println();
System.out.println("Testing if the point (10,-20) is inside the circle...");
System.out.println();
if (c1.isInside(10,-20)){
System.out.println("The point (10,-20) is inside the circle");
}
else {
System.out.println("The point (10,-20) is not inside the circle");
}
} // end of main
} // end of class
If you don’t use it you should delete it. Sometimes you will need to create empty objects in order to set attributes a posteriori, but if you are not using it at all there is no point to have it
The point of making default constructors is sometimes for back end stuff and is considered a "good programming practice" no you don't use the default constructor here in your main and in fact your code would run just fine with no default constructor comment it out and re run your tester you will see it works fine.

Linking buttons to imported information from csv file

I would like to ask some help turning this representation into something more interactive. Im working with Processsing latest version. The main idea is I have a table in excel, I imported it into processsing. So far so good. Displayed the values as bubbles. My problem is that would like to create buttons to See further details from each bubble. So, click a button A, the corresponding bubbleA would light up and display its specific value, according to the imported table. I dont know how to connect the button to each bubble, neither how to turn the bubble to its original state once the button is pressed again.
I`m not from the programming field, I just manage to get this far with info that I have found online, so the code must be pretty messed up. I was trying to use the libraries from Processing but I cant really understand how the controlP5 works.. I asssume the structure is way more advanced than what I can handle now.
So, if anyone can help me, I would appreciate it very much.
Table B_A_table;
//Bubble[] bubbles = new Bubble[29];
ArrayList<Bubble> bubbles = new ArrayList<Bubble>();
float scale = 3;
int c_verdeClaro = color(182,189,149);
import controlP5.*;
ControlP5 cp5;
PFont font;
PFont font1;
void setup() {
size(1000, 1000);
colorMode(HSB,255);
loadData();
font = createFont("Verdana", 18);
font1 = createFont("Verdana Bold", 18);
//font = loadFont("Arial-Black-48.vlw");
//BEGIN TEST
cp5 = new ControlP5(this);
noStroke();
smooth();
//TEST
cp5 = new ControlP5(this);
ButtonBar b = cp5.addButtonBar("bar")
.setPosition(500, 0)
.setSize(400, 20)
.addItems(split("Man Woman 20s 30s 40s 50s µµ½É±Ç"," "))
;
println(b.getItem("Man"));
b.changeItem("a","text","first");
b.changeItem("b","text","second");
b.changeItem("c","text","third");
b.onMove(new CallbackListener(){
public void controlEvent(CallbackEvent ev) {
ButtonBar bar = (ButtonBar)ev.getController();
println("hello ",bar.hover());
}
});
//WND TEST
}
void draw() {
// Display all bubbles
background(0);
Graph_Bike_Aware_Experience_Sim();
//Graph_Bike_Uso_Satisf();
pushMatrix();
translate(400,500);
for (Bubble bubble : bubbles){
bubble.display();
}
popMatrix();
}
void loadData() {
// "header" indicates the file has header row. The size of the array
// is then determined by the number of rows in the table.
B_A_table = loadTable("BikeAwareExpr_Nao.csv", "header");
for (int i = 0; i<B_A_table.getRowCount(); i++) {
// Iterate over all the rows in a table.
TableRow row = B_A_table.getRow(i);
// Access the fields via their column name (or index).
float x = row.getFloat("awareness_x")*scale;
float y = row.getFloat("experi")*scale;
float d = row.getFloat("awareness_x")*0.2;
String n = row.getString("Awareness_Bike");
Float id = row.getFloat("ID");
// Make a Bubble object out of the data from each row.
bubbles.add(new Bubble(x, y, d, n,id));
//bubbles[i] = new Bubble(x, y, d, n);
}
}
// This simple Bubble class draws a circle to the window
// and displays a text label when the mouse hovers.
class Bubble {
float x, y;
float diameter;
String name;
Float id;
// Create the Bubble
Bubble(float tempX, float tempY, float tempD, String s, Float id) {
x = tempX;
y = tempY;
diameter = tempD;
name = s;
}
// Display the Bubble
void display() {
stroke(220);
strokeWeight(1);
noFill();
ellipse(x, y, diameter, diameter);
fill(200);
textFont(font,15);
textAlign(CENTER);
text(name, x,y);
}
}
void Graph_Bike_Aware_Experience_Sim(){
pushMatrix();
int tam_table = B_A_table.getRowCount();
translate(400,500);
stroke(150);
strokeWeight(1);
line( - 100 *scale, 0*scale, + 100*scale, 0*scale);
line(0*scale, - 100*scale, 0*scale, + 100*scale);
//fill(c_verdeClaro);
noStroke();
fill(255);
textFont(font,13);
text("Experience", 40 , -97*scale);
text("Awareness", -89*scale, -10);
fill(50);
//textFont(Arial-Black-48, 32);
text("0", 10,15);
pushMatrix();
fill(0);
textFont(font1,30 );
text("IDEAL", 80*scale , -120*scale);
fill(70);
textFont(font1,25 );
text("Bicycle", 0 , -110*scale);
popMatrix();
popMatrix();
}
/*void Graph_Bike_Uso_Satisf(){
pushMatrix();
int tam_table = B_A_table.getRowCount();
translate(900,400);
stroke(150);
strokeWeight(1);
line( - 100 *scale, 0*scale, + 100*scale, 0*scale);
line(0*scale, - 100*scale, 0*scale, + 100*scale);
//fill(c_verdeClaro);
noStroke();
c_verdeClaro_grad();
c_verdeEscuro_grad();
c_Vermelho_grad();
fill(255);
text("Experience", 40 , -97*scale);
text("Awareness", -89*scale, -10);
fill(0);
//textFont(Arial-Black-48, 32);
text("word", 10, 50);
text("IDEAL", 97*scale , -97*scale);
popMatrix();
}
*/
To handle this without Object Oriented Programing, or 'OOP' is a waste of time and code.
But relax OOP also referred to as "Objects" or " Classes". It is not that hard to get. In fact it is simple to learn, I mean, the basic stuff. And it makes things very easy.
In your case, you need to build an object to represent your data. Then you create several of them, populate with data, and all will be hold together. Kind of knowing it own business.
The usual example is
Class car
has those properties
color
plate
Then you can say:
Make a Blue, 3231 car!
Make a Red, 3001 car!
and so on...
When you need it you can ask, Blue car what's your plate, and it will know.
They can also have kind of "behaviours" known as functions or methods. Those do things, so you could say: "Red, turn right", or "Bubble, show me your data!" and they will OBEY you. :)
There is no point in trying to teach this hear though. There are TONs of great tutorials around. Use Duck Duck Go :) or google if you like.
This one here are from Processing's tutorials section itself. Great ones to begin with. :)

Liskov Substitution Principle example

LSP is the hardest in SOLID for me to understand correctly.
LSP states that objects in a program should be replaceable with instances of their subtypes without altering the correctness of the program.
So if we have this typical rectangle - square example:
rect = new Rectangle();
rect.width = 10;
rect.height = 20;
and then we try to test it:
assert 10 == rect.width
assert 20 == rect.height
Everything is ok, but when we try to say that square is rectangle as well we use:
rect = new Square();
Square actually has both height and width the same, which will make tests fail.
So how do we resolve this problem? We segragate classes for Square and Rectangle to avoid LSP problem in this case?
In this particular example, the solution is to not let Square derive from Rectangle, because although we usually say inheritance is an 'is a' relationship, you should see it as an 'behaves like' relationship. So although mathematically, a Square is a Rectangle, a Square does certainly not behave like a Rectangle (as you prove in the code above).
Instead, let them both derive from the same base class:
public abstract class Shape { }
public class Square : Shape {
public int Size;
}
public class Rectangle : Scape {
public int Height;
public int Weight;
}

In libgdx, correct placement of ShapeRenderer begin and end

My question is whether I should place sRenderer.begin(ShapeType.Filled); and sRenderer.end(); outside of Shape? so they're not called for every Shape.draw()
Or is the approach below ok in terms of performance?
Snippet from one of my Shapes ..
private Body body; // initialized elsewhere
private float width = 1.0f;
private float height = 1.0f;
public void draw(ShapeRenderer sRenderer) {
sRenderer.begin(ShapeType.Filled);
sRenderer.setColor(1.0f, 0.0f, 0.0f, 1.0f);
sRenderer.identity();
sRenderer.translate(getBody().getPosition().x, getBody().getPosition().y, 0);
sRenderer.rotate(0.0f, 0.0f, 1.0f, (float) Math.toDegrees(getBody().getAngle()));
sRenderer.rect(-getWidth(), -getHeight(), getWidth() * 2, getHeight() * 2);
sRenderer.end();
}
In my Level class, theres a draw() method called every frame e.g
for (Body body : bodies) {
if (body.getUserData() instanceof Shape){
((Shape) body.getUserData()).draw(getShapeRenderer());
}
}
Each time you call begin(),identity(), translate(), rotate(), or etc., it will trigger a new flush to the GPU the next time you draw something with the shape renderer. So in your case, moving begin() and end() out of the loop won't have a very significant impact.
If this is a bottle neck, you could try calculating your rectangle corners independently from the shape renderer and submitting four lines to the shape renderer, using world space coordinates instead of local coordinates like you're doing now. Then move begin() and end() out of the loop like you suggested and benchmark the difference. I'm not sure which would be faster in your case. This would reduce draw calls but you'd be translating more points on the CPU as well.