Libgdx for loop lag - android

I have problems with my game. The game runs ok until the time where I have to reposition the objects, which happens every frame. For example here I have to reposition some parked cars (around 6 cars on each side of the road), the cars are constantly moving down in the screen, then they reset and reposition at the top again. I have used Poolable to save resources. However, the game is still very jumpy when it comes to running these lines of code. Is there any way I could improve the code to prevent lag? Maybe a new thread? If so how would be the right way of creating a new thread and updating it every frame.
private void updateParkedVehicles(float delta){
for (int i = 0; i < parkedCarLeft1Array.size; i++){
parkedCarLeft1Array.get(i).update(delta);
for (int c = 0; c < parkedCarLeft1Array.size; c++){
if (c != i){
if (Intersector.overlaps(parkedCarLeft1Array.get(i).bounds, parkedCarLeft1Array.get(c).bounds)){
parkedCarLeft1Array.get(i).reset();
}
}
}
}
for (int i = 0; i < parkedCarRight1Array.size; i++){
parkedCarRight1Array.get(i).update(delta);
for (int c = 0; c < parkedCarRight1Array.size; c++){
if (c != i){
if (Intersector.overlaps(parkedCarRight1Array.get(i).bounds, parkedCarRight1Array.get(c).bounds)){parkedCarRight1Array.get(i).reset();
}
}
}
}
}

One way to handle items in your game is through the use of the Scene2d.
Scene2D allows you to step out from having to move yourself the items. Instead you give them instructions (as a director would) if and when you need to move them instead of having to handle yourselve every frame update.
in a nutshell, to add an Action you would do this:
if(SomeCondition){
MoveToAction moveCar = new MoveToAction();
moveCar.setPosition(anX,anY);
moveCar.setDuration(aDuration);
myCarActor.addAction(moveCar);
}
That way, the only thing you need to check for is the occurence of the event and you call your function to move the car only once (when the event occurs).
LibGdx will take care of updating your actor each frame.
The only thing you will need to do in your loop is to check the collision. If they occur then you will assign a new Action to your actor.
Another thing to keep in Mind, if you use Scene2D is that you can use the Camera. This means that if you need to scroll, instead of moving each item, you simply move the camera (which has all the convenience method you need to zoom etc).
For more information on Scene2D check out: https://github.com/libgdx/libgdx/wiki/scene2d
For more information specifically on Actions check this out:
https://github.com/libgdx/libgdx/wiki/Scene2d#actions
Hope it helps.

It seems to me that the problem is with double looping through arrays --> O(n^2) complexity!!
It's not clear for me why you need to check overlapping of each car with each car except this car if "the cars are constantly moving down in the screen, then they reset and reposition at the top again". For the described behaviour the simplest way would be to check is the current y position is less that 0 and rest position if so:
for (Car car : parkedCarLeft1Array){
car.update(delta);
if (car.getY <= 0) {
car.reset();
}
}
I assume that you update car position in update() method.

Related

Doing position calculation in onDraw it's faster than in game loop thread... why?

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.

Unity2D - How to rotate a 2D object on touch/click/press

