Translate model over time like actor? - animation

I recently picked up learning LibGDX and loved the simplicity of the Actor system when it came to moving/fading/rotating stuff. So simple! But, moving into 3d, I wondered if there was a similar style of implementation.
I've seen people saying "instance.transform(x,y,z)", but that's immediately applied and shown on the next render. I was wondering if I could interpolate that transformation using some of the built-in frameworks ala "model.addAction(moveTo(x,y,z), duration(0.4f));" I know that Model doesn't inherit from Actor in the way that most elements in scene2d do. When it comes to skeletal animation and imported animations for said model, I understand the current animation framework in place, but I'm looking more for a solution to move my model around my gameworld without having to do a ton of dependent logic in the render.
Instead of cluttering up my render loop with a custom interpolation implementation, is there a way to use the Action framework on a Model? Just stuff like translate, rotate, etc. (If not, I may go down the path of implementing the action, pool, etc. on the Model object.)
Thanks!

A quick and dirty trick is to use scene2d's actions system on the side. Create a Stage with no actors in it. You can send your actions directly to the stage and call stage.update(delta); once per frame to handle all your actions. You don't need to draw the stage to do this. (Down the road, you will likely want a stage for your 2D UI stuff anyway though.)
You will need to create your own Actions. Since a stage is not meant for 3D, there's no reason to try to use Actors. Your Actions can be applied directly to the stage for processing, and designed not to target any Actor.
Here's an example (untested). Since you are mainly concerned with blending stuff over time, you probably will be extending most of your Actions from TemporalAction.
public class MoveVector3ToAction extends TemporalAction {
private Vector3 target;
private float startX, startY, startZ, endX, endY, endZ;
protected void begin(){
startX = target.x;
startY = target.y;
startZ = target.z;
}
protected void update (float percent) {
target.set(startX + (endX - startX) * percent, startY + (endY - startY) * percent, startZ + (endZ - startZ) * percent);
}
public void reset(){
super.reset();
target = null; //must clear reference for pooling purposes
}
public void setTarget(Vector3 target){
this.target = target;
}
public void setPosition(float x, float y, float z){
endX = x;
endY = y;
endZ = z;
}
}
You can create a convenience class analogous to the Actions class to make it easy to set up generating your actions with automatic pooling:
public class MyActions {
public static MoveVector3ToAction moveVector3To (Vector3 target, float x, float y, float z, float duration){
return moveVector3To(target, x, y, z, duration, null);
}
public static MoveVector3ToAction moveVector3To (Vector3 target, float x, float y, float z, float duration, Interpolation interpolation){
MoveVector3ToAction action = Actions.action(MoveVector3ToAction.class);
action.setTarget(target);
action.setPosition(x, y, z);
action.setDuration(duration);
action.setInterpolation(interpolation);
return action;
}
}
Sample usage. ModelInstances are a bit tricky to move around, because you have to do it with their Matrix4 transform, but you can't safely back the position or rotation or scale out of the transform. So you need to keep a separate Vector3 position and Quaternion rotation, and apply them on each frame to update the instance's transform.
//Static import MyActions to avoid needing to type "MyActions" over and over.
import static com.mydomain.mygame.MyActions.*;
//To move some ModelInstance
stage.addAction(moveVector3To(myInstancePosition, 10, 10, 10, 1f, Interpolation.pow2));
//In render():
stage.update(delta);
myInstance.transform.set(myInstancePosition, myInstanceRotation);

Related

Best practice on instantiating different types of the same es6 class

