System.InvalidOperationException when drawing into HelixViewPort3D - process

Always when I want to draw into ViewPort3D out from a process I get a System.InvalidOperationException.
What is it I do not understand?
Is a process not able to access the ui process?
How can I solve this problem?
private void Pro_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
Random r = new Random();
DrawSphere(counter, Colors.Red, (double)r.Next(400) / 100);
counter++;
}
private void DrawSphere(int i, Color color, double radius)
{
SphereVisual3D sphere = new SphereVisual3D();
sphere.Center = new Point3D(i * 5, counter * 5, 0);
sphere.Visible = true;
sphere.Fill = new SolidColorBrush(color);
sphere.Radius = radius;
viewPort.Children.Add(sphere);
}

You need to use the dispatcher to check the access. You have 2 options:
First Option:
private void Pro_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
Random r = new Random();
Application.Current.Dispatcher.Invoke(new Action(() => DrawSphere(counter, Colors.Red, (double)r.Next(400) / 100)));
counter++;
}
Second Option:
private void Pro_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
Random r = new Random();
DrawToViewPort(counter, Colors.Red, (double)r.Next(400) / 100);
counter++;
}
private void DrawToViewPort(int i, Color color, double radius)
{
if (viewPort.Dispatcher.CheckAccess())
{
DrawSphere(i, color, radius);
}
else
{
viewPort.Dispatcher.Invoke((Action<int, Color, double>)DrawToViewPort, i, color, radius);
}
}

Related

JavaFx Problem with Service and Task with different Parameters and multiple calls

