Scrolling in a Stage in Libgdx seems to be laggy - scroll

So I am trying to implement scrolling using this tutorial as a starting point.
I am running the tests on a Desktop.
I added an ActionGestureListener to the stage so I could call the pan(...) function. It works, but when I try to scroll, it looks really laggy, sort of like it's "vibrating".
What am I missing?
Here is what I have so far:
public class Store extends ScreenAdapter {
SpriteBatch spritebatch;
Stage stage;
Texture texture;
Image image;
Group background, foreground;
#Override
public void show() {
spritebatch = new SpriteBatch();
stage = new Stage();
background = new Group();
foreground = new Group();
texture = new Texture("badlogic.jpg");
image = new Image(texture);
//Building background/foreground.
background.addActor(image);
//Adding to stage.
stage.addActor(background);
stage.addActor(foreground);
stage.addListener(new ActorGestureListener() {
// TODO Auto-generated method stub
#Override
public void pan(InputEvent event, float x, float y, float deltaX, float deltaY) {
stage.getCamera().translate(-deltaX, -deltaY, 0);
stage.getCamera().update();
//System.out.println(x + ", " + y + ", " + " " + deltaX + ", " + deltaY);
}
});
Gdx.input.setInputProcessor(stage);
}
#Override
public void render(float delta){
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
spritebatch.setProjectionMatrix(stage.getCamera().combined);
spritebatch.begin();
stage.draw();
spritebatch.end();
}
#Override
public void resize(int width, int height){
System.out.println("resize() executed.");
//stage.getViewport().update(width, height, true);
}
#Override
public void dispose(){
stage.dispose();
texture.dispose();
spritebatch.dispose();
}
}

