How to optimize my Android flash game? - android

I have a game that I converted to my Android phone. I tried both renders, and found out that CPU mode is a better option than GPU for my type of game. In GPU mode, the game has a lot of lag and the graphics are not sharp as it is in CPU mode. The purpose of the game is to kill enemies coming from the top of the screen before they hit the bottom. When the game starts, it's not laggy at all, but then it starts to lag when there are a few enemies on the screen and they start coming down faster. This is the code of spawning the enemies:
function makeEnemies():void
{
var chance:Number = Math.floor(Math.random() * 150);
if (chance <= level && enemies.length < 4)
{
tempEnemy = new Enemy();
tempEnemy.x = Math.round(Math.random() * 480);
tempEnemy.cacheAsBitmap = true;
addChild(tempEnemy);
tempEnemy.scaleX = 1.5;
tempEnemy.scaleY = 1.5;
enemies.push(tempEnemy);
tempEnemy.speed = enemyBaseSpeed + ((level - 1) * speedLevelInc);
if (tempEnemy.speed > MAX_SPEED)
{
tempEnemy.speed = MAX_SPEED;
}
}
}
function moveEnemies():void
{
var tempEnemy:MovieClip;
for (var i:int =enemies.length-1; i>=0; i--)
{
tempEnemy = enemies[i];
if (tempEnemy.dead)
{
score++;
score++;
roachLevel.score_txt.text = String(score);
enemies.splice(i,1);
}
else
{
tempEnemy.rotation += (Math.round(Math.random()*.4));
tempEnemy.x -= (Math.sin((Math.PI/180)*tempEnemy.rotation))*tempEnemy.speed;
tempEnemy.y += (Math.cos((Math.PI/180)*tempEnemy.rotation))*tempEnemy.speed;
if (tempEnemy.x < 10)
{
tempEnemy.x = 11;
}
if (tempEnemy.x > stage.stageWidth - offset)
{
tempEnemy.x = stage.stageWidth - offset;
}
if (tempEnemy.y > stage.stageHeight)
{
removeEnemy(i);
lives--;
roachLevel.lives_txt.text = String(lives);
}
}
}
}
This code is always looped to spawn multiple enemies. All my images have been converted to bitmaps. Is there any other way for me to make my game with no lag? The faster they get, the more lag they have and the user can't kill them anymore. Please help!

There are certain optimizations you can make (whether or not it's enough I can't tell):
you don't need cacheAsBitmap if you've converted everything to bitmaps, so comment this out
don't set scale! this will definitely slow things down. Since scale always seems to be 1.5, just resize your graphics
don't set tempEnemy.rotation on each iteration, if possible. Can you make tempEnemy a MovieClip that "pre-rotates" each frame in the timeline? This will be way more efficient for Flash. The rotation can be set as a Number property in the MovieClip class if you still need it for calculating tempEnemy.x and y.
(There are several minor things you can optimize, like setting var K = (Math.PI/180)*tempEnemy.rotation) in the enemies loop-- but this won't gain you a lot)

Related

LibGDX texture bleeding issue