I am building an HTML5 Canvas 2d game and i have some es6 classes on my project. One of them is Obstacles. What i want to do is having the ability to create a different instance of this class depending on a given type (eg. small, thick, tall etc).
What is the best way to do this?
Just add another parameter to the constructor of the class and name it type?
Or just create subclasses of the main class Obstacle by extending it (eg. SmallObstacle, TallObstacle) given a random type value?
Thanks in advance.
Your question is based around how you want to build and implement your data structures. Neither option is necessarily better than the other 100% of the time. I'll explain the pro's and con's of each below along with my personal solution. You can decide which one is more feasible for you to implement.
Option 1:
Pros:
Easy to insert into the class and deal with later in your code
Leaves your class neat and slimmer
Cons:
You have to deal with it later in your code. When initializing (maybe even when updating/rendering) your code needs to interpret what the types are and build each obstacle based on that.
Option 2:
Pros:
Makes an organized class
Not much work later in your code since you're just pulling preset specifications rather than interpreting them
Cons:
The class is much larger
You are likely to be repeating some code (although if you do it well, you won't)
My Opinion:
Personally I would skip specifying "large," "medium," "tall," "wide." Instead, I would use some logic when implementing the class and make the height and width whatever I want. You could take advantage of how one can easily specify a value while also providing a default with a function constructor.
Here is a snippet example:
class obstacle {
constructor(x, y, w=150, h=150) {
this.x = x;
this.y = y;
this.width = w; //default is 150
this.height = h; //so it's medium or something
this.sprite = ...; //etc.
}
}
// Initialize 100 obstacles :P
for (let i=0; i<100; i++) {
let x = Math.random() * scene.width;
let y = Math.random() * scene.height;
let foo = new obstacle(x, y);
/* When you want different width and height instead
of the default, construct like this:
let bar = new obstacle(x, y, width, height);
*/
}

How can I make window smaller than 100 pixels

I try to make a status bar on the bottom of my screen, but the window can not be made less than 100 pixels. I'm working on Processing 3.0.1.
I use the following code
void setup() {
surface.setResizable(true);
surface.setSize(300, 20);
surface.setLocation(displayWidth-300, displayHeight-50);
}
void draw() {
background(128);
}
any ideas??
Thank you all in advance
J!
If you remove the surface.setResizable(true); statement, you can see the canvas is 300x20, but the window is not:
Processing 3.0 has a lot of changes including refactoring the windowing code, which previously relied on Java's AWT package.
Going through the current source code, you can see:
static public final int MIN_WINDOW_WIDTH = 128;
static public final int MIN_WINDOW_HEIGHT = 128;
defined in PSurface.java line 34
and used through out PSurfaceAWT.java to ensure these minimum window dimensions.
Trying to access the Surface's canvas (println(surface.getNative());) I can it's listed as processing.awt.PSurfaceAWT$SmoothCanvas and I can see a SmoothCanvas class with a getFrame() method which looks promising, but that doesn't seem to be accessible (even though it's a public method of a public class).
So by default, at this time, I'd say resizing the window to be smaller than 128x128 in Processing 3.x is a no go.
If Processing 3.x and smaller window is a must it might be possible to tweak the source code yourself and recompile the core library, but this may bite you later on when having multiple Processing project with multiple versions of the Processing core library. I wouldn't recommend tinkering with the core library normally.
If you can use Processing 2.x for your project, making the window size smaller than 100 pixels is achievable:
import java.awt.Dimension;
int w = 300;
int h = 20;
int appBarHeight = 23;//this is on OSX, on Windows/Linux this may be different
void setup() {
size(w, h);
frame.setResizable(true);
}
void draw() {
if (frame.getHeight() != h+appBarHeight){//wait for Processing to finish setting up it's window dimensions (including minimum window dimensions)
frame.setSize(w,h+appBarHeight);//set your dimensions
}
background(128);
}

LibGDX rotation Bodies issue

