Safely remove a sprite using Andengine - sprite

I am creating lots of ball sprites which bounce around the screen randomly. When touched, I want to the ball to be removed from the scene. (If more than one ball occupies the same space, that will be removed as well at the moment).
I realise the scene.detachChild must be run on the runOnUpdateThread, so within my Ball sprite subclass, I detachChild on touch by overriding onAreaTouched:
#Override
public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY)
{
((BaseGameActivity) thisAct).runOnUpdateThread(new Runnable() {
#Override
public void run() {
/* Now it is save to remove the entity! */
//scene.unregisterTouchArea(Ball.this);
scene.detachChild(Ball.this);
}
});
return false;
}
I have to pass in the main Activity to the constructor of the ball sprite and then remove the ball from the main Activities scene.
If I uncomment the scene.unregisterTouchArea(Ball.this) line, to stop the sprites acting on touches (this doesn't affect the removal, but thought it better to stop the touch being processed), I will receive the indexOutOfBoundsException that I think is related to not detaching sprites from within a runOnUpdateThread.
**java.lang.IndexOutOfBoundsException: Invalid index 90, size is 90
at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:257)
at java.util.ArrayList.get(ArrayList.java:311)
at org.anddev.andengine.entity.scene.Scene.onSceneTouchEvent(Scene.java:320)**
Two questions:
Am I correct to process the removal of the sprite within the ball subclass, using the override onAreaTouched, or should I somehow take the removal back into the main activity (do I need a subclass in the first place)?
Any idea why I get the IndexOutOfBoundsException if I include the unregisterTouchArea?
Thanks for any help.

Never do removal in the TouchListener. You should stick with a IUpdateHandler.
1.) It is not necessary to subclass you might do the removal everywhere where you have access to a scene.
2.) The IndexOutOfBoundException happens because you do the removal in the TouchListener. Probably some method adds new things to the scene while you are removing the sprite. Putting the removal in an UpdateHandler solves this.

/*
* Removing entities can only be done safely on the UpdateThread. Doing
* it while updating/drawing can cause an exception with a suddenly
* missing entity. Alternatively, there is a possibility to run the
* TouchEvents on the UpdateThread by default, by doing:
* engineOptions.getTouchOptions().setRunOnUpdateThread(true); when
* creating the Engine in onLoadEngine();
*/
MainActivity.this.runOnUpdateThread(new Runnable() {
#Override
public void run() {
/* Now it is safe to remove the entity! */
mScene.detachChild(face);
}
});

Related

Can you override the Navigation Controllers 'InteractivePopGestureRecognizer' action?

I'm searching for ways to implement a swipe gesture recognizer which only triggers when you swipe from the outer left side of the screen to the right. We need the gesture to open our custom SideMenu. I tried to use a simple UISwipeGestureRecognizer with the SwipeDirection property set to right, but that gets triggered on every swipe from left to right, no matter what the startpoint of the swipe is.
Ideally, we want the animation of it to look and feel like the InteractivePopGestureRecognizer of a UINavigationController. We are already using a NavigationController, which pushed our MainView over our IntroView. Now, we disable the InteractivePopGestureRecognizer, so you aren't able to go back to the IntroView. That's our problem. If it is possible, we don't want to disable the gesture of the NavigationController, but change the action of it. So the swipe from the far left side of the screen to the right would not pop the current viewcontroller, but open our SideMenu.
Is it possible to override the InteractivePopGestureRecognizer to change the action of it? If this isn't possible, do you have another idea on how to create the exact same gesture recognizer? It has to be possible somehow because many apps only open their SideMenu if your startpoint of the gesture is the left (or right) side of the screen. (e.g. Reddit)
Thanks for any help in advance.
You could use Touch Events and UISwipeGestureRecognizer to do that.
The workaround that is override TouchesBegan method to detect the started point whether fit your needs, and if so add UISwipeGestureRecognizer for View.
SwipeGestureRecognizer rightSwipeGesture;
public override void TouchesBegan (NSSet touches, UIEvent evt)
{
base.TouchesBegan (touches, evt);
UITouch touch = touches.AnyObject as UITouch;
if (touch != null)
{
//code here to handle touch
CoreGraphics.CGPoint swipPoint = touch.LocationInView(View);
if(swipPoint.X < 0.5)
{
rightSwipeGesture = new SwipeGestureRecognizer { Direction = SwipeDirection.Right };
rightSwipeGesture.Swiped += OnSwiped;
View.AddGestureRecognizers(rightSwipeGesture);
}
}
}
public override void TouchesEnded (NSSet touches, UIEvent evt)
{
base.TouchesBegan (touches, evt);
if(null != rightSwipeGesture ){
rightSwipeGesture.Swiped -= OnSwiped;
View.RemoveGestureRecognizers(rightSwipeGesture);
}
}
=============================Update=================================
I found a workaround only use one GestureRecognizer will make it works. You could have a look at UIScreenEdgePanGestureRecognizer. Although it's a Pan gesture, however if you not deal with somethind with the added view, it will work as a swip gesture. In addition, UIScreenEdgePanGestureRecognizer only can work when on the screen edge. You could set the Left edge to handle your needs.
For example:
UIScreenEdgePanGestureRecognizer panRightGestureRecognizer = new UIScreenEdgePanGestureRecognizer();
panRightGestureRecognizer.Edges = UIRectEdge.Left;
panRightGestureRecognizer.AddTarget(() => HandleSwap(panRightGestureRecognizer));
View.AddGestureRecognizer(panRightGestureRecognizer);
private void HandleSwip(UIScreenEdgePanGestureRecognizer panRightGestureRecognizer)
{
Point point = (Point)panRightGestureRecognizer.TranslationInView(View);
if (panRightGestureRecognizer.State == UGestureRecognizerState.Began)
{
Console.WriteLine("Show slider view");
}
}