You should not re-allocate memory for your field objects in your show method. That will drive the garbage collector crazy and probably cause some lag like you're seeing. Move all the new statements from show() into the class constructor or directly onto the field members like this:
public class Store extends ScreenAdapter {
SpriteBatch spritebatch = new SpriteBatch();
Stage stage = new Stage();
// ETC...
That way, the memory for those objects will only be allocated once at object creation.
**EDIT: I just looked and saw that the show method should not be getting repeatedly called like I assumed it was so the above might not work.

I finally got rid of the "vibrating" by editing the translate call.
stage.getCamera().translate(-deltaX / 2, -deltaY / 2, 0);
Instead of dividing by 2, it could be 3 or whatever increment you want. I feel this is solution is more like putting a band-aid on a problem, rather than actually fixing what's wrong. But it has the appearance of something that works, so I will go with it.

Related

LibGDX / Box2d - only one rectangle is being rendered by debugrenderer

I'm revisiting LibGDX game programming and I am unfortunately having to re-learn stuff I used to know.
I'm currently using Tiled Map Editor to make a very simple Donkey Kong style level. I have around 20 rectangles in total for the level.
I've created a box2d world in my main GameScreen class and have a for loop to get the rectangle objects into the world and debugrenderer.
My problem is that only the bottom (and first) rectangle I drew is showing up. I have checked the scale, also I put a println() which tells me the object information has been parsed with all the rectangles info showing correct (ie. the rectangles x,y,w,h values) but as I say, only one rectangle shows up on the debugrenderer.
I've just got back into programming after around 6month break and so I'm hoping i've missed something simple. The same code in my old projects still works fine as I've tested some.
Here is my code, any help is massively appreciated. Thanks
public class GameScreen implements Screen {
SpriteBatch spriteBatch;
OrthographicCamera cam;
Viewport v;
TmxMapLoader mapLoader;
TiledMap map;
OrthogonalTiledMapRenderer mapRenderer;
World world;
Box2DDebugRenderer b2dr;
float mapScale = 10f/140f;
public GameScreen(){
spriteBatch = new SpriteBatch();
cam = new OrthographicCamera();
v = new FitViewport(Constants.V_WIDTH, Constants.V_HEIGHT, cam);
cam.setToOrtho(false, v.getWorldWidth(), v.getWorldHeight());
mapLoader = new TmxMapLoader();
map = mapLoader.load("level1.tmx");
mapRenderer = new OrthogonalTiledMapRenderer(map, mapScale);
world = new World(new Vector2(0,-9.8f), true);
b2dr = new Box2DDebugRenderer();
// box2d local variables
BodyDef bdef = new BodyDef();
PolygonShape shape = new PolygonShape();
FixtureDef fdef = new FixtureDef();
Body body;
// create platform object rectangles
for (MapObject object : map.getLayers().get(2).getObjects().getByType(RectangleMapObject.class)){
Rectangle rect = ((RectangleMapObject)object).getRectangle();
bdef.type = BodyDef.BodyType.StaticBody;
bdef.position.set(rect.getX() + rect.getWidth() / 2 * mapScale, rect.y + rect.getHeight() / 2 * mapScale);
body = world.createBody(bdef);
shape.setAsBox(rect.getWidth() / 2 * mapScale, rect.getHeight() / 2 * mapScale);
fdef.shape = shape;
body.createFixture(fdef);
}
}
#Override
public void show() {
}
#Override
public void render(float delta) {
update(delta);
clearScreen();
draw();
}
public void update(float dt){
mapRenderer.setView(cam);
}
public void clearScreen(){
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
}
public void draw(){
spriteBatch.setProjectionMatrix(cam.combined);
mapRenderer.render();
b2dr.render(world, cam.combined);
spriteBatch.begin();
spriteBatch.end();
}
#Override
public void resize(int width, int height) {
v.update(width, height);
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
spriteBatch.dispose();
}
}
Sorry for wasting time here. I have fixed this.
It was just that I hadnt applied the scale of the map also to the x,y of the rectangles. So i change one line like so, and now it works:
bdef.position.set(rect.getX() * mapScale + rect.getWidth() / 2 * mapScale, rect.y * mapScale + rect.getHeight() / 2 * mapScale);

libgdx fails to load textures after some time

So I'm making a zombie shooter game that works well, but after running for a while I get hit with this exception:
Exception in thread "LWJGL Application" com.badlogic.gdx.utils.GdxRuntimeException:
Couldn't load file: 1zom3.png
at com.badlogic.gdx.graphics.Pixmap.<init>(Pixmap.java:140)
at com.badlogic.gdx.graphics.TextureData$Factory.loadFromFile(TextureData.java:98)
at com.badlogic.gdx.graphics.Texture.<init>(Texture.java:100)
at com.badlogic.gdx.graphics.Texture.<init>(Texture.java:92)
at com.lastride.game.Entity.changeState(Entity.java:51)
at com.lastride.game.Enemy.seek(Enemy.java:39)
at com.lastride.game.LastRideGame.update(LastRideGame.java:149)
at com.lastride.game.LastRideGame.render(LastRideGame.java:229)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:215)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:120)
Caused by: java.io.IOException: Error loading pixmap:
at com.badlogic.gdx.graphics.g2d.Gdx2DPixmap.<init>(Gdx2DPixmap.java:57)
at com.badlogic.gdx.graphics.Pixmap.<init>(Pixmap.java:138)
... 9 more
I know for a fact that the image is there as it works, but it seems that after running for a bit it crashes.
This is the method where it crashes on:
public void changeState(int i)
{
//changes the state and concurrently the image associated with the given state
state = i;
sprite = new Sprite(new Texture(Gdx.files.internal(name+i+suff)));//crashes here
bounding = (sprite.getBoundingRectangle());
if (sprite.getTexture().getTextureData().isPrepared()==false)
{
sprite.getTexture().getTextureData().prepare();
}
playerMap = sprite.getTexture().getTextureData().consumePixmap();
}
As #Tenfour04 points out, it could be an out-of-memory problem.
Instead of doing this:
sprite = new Sprite(new Texture(Gdx.files.internal(name+i+suff)));
Create an global (and/or possible static and/or possible final) Texture object, and load it just once at the beginning of your game and use it repeatably.
Something like this:
public static Texture myTexture_1; //<< your texture
public static final int ID_MY_TEXTURE_1 = 1; //<< this will work as an ID
// This method is called once in your game (like in the create() method)...
public static void load() {
myTexture_1 = new Texture(Gdx.files.internal(name + ID_MY_TEXTURE_1 + suff));
}
// when no longer necessary, remove it...
public static void dispose() {
myTexture_1.dispose();
// and so on...
}
then, in your changeState() method, do a switch to retrieve the correct texture:
public void changeState(int i) {
state = i;
switch(i){
case ID_MY_TEXTURE_1 :
sprite = new Sprite(myTexture_1);
break;
// rest of cases...
}
// rest of your code...
}

When dragging an object with rigidbody2D it passes through colliders (walls)