I'm new to LibGDX and was trying to implement parallax background.
Everything went good until I faced such issue: I get some stripes when scrolling background. You can see it in attached image:
So I looked deeper into an issue and figured out that this some sort of texture bleeding. But the case is that my textures already have [Linear, Nearest] filter set and TexturePacker uses duplicatePadding. Actually, I don't know any other methods to solve this issue. Please help!
Here's some of my code:
TexturePacker
TexturePacker.Settings settings = new TexturePacker.Settings();
settings.minWidth = 256;
settings.minHeight = 256;
settings.duplicatePadding = true;
TexturePacker.process(settings, "../../design", "./", "textures");
AssetLoader
textureAtlas = new TextureAtlas(Gdx.files.internal("textures.atlas"));
for (int i = 0; i < 2; i++) {
Background.skies.add(textureAtlas.findRegion("background/sky", i));
Background.skies.get(i).getTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Nearest);
}
for (int i = 0; i < 2; i++) {
Background.clouds.add(textureAtlas.findRegion("background/cloud", i));
Background.clouds.get(i).getTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Nearest);
}
for (int i = 0; i < 8; i++) {
Background.cities.add(textureAtlas.findRegion("background/city", i));
Background.cities.get(i).getTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Nearest);
}
Background.moon = textureAtlas.findRegion("background/moon");
Background.forest = textureAtlas.findRegion("background/forest");
Background.road = textureAtlas.findRegion("background/road");
Background.moon.getTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Nearest);
Background.forest.getTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Nearest);
Background.road.getTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Nearest);
BackgroundDrawer
private void drawParallaxTextureList(Batch batch, List<TextureAtlas.AtlasRegion> list,
float moveX, float posY) {
for (int i = 0; i < list.size(); i++) {
boolean needDraw = false;
float shift = GameScreen.VIEWPORT_WIDTH * i;
float drawX = 0.0f;
if (shift - moveX <= -(GameScreen.VIEWPORT_WIDTH)) { // If it's behind the screen
if (i == 0) { // If it's first element
if (moveX >= GameScreen.VIEWPORT_WIDTH * (list.size() - 1)) { // We need to show first after last
needDraw = true;
drawX = (GameScreen.VIEWPORT_WIDTH) - (moveX - ((GameScreen
.VIEWPORT_WIDTH) * (list.size() - 1)));
}
}
} else if (shift - moveX < (GameScreen.VIEWPORT_WIDTH - 1)) {
needDraw = true;
drawX = shift - moveX;
}
if (needDraw) {
batch.draw(list.get(i), (int) drawX, (int) posY);
}
}
}
NOTE: I don't use any camera for drawing right now. I only use FitViewport with size of 1920x1280. Also, bleeding sometimes appears even in FullHD resolution.
UPDATE: Setting both Nearest filters for minification and magification with increasing paddingX and disabling antialiasing solved issue, but final image become too ugly! Is there way to avoid disabling antialiasing? Because without it, downscale look awful.
Try to set both min and mag filters as Nearest
.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest);
In GUI TexturePacker there is an option to extrude graphics - it means repeating every of border pixel of texture. Then you can set both filters to Linear
.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
but unfortunately I cannot see this option in the TexturePacker.Settings object you are using. You can try to set Linear to both but I'm pretty sure it won't be working (Linear filter takes nearest 4 texels to generate the one so it will probably still generate issues).
Try to use GUI Texturepacker then with extrude option maybe
A few possible reasons for this artifact:
Maybe the padding is not big enough when the sprite resolution is shrunk down. Try changing your texture packer's filterMin to MipMapLinearNearest. And also try increasing the size of paddingX and paddingY.
Maybe you're seeing dim or brightened pixels at the edge of your sprite because you're not using pre-multiplied alpha and your texture's background color (where its alpha is zero) is white. Try setting premultiplyAlpha: true. If you do this, you need to also change the SpriteBatch's blend function to (GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA) to render properly.
You seem to be rounding your sprite positions and sizes to integers when you draw them. This would work in a pixel perfect game, where you're sure the sprites are being rendered exactly at 1:1 resolution to the screen. But once the screen size does not match exactly, your rounding might produce gaps that are less than 1 pixel wide, which will look like semi-transparent pixels.

How to smooth out the android compas sensor

I am working on a semi augmented reality app where smooth and accurate data is very important. the sensors return values that jump around between 0 and 4 degrees and unfortunately it is making life difficult.
i have tried implementing a temporary solution:
private float[] Total = new float[11];
private float Average(){
if (counter == Total.length - 1) {
counter --;
for (int i = 0; i < Total.length - 1; i++) {
Total[i] = Total[i + 1];
}
}
float tot = 0;
for (int i = 0; i < Total.length - 1; i++) {
tot = tot + Total[i];
}
return tot/counter;
}
but this does not meet my needs any advice or help?
You are using a moving mean filter in a FIR implementation. In spite of its simplicity, the moving average filter is optimal for a common task: reducing random noise while retaining a sharp step response.
A disadvantage of the FIR implementation is that the computation time increases with the size of the filter. You could look into implementing the filter in a IIR filter instead but for this simple application I would not recommend it.
Another improvement might be to use a window function to minimize edge effects.
You may find a good example of a low pass filter using a Hamming window here

Android OpenGL ES 2: Draw frame by frame