It is hard to explain the problem so I recorded a video in order to illustrate the issue. [Video here]
I have image in box2d objects (bodies). When user drags an actor the body underneath moves too so that images follow physics. When the body is not fully rotated everything works as expected (drag&drop) but when rotation happens the movement goes crazy making that unwanted effect of infinite rotation.
Here's my approach:
In the constructor:
for(final Brick b : map.list){
stage.addActor(b.img);
Vector3 v = new Vector3(b.box.getPosition().x,b.box.getPosition().y,0);
camera.project(v);
b.img.setPosition(v.x-b.img.getWidth()*0.5f, v.y-b.img.getHeight()*0.5f);
b.img.setOrigin(b.img.getWidth()*0.5f, b.img.getHeight()*0.5f);
b.img.setRotation((float) Math.toDegrees(b.box.getAngle()));
b.img.addListener((new DragListener() {
public void touchDragged (InputEvent event, float x, float y, int pointer) {
float newPosX =b.img.getX() + x;
float newPosY = b.img.getY() + y;
b.img.setPosition(newPosX-b.img.getWidth()*0.5f,newPosY-b.img.getHeight()*0.5f);
b.box.setTransform(newPosX, newPosY, b.box.getAngle());
}
}));
}
Where map.list is a list containing all bodies that can be dragged.
In the render function:
for(final Brick b : map.list){
b.img.setVisible(true);
b.img.setPosition(b.box.getPosition().x-b.img.getWidth()*0.5f, b.box.getPosition().y-b.img.getHeight()*0.5f);
b.img.setOrigin(b.img.getWidth()*0.5f, b.img.getHeight()*0.5f);
b.img.setRotation((float) Math.toDegrees(b.box.getAngle()));
}
Thanks a lot in advance!
I think your problem is that you set the origin for rotation incorrectly.
b.img.setOrigin(b.img.getWidth()*0.5f, b.img.getHeight()*0.5f);
As long as the bodies aren't rotated at all, everything works fine. Assuming that your bodies position is at the center of the bodies, this should actually be
b.img.setOrigin(v.x, v.y);
Try to use the Box2dDebugRenderer to quickly check if the bodies are really moving so weird, or whether you just draw the pictures incorrectly.

How to use Transformation Matrix for SpriteBatch correctly?

I'm new to XNA and would like to develop a light-weight 2D engine over it, with the entities organized into parent-child hierarchy. I think of matrix when drawing children, because their position, rotation and scale are depend on their parent.
If I use SpriteBatch.Begin(), my rectangles can be drawn on the screen, but when I change them into:
this.DrawingMatrix = Matrix.Identity;
this.SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.None, RasterizerState.CullClockwise, null, this.DrawingMatrix);
nothing is drawn anymore. I even tried new Matrix() or Matrix.CreateTranslation(0, 0, 0) for DrawingMatrix.
My first question is: why doesn't it work? I'm not working with any camera or viewport.
Secondly, before drawing an entity, I call the PreDraw to transform the matrix (I will then reset to original state at PostDraw):
protected virtual void PreDraw(Engine pEngine)
{
pEngine.DrawingMatrix *=
Matrix.CreateTranslation(this.X, this.Y, 0) *
Matrix.CreateScale(this.ScaleX, this.ScaleY, 1) *
Matrix.CreateRotationZ(this.Rotation);
}
Please clarify the correction of above code. And I need to scale not at the origin, but at ScaleCenterX and ScaleCenterY, how can I achieve this?
ADDED: Here is an example of my engine's draw process:
Call these code:
this.DrawingMatrix = Matrix.CreateTranslation(0, 0, 0);
this.SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.None, RasterizerState.CullClockwise, null, this.DrawingMatrix);
Call PreDraw(), with is:
protected virtual void PreDraw(Engine pEngine)
{
pEngine.DrawingMatrix *=
Matrix.CreateTranslation(this.X, this.Y, 0) *
Matrix.CreateScale(this.ScaleX, this.ScaleY, 1) *
Matrix.CreateRotationZ(this.Rotation);
}
Call Draw(), for example, in my Rect class:
protected override void Draw(Engine pEngine)
{
pEngine.SpriteBatch.Draw(pEngine.RectangleTexture, new Rectangle(0, 0, (int)this.Width, (int)this.Height), new Rectangle(0, 0, 1, 1), this.Color);
}
If I replace above Begin code with this.SpriteBatch.Begin(), the rectangle is drawn correctly, so I guess it is because of the matrix.
First issue is a simple bug: The default for SpriteBatch is CullCounterClockwise, but you have specified CullClockwise causing all your sprites to get back-face-culled. You can pass null if you just want to use the default render states - you don't need to specify them explicitly.
(You would need to change the cull mode if you used a negative scale.)
To answer your second question: You need to translate "back" to place the scaling origin (your ScaleCenterX and ScaleCenterY) at the world origin (0,0). Transformations always happen around (0,0). So normally the order is: translate sprite origin back to the world origin, scale, rotate, translate to place sprite origin at desired world position.
Also, I hope that your PostDraw is not applying the reverse transformations (you made it sound like it does). That is very likely to cause precision problems. You should save and restore the matrix instead.

