I'm a beginner programmer and I'm trying to make a game for android using LibGDX. I don't understand why it freezees for less than half second all the game (running on desktop) and if I run it on my phone or on the Emulator the freezing time is longer than half a second. This is the code:
#Override
public void show() {
stage = new Stage(physicWidth, physicHeight, true);
gun = new ArrayList<Guns>();
buildingAtlas = new TextureAtlas(Gdx.files.internal("ui/cladiri.pack"));
buildingSkin = new Skin(buildingAtlas);
building1 = new ImageButton(buildingSkin.getDrawable("cladire1"));
building2 = new ImageButton(buildingSkin.getDrawable("cladire2"));
table = new Table();
table.setBounds(0, tileH * 4, tileW * 6, tileH);
table.left();
table.add(building1).width((float) (tileW * 0.8)).height((float) (tileH * 0.7));
table.add(building2).width((float) (tileW * 0.8)).height((float) (tileH * 0.7));
stage.addActor(table);
Gdx.input.setInputProcessor(stage);
building1.addListener(new InputListener(){
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
gun.add(new Guns(selectedTile.x, selectedTile.y));
return true;
}
});
building2.addListener(new InputListener(){
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
System.out.println("Touch on Building 2");
return true;
}
});
}
#Override
public void render(float delta) {
batch.begin();
for(int i = 0; i < gun.size(); i++){
gun.get(i).render(batch, tileW, tileH);
}
batch.end();
}
The Guns class is:
public Guns(float x, float y) {
this.y = y;
this.x = x;
gunTexture = new Texture(Gdx.files.internal("img/gunTest1.png"));
TextureRegion[][] tmp = TextureRegion.split(gunTexture, gunTexture.getWidth() /
COLS, gunTexture.getHeight() / ROWS);
gunFrames = new TextureRegion[COLS * ROWS];
int index = 0;
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
cladireFrames[index++] = tmp[i][j];
}
}
gunAnimation = new Animation(0.1f, gunFrames);
stateTime = 0f;
bounds = new Rectangle();
}
public void update(){
stateTime += Gdx.graphics.getDeltaTime();
curGunFrame = gunAnimation.getKeyFrame(stateTime, true);
}
public void render(SpriteBatch batch, float w, float h){
batch.draw(getCurGunFrame(), x, y, w, h);
}
If touched the building2 button who execute the "System.out.println" the game doesn't freeze, but on building1 who adds a new Gun then it does freeze.
The code I posted is simplified, only whats relevant to my problem.
It looks like one of these lines will be causing your problem:
gunTexture = new Texture(Gdx.files.internal("img/gunTest1.png"));
TextureRegion[][] tmp = TextureRegion.split(gunTexture, gunTexture.getWidth() /
COLS, gunTexture.getHeight() / ROWS);
Texture loading is often an expensive operation, you're then operating on it after loading it in and one, or both of these operations is almost certainly going to be causing the lag you are experiencing. I believe a standard mechanism to solve this problem is to share textures between objects and load the texture when the level starts, rather than while it's running.
Rather than having your Gun class creating a new texture on creation, your game should pass the texture in to the constructor along with the x and y variables.
The reason for the different lag times experienced between your desktop and your phone is most likely because your desktop is a lot more powerful.
Related
There are balls in my app that just fly through display. They draws as I want. But now I want to draw the trail behind them.
All I could make is just drawing by canvas.drawPath something like following picture:
But it is not what I want. It should have pointed tail and gradient color like this:
I have no idea how to make it. Tried BitmapShader - couldn't make something right. Help, please.
Code:
First of all, there is Point class for position on display:
class Point {
float x, y;
...
}
And trail is stored as queue of Point:
private ConcurrentLinkedQueue<Point> trail;
It doesn't matter how it fills, just know it has size limit:
trail.add(position);
if(trail.size() > TRAIL_MAX_COUNT) {
trail.remove();
}
And drawing happened in DrawTrail method:
private void DrawTrail(Canvas canvas) {
trailPath.reset();
boolean isFirst = true;
for(Point p : trail) {
if(isFirst) {
trailPath.moveTo(p.x, p.y);
isFirst = false;
} else {
trailPath.lineTo(p.x, p.y);
}
}
canvas.drawPath(trailPath, trailPaint);
}
By the way, trailPaint is just really fat paint :)
trailPaint = new Paint();
trailPaint.setStyle(Paint.Style.STROKE);
trailPaint.setColor(color);
trailPaint.setStrokeWidth(radius * 2);
trailPaint.setAlpha(150);
I see you want to see a gradient on the ball path, you could use something like this
int x1 = 0, y1 = 0, x2 = 0, y2 = 40;
Shader shader = new LinearGradient(0, 0, 0, 40, Color.WHITE, Color.BLACK, TileMode.CLAMP);
trailPaint = new Paint();
trailPaint.setShader(shader);
This is what you should change your trailPaint to and see if it works.
provided from here.
I found solution. But still think it is not the best one.
First of all there are my class fields used for that task.
static final int TRAIL_MAX_COUNT = 50; //maximum trail array size
static final int TRAIL_DRAW_POINT = 30; //number of points to split the trail for draw
private ConcurrentLinkedQueue<Point> trail;
private Paint[] trailPaints;
private float[][] trailPoss, trailTans;
private Path trailPath;
Additionally to trailPath object I used PathMeasure object to split path to multiple equal parts.
After filling trail array object added call of trail calculating function.
lastTrailAdd = now;
trail.add(pos.Copy());
if (trail.size() > TRAIL_MAX_COUNT) {
trail.remove();
}
FillTrail();
Then my FillTrail function.
private void FillTrail() {
trailPath.reset();
boolean isFirst = true;
for(Point p : trail) {
if(isFirst) {
trailPath.moveTo(p.x, p.y);
trailPoss[0][0] = p.x;
trailPoss[0][1] = p.y;
isFirst = false;
} else {
trailPath.lineTo(p.x, p.y);
}
}
PathMeasure path = new PathMeasure(trailPath, false);
float step = path.getLength() / TRAIL_DRAW_POINT;
for(int i=0; i<TRAIL_DRAW_POINT; i++) {
path.getPosTan(step * i, trailPoss[i], trailTans[i]);
}
}
It separated from drawing thread. Next code is drawing function.
private void DrawTrail(Canvas canvas) {
if(trail.size() > 1) {
float prevWidthHalfX = 0f, prevWidthHalfY = 0f, prevX = 0f, prevY = 0f;
Path trailStepRect = new Path();
boolean isFirst = true;
for (int i = 0; i < TRAIL_DRAW_POINT; i++) {
float currWidthHalf = (float) (radius) * i / TRAIL_DRAW_POINT / 2f,
currWidthHalfX = currWidthHalf * trailTans[i][1],
currWidthHalfY = currWidthHalf * trailTans[i][0],
currX = trailPoss[i][0], currY = trailPoss[i][1];
if (!isFirst) {
trailStepRect.reset();
trailStepRect.moveTo(prevX - prevWidthHalfX, prevY + prevWidthHalfY);
trailStepRect.lineTo(prevX + prevWidthHalfX, prevY - prevWidthHalfY);
trailStepRect.lineTo(currX + currWidthHalfX, currY - currWidthHalfY);
trailStepRect.lineTo(currX - currWidthHalfX, currY + currWidthHalfY);
canvas.drawPath(trailStepRect, trailPaints[i]);
} else {
isFirst = false;
}
prevX = currX;
prevY = currY;
prevWidthHalfX = currWidthHalfX;
prevWidthHalfY = currWidthHalfY;
}
}
}
Main point of this is drawing trail by parts with different paints. Closer to ball - wider the trail. I think I will optimise it, but it is allready work.
If you want to watch how it looks just install my app from google play.
I've recently started my first libGDX game, and it is all going well, everything renders fine but after about a minute nothing renders, the rendering calls are still made and the spritebatch works fine, I'm just left with a black screen, I have even changed the 'glClearColor()' to but I'm still left with a black screen. I've have no idea what this could be.
My main class:
#Override
public void create() {
Gdx.graphics.setDisplayMode(Settings.screenWidth, Settings.screenHeight, Settings.fullscreen);
Gdx.graphics.setVSync(Settings.VSync);
Gdx.graphics.setTitle("Trench Warfare");
batch = new SpriteBatch(1000);
previous = System.currentTimeMillis();
currentMap = new Map(this, 0);
currentMap.addObject(new ColourMapObject(this, 0));
}
private void update() {Settings.screenHeight, Settings.fullscreen);
Gdx.graphics.setVSync(Settings.VSync);
batch.setColor(new Color(Settings.brightness, Settings.brightness, Settings.brightness, 1.0f));
float delta = ((float)(System.currentTimeMillis() - previous)) / 1000.0f;
previous = System.currentTimeMillis();
currentMap.update(delta);
}
#Override
public void render() { //Always called
update();
Gdx.gl.glClearColor(1, 0, 0, 1); //Red colour still black screen.
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
currentMap.render(batch); //Basicly list of textures to be rendered, they never stop rendering (Being called) despite black screen.
batch.end();
batch.flush();
}
EDIT:
We've determined that after some time SpriteBatch render a black screen over the red clear colour, It also stops rendering the texture.
I've also determined that the SpriteBatch's tint or colour stays white even during the black screen.
EDIT, this code takes in a texture and then turns into a different texture with different colours:
public class ColourMapObject extends MapObject {
public enum Type {
Dirt,
Water,
Trench,
}
private Texture terrainMap;
private Texture trenchMap;
private Texture soldierMap;
private Texture buildingMap;
private Texture shipMap;
private int levelId;
private Texture finalTexture;
private Type[][] types;
public ColourMapObject(TrenchMain main, int levelId) {
super(main);
this.levelId = levelId;
//finalTexture = new Texture("/map" + String.valueOf(levelId) + "/terrainMap.png");
finalTexture = new Texture("black.png");
finalTexture.getTextureData().prepare();
loadMap(levelId);
}
private void loadMap(int levelId) {
//terrainMap = new Texture("/map" + String.valueOf(levelId) + "/terrainMap.png");
terrainMap = new Texture("terrainMap.png");
types = new Type[terrainMap.getWidth()][terrainMap.getHeight()];
terrainMap.getTextureData().prepare();
Pixmap pixmap = terrainMap.getTextureData().consumePixmap();
for(int x = 0; x < terrainMap.getWidth(); x++) {
for(int y = 0; y < terrainMap.getHeight(); y++) {
types[x][y] = RandomMapColour.getType(new Color(pixmap.getPixel(x, y)));
if(types[x][y] == null) types[x][y] = Type.Dirt;
}
}
// trenchMap = new Texture("/map" + String.valueOf(levelId) + "/trenchMap.png");
//
//
// soldierMap = new Texture("/map" + String.valueOf(levelId) + "/soldierMap.png");
//
//
// buildingMap = new Texture("/map" + String.valueOf(levelId) + "/buildingMap.png");
//
//
// shipMap = new Texture("/map" + String.valueOf(levelId) + "/shipMap.png");
}
#Override
public void update(float delta) {
super.update(delta);
Pixmap draw = new Pixmap(Settings.screenWidth, Settings.screenHeight, Format.RGB888);
float pX = (float)terrainMap.getWidth() / (float)draw.getWidth();
float pY = (float)terrainMap.getHeight() / (float)draw.getHeight();
for(int x = 0; x < draw.getWidth(); x++) {
for(int y = 0; y < draw.getHeight(); y++) {
switch(types[(int)((float)x * pX)][(int)((float)y * pY)]) {
case Dirt:
draw.drawPixel(x, y, RandomMapColour.getDirtColour());
break;
case Trench:
draw.drawPixel(x, y, RandomMapColour.getTrenchColour());
break;
case Water:
draw.drawPixel(x, y, RandomMapColour.getWaterColour());
break;
}
}
}
finalTexture = new Texture(draw);
}
#Override
public void render(SpriteBatch batch) {
super.render(batch);
float sx = ((float)TrenchMain.getScreenWidth()) / ((float)finalTexture.getWidth());
float sy = ((float)TrenchMain.getScreenHeight()) / ((float)finalTexture.getHeight());
batch.draw(finalTexture, 0, 0, 0, 0, finalTexture.getWidth(), finalTexture.getHeight(), sx, sy, 0, 0, 0, finalTexture.getWidth(), finalTexture.getHeight(), false, false);
}
I finally figuired it out, for those who are wonder, what I was doing was creating a new finalTexture every update with disposing of the old one.
Simply dispose of the texture.
finalTexture.dispose();
So my goal is to draw a spline similar to this one (where the line goes through each point):
But the spline loops around (from the end point 2 back to the start point):
I tried changing the "continuous" boolean in the catmullromspline, but that resulted in only a dot being drawn in the center of the screen.
I also ended the line drawing when it hit the last point, but the result was ugly because the line was still curving at the start and end points.
I looked everywhere in the source code, and could not find a function that could prevent it from looping.
And as far as i know, bezier splines don't go through all the points (they only pass near them).
So what should I do?
Here's my code:
...
public class GameScreen implements Screen {
final game game;
float w=800;
float h=480;
OrthographicCamera camera;
long startTime;
Texture baseTexture=new Texture(Gdx.files.internal("white.png"));
public GameScreen(final game gam) {
this.game = gam;
startTime = TimeUtils.millis();
camera = new OrthographicCamera();
camera.setToOrtho(false, w, h);
setup();
}
//https://github.com/libgdx/libgdx/wiki/Path-interface-&-Splines
int k = 10000; //increase k for more fidelity to the spline
Vector2[] points = new Vector2[k];
Vector2 cp[] = new Vector2[]{
new Vector2(w/2, h), new Vector2(w/2, h/2),new Vector2(50, 50)
};
ShapeRenderer rope=new ShapeRenderer();
public void setup(){
CatmullRomSpline<Vector2> myCatmull = new CatmullRomSpline<Vector2>( cp, true);
for(int i = 0; i < k; ++i)
{
points[i] = new Vector2();
myCatmull.valueAt(points[i], ((float)i)/((float)k-1));
}
}
#Override
public void render(float delta) {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Gdx.gl20.glLineWidth(50);
game.batch.begin();
rope.setAutoShapeType(true);
rope.begin();
for(int i = 0; i < k-1; ++i)
{
//rope.line(points[i], points[i+1]);
//shaper.line(myCatmull.valueAt(points[i], ((float)i)/((float)k-1)), myCatmull.valueAt(points[i+1], ((float)i)/((float)k-1)));
game.batch.draw(baseTexture, points[i].x, points[i].y, 5, 5);
}
rope.end();
for(int i=0;i<cp.length;i++){//draw the location of each point
game.font.draw(game.batch, "point "+i, cp[i].x, cp[i].y);
}
//logging systems
for(int i=0;i<20;i++){
if(Gdx.input.isTouched(i))
game.font.draw(game.batch, "x:"+Gdx.input.getX(i)+" y:"+Gdx.input.getY(i), 0, (game.font.getCapHeight()+10)*(i+1));
}
game.font.draw(game.batch, "fps:"+Gdx.graphics.getFramesPerSecond()+" log:"+log, 0, h-game.font.getCapHeight());
game.batch.end();
}
...
So I'm trying to map the pixel on the rgbMap to one on the depthMap so I can get the depth from a color tracked object.
I've noticed the depth map is smaller than the rgb map in addition to the different POV from being on a different spot on the kinect itself.
Is there an efficient way to do this that I'm unaware of? Currently I'm thinking of trying to line up the example pixels and then try to figure out an equation for the offset as you get farther away.
Code below, please not that the color tracking is far from done, and that I'm using mouse pressed for testing the pixel position.
/**
* ControlP5 Controlframe
* with controlP5 2.0 all java.awt dependencies have been removed
* as a consequence the option to display controllers in a separate
* window had to be removed as well.
* this example shows you how to create a java.awt.frame and use controlP5
*
* by Andreas Schlegel, 2012
* www.sojamo.de/libraries/controlp5
*
*/
import java.awt.Frame;
import java.awt.BorderLayout;
import controlP5.*;
import SimpleOpenNI.*;
private ControlP5 cp5;
ControlFrame cf;
SimpleOpenNI context;
Ktracker p,o,b;
float rx,ry,dx,dy;
int def;
void setup() {
size((2 * 640),480);
cp5 = new ControlP5(this);
o = new Ktracker(188,57,49);
// by calling function addControlFrame() a
// new frame is created and an instance of class
// ControlFrame is instanziated.
cf = addControlFrame("Output", 640,480);
// add Controllers to the 'extra' Frame inside
// the ControlFrame class setup() method below.
context = new SimpleOpenNI(this);
context.enableRGB();
context.enableDepth();
smooth();
rx=context.rgbWidth()/2;
ry=height/2;
}
void draw() {
context.update();
background(0,150,0);
image(context.depthImage(),context.rgbWidth(),0);
image(context.rgbImage(), 0,0);
int[] dm = context.depthMap();
o.run();
rectMode(CENTER);
noStroke();
fill(255,255,0);
rect(rx,ry,5,5);
dx=rx;
dy=ry;
fill(0,255,255);
rect(dx+context.rgbWidth(),dy,5,5);
rectMode(CORNER);
if(o.wr<10){
fill(0,0,255);
noStroke();
ellipse(o.currentPoints[0]+context.rgbWidth(),o.currentPoints[1],10,10);
cf.z = dm[int(o.currentPoints[0]*o.currentPoints[1])];
} else {
cf.z=0;
}
}
void mousePressed(){
rx=mouseX;
ry=mouseY;
}
ControlFrame addControlFrame(String theName, int theWidth, int theHeight) {
Frame f = new Frame(theName);
ControlFrame p = new ControlFrame(this, theWidth, theHeight);
f.add(p);
p.init();
f.setTitle(theName);
f.setSize(p.w, p.h);
f.setLocation(100, 100);
f.setResizable(false);
f.setVisible(true);
return p;
}
// the ControlFrame class extends PApplet, so we
// are creating a new processing applet inside a
// new frame with a controlP5 object loaded
public class ControlFrame extends PApplet {
int w, h;
float z;
int abc = 100;
public void setup() {
size(w, h, P3D);
frameRate(25);
z=0;
}
public void draw() {
background(abc);
translate(width/2,height/2,z/100);
sphere(250);
}
private ControlFrame() {
}
public ControlFrame(Object theParent, int theWidth, int theHeight) {
parent = theParent;
w = theWidth;
h = theHeight;
}
public ControlP5 control() {
return cp5;
}
ControlP5 cp5;
Object parent;
}
class Ktracker{
float mx,my,wr;
// A variable for the color we are searching for.
color trackColor;
float[] currentPoints, prevPoints;
Ktracker(int r,int g, int b){
trackColor = color(r,g,b);
currentPoints = new float[2];
prevPoints = new float[2];
prevPoints[0]=0;
prevPoints[1]=0;
}
void run(){
loadPixels();
// Before we begin searching, the "world record" for closest color is set to a high number that is easy for the first pixel to beat.
float worldRecord = 500;
// XY coordinate of closest color
int closestX = 0;
int closestY = 0;
// Begin loop to walk through every pixel
for (int x = 0; x < width/2; x ++ ) {
for (int y = 0; y < height; y ++ ) {
int loc = x + y*width;
// What is current color
color currentColor = pixels[loc];
float r1 = red(currentColor);
float g1 = green(currentColor);
float b1 = blue(currentColor);
float r2 = red(trackColor);
float g2 = green(trackColor);
float b2 = blue(trackColor);
// Using euclidean distance to compare colors
float d = dist(r1,g1,b1,r2,g2,b2); // We are using the dist( ) function to compare the current color with the color we are tracking.
// If current color is more similar to tracked color than
// closest color, save current location and current difference
if (d < worldRecord) {
worldRecord = d;
closestX = x;
closestY = y;
currentPoints[0] = closestX;
currentPoints[1] = closestY;
}
}
}
wr=worldRecord;
// We only consider the color found if its color distance is less than 10.
// This threshold of 10 is arbitrary and you can adjust this number depending on how accurate you require the tracking to be.
if (worldRecord < 10) {
// Draw a circle at the tracked pixel
fill(255,0,0);
//strokeWeight(4.0);
stroke(0,0);
ellipse(currentPoints[0],currentPoints[1],16,16);
}
println("wr: "+wr);
println("worldRecord: "+worldRecord);
}
}
If you want to align the depth map with the RGB map you need to simply tell OpenNI to do so fo you in setup:
context.alternativeViewPointDepthToImage();
Have a look at the AlternativeViewpoint3d sketch in Examples > SimpleOpenNI > OpenNI
OpenNI has the registration done already so all you need to do is enable it when you need it.
In the effort to learn more about applets and Java, I am experimenting making wave applets by drawing lines (drawLine) and making animated line graphs.
I can make a static graph just fine. However I am struggling with the animated aspect of the graph: the axes of the graph should move from left to right, increasing and growing larger than 0.
My problem is translating my needs into a solution. Can anyone give me any pointers with my problem?
I have a multidimensional array indexed by points containing the x and y of a particular point. I have tried modifying my render function to decrease the Xs to make it appear as if it is moving left but this doesn't work right.
What approach am I looking to take? How different will my approach be if the values of Y could change due to user action or added data?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;
/**
* A graph that should in the future represent a wave according to my inputs
*
* #authorImprofane
* #version 1
*/
public class Graph extends JFrame
{
private InnerGraph inner;
private int width;
private Random RNG;
private int height;
private int[][] series;
private int xoffset;
int prevx = 0;
int prevy = 0;
/**
* Constructor for objects of class Graph
*/
public Graph(int width, int height) throws InterruptedException
{
RNG = new Random();
setTitle(" Graph");
series = new int[width][2];
this.width = width;
this.height = height;
inner = new InnerGraph(width, height);
add(inner, BorderLayout.CENTER);
setVisible(true);
inner.preparePaint();
pack();
updateGraph();
}
public static void main(String[] args) throws InterruptedException
{
new Graph(300, 300);
}
public void updateGraph() throws InterruptedException
{
// virtual x is how far along on the x axis we are, I ignore the 'real' X axis
int vx = 0;
int point = 0;
int xdecay = 0;
int inc = 5;
// how many times we need to plot a point
int points = (int) java.lang.Math.floor( width / inc );
System.out.println(points);
inner.preparePaint();
// draw all points to graph
// make some junk data, a saw like graph
for (vx = 0 ; vx < points ; vx++) {
series[vx] = new int[] { vx*inc, ( (vx*inc) % 120 ) };
}
Thread.sleep(150);
int n = 5;
while(n > 0) {
System.out.println(xdecay);
inner.preparePaint();
for (vx = 0 ; vx < points ; vx++) {
inner.updateSeries(vx, xdecay);
inner.repaint();
Thread.sleep(50);
}
xdecay += inc;
// shift the data points to the left
int[][] nseries = new int[points][2];
// System.arraycopy(series, 1, nseries, 0, points-1);
n--;
}
}
public class InnerGraph extends JPanel
{
private Graphics g;
private Image img;
private int gwidth;
private int gheight;
Dimension size;
public InnerGraph(int width, int height)
{
gwidth = width;
gheight = height;
size = new Dimension(1, 1);
}
/**
* Try make panel the requested size.
*/
public Dimension getPreferredSize()
{
return new Dimension(gwidth, gheight);
}
/**
* Create an image and graphics context
*
*/
public void preparePaint()
{
size = getSize();
img = inner.createImage( (size.width | gwidth), (size.height | gheight) );
g = img.getGraphics();
}
/**
* Draw a point to the chart given the point to use and the decay.
* Yes this is bad coding style until I work out the mathematics needed
* to do what I want.
*/
public void updateSeries(int point, int decay)
{
g.setColor(Color.blue);
int nx = series[point][0];
series[point][0] -= decay;
if ( point-1 >= 0 ) {
series[point-1][0] -= decay;
}
int ny = series[point][1];
prevx -= decay;
g.drawLine(prevx-decay, prevy, nx-decay, ny );
prevx = nx-decay;
prevy = ny;
}
public void paintComponent(Graphics g)
{
g.drawImage(img, 0, 0, null);
}
}
}
First, it looks like you are subtracting the decay too often in the updateSeries method.
Below is a new version of that method.
public void updateSeries(int point, int decay)
{
g.setColor(Color.blue);
int nx = series[point][0];
series[point][0] -= decay;
if ( point-1 >= 0 ) {
series[point-1][0] -= decay;
}
int ny = series[point][1];
// prevx -= decay;
// g.drawLine(prevx-decay, prevy, nx-decay, ny );
g.drawLine(prevx, prevy, nx-decay, ny );
prevx = nx-decay;
prevy = ny;
}
With those changes, the lines draw better, but they draw so slowly that the animation is hard to see. You probably need to build a new graphics and swap the whole thing so that you don't have to watch each individual line segment being drawn.
For a starter you could check out the following example (and the ones related to this)
Scroll Chart #java2s.com