I am quite new to opengl es 2.0 on android. I am working on a project which draws a few plane indicators on screen(like altimeter, compass etc). After doing the tutorial from the official google dev site here http://developer.android.com/training/graphics/opengl/index.html I just continued along this path, drawing circles, triangles, squares etc (only 2d stuff). I can make the drawn objects move using rotation and translation matrices, but the only way I know how to do this(except for how they did it in the tutorial) is like this in the onDrawFrame() method of my renderer class:
//set values for all Indicators
try {
Thread.sleep(1);
// for roll + pitch:
if(roll < 90) {
roll += 1.5f;
} else roll = 0;
if(pitch < 90) {
pitch += 0.5f;
} else pitch = 0;
// for compass:
if(compassDeg > 360) compassDeg = 0;
else compassDeg += 1;
//for altimeter
if(realAltitude >= 20000) realAltitude = 0;
else realAltitude += 12;
//for speedometer:
if(realSpeed >= 161) realSpeed = 0;
else realSpeed += 3;
} catch (InterruptedException e) {
e.printStackTrace();
}
roll, pitch, compassDeg, speed etc are the parameters the indicators receive and I designed them to move accordingly (if compassDeg = 0 for example, the compass will point north and so on). These parameters will eventually be received via bluetooth but for now I'm modifying them from the code directly because I don't have a bluetooth implementation yet.
I am pretty sure this is not the best way to do it, sometimes the drawn objects stutter and seem to go back a few frames, then back again and I don't think pausing the drawing method is a good idea in general.
I've seen that in the tutorial I mentioned in the beginning they use something like this:
//Use the following code to generate constant rotation.
//Leave this code out when using TouchEvents.
long time = SystemClock.uptimeMillis() %4000L ;
float contAngle = -0.090f * ((int) time);
Matrix.setRotateM(contRotationMatrix, 0, contAngle, 0, 0, -1.0f);
Matrix.multiplyMM(contMVPMatrix, 0, mMVPMatrix4, 0, contRotationMatrix, 0);
which is still kinda weird I think, there has to be a more straightforward way in which to specify how to draw each frame, to rotate and translate objects frame by frame.
So my question is how do I make everything move frame by frame or something like that, or at least how do I find out when one frame has been drawn?

libgdx smooth movement of rectangles

I want to moove two objects smoothely at Touching.
Here is my Code:
for(int i = 0; i <96; i++){
Asstest.rect_pipe_down.y--);
}
This should move the rect 96 pixels down (SMOOTH)
But it just close without smoothed...
What did I wrong?
If you Touch, the pipes should close, but not hard, smooth should they close.
But with following code they just close hard...
Here is the full touched code:
if(Gdx.input.isTouched()){
Assets.rect_pipe_down.y = 512 - 320/2;
Assets.rect_pipe_up.y = -320 + 320/2;
for (int i = 0; i < 96; i++){
smoothTime = TimeUtils.millis();
if(TimeUtils.millis() - smoothTime > 10) {
Assets.rect_pipe_down.y--;
Assets.rect_pipe_up.y++;
batch.begin();
batch.draw(Assets.region_pipe_down, Assets.rect_pipe_down.x, Assets.rect_pipe_down.y);
batch.draw(Assets.region_pipe_up, Assets.rect_pipe_up.x, Assets.rect_pipe_up.y);
batch.end();
}
}
closed = true;
}
You cannot do rendering multiple times in one render() call, one call is for drawing exactly one frame. In your current code, the later images simply overwrite the previous ones.
What you could do is have a variable which persists between frames which stores whether or not the pipes are currently closing, a constant for the speed and some condition to tell when they can stop - maybe when they are some given distance from each other, not sure what you would want here. Anyway, that's what I'll use in my example.
Then in the render() method, before drawing anything, you can do this:
if (closing) {
Assets.rect_pipe_down.y -= CLOSE_SPEED * delta;
Assets.rect_pipe_up.y += CLOSE_SPEED * delta;
if (Assets.rect_pipe_down.y - Assets.rect_pipe_up.y < TARGET_DIST) {
Assets.rect_pipe_down.y = Assets.rect_pipe_up.y + TARGET_DIST;
closing = false;
}
}
Here, closing is a variable you set to true when you want them to start closing, the others are constants. You could add some more variables/constants if you want to make sure they end up at a specific height independent on framerate.

Android Compass orientation on unreliable (Low pass filter)