Ok, so I'm making this game where the user can drag a ball around the screen, but it's not supposed to leave the play area. I'm getting the following problem though, when I push it towards the colliders it bounces back, and if I push too hard it simply goes off screen (I need to make it do not go off screen. the user is free to drag it all over the place, but within the screen of course).
any tips on how I could solve this issue?
Here is the code for dragging which I'm using:
using UnityEngine;
using System.Collections;
public class CircleManager : MonoBehaviour {
private bool dragging = false;
private Vector3 screenPoint;
private Vector3 offset;
// Pressionando
void OnMouseDown()
{
dragging = true;
screenPoint = Camera.main.WorldToScreenPoint(gameObject.transform.position);
offset = gameObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z));
}
// Arrastando
void OnMouseDrag()
{
Vector3 cursorPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z);
Vector3 cursorPosition = Camera.main.ScreenToWorldPoint(cursorPoint) + offset;
//i tried with both below.
//transform.position = cursorPosition;
transform.GetComponent<Rigidbody2D>().MovePosition(cursorPosition);
}
// Soltando
void OnMouseUp()
{
dragging = false;
}
}
Thanks!
You could try to do something like,
if( transform.position.x > xMaxPos )
{
transform.position.x = new Vector3( xMaxPos, transform.position.y, transform.position.z );
}
You could set up for each min and max. Then when you create the xMaxPos variables, create them like:
[serializeField]
private float xMaxPos;
That way they will appear in the inspector and you can tweak their values as you please. You could also throw in an offset that's the width of the ball i.e.
transform.position.x = new Vector3( xMaxPos - transform.localscale.x/2, transform.position.y, transform.position.z );
Try using velocity
public class CircleManager : MonoBehaviour {
private bool dragging = false;
private Vector3 screenPoint;
private Vector3 offset;
public float speed = 5.0f;
// Pressionando
void OnMouseDown()
{
dragging = true;
Vector3 cursorPosition = Camera.main.ScreenToWorldPoint(ToDepth(Input.mousePosition, transform.position.z));
offset = gameObject.transform.position - cursorPosition;
}
// Arrastando
void OnMouseDrag()
{
Vector3 cursorPosition = Camera.main.ScreenToWorldPoint(ToDepth(Input.mousePosition, transform.position.z)) + offset;
Vector3 direction = (transform.position - cursorPosition).normalized;
transform.GetComponent<Rigidbody2D>().velocity = direction * speed * Time.deltaTime;
}
// Soltando
void OnMouseUp()
{
dragging = false;
}
Vector3 ToDepth(Vector3 value, float depth)
{
return new Vector3(value.x, value.y, depth);
}
}
Few things to note:
You don't have to write out gameObject.transform.position i see you did that a few times, as well as calling transform... directly. Its both the same thing, so you don't need the gameObject part.
Also your getting the screenPoint of the transform, then using the z value of that later on, which doesn't really make much sense to me.
Anyways, i don't see why this shouldn't work for you, i haven't tested it though.

Create more than one window of a single sketch in Processing