JavaFX: Autoscroll of TextArea with appendText but without Listeners

I've read the other articles on Stackoverflow on this topic. But none of them matches my problem exactly.
I want to log an algorithm in a TextArea. In each iteration of the algorithm the text in this TextArea should be expanded via appendText().
My first problem is: Where should I create the new Thread and how can the both threads communicate with each other (GUI and algorithm)?
In my actual design I have three important classes: The view, which holds the TextArea, the controller, which calls the algorithm and the algorithm, which takes a number of iterations and the TextArea (to call the appendText()-method on severage places in the code).
In this design the controller calls the algorithm, the algorithm iterates n times with a for-loop and after it terminates, the GUI shows the changes. But I want the GUI to show the changes simultaneously, when the algorithm calls the appendText()-method.
And my second problem is the autoscroll of the TextArea. After each appendText-call the TextArea should be scrolled completely down. But I think the solution of this problem is the same solution of my first problem.
I would be very grateful for some help.
It's pretty much impossible to answer your question completely without (a lot) more information, but the general approach I would use would be for the algorithm to have a callback to process a message, which could be invoked by each step of the algorithm. From the controller, pass an implementation of the callback which updates the text area with the message, on the FX Application Thread.
Something like:
public class Algorithm {
private Consumer<String> statusCallback ;
public Algorithm(Consumer<String> statusCallback) {
this.statusCallback = statusCallback ;
}
public Algorithm() {
// by default, callback does nothing:
this(s -> {});
}
public void performAlgorithm() {
while (! finished() ) {
doNextStep();
String statusMessage = getStatus();
statusCallback.accept(statusMessage);
}
}
}
and then
public class Controller {
private View view = ... ;
public void startAlgorithm() {
Algorithm algorithm = new Algorithm(s -> Platform.runLater(view.appendStatus(s)));
Thread t = new Thread(algorithm::performAlgorithm);
t.setDaemon(true);
t.start();
}
}
For the View you then do the following (note that you can scroll down with textArea.setScrollTop(Double.MAX_VALUE);):
public class View {
private TextArea textArea ;
public View() {
textArea = new TextArea();
// ...
}
public void appendStatus(String status) {
if (!textArea.getText().isEmpty()) {
textArea.appendText("\n");
}
textArea.appendText(status);
textArea.setScrollTop(Double.MAX_VALUE);
}
}
This should work as long as your algorithm doesn't create too many status updates too fast (so that they flood the FX Application Thread and prevent it doing its normal work).

Is it a good idea to use repaint() as a game loop?