First of all, I'll let you know that I'm new to Unity and to coding overall (I do know some very basic javascript coding). My question: How can I rotate a 2D object (prefab) 120 degrees on a certain axis (in my case the z-axis, so it rotates like you're looking at a steering wheel) every time I touch on the screen. Right now I have it like this:
function TouchOnScreen ()
{
if (Input.touchCount > 0)
{
var touch = Input.touches[0];
if (touch.position.x < Screen.width/2)
{
transform.rotation = Quaternion.Euler(0,0,120);
Debug.Log("RotateRight");
}
else if (touch.position.x > Screen.width/2)
{
transform.rotation = Quaternion.Euler(0,0,-120);
Debug.Log("RotateLeft");
}
}
}
This code rotates the object whenever I press on a certain side of the screen, but not how I want it to. I want it to rotate so you see the object rotating from A to B, but not (like it is now) in one frame from A to B. Also, this code lets me only rotate one time to each direction.
How can I make it that whenever I press on a certain side of the screen, that it adds or subtracts to/from the previous rotated angle, so I can keep on rotating.
NOTE: Please use javascript, and if you know a simpler code, let me know!
Help is highly appreciated, thanks in advance!
Instead of
transform.rotation = Quaternion.Euler(0,0,-120);
You use:
var lSpeed = 10.0f; // Set this to a value you like
transform.rotation = Quaterion.Lerp ( transform.rotation, Quaternion.Euler(0,0,-120), Time.deltaTime*lSpeed);

Unity2D Android Touch misbehaving

I am attempting to translate an object depending on the touch position of the user.
The problem with it is, when I test it out, the object disappears as soon as I drag my finger on my phone screen. I am not entirely sure what's going on with it?
If somebody can guide me that would be great :)
Thanks
This is the Code:
#pragma strict
function Update () {
for (var touch : Touch in Input.touches)
{
if (touch.phase == TouchPhase.Moved) {
transform.Translate(0, touch.position.y, 0);
}
}
}
The problem is that you're moving the object by touch.position.y. This isn't a point inworld, it's a point on the touch screen. What you'll want to do is probably Camera.main.ScreenToWorldPoint(touch.position).y which will give you the position inworld for wherever you've touched.
Of course, Translate takes a vector indicating distance, not final destination, so simply sticking the above in it still won't work as you're intending.
Instead maybe try this:
Vector3 EndPos = Camera.main.ScreenToWorldPoint(touch.position);
float speed = 1f;
transform.position = Vector3.Lerp(transform.position, EndPos, speed * Time.deltaTime);
which should move the object towards your finger while at the same time keeping its movements smooth looking.
You'll want to ask this question at Unity's dedicated Questions/Answers site: http://answers.unity3d.com/index.html
There are very few people that come to stackoverflow for Unity specific question, unless they relate to Android/iOS specific features.
As for the cause of your problem, touch.position.y is define in screen space (pixels) where as transform.Translate is expecting world units (meters). You can convert between the two using the Camera.ScreenToWorldPoint() method, then creating a vector out of the camera position and screen world point. With this vector you can then either intersect some geometry in the scene or simply use it as a point in front of the camera.
http://docs.unity3d.com/Documentation/ScriptReference/Camera.ScreenToWorldPoint.html

Detaching all instances of a sprite AndEngine

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()

Why aren't I getting One Bullet One Hit?

In my collision detection code, bullets are deactivated once they have been involved in a collision:
for(int j = 0; j < enemies.size(); j++){
//check for collision
if(bullets[i].isActive() && bullets[i].getSprite().collidesWith(enemies.get(j).getSprite())){
//remove bullet
removeBullet(i); //bullet is deactivated here, .isActive() will return false
if(enemies.get(j).damage(1)){
// --snip--
}
break;
}
}
The only place bullets are deactivated is in this section of code. The only place they are activated is when they are created.
Despite this a bullet will inflict damage multiple times. removeBullet() triggers an explosion animation, and this plays multiple times. What could be going wrong?
Update
Here's removeBullet()
private void removeBullet(int i){
if(bullets[i] == null) return;
bullets[i].deactivate();
makeSmallExplosion(bullets[i].getSprite().getX(),bullets[i].getSprite().getY());
bulletPool.recyclePoolItem(bullets[i]);
bullets[i] = null;
}
More than one thread may be running? Alternatively it might not be a problem with removing the bullet. But there are multiple bullets at that position and/or enemies?
Ah AndEngine; I'm actually a Mod on the forum :)
I've wrote this blog post about object pools in case you need to check the way you've implemented yours:
http://c0deattack.wordpress.com/category/programming/andengine/
I wonder if you're recycling the bullet properly?

Categories

Resources