How to create more than one window of a single sketch in Processing?
Actually I want to detect and track a particular color (through webcam) in one window and display the detected co-ordinates as a point in another window.Till now I'm able to display the points in the same window where detecting it.But I want to split it into two different windows.
You need to create a new frame and a new PApplet... here's a sample sketch:
import javax.swing.*;
SecondApplet s;
void setup() {
size(640, 480);
PFrame f = new PFrame(width, height);
frame.setTitle("first window");
f.setTitle("second window");
fill(0);
}
void draw() {
background(255);
ellipse(mouseX, mouseY, 10, 10);
s.setGhostCursor(mouseX, mouseY);
}
public class PFrame extends JFrame {
public PFrame(int width, int height) {
setBounds(100, 100, width, height);
s = new SecondApplet();
add(s);
s.init();
show();
}
}
public class SecondApplet extends PApplet {
int ghostX, ghostY;
public void setup() {
background(0);
noStroke();
}
public void draw() {
background(50);
fill(255);
ellipse(mouseX, mouseY, 10, 10);
fill(0);
ellipse(ghostX, ghostY, 10, 10);
}
public void setGhostCursor(int ghostX, int ghostY) {
this.ghostX = ghostX;
this.ghostY = ghostY;
}
}
One option might be to create a sketch twice the size of your original window and just offset the detected coordinates by half the sketch's size.
Here's a very rough code snippet (assumming blob will be a detected color blob):
int camWidth = 320;
int camHeight = 240;
Capture cam;
void setup(){
size(camWidth * 2,camHeight);
//init cam/opencv/etc.
}
void draw(){
//update cam and get data
image(cam,0,0);
//draw
rect(camWidth+blob.x,blob.y,blob.width,blob.height);
}
To be honest, it might be easier to overlay the tracked information. For example, if you're doing color tracking, just display the outlines of the bounding box of the tracked area.
If you really really want to display another window, you can use a JPanel.
Have a look at this answer for a running code example.
I would recommend using G4P, a GUI library for Processing that has some functionality built in for handling multiple windows. I have used this before with a webcam and it worked well. It comes with a GWindow object that will spawn a window easily. There is a short tutorial on the website that explains the basics.
I've included some old code that I have that will show you the basic idea. What is happening in the code is that I make two GWindows and send them each a PImage to display: one gets a webcam image and the other an effected image. The way you do this is to augment the GWinData object to also include the data you would like to pass to the windows. Instead of making one specific object for each window I just made one object with the two PImages in it. Each GWindow gets its own draw loop (at the bottom of the example) where it loads the PImage from the overridden GWinData object and displays it. In the main draw loop I read the webcam and then process it to create the two images and then store them into the GWinData object.
Hopefully that gives you enough to get started.
import guicomponents.*;
import processing.video.*;
private GWindow window;
private GWindow window2;
Capture video;
PImage sorted;
PImage imgdif; // image with pixel thresholding
MyWinData data;
void setup(){
size(640, 480,P2D); // Change size to 320 x 240 if too slow at 640 x 480
// Uses the default video input, see the reference if this causes an error
video = new Capture(this, 640, 480, 24);
numPixels = video.width * video.height;
data = new MyWinData();
window = new GWindow(this, "TEST", 0,0, 640,480, true, P2D);
window.isAlwaysOnTop();
window.addData(data);
window.addDrawHandler(this, "Window1draw");
window2 = new GWindow(this, "TEST", 640,0 , 640,480, true, P2D);
window2.isAlwaysOnTop();
window2.addData(data);
window2.addDrawHandler(this, "Window2draw");
loadColors("64rev.csv");
colorlength = mycolors.length;
distances = new float[colorlength];
noCursor();
}
void draw()
{
if (video.available())
{
background(0);
video.read();
image(video,0,0);
loadPixels();
imgdif = get(); // clones the last image drawn to the screen v1.1
sorted = get();
/// Removed a lot of code here that did the processing
// hand data to our data class to pass to other windows
data.sortedimage = sorted;
data.difimage = imgdif;
}
}
class MyWinData extends GWinData {
public PImage sortedimage;
public PImage difimage;
MyWinData(){
sortedimage = createImage(640,480,RGB);
difimage = createImage(640,480,RGB);
}
}
public void Window1draw(GWinApplet a, GWinData d){
MyWinData data = (MyWinData) d;
a.image(data.sortedimage, 0,0);
}
public void Window2draw(GWinApplet a, GWinData d){
MyWinData data = (MyWinData) d;
a.image(data.difimage,0,0);
}

My AsyncTask does not update UI smoothly (animation)

I want to make a TextView appear little by little, like animation. The problem is, the animation is not smooth. It gets stuck for a little while sometimes and then resumes. Sometimes even worse, it goes back... I mean, the TextView gets bigger and bigger but suddenly gets smaller then bigger again. Could anyone help me?
private class UnfoldTask extends AsyncTask<Integer, Integer, Integer> {
View view;
public UnfoldTask(View v) {
this.view = v;
ViewGroup.LayoutParams pa = view.getLayoutParams();
pa.height = 0;
view.setLayoutParams(pa);
}
#Override
protected Integer doInBackground(Integer... maxHeight) {
ViewGroup.LayoutParams pa = view.getLayoutParams();
while (pa.height < maxHeight[0]) {
pa.height += (int) (24 * getResources().getDisplayMetrics().density + 0.5f);
sleep(100);
publishProgress(pa.height);
}
return maxHeight[0];
}
private void sleep(int i) {
try {
Thread.sleep(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
protected void onProgressUpdate(Integer... values) {
ViewGroup.LayoutParams pa = view.getLayoutParams();
pa.height = values[0];
view.setLayoutParams(pa);
}
#Override
protected void onPostExecute(Integer result) {
ViewGroup.LayoutParams pa = view.getLayoutParams();
pa.height = result;
view.setLayoutParams(pa);
}
}
You should be using a scale animation for this. Here's an example:
ScaleAnimation animation = new ScaleAnimation(1, 2, 1, 2, centerX, centerY); // Scales from normal size (1) to double size (2). centerX/Y is the center of your text view. Change this to set the pivot point of your animation.
animation.setDuration(1000);
myTextView.startAnimation(animation);
You can use droidQuery to simplify this:
//this will set the height of myView to 0px.
$.with(myView).height(0);
//when you are ready to animate to height (in pixels):
$.with(myView).animate("{height:" + height + "}", new AnimationOptions());
Check the documentation if you want to get fancy - such as adding duration, and event callbacks. If you are still noticing non-smooth animation, consider adding the application attribute to your AndroidManifest:
android:hardwareAccelerated="true"

Resources