How to animate data visualization in Processing?

I'm trying to create an animated data visualization and currently only know how to do the following "static" code, which puts a string of dots in a straight line. How do I make them jump up and down? Also, if there is anyone in Dublin, Ireland, who wouldn't mind giving a few tutorial sessions to a couple of college students working on a data visualization project in Processing, we have a small budget to compensate you for your time. Thanks very much!
For now, here's the code I was talking about...
SimpleSpreadsheetManager sm;
String sUrl = "t6mq_WLV5c5uj6mUNSryBIA";
String googleUser = "USERNAME";
String googlePass = "PASSWORD";
void setup() {
//This code happens once, right when our sketch is launched
size(800,800);
background(0);
smooth();
//Ask for the list of numbers
int[] numbers = getNumbers();
fill(255,40);
noStroke();
for (int i = 0; i < numbers.length; i++) {
ellipse(numbers[i] * 8, width/2, 8,8);
};
};
void draw() {
//This code happens once every frame.
};
Essentially the x position you use for drawing the ellipse is a number value you get from external data. You need a variable that changes value. Redrawing the ellipse at the updated value should get things animated.
Take this basic example:
float x,y;//position variables for the ellipse
void setup(){
size(800,800);
smooth();
fill(255,40);
noStroke();
y = 400;
}
void draw(){
//update values
x = mouseX + (sin(frameCount * .05) * 30);//update x to an arbitrary value
//draw
background(0);//clear the screen for the new frame
ellipse(x,y,8,8);//draw the ellipse at the new position
}
the x variable is a bit like numbers[i] - just a value that chances.
Nothing special happens in draw() other than clearing the screen(by calling background()) and drawing. The example above uses an arbitrary value, but with your setup that might be something else, maybe a certain value in a data set that changes in time (like the population of a country, etc.)
Another handy thing to keep in mind is the separation between the data and visuals code wise. If values in the data set are higher than what can be displayed on screen as raw values, you can map() values so they can be viewer, add some sort of navigation controls, etc. The values analysed will not be affected by what's being displayed. In programming terms this separation between the data/model, the visuals/view (how the data is rendered) and the controls/controller is known as the Model-View-Controller pattern.
This might be a bit much for people just starting with code, but just being aware of the separation without worrying to much on the specific implementation can be helpful.
Here's a very basic example having the width of the sketch mapped to the size of the data (numbers)
SimpleSpreadsheetManager sm;
String sUrl = "t6mq_WLV5c5uj6mUNSryBIA";
String googleUser = "USERNAME";
String googlePass = "PASSWORD";
int[] numbers;//data used for visualisation
void setup() {
//sketch setup
size(800,800);
smooth();
fill(255,40);
noStroke();
//retrieve data
numbers = getNumbers();
}
void draw() {
background(0);
int numId = int(map(mouseX,0,width,0,numbers.length));//map mouse x position based on sketch width and data size
ellipse(numbers[numId] * 8, height/2, 8,8);
}
For an animation you need one or more parameters that their values changed in time, currently there is a library for processing which do such things: Ani
For more information see the site and provided examples.

Resources