Im creating an application where i need to position a ImageView depending on the Orientation of the device.
I use the values from a MagneticField and Accelerometer Sensors to calculate the device orientation with
SensorManager.getRotationMatrix(rotationMatrix, null, accelerometerValues, magneticFieldValues)
SensorManager.getOrientation(rotationMatrix, values);
double degrees = Math.toDegrees(values[0]);
My problem is that the positioning of the ImageView is very sensitive to changes in the orientation. Making the imageview constantly jumping around the screen. (because the degrees change)
I read that this can be because my device is close to things that can affect the magneticfield readings. But this is not the only reason it seems.
I tried downloading some applications and found that the "3D compass" and "Compass" remains extremely steady in its readings (when setting the noise filter up), i would like the same behavior in my application.
I read that i can tweak the "noise" of my readings by adding a "Low pass filter", but i have no idea how to implement this (because of my lack of Math).
Im hoping someone can help me creating a more steady reading on my device, Where a little movement to the device wont affect the current orientation.
Right now i do a small
if (Math.abs(lastReadingDegrees - newReadingDegrees) > 1) { updatePosition() }
To filter abit of the noise. But its not working very well :)
Though I havn't used the compass on Android, the basic processing shown below (in JavaScript) will probably work for you.
It's based on the low pass filter on the accelerometer that's recommended by the Windows Phone team with modifications to suit a compass (the cyclic behavior every 360").
I assume the compass reading is in degrees, a float between 0-360, and the output should be similar.
You want to accomplish 2 things in the filter:
If the change is small, to prevent gitter, gradually turn to that direction.
If the change is big, to prevent lag, turn to that direction immediatly (and it can be canceled if you want the compass to move only in a smooth way).
For that we will have 2 constants:
The easing float that defines how smooth the movement will be (1 is no smoothing and 0 is never updating, my default is 0.5). We will call it SmoothFactorCompass.
The threshold in which the distance is big enough to turn immediatly (0 is jump always, 360 is never jumping, my default is 30). We will call it SmoothThresholdCompass.
We have one variable saved across the calls, a float called oldCompass and it is the result of the algorithm.
So the variable defenition is:
var SmoothFactorCompass = 0.5;
var SmoothThresholdCompass = 30.0;
var oldCompass = 0.0;
and the function recieves newCompass, and returns oldCompass as the result.
if (Math.abs(newCompass - oldCompass) < 180) {
if (Math.abs(newCompass - oldCompass) > SmoothThresholdCompass) {
oldCompass = newCompass;
}
else {
oldCompass = oldCompass + SmoothFactorCompass * (newCompass - oldCompass);
}
}
else {
if (360.0 - Math.abs(newCompass - oldCompass) > SmoothThresholdCompass) {
oldCompass = newCompass;
}
else {
if (oldCompass > newCompass) {
oldCompass = (oldCompass + SmoothFactorCompass * ((360 + newCompass - oldCompass) % 360) + 360) % 360;
}
else {
oldCompass = (oldCompass - SmoothFactorCompass * ((360 - newCompass + oldCompass) % 360) + 360) % 360;
}
}
}
I see that the issue was opened 5 months ago and probably isn't relevant anymore, but I'm sure other programmers might find it useful.
Oded Elyada.
This lowpass filter works for angles in radians. Use the add function for each compass reading, then call average to get the average.
public class AngleLowpassFilter {
private final int LENGTH = 10;
private float sumSin, sumCos;
private ArrayDeque<Float> queue = new ArrayDeque<Float>();
public void add(float radians){
sumSin += (float) Math.sin(radians);
sumCos += (float) Math.cos(radians);
queue.add(radians);
if(queue.size() > LENGTH){
float old = queue.poll();
sumSin -= Math.sin(old);
sumCos -= Math.cos(old);
}
}
public float average(){
int size = queue.size();
return (float) Math.atan2(sumSin / size, sumCos / size);
}
}
Use Math.toDegrees() or Math.toRadians() to convert.
Keep in mind that, for example the average of 350 and 10 is not 180. My solution:
int difference = 0;
for(int i= 1;i <numberOfAngles;i++){
difference += ( (angles[i]- angles[0] + 180 + 360 ) % 360 ) - 180;
}
averageAngle = (360 + angles[0] + ( difference / numberOfAngles ) ) % 360;
A low pass filter (LPF) blocks fast changing signals and
allows only slow changes in the signals. This means any small
sudden changes will be ignored.
The standard way to implement this in software is to take a running average
of the last N samples and report that value. Start with N as small as 3 and
keep increasing N until you find sufficient smoothed out response in your app.
Do keep in mind that the higher you make N, slower the response of the system.
See my answer to this related question: Smoothing data from a sensor
A software low pass filter is basically a modified version of that. Indeed, in that answer I even provided this link to another related question: Low pass filter software?

Categories

Resources