I'm building a tank game using AndEngine that has multiple levels, but I'm not using multiple scenes, I'm sticking to 1 Main Game Scene that should reset and modify itself when the user beats the level.
I'm able to successfully modify the scene, but I'm having an issue with removing the enemies. There are multiple instances of an enemy sprite that the user has to kill, but when the user successfully completes the requirement to advance a level(killing x number of enemies), the enemies aren't reset; the instances from the previous level haven't been removed from the screen.
As a result, when a user is on Level 2, there might still be 3 or 4 enemies roaming around from Level 1 that the user didn't need to kill.
I tried using detachChild to remove the enemy from the screen and attachChild to instantly add them back, but when the next level started, the enemies wouldn't spawn.
How can I remove all instances of the enemy sprite that are currently on the screen without affecting the spawning?
when you are starting the game you have to create different layers(Entities) like gameLayer,
background Layer, HUD Layer... .So that you can update the items based on the situation.
This process make you unload resources smoothly when level is completed.
Coming to your requirement ... add every sprite instance to array list when it is created.
Remove all these as follows
public static void removeSprites(List<Sprite> spriteList, IEntity scene){
for(int i = spriteList.size() - 1; i >= 0; i--) {
final Sprite sprite = spriteList.get(i);
scene.detachChild(sprite);
spriteList.remove(i);
}
spriteList = null;
System.gc();
}
you must also unload Texture Atlases in your game
Well, try to use this method: sprite.detachchildren()
Related
I'm developing a simple game which uses normal android views, not openGL or other apis, simply uses views and moves them on the scren. I have a game loop which calls to AsteroidManager.updateAsteroidsPositions() which iterates in all the screen asteroids calculating it's possitions.
After that, the thread, calls to a AsteroidManager.invalidateAsteroids() method using runOnUiThread() method, because in Android you need to manipulate views on the main thread. AsteroidManager.invalidateAsteroids() method simply iterates all the asteroids and set's x,y positions to the view and calls invalidate().
The problem is that I disscovered that it gives a much more smooth and faster behaviour if you put the logic of calculatePositions inside the onDraw method of the view. Doing that, the logic of calculating possitions is not being done in the game loop thread... its being done in the main UI thread!!
How is that possible? It is breaking all the game development logic... about doing the position calculations on Game Loop thread instead of other places like main thread or onDraws...
This the slower original code:
AsteroidManager class:
public void updateAsteroidsPositions(){
for (int i = 0; i<onScreenAsteroids.size(); i++){
onScreenAsteroids.get(i).updatePosition();
}
}
public void invalidateAsteroids() {
for (int i = 0; i<onScreenAsteroids.size(); i++){
onScreenAsteroids.get(i).invalidate();
}
}
Asteroid Class:
public void updatePosition(){
currentScale = (Float) scaleX.getAnimatedValue();
factor = currentScale/MAX_SCALE;
//adding a minimum of factor, because with too low factor the movement is not realistic
if (factor < 0.250f)
factor = 0.250f;
x = x-((float)GameState.getInstance().getJoyX()*factor);
y = y-((float)GameState.getInstance().getJoyY()*factor);
}
public void invalidate(){
view.setX(x);
view.setY(y);
view.invalidate();
}
this is the trick done in Asteroid class which does the behaviour of the game smooth and faster:
Asteroid Class:
public Asteroid(Bitmap bitmap, Context context) {
view = new ImageView(context){
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
currentScale = (Float) scaleX.getAnimatedValue();
factor = currentScale/MAX_SCALE;
//adding a minimum of factor, because with too low factor the movement is not realistic
if (factor < 0.250f)
factor = 0.250f;
x = x-((float)GameState.getInstance().getJoyX()*factor);
y = y-((float)GameState.getInstance().getJoyY()*factor);
view.setX(x);
view.setY(y);
}
};
view.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
view.setImageBitmap(bitmap);
}
public void updatePosition(){
}
public void invalidate(){
view.invalidate();
}
If you have too many items in onScreenAsteroids list it takes some time to execute updatePosition() for each of them. Try to use single method for them:
public void updateAndInvalidateAsteroidsPositions(){
for (int i = 0; i<onScreenAsteroids.size(); i++){
onScreenAsteroids.get(i).updatePosition();
onScreenAsteroids.get(i).invalidate();
}
}
Not all games need game loop. Thread switching has its own cost.
Game Loop separates game state from rendering. Ideally the game loop has the responsibility to processes all the onscreen objects in the game and objects have the responsibility to draw itself in its place. This way we have central place to react to events(mouse click, user touch etc) and update view positions and views have the responsibility to draw themselves at updated position.
For eg consider that we have 10 moving asteroids on screen and we are updating them in onDraw(), now two of them collide, but asteroid1 does not know position of asteroid2, so how will they detect collision? By game logic the game loop knows position of all 10 asteroids, it can detect collision. If don't care about messy code, then collision can be detected in onDraw also. But consider following...
If two are colliding , then we need to check if some other asteroid is near by collision region, if so then how much impact? Mess increases linearly...
After collision we decide to show collision graphic effects. Mess increases exponentially....
Asteroids collided, game state = 'EXPLOSIONS IN THE SKY', user gets a call, game goes to background, game state is to be saved, but our asteroids are master of their own destiny, now we need to provide every asteroid's state to our activity and save it in onPause(). Its all mess now...
User returns after few hours, we can't welcome them directly with 'EXPLOSIONS IN THE SKY', need to rewind to the state where asteroids are about to collide and then show BANG-BANG... Mess goes ALL HELL BREAK LOOSE.....
Views are slaves and they should not be empowered.
Where to display view, its dimens? -> comes from outside.
What to draw in view? -> comes from outside/ can have little say here.
How to animate view? -> comes from outside.
Coming to your particular case, you are using both versions differently, in onDraw() case you are directly invalidating asteroid's (first one is drawn instantly) whereas in game loop case you are first computing all asteroid's position and then invalidating, I don't know how many asteroids you have but if they are significant number, then this coupled with thread switching costs, may trick you to believe onDraw() is faster.
I am developing a game using andEngine in android, I've developed animated sprites background, platforms and scores. for loading level, I've made a
.lvl
extension file in which I've defined platforms, player and obstacles at fixed positions. I want to know is there anything provided by andEngine so that I can dynamically load obstacles, platforms, coins and other objects rather than loading any file, my aim is to keep my game-world going as long as my player is alive.
I think I am clear.
Thanks!!!
I would like to point you to investigate "TimerHandler" as your dynamic time handler (Defining how often to attach another object/entity.
With a time handler in place, you can assign nearly any int/double/float value of an object/entity with MathUtils.random(min, max).
Example:
TimerHandler objectTimerHandler = new TimerHandler(1f, true, new ITimerCallback() {
#Override
public void onTimePassed(TimerHandler pTimerHandler) {
int timerSeconds = 0;
timerSeconds++;
final Sprite object1 = new Sprite(0, 0, resourcesManager.object1_region, vbom);
if (timerSeconds == MathUtils.random(1, 4))
{
attachChild(object1);
object1.setX(MathUtils.random(0, 480));
}
});
registerUpdateHandler(objectTimerHandler);
So, the TimeHandler "objectHandler" is called every 1 seconds defined by the 1f variable.
An integer counter "timerSeconds" is setup as a base.
The Sprite object/entity is initialized.
Now the "magic": the if boolean is in place to set a sense of true randomness. So here's the math... Every second passed, add a "timerSecond". Then, IF "timerSecond" is EQUAL to a random number between 1-4, then attach the sprite "object1" and set it's X position, also on a random range 0-480.
In reality, this means for every 1 second passed, there is a 1/4 chance that this sprite will be created/attached. (this can be altered to any desired chance range by changing that random range max value. EG: MathUtils.random(1, 100) <-- this would state a 1 in 100 chance to spawn the sprite each second.)
The 2nd to last line closes the Timehandler code, and the last line registers the Timehandler to the class/scene/entity/engine (ect..).
I am new to andengine and want to know that how I can switch between two BaseGameActivities. And also when switching from first activity to second, there is no black screen transition in between switching. Is there any possible way to do it.
Please help me out.
A BaseGameActivity can be used as any other Android Activity, too:
Intent intent = new Intent(this, MyOtherBaseGameActivity.class);
startActivity(intent);
So if you want to change from your program to another app (maybe by opening the browser…) you can do that as with any other Android App, too. However if both Activities are part of your own App, there is rarely a case where this is recommendable (It is like starting a second program). Although it is possible to exchange data between the activities as described in this post.
But maybe you are only looking for a way to switch between Views in AndEngine. If that's the case you can switch between Scenes without any transition necessary.
MyOtherScene secondScene = new MyOtherScene();
mEngine.setScene(secondScene);
That way you can switch between what is being displayed, without needing to load every image again.
EDIT:
Since you can't use AndEngine to switch between Activities, nor is a smooth switching between scenes possible. Here a quick example on how to switch between two screens (e.g. menus). In this example the screens are actually 2 different images (as big as the display … maybe some background images). Note: there is no such thing as 'screens' in AndEngine, it is simply a self made class that extends Entity.
Your Screen
public MyScreen extends Entity{
private float firstX;
public MyScreen(Sprite niceBackgroundImage1, Sprite niceBackgroundImage2){
this.attachChild(niceBackgroundImage1); // attach something to the screen, so you can see it (preferably an image that is as big as your camera)
this.attachChild(niceBackgroundImage2);
this.firstY=-1; // this is a variable to remember the first x coordinate touched
}
#Override
public boolean onAreaTouched(TouchEvent sceneTouchEvent, float touchAreaLocalX, float touchAreaLocalY) {
if(sceneTouchEvent.getAction()==TouchEvent.ACTION_DOWN){
this.firstY=touchAreaLocalX; // remember the x, on the first touch
}
if(sceneTouchEvent.getAction()==TouchEvent.ACTION_MOVE){
if(touchAreaLocalX>firstY+20){
// user swiped from left to right (at least 20 pixels)
niceBackgroundImage1.registerEntityModifier(new MoveModifier(3f, 0, niceBackgroundImage1.getWidth(), 0, 0, EaseBounceOut.getInstance()));
// the last line actualy moves the nice..image1 from left to right (in 3 seconds) and lets it bounce a little bit before it is completely out of the screen
return true;
}
}
return false;
}
...
}
Your Activity
private HUD hud; // create a HUD
...
#Override
protected void onCreateResources() {
this.hud = new HUD(); // init the HUD
this.myScreen = new MyScreen(image1, image2) // init the screen
this.hud.attachChild(myScreen); // attach the screen to the hud
mEngine.getCamera().setHud(hud); // attach your HUD to the camera
}
#Override
protected Scene onCreateScene() {
Scene myScene = new Scene();
myScene.registerTouchArea(myScreen); // you have to register the touch area of your Screen Class to the scene.
mEngine.setScene(myScene);
}
And this is how it works:
you create yourself a own screen class that extends Entity. An Entity can be everything visible in AndEngine (like a Sprite, Rectangle or even a whole scene). Put something in your screen class to make it look nice, preferably a big image that fills the whole display. That image will be responsible to register the touch afterwards. If the image is too small and the user misses the image, then no touch will be registered.
In this case I attach the instance of MyScreen to the cameras HUD. That way it will be at a fixed position on the display and it will have a fixed size (just in case you want to make the scene scrollable or zoomable).
Now when the app starts the HUD will be created and attached to the camera and with it your MyScreen class. Then the scene will be created and the screen's area will be registered as touch area to the scene. When a swipe movement on a horizontal axis gets noticed by the screen class, the first image will move outside the screen (in the same direction as the swipe).
But be careful, this is just an example. There is nothing defined on how the touch has to act when the first image was moved outside the screen or how big the screen actually is etc...
I know this is quite a long example, maybe it won't even work the first time and it is definitely not the only way on how switching between different screens can be done. But it shows you how to override the onAreaTouched() method and register the entity modifier to make the image move. Hopefully it will lead you in the right direction, to accomplish what you want to do.
Hey all I'm at a crossroads with my app that I've been working on.
It's a game and an 'arcade / action' one at that, but I've coded it using Surfaceview rather than Open GL (it just turned out that way as the game changed drastically from it's original design).
I find myself plagued with performance issues and not even in the game, but just in the first activity which is an animated menu (full screen background with about 8 sprites floating across the screen).
Even with this small amount of sprites, I can't get perfectly smooth movement. They move smoothly for a while and then it goes 'choppy' or 'jerky' for a split second.
I noticed that (from what I can tell) the background (a pre-scaled image) is taking about 7 to 8 ms to draw. Is this reasonable? I've experimented with different ways of drawing such as:
canvas.drawBitmap(scaledBackground, 0, 0, null);
the above code produces roughly the same results as:
canvas.drawBitmap(scaledBackground, null, screen, null);
However, if I change my holder to:
getHolder().setFormat(PixelFormat.RGBA_8888);
The the drawing of the bitmap shoots up to about 13 MS (I am assuming because it then has to convert to RGB_8888 format.
The strange thing is that the rendering and logic move at a very steady 30fps, it doesn't drop any frames and there is no Garbage Collection happening during run-time.
I've tried pretty much everything I can think of to get my sprites moving smoothly
I recently incorporated interpolation into my gameloop:
float interpolation = (float)(System.nanoTime() + skipTicks - nextGameTick)
/ (float)(skipTicks);
I then pass this into my draw() method:
onDraw(interpolate)
I have had some success with this and it has really helped smooth things out, but I'm still not happy with the results.
Can any one give me any final tips on maybe reducing the time taken to draw my bitmaps or any other tips on what may be causing this or do you think it's simply a case of Surfaceview not being up to the task and therefore, should I scrap the app as it were and start again with Open GL?
This is my main game loop:
int TICKS_PER_SECOND = 30;
int SKIP_TICKS = 1000 / TICKS_PER_SECOND;
int MAX_FRAMESKIP = 10;
long next_game_tick = GetTickCount();
int loops;
bool game_is_running = true;
while( game_is_running ) {
loops = 0;
while( GetTickCount() > next_game_tick && loops < MAX_FRAMESKIP) {
update_game();
next_game_tick += SKIP_TICKS;
loops++;
}
interpolation = float( GetTickCount() + SKIP_TICKS - next_game_tick )
/ float( SKIP_TICKS );
display_game( interpolation );
}
Thanks
You shouldn't use Canvas to draw fast sprites, especially if you're drawing a fullscreen image. Takes way too long, I tell you from experience. I believe Canvas is not hardware accelerated, which is the main reason you'll never get good performance out of it. Even simple sprites start to move slow when there are ~15 on screen. Switch to OpenGL, make an orthographic projection and for every Sprite make a textured quad. Believe me, I did it, and it's worth the effort.
EDIT: Actually, instead of a SurfaceView, the OpenGL way is to use a GLSurfaceView. You create your own class, derive from it, implement surfaceCreated, surfaceDestroyed and surfaceChanged, then you derive from Renderer too and connect both. Renderer handles an onDraw() function, which is what will render, GLSurfaceView manages how you will render (bit depth, render modes, etc.)
I have a little experimentation app (essentially a very cut-down version of the LunarLander demo in the Android SDK), with a single SurfaceView. I have a Drawable "sprite" which I periodically draw into the SurfaceView's Canvas object in different locations, without attempting to erase the previous image. Thus:
private class MyThread extends Thread {
SurfaceHolder holder; // Initialised in ctor (acquired via getHolder())
Drawable sprite; // Initialised in ctor
Rect bounds; // Initialised in ctor
...
#Override
public void run() {
while (true) {
Canvas c = holder.lockCanvas();
synchronized (bounds) {
sprite.setBounds(bounds);
}
sprite.draw(c);
holder.unlockCanvasAndPost(c);
}
}
/**
* Periodically called from activity thread
*/
public void updatePos(int dx, int dy) {
synchronized (bounds) {
bounds.offset(dx, dy);
}
}
}
Running in the emulator, what I'm seeing is that after a few updates have occurred, several old "copies" of the image begin to flicker, i.e. appearing and disappearing. I initially assumed that perhaps I was misunderstanding the semantics of a Canvas, and that it somehow maintains "layers", and that I was thrashing it to death. However, I then discovered that I only get this effect if I try to update faster than roughly every 200 ms. So my next best theory is that this is perhaps an artifact of the emulator not being able to keep up, and tearing the display. (I don't have a physical device to test on, yet.)
Is either of these theories correct?
Note: I don't actually want to do this in practice (i.e. draw hundreds of overlaid copies of the same thing). However, I would like to understand why this is happening.
Environment:
Eclipse 3.6.1 (Helios) on Windows 7
JDK 6
Android SDK Tools r9
App is targetting Android 2.3.1
Tangential question:
My run() method is essentially a stripped-down version of how the LunarLander example works (with all the excess logic removed). I don't quite understand why this isn't going to saturate the CPU, as there seems to be nothing to prevent it running at full pelt. Can anyone clarify this?
Ok, I've butchered Lunar Lander in a similar way to you, and having seen the flickering I can tell you that what you are seeing is a simple artefact of the double-buffering mechanism that every Surface has.
When you draw anything on a Canvas attached to a Surface, you are drawing to the 'back' buffer (the invisible one). And when you unlockCanvasAndPost() you are swapping the buffers over... what you drew suddenly becomes visible as the "back" buffer becomes the "front", and vice versa. And so your next frame of drawing is done to the old "front" buffer...
The point is that you always draw to seperate buffers on alternate frames. I guess there's an implicit assumption in graphics architecture that you're always going to be writing every pixel.
Having understood this, I think the real question is why doesn't it flicker on hardware? Having worked on graphics drivers in years gone by, I can guess at the reasons but hesitate to speculate too far. Hopefully the above will be sufficient to satisfy your curiousity about this rendering artefact. :-)
You need to clear the previous position of the sprite, as well as the new position. This is what the View system does automatically. However, if you use a Surface directly and do not redraw every pixel (either with an opaque color or using a SRC blending mode) you must clear the content of the buffer yourself. Note that you can pass a dirty rectangle to lockCanvas() and it will do the union for you of the previous dirty rectangle and the one you are passing (this is the mechanism used by the UI toolkit.) It will also set the clip rect of the Canvas to be the union of these two rectangles.
As for your second question, unlockAndPost() will do a vsync, so you will never draw at more than ~60fps (most devices that I've seen have a display refresh rate set around 55Hz.)