i need to create a Service and a Task to calculate the Mandelbrot and JuliaSet.
The calculation is working pretty good and now we need to give it into a Service and call it inside the task.
I have now the Problem, that every Time the task is executed, the Parameters are different.
I wrote a little Setter Function to parse those Arguments to the Service first.
But i'm not sure if this is the right Way?!
I'm also not sure how to correctly call the service in the main Function?
Now it works like this:
First time the service is executed, everything seems to work, but when i call it a secound Time, nothing seems to happen.....
Just to make sure: A Service can execute the Task multiple Times at the same Time?
Is it also posible with different Parameters?
Code Task:
private MandelbrotRenderOptions mandelbrot;
private JuliaRenderOptions juliaset;
private Canvas leftCanvas;
private Canvas rightCanvas;
//Constructor
public RenderTask(Canvas leftCanvas, Canvas rightCanvas) {
this.leftCanvas = leftCanvas;
this.rightCanvas = rightCanvas;
}
public void setOptions(MandelbrotRenderOptions mandelbrot, JuliaRenderOptions juliaset) {
this.mandelbrot = mandelbrot;
this.juliaset = juliaset;
}
#Override
protected Void call() throws Exception {
try {
System.out.println("HALLO SERVICE");
// instances for rendering the left canvas [pixel.data -> PixelWriter -> WritableImage -> GraphicsContext -> Canvas]
// creates an writable image which contains the dimensions of the canvas
WritableImage wimLeftCanvas = new WritableImage((int) leftCanvas.getWidth(), (int) leftCanvas.getHeight());
// instance which can write data into the image (instance above)
PixelWriter pwLeftCanvas = wimLeftCanvas.getPixelWriter();
// instance which fills the canvas
GraphicsContext gcLeftCanvas = leftCanvas.getGraphicsContext2D();
// instances for rendering the right canvas [pixel.data -> PixelWriter -> WritableImage -> GraphicsContext -> Canvas]
WritableImage wimRightCanvas = new WritableImage((int) rightCanvas.getWidth(), (int) rightCanvas.getHeight());
PixelWriter pwRight = wimRightCanvas.getPixelWriter();
GraphicsContext gcRightCanvas = rightCanvas.getGraphicsContext2D();
gcLeftCanvas.clearRect(0, 0, leftCanvas.getWidth(), leftCanvas.getHeight());
//Pixel[][] pixels; // contains pixel data for rendering canvas
// instances for logging the rendered data
SimpleImage simpleImageLeftCanvas = new SimpleImage((int) leftCanvas.getWidth(), (int) leftCanvas.getHeight());
SimpleImage simpleImageRightCanvas = new SimpleImage((int) rightCanvas.getWidth(), (int) rightCanvas.getHeight());
short dataSimpleImage[] = new short[3]; // contains pixel data for logging rendered data
// fills left canvas (mandelbrot) PixelWriter instance with data
Pixel[][] pixels = mandelbrot.setAllPixels();
FractalLogger.logRenderCall(mandelbrot);
for (int y = 0; y < (int) leftCanvas.getHeight(); y++) {
for (int x = 0; x < (int) leftCanvas.getWidth(); x++) {
// parses color data to PixelWriter instance
Color color = Color.rgb(pixels[y][x].getRed(), pixels[y][x].getGreen(), pixels[y][x].getBlue());
pwLeftCanvas.setColor(x, y, color);
for (int depth = 0; depth < 3; depth++) {
if (depth == 0) {
dataSimpleImage[depth] = pixels[y][x].getRed();
} else if (depth == 1) {
dataSimpleImage[depth] = pixels[y][x].getGreen();
} else {
dataSimpleImage[depth] = pixels[y][x].getBlue();
}
}
try {
simpleImageLeftCanvas.setPixel(x, y, dataSimpleImage); // because data must not be null
} catch (InvalidDepthException e) {
e.printStackTrace();
}
}
}
// logs that rendering of mandelbrot is finished
FractalLogger.logRenderFinished(FractalType.MANDELBROT, simpleImageLeftCanvas);
// fills left canvas (juliaset) PixelWriter instance with data
pixels = juliaset.setAllPixels();
FractalLogger.logRenderCall(mandelbrot);
for (int y = 0; y < (int) rightCanvas.getHeight(); y++) {
for (int x = 0; x < (int) rightCanvas.getWidth(); x++) {
// pareses color to PixelWriter instance
Color color = Color.rgb(pixels[y][x].getRed(), pixels[y][x].getGreen(), pixels[y][x].getBlue());
pwRight.setColor(x, y, color);
for (int depth = 0; depth < 3; depth++) {
if (depth == 0) {
dataSimpleImage[depth] = pixels[y][x].getRed();
} else if (depth == 1) {
dataSimpleImage[depth] = pixels[y][x].getGreen();
} else {
dataSimpleImage[depth] = pixels[y][x].getBlue();
}
}
try {
simpleImageRightCanvas.setPixel(x, y, dataSimpleImage); // because data must not be null
} catch (InvalidDepthException e) {
e.printStackTrace();
}
}
}
// logs that rendering of juliaset is finished
FractalLogger.logRenderFinished(FractalType.JULIA, simpleImageRightCanvas);
// writes data from WriteableImage instance to GraphicsContext instance, which finally parses renders it into the canvas
gcLeftCanvas.drawImage(wimLeftCanvas, 0, 0);
FractalLogger.logDrawDone(FractalType.MANDELBROT);
gcRightCanvas.drawImage(wimRightCanvas, 0, 0);
FractalLogger.logDrawDone(FractalType.JULIA);
return null;
} catch (Exception e) {
System.out.println("ERROR");
System.out.println(e);
return null;
}
}
#Override
protected void cancelled()
{
super.cancelled();
updateMessage("The task was cancelled.");
}
#Override
protected void failed()
{
super.failed();
updateMessage("The task failed.");
}
#Override
public void succeeded()
{
super.succeeded();
updateMessage("The task finished successfully.");
} ```
And i call it like this in the main:
``` Service service = new Service() {
#Override
protected Task createTask() {
return new RenderTask(leftCanvas, rightCanvas);
}
};
task.setOptions(mandelbrot, juliaset);
service.restart(); ```

Custom Renderer for Dashed Border of frame in UWP Xamarin

I want a frame with a dashed border (as shown in the image). I am looking for UWP Renderer if anyone has any suggestions on that please share them with me. I am stuck with this.
Custom Renderer for Dashed Border of frame in UWP Xamarin
Current there is not such Dashed Border of frame in UWP Xamarin, but you can make it with Rectangle and set available StrokeDashArray to implement it and then use ViewRenderer to render it within Xamarin. We will share DashedBorderRenderer below, for the complete control please refer code sample here.
public class DashedBorderRenderer : ViewRenderer<DashedBorder, DottedBorder>
{
DottedBorder _dottedBorder;
FrameworkElement _navtiveContent;
double defaultPadding = 2;
bool isOpened;
public DashedBorderRenderer()
{
}
protected override void OnElementChanged(ElementChangedEventArgs<DashedBorder> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
_navtiveContent.Loaded -= Native_Loaded;
_navtiveContent.SizeChanged -= Native_SizeChanged;
}
if (e.NewElement != null)
{
if (Control != null)
{
var stroke = Element.DashedStroke == 0 ? Element.DashedStroke : 2.0;
var borderColor = Element.BorderColor.ToWindowsColor() == null ? Element.BorderColor.ToWindowsColor() : Colors.Red;
Control.DashedStroke = new Windows.UI.Xaml.Media.DoubleCollection() { stroke };
Control.StrokeBrush = new Windows.UI.Xaml.Media.SolidColorBrush(borderColor);
}
else
{
_dottedBorder = new DottedBorder();
_navtiveContent = Element.Content.GetOrCreateRenderer().GetNativeElement() as FrameworkElement;
_navtiveContent.Loaded += Native_Loaded;
_navtiveContent.SizeChanged += Native_SizeChanged;
var stroke = Element.DashedStroke == 0 ? 2.0 : Element.DashedStroke;
var borderColor = Element.BorderColor.ToWindowsColor() == null ? Element.BorderColor.ToWindowsColor() : Colors.Red;
_dottedBorder.DashedStroke = new Windows.UI.Xaml.Media.DoubleCollection() { stroke };
_dottedBorder.StrokeBrush = new Windows.UI.Xaml.Media.SolidColorBrush(borderColor);
SetNativeControl(_dottedBorder);
}
}
}
private void Native_SizeChanged(object sender, SizeChangedEventArgs e)
{
UpdateSize(sender);
}
private void Native_Loaded(object sender, RoutedEventArgs e)
{
UpdateSize(sender);
}
private void UpdateSize(object sender)
{
var content = sender as FrameworkElement;
if (content is Windows.UI.Xaml.Controls.Image)
{
if (!isOpened)
{
(content as Windows.UI.Xaml.Controls.Image).ImageOpened += (s, e) =>
{
isOpened = true;
var image = sender as Windows.UI.Xaml.Controls.Image;
_dottedBorder.Height = image.ActualHeight + defaultPadding;
_dottedBorder.Width = image.ActualWidth + defaultPadding;
};
}
else
{
_dottedBorder.Height = content.ActualHeight + defaultPadding;
_dottedBorder.Width = content.ActualWidth + defaultPadding;
}
}
_dottedBorder.Height = content.ActualHeight+defaultPadding;
_dottedBorder.Width = content.ActualWidth + defaultPadding;
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
}
}

How to set both axis's scales to be always the same?

MPAndroidChart allows you to zoom in the X axis, Y axis and both. I would like to rescale the remaining axis (or both) to match the one(s) being scaled.
For that I've created a OnChartGestureListener:
public class ZoomNotDistorting implements OnChartGestureListener {
private Chart chart;
private ViewPortHandler viewPortHandler;
private float startDist = 1f;
private float scaleX, scaleY;
public ZoomNotDistorting(Chart chart) {
this.chart = chart;
this.viewPortHandler = chart.getViewPortHandler();
}
#Override
public void onChartGestureStart(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
int action = me.getAction() & MotionEvent.ACTION_MASK;
if(action == MotionEvent.ACTION_POINTER_DOWN && me.getPointerCount() >= 2) {
startDist = spacing(me);
}
}
#Override
public void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
switch (lastPerformedGesture) {
case PINCH_ZOOM:
float scale = spacing(me) / startDist; // total scale
boolean isZoomingOut = (scale < 1);
if(isZoomingOut) {
if(scaleX < scaleY) {
viewPortHandler.zoom(scaleX, scaleX);
} else {
viewPortHandler.zoom(scaleY, scaleY);
}
} else {
if(scaleX > scaleY) {
viewPortHandler.zoom(scaleX, scaleX);
} else {
viewPortHandler.zoom(scaleY, scaleY);
}
}
break;
case X_ZOOM:
viewPortHandler.zoom(scaleX, scaleX);
break;
case Y_ZOOM:
viewPortHandler.zoom(scaleY, scaleY);
break;
}
chart.invalidate();
}
#Override
public void onChartLongPressed(MotionEvent me) {}
#Override
public void onChartDoubleTapped(MotionEvent me) {}
#Override
public void onChartSingleTapped(MotionEvent me) {}
#Override
public void onChartFling(MotionEvent me1, MotionEvent me2, float velocityX, float velocityY) {}
#Override
public void onChartScale(MotionEvent me, float scaleX, float scaleY) {
this.scaleX = scaleX;
this.scaleY = scaleY;
}
#Override
public void onChartTranslate(MotionEvent me, float dX, float dY) {}
/**
* returns the distance between two pointer touch points
*/
private static float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);
}
}
That class doesn't seem to be doing anything,How to set both axis's scales to be always the same?
Also, here is my chart class:
public class MathGraph extends LineChart {
public static final int BOUNDARIES = 100;
public static final int DATA_POINTS = 200;
private static final int LINE_WIDTH = 2;
private LineData data;
public MathGraph(Context context, AttributeSet attrs) {
super(context, attrs);
super.setDescription(null);
//Misc
getLegend().setEnabled(false);
setRenderer(new LineChatRendererNoData(this, mAnimator, mViewPortHandler));
//Lines encasing the chart
getXAxis().setAxisLineWidth(LINE_WIDTH);
getAxisLeft().setAxisLineWidth(LINE_WIDTH);
getAxisRight().setEnabled(false);
//Line for (x; 0)
getAxisLeft().setDrawZeroLine(true);
getAxisLeft().setZeroLineWidth(LINE_WIDTH);
getAxisRight().setDrawZeroLine(true);
getAxisRight().setZeroLineWidth(LINE_WIDTH);
//Line for (0; y)
LimitLine limitLine = new LimitLine(0f);
limitLine.setLineColor(Color.GRAY);
limitLine.setLineWidth(LINE_WIDTH);
getXAxis().addLimitLine(limitLine);
setOnChartGestureListener(new ZoomNotDistorting(this));
}
public void setFunction(Function f) {
if(!f.checkSyntax()) throw new IllegalStateException("Error in function: " + f.toString() + "!");
setDescription(f);
data = null;
LoadFunctionAsyncTask l = new LoadFunctionAsyncTask(f, -BOUNDARIES, BOUNDARIES, DATA_POINTS,
(List<Entry> pointList) -> {
if(data == null) {
ILineDataSet dataSet = new LineDataSet(new ArrayList<>(), null);
dataSet.setValueFormatter(new PointValueFormatter());
dataSet.setHighlightEnabled(true);
for (Entry dataPoint : pointList) {
dataSet.addEntry(dataPoint);
}
data = new LineData(dataSet);
setData(data);
} else {
for (Entry dataPoint : pointList) {
data.addEntry(dataPoint, 0);// 0 is the only dataset
}
data.notifyDataChanged();
notifyDataSetChanged();
invalidate();
}
});
l.execute();
}
private void setDescription(Function f) {
Description desc = new Description();
desc.setText(f.getDescription());
desc.setPosition(16, getBottom() - 16);
setDescription(desc);
}
private class PointValueFormatter implements IValueFormatter {
#Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
return "(" + entry.getX() + ", " + entry.getY() + ")";
}
}
}
OK, apparently chart.invalidate() isn't enough, the Matrix needs to be refreshed:
Matrix matrix = null;
//...
matrix = viewPortHandler.zoom(scaleX, scaleX);
//...
if(matrix != null) {
viewPortHandler.refresh(matrix, chart, true);
}
As a bonus, the last true in refresh() is for invalidate, so no need for chart.invalidate();.

MPAndroidChart multiple real time line chart - entries not added at correct xIndex

I modified a little bit the Real Time Line Chart example to show two LineChart like the code below.
Problem: the ViewPort is moving incorrectly does not work properly. It is moving much faster than real points (Entry) are added. In other words, the Entry get added in the wrong place and the ViewPort keeps moving right uncontrollably. It should move right only gradually as each Entry is added. Please help me to fix this one.
private int year = 2015;
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss.SSS");
private int[] mColors = {Color.BLUE,Color.YELLOW,Color.CYAN,Color.MAGENTA,Color.GREEN};
private int mCurrentColorIndex = 0;
private synchronized void addEntry(String id, float value) {
LineData data = mChart.getData();
if (data != null) {
ILineDataSet set = data.getDataSetByLabel(id,true);
//ILineDataSet set1 = data.getDataSetByIndex(0);
if (set == null) {
set = createSet(id, mColors[(mCurrentColorIndex++)%mColors.length ]);
data.addDataSet(set);
}
String xValue = sdf.format(new Date());
// add a new x-value first
data.addXValue(xValue);
set.addEntry(new Entry(value, set.getEntryCount(), 0));
// let the chart know it's data has changed
mChart.notifyDataSetChanged();
// limit the number of visible entries
mChart.setVisibleXRangeMaximum(30);
// mChart.setVisibleYRange(30, AxisDependency.LEFT);
// move to the latest entry
mChart.moveViewToX(data.getXValCount() - 31);
// this automatically refreshes the chart (calls invalidate())
// mChart.moveViewTo(data.getXValCount()-7, 55f,
// AxisDependency.LEFT);
}
}
private LineDataSet createSet(String label, int color) {
LineDataSet set = new LineDataSet(null, label);
set.setAxisDependency(AxisDependency.LEFT);
set.setColor(color);
set.setCircleColor(Color.WHITE);
set.setLineWidth(2f);
set.setCircleRadius(4f);
set.setFillAlpha(65);
set.setFillColor(color);
set.setHighLightColor(Color.rgb(244, 117, 117));
set.setValueTextColor(Color.WHITE);
set.setValueTextSize(9f);
set.setDrawValues(false);
return set;
}
private void feedMultiple() {
new Thread(new Runnable() {
#Override
public void run() {
for(int i = 0; i < 50; i++) {
runOnUiThread(new Runnable() {
#Override
public void run() {
addEntry("name1", (float)(Math.random() * 40) + 30f);
}
});
try {
Thread.sleep(35);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(new Runnable() {
#Override
public void run() {
for(int i = 0; i < 100; i++) {
runOnUiThread(new Runnable() {
#Override
public void run() {
addEntry("name2", (float)(Math.random() * 40) + 30f);
}
});
try {
Thread.sleep(35);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
Resolved in the comments by #Tony with the following change:
//set.addEntry(new Entry(value, set.getEntryCount(), 0)); //incorrect
set.addEntry(new Entry(value, data.getXValCount(), 0)); //correct
Explanation:
A LineData is composed of multiple ILineDataSet:
set.getEntryCount() returns the number of y-values in one DataSet and is effectively equivalent to yvals.size().
data.getXValCount() returns the total number of x-values the ChartData object represents.
Since we wish to add an entry at the last x-index, we should use data.getXValCount()
NOTE:
In MPAndroidCharts 3.0.1 data.getXValCount() is no longer present. You can instead use data.getXMax() + 1 instead.

(libgdx/java) ArrayList won't clear/delete instance of class?

Item class:
public class Item {
public float x, y, speedx, speedy;
public Rectangle container;
public Texture texture;
static Timer timer = new Timer();
static int amount;
static int spawned;
public int itemtype;
// float delay = 1; // seconds
public void move() {
x += speedx;
y += speedy;
container.x = x;
container.y = y;
}
public void setTexture(int itemtype){
switch(itemtype){
case 1:
texture = new Texture("items/item1.png");
break;
case 2:
texture = new Texture("items/item2.png");
break;
case 3:
texture = new Texture("items/item3.png");
break;
case 4:
texture = new Texture("items/item4.png");
break;
case 5:
texture = new Texture("items/item5.png");
break;
case 6:
texture = new Texture("items/item6.png");
break;
case 7:
texture = new Texture("items/item7.png");
break;
case 8:
texture = new Texture("items/item8.png");
break;
case 9:
texture = new Texture("items/item9.png");
break;
case 10:
texture = new Texture("items/item10.png");
break;
default:
texture = new Texture("items/error.png");
break;
}
}
public static void spawnItem(int amount){
Item.amount = amount;
mainscreen.items.clear();
// for(int spawned = 0; spawned <= amount; spawned++){
timer.schedule(new Timer.Task() {
#Override
public void run() {
if (mainscreen.canclick == false) {
Item item = new Item();
item.x = 600;
item.y = -42;
item.speedx = -20;
item.speedy = 0;
Rectangle itemcontainer = new Rectangle();
itemcontainer.x = item.x;
itemcontainer.y = item.y;
itemcontainer.width = mainscreen.container.getWidth() / 4f;
itemcontainer.height = mainscreen.container.getHeight() - 15f;
item.container = itemcontainer;
item.itemtype = MathUtils.random(1, 10);
item.setTexture(item.itemtype);
mainscreen.items.add(item);
spawned++;
}
for (Item item : mainscreen.items) {
if (item.x <= -4000) {
if (spawned >= Item.amount) {
mainscreen.canclick = true;
timer.stop();
spawned = 0;
}
} else {
}
}
}
}, 0, 0.325f);
}
public void dispose(){
texture.dispose();
}
}
Mainscreen class:
public class mainscreen implements Screen, GestureDetector.GestureListener,InputProcessor {
#Override
public void render(float delta) {
this.delta = delta;
Gdx.gl.glClearColor(115 / 255F, 115 / 255F, 115 / 255F, 1 / 255F);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
if(Gdx.input.justTouched()) {
Vector3 touch1 = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(touch1);
if (debug.contains(touch1.x, touch1.y)) {
items.clear();
}
if (start.contains(touch1.x, touch1.y)) {
if (canclick == true) {
canclick = false;
Item.spawnItem(20);
}
}
}
}
LOG:
On first click start:
(After the Timer has finished)
canclick: true
items list: [com.abc.luckyllama.Item#37237aa0, com.abc.luckyllama.Item#2de938e3, com.abc.luckyllama.Item#3cb912d5, com.abc.luckyllama.Item#2bae592c, com.abc.luckyllama.Item#774c083, com.abc.luckyllama.Item#633edeae, com.abc.luckyllama.Item#176557a6, com.abc.luckyllama.Item#4edb1b5f, com.abc.luckyllama.Item#6f8abadf, com.abc.luckyllama.Item#7a54d22e, com.abc.luckyllama.Item#473162a5, com.abc.luckyllama.Item#51a698ff, com.abc.luckyllama.Item#6bc08c56, com.abc.luckyllama.Item#37d9e6a2, com.abc.luckyllama.Item#7bb19eb6, com.abc.luckyllama.Item#1eb5805f, com.abc.luckyllama.Item#71780de3, com.abc.luckyllama.Item#9ec0998, com.abc.luckyllama.Item#7edf723d, com.abc.luckyllama.Item#4c5aa2c1]
After clicking the debug button(clears arraylist):
canclick: true
items list: []
After clicking the start button again:
(After the Timer has finished)
canclick: true
items list: [com.abc.luckyllama.Item#7d7cb9bc, com.abc.luckyllama.Item#1435cf42, com.abc.luckyllama.Item#117e1963, com.abc.luckyllama.Item#82bfd27, com.abc.luckyllama.Item#108214c7, com.abc.luckyllama.Item#2a77864a, com.abc.luckyllama.Item#4b232766, com.abc.luckyllama.Item#1cb629e0, com.abc.luckyllama.Item#1c92229d, com.abc.luckyllama.Item#ac1b293, com.abc.luckyllama.Item#588bbcba, com.abc.luckyllama.Item#75df6762, com.abc.luckyllama.Item#78d4358e, com.abc.luckyllama.Item#7f86452d, com.abc.luckyllama.Item#7aed480b, com.abc.luckyllama.Item#7407d443, com.abc.luckyllama.Item#2da6e708, com.abc.luckyllama.Item#604470bc, com.abc.luckyllama.Item#70f9d1af, com.abc.luckyllama.Item#3a16a63f, com.abc.luckyllama.Item#201288d2, com.abc.luckyllama.Item#6310ddfc, com.abc.luckyllama.Item#5d5a1c98, com.abc.luckyllama.Item#52727e52, com.abc.luckyllama.Item#669228d6]
You see that the Items inside the ArrayList didn't get cleared. It increased. I think that's because the instances of Item created in spawnItem() are still there. How do I fix this?
I noticed that every time I click the button there aren't more items. The items are spawned faster. But how to stop this?
I fixed it! The problem was that I needed to create a Timer.Task seperately and the use task.cancel(); to stop the Timer.Task:
import com.badlogic.gdx.utils.Timer;
public class Item {
public static Timer.Task task;
public static void spawnItem(int amount){
Item.amount = amount;
task = new Timer.Task() {
#Override
public void run() {
if (mainscreen.canclick == false) {
item = new Item();
item.x = 600;
item.y = -42;
item.speedx = -20;
item.speedy = 0;
Rectangle itemcontainer = new Rectangle();
itemcontainer.x = item.x;
itemcontainer.y = item.y;
itemcontainer.width = mainscreen.container.getWidth() / 3f;
itemcontainer.height = mainscreen.container.getHeight() - 15f;
item.container = itemcontainer;
item.itemtype = MathUtils.random(1, 10);
item.setTexture(item.itemtype);
mainscreen.items.add(item);
mainscreen.itemsspawned += 1;
// mainscreen.items.remove(item);
spawned++;
}
for (Item item : mainscreen.items) {
if (item.x <= -4000) {
if (spawned >= Item.amount) {
mainscreen.canclick = true;
timer.clear();
timer.stop();
task.cancel();
spawned = 0;
}
}
}
}
};
timer.schedule(task, 0, 0.4f);
}
}