class MyCanvas extends Canvas{
protected void paint(Graphics g) {
//Process keyboard
//Update movement/position
//Draw
repaint(); //loop
}
}
Until now I used the Canvas's paint() for the game loop, but I came across some article in the web that says that another thread should be used here
Now I'm wondering if paint() is a good/safe place to process all the data.
So can I continue doing it like this?
Or should I make another thread for that?
I'm not sure of pros and cones of each so I'm not sure which method to choose but I got used to repaint method
I would not use paint() that way, no. paint() should be for painting ... drawing. I would split your monitoring of user input, and game logic processing, outside that method.
Have you considered using the GameCanvas subclass of Canvas?
It gives you some nice double-buffering features. You would create another thread, which would call your GameCanvas' run() method, where it would check for user input, update the game logic, then draw to the off-screen buffer, and finally trigger repainting of the on-screen buffer.
Something like this:
class MyGameCanvas extends GameCanvas implements Runnable {
/** start this game! */
public void start() {
Thread worker = new Thread(this);
worker.start();
}
/** run the game loop */
public void run() {
// Get the Graphics object for the off-screen buffer
Graphics g = getGraphics();
while (true) {
// Check user input and update positions if necessary
int keyState = getKeyStates();
if ((keyState & LEFT_PRESSED) != 0) {
sprite.move(-1, 0);
}
else if ((keyState & RIGHT_PRESSED) != 0) {
sprite.move(1, 0);
}
// Clear the background to white
g.setColor(0xFFFFFF);
g.fillRect(0,0,getWidth(), getHeight());
// Draw the Sprite
sprite.paint(g);
// Flush the off-screen buffer
flushGraphics();
try {
// TODO: of course, you might want a more intelligent
// sleep interval, that reflects the amount of time
// remaining (if any) in the cycle ...
Thread.sleep(10); //sleep 10 ms
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Note that I put basically everything in the run() method, for brevity. I'm assuming your game is more complicated, and would warrant splitting off separate methods for getting user input, updating logic, and then calling graphics/paint methods. Those would all be called from run().
Usage
Start this in your MIDlet's startApp() method:
MyGameCanvas gameCanvas = new MyGameCanvas();
gameCanvas.start();
exitCommand = new Command("Exit", Command.EXIT, 1);
gameCanvas.addCommand(exitCommand);
gameCanvas.setCommandListener(this);
Display.getDisplay(this).setCurrent(gameCanvas);
References
http://www.codeproject.com/Articles/35833/Programming-2D-Games-in-J2ME
an example that shows a better implementation, if you don't use GameCanvas and just use Canvas.
PowerPoint overview of Game APIs and looping , with code and general theory

Having trouble with AsyncTask using a recursive method

I've been reading about AsyncTasks and Hanlders and Loopers but I still can't figure out where I'm going wrong in my code. I'm trying to run code that will look over a Tic Tac Toe grid and determine the best move for the computer. I want this code to run in the background 'cause it can take some time and then I can update the UI level with a textbox that says something like "I'm Thinking". I've tried this a bunch of different ways, none with success.
private class PostTask extends AsyncTask<String, Integer, String> {
private Board _b;
private Welcome.Player _opp;
private int _depth;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
protected void SetVars(Board b, Player p, int depth){
_b = b;
_opp = p;
_depth = depth;
}
#Override
protected String doInBackground(String... params) {
Looper.prepare();
try{
_bestMove = _b.GetBestMove(_opp,_depth);
}
catch(Exception err){
_bestMove = -1;
}
return "All done";
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if(_bestMove == -1){
TextView tv = (TextView) findViewById(R.id.tv_Score);
tv.setText("Had and error, couldn't make a move.");
}
FollowUpComputerMove(this);
}
The above code will work for exactly 5 moves and then it crashes. When I watch in the debugger I see new theads being created named Thread<#> AsyncTask #1. Once I get to five of those AsyncTasks it goes back to try and grab the first AsyncTask and crashes. When it crashes I'm shown the ThreadPoolExecutor.class file.
I've also read that I shouldn't be using both the AsyncTask and the Looper objects together so I've tried taking the Loooper.prepare() statement out, but then my AsyncTask fails immediately with the error message:
Can't create handler inside thread that has not called Looper.prepare() - AsyncTask inside a dialog
I've read repeatedly that you shouldn't be trying to update the UI from an AsyncTask and that often the above error is because of that, but GetBestMove isn't updating the UI thread. When I trace through to see where the error comes, it fails when calling a constructor saying it can't find the class.
Can anyone point me in the right direction? My end goal is to use one main thread and only one background thread, and just keep re-using the background thread whenever the computer needs to make a move. I know that the recursive method GetBestMove works when I run this program in a single-thread manner. But the screen freezes for too long on some moves as the method is being run. Thank you so much.
-NifflerX
Apologies for answering my own question, but the issue I was facing had nothing to do with recursion. The class I was calling was extending the class Activity, and while trying to call that from an AsyncTask the program was erroring out. When I removed the extends Activity from the class definition it started working again. Sorry for the post.
-NifflerX

Can anybody explain me this code?

import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class SlideImage extends MIDlet{
private Display display;
public void startApp(){
display = Display.getDisplay(this);
display.setCurrent(new IconsCanvas());
}
public void pauseApp(){}
public void destroyApp(boolean unconditional){
notifyDestroyed();
}
}
class IconsCanvas extends Canvas implements Runnable{
SlideMenu menu = null;
public IconsCanvas(){
Image[] image = new Image[10];
try{
image[0] = Image.createImage("/bollywood-height.png");
image[1] = Image.createImage("/212229_1193669628.png");
image[2] = Image.createImage("/95936_50.png");
image[3] = Image.createImage("/shreya.png");
image[4] = Image.createImage("/Aishw.png");
image[5] = Image.createImage("/karishma.png");
image[6] = Image.createImage("/tmb_jiahkhannishabd.png");
image[7] = Image.createImage("/amisha.png");
image[8] = Image.createImage("/shilpashetty.png");
image[9] = Image.createImage("/priti.png");
menu = new SlideMenu(new String[]{"1", "2", "3", "4",
"5", "6", "7", "8", "9", "10"},
image, getWidth(), getHeight());
new Thread(this).start();
}catch(Exception e){
e.printStackTrace();
}
}
protected void paint(Graphics g){
menu.paint(g);
}
public void keyPressed(int key){
int gameKey = getGameAction(key);
if(gameKey == Canvas.RIGHT){
menu.slideItem(1);
}else if(gameKey == Canvas.LEFT){
menu.slideItem(- 1);
}
}
public void run(){
try{
while(true){
repaint();
synchronized(this){
wait(100L);
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
Most of things in this code i got the reason for usage..but the rest of things like
SlideMenu,
menu.paint(g),
menu.slideItem(1);
menu.slideItem(-1);
The above things, i find difficult to know why they have been used...
It (your original snippet, the run method) looks like a thread whose sole task it is to just repaint the component every tenth of a second.
As to what component it refers to, you haven't provided enough information. It depends on the object that the run() is running for.
In terms of the synchronized bit, this is most likely a way to prevent other threads doing stuff to the component while this thread is within the sleep.
If this is the object xyz, then any other thread trying to execute a block like:
synchronized (xyz) {
// Work your magic here.
}
will not be able to run while the wait is progressing.
By the way, if you use four spaces at the start of each code line (instead of <pre>), you get the nice syntax colouring as well. If you just mark the entire bit of code in the editor and use CTRLK, it will do it for you automagicaly.
And, in terms of your update, SlideMenu (picture on this page) appears to be a menu where one item is shown on the screen and left/right arrows allow you to scroll:
+---------+
| |
/ | | \
< | image | >
\ | | /
| |
+---------+
(forgive my pitiful graphic ability, I'll leave it there in case the link below ever disappears).
No doubt the images in the IconsCanvas ate the menu items to display. With that in mind, the other things make sense.
SlideMenu, I've already described.
menu.paint(g) is called to display the new menu in response to the IconsCanvas getting a paint request.
menu.SlideItem() slides the menu left or right depending on the argument.
The 100ms makes more sense now, if the image actually scrolls smoothly to the left or right.
In the code snippet above, on the synchronized block, the author's intention is just to wait/sleep so to be cooperative and let other threads run, and wait() must always be synchronized. But there is no need to queue so many repaints as there is no true animation going on, just displaying static slides (Images) when advancing to next/prev; the Canvas won't get invalidated until a new slide is shown (or a call comes in, etc), meaning it should be Ok to only repaint when a new slide is shown. Note that if "smooth scrolling" is desired, such effect should be implemented by SlideMenu itself which must also take care of repaints() scheduling (vs. IconCanvas)
Other comments:
On SlideMenu -- need to see the implementation of it
On menu.paint(g) -- it is delegating to the slide menu itself to paint/ refresh the current slide
On menu.slideItem(1); / menu.slideItem(-1); -- without looking at SlideMenu it seems to be a mechanism for navigation next/previous
You should consider making IconCanvas and SlideMenu Singletons.

Resources