while I scroll between the layout it takes too long to be able to scroll between the gallerie's pictures. Is there any way to reduce this time? - dynamic

this is my first question here, though I've being reading this forum for quite a while. Most of the answers to my doubts are from here :)
Getting back on topic. I'm developing an Android application. I'm drawing a dynamic layout that are basically Galleries, inside a LinearLayout, inside a ScrollView, inside a RelativeLayout. The ScrollView is a must, because I'm drawing a dynamic amount of galleries that most probably will not fit on the screen.
When I scroll inside the layout, I have to wait 3/4 seconds until the ScrollView "deactivates" to be able to scroll inside the galleries. What I want to do is to reduce this time to a minimum. Preferably I would like to be able to scroll inside the galleries as soon as I lift my finger from the screen, though anything lower than 2 seconds would be great as well.
I've being googling around for a solution but all I could find until now where layout tutorials that didn't tackle this particular issue. I was hoping someone here knows if this is possible and if so to give me some hints on how to do so.
I would prefer not to do my own ScrollView to solve this. But if that is the only way I would appreciate some help because I'm not really sure how would I solve this issue by doing that.
this is my layout:
public class PicturesL extends Activity implements OnClickListener,
OnItemClickListener, OnItemLongClickListener {
private ArrayList<ImageView> imageView = new ArrayList<ImageView>();
private StringBuilder PicsDate = new StringBuilder();
private CaWaApplication application;
private long ListID;
private ArrayList<Gallery> gallery = new ArrayList<Gallery>();
private ArrayList<Bitmap> Thumbails = new ArrayList<Bitmap>();
private String idioma;
private ArrayList<Long> Days = new ArrayList<Long>();
private long oldDay;
private long oldThumbsLoaded;
private ArrayList<Long> ThumbailsDays = new ArrayList<Long>();
private ArrayList<ArrayList<Long>> IDs = new ArrayList<ArrayList<Long>>();
#Override
public void onCreate(Bundle savedInstancedState) {
super.onCreate(savedInstancedState);
RelativeLayout layout = new RelativeLayout(this);
ScrollView scroll = new ScrollView(this);
LinearLayout realLayout = new LinearLayout(this);
ArrayList<TextView> texts = new ArrayList<TextView>();
Button TakePic = new Button(this);
idioma = com.mateloft.cawa.prefs.getLang(this);
if (idioma.equals("en")) {
TakePic.setText("Take Picture");
} else if (idioma.equals("es")) {
TakePic.setText("Sacar Foto");
}
RelativeLayout.LayoutParams scrollLP = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT);
layout.addView(scroll, scrollLP);
realLayout.setOrientation(LinearLayout.VERTICAL);
realLayout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT));
scroll.addView(realLayout);
TakePic.setId(67);
TakePic.setOnClickListener(this);
application = (CaWaApplication) getApplication();
ListID = getIntent().getExtras().getLong("listid");
getAllThumbailsOfID();
LinearLayout.LayoutParams TakeLP = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
realLayout.addView(TakePic);
oldThumbsLoaded = 0;
int galler = 100;
for (int z = 0; z < Days.size(); z++) {
ThumbailsManager croppedThumbs = new ThumbailsManager(Thumbails,
oldThumbsLoaded,
ThumbailsDays.get(z));
oldThumbsLoaded = ThumbailsDays.get(z);
texts.add(new TextView(this));
texts.get(z).setText("Day " + Days.get(z).toString());
gallery.add(new Gallery(this));
gallery.get(z).setAdapter(new ImageAdapter(this, croppedThumbs.getGallery(), 250, 175, true,
ListID));
gallery.get(z).setOnItemClickListener(this);
gallery.get(z).setOnItemLongClickListener(this);
gallery.get(z).setId(galler);
galler++;
realLayout.addView(texts.get(z));
realLayout.addView(gallery.get(z));
}
Log.d("PicturesL", "ListID: " + ListID);
setContentView(layout);
}
private void getAllThumbailsOfID() {
ArrayList<ModelPics> Pictures = new ArrayList<ModelPics>();
ArrayList<String> ThumbailsPath = new ArrayList<String>();
Pictures = application.dataManager.selectAllPics();
long thumbpathloaded = 0;
int currentID = 0;
for (int x = 0; x < Pictures.size(); x++) {
if (Pictures.get(x).walkname == ListID) {
if (Days.size() == 0) { Days.add(Pictures.get(x).day); oldDay = Pictures.get(x).day;
IDs.add(new ArrayList<Long>()); currentID = 0; }
if (oldDay != Pictures.get(x).day) {
oldDay = Pictures.get(x).day;
ThumbailsDays.add(thumbpathloaded);
Days.add(Pictures.get(x).day);
IDs.add(new ArrayList<Long>());
currentID++;
}
StringBuilder tpath = new StringBuilder();
tpath.append(Pictures.get(x).path.substring(0,
Pictures.get(x).path.length() - 4));
tpath.append("-t.jpg");
IDs.get(currentID).add(Pictures.get(x).id);
ThumbailsPath.add(tpath.toString());
thumbpathloaded++;
if (x == Pictures.size() - 1) {
Log.d("PicturesL", "El ultimo de los arrays, tamaƱo: " + Days.size());
ThumbailsDays.add(thumbpathloaded);
}
}
}
for (int y = 0; y < ThumbailsPath.size(); y++) {
Thumbails.add(BitmapFactory.decodeFile(ThumbailsPath.get(y)));
}
}
I had a memory leak on another activity when screen orientation changed that was making it slower, now it is working better. The scroller is not locking up. But sometimes, when it stops scrolling, it takes a few seconds (2/3) to disable itself. I just want it to be a little more dynamic, is there any way to override the listener and make it stop scrolling ON_ACTION_UP or something like that?
I don't want to use the listview because I want to have each gallery separated by other views, now I just have text, but I will probably separate them with images with a different size than the galleries.
I'm not really sure if this is possible with a listadapter and a listview, I assumed that a view can only handle only one type of object, so I'm using a scrollview of a layout, if I'm wrong please correct me :)
Also this activity works as a preview or selecting the pictures you want to view in full size and manage their values. So its working only with thumbnails. Each one weights 40 kb. Guessing that is very unlikely that a user gets more than 1000~1500 pictures in this view, i thought that the activity wouldn't use more than 40~50 mb of ram in this case, adding 10 more if I open the fullsized view. So I guessed as well most devices are able to display this view in full size. If it doesn't work on low-end devices my plan was to add an option in the app preferences to let user chop this view according to some database values.
And a last reason is that during most of this activity "life-cycle" (the app has pics that are relevant to the view, when it ends the value that selects which pictures are displayed has to change and no more pictures are added inside this instance of this activity); the view will be unpopulated, so most of the time showing everything wont cost much, just at the end of its cycle
That was more or less what I thought at the time i created this layout. I'm open to any sort of suggestion or opinion, I just created this layout a few days ago and I'm trying to see if it can work right, because it suits my app needs. Though if there is a better way i would love to hear it
PD: I've being toying to see how much it can actually draw. I managed to draw 530 galleries with 600 thumbnails on the same layout, the app is using 42 mb, and I don't have access to more memory to start my full sized view afterwards :( .I tried to do the same with 1000 but it throws OutOfMemory error, bitmap size exceeds vm budget. Is there any way to make more memory availeable on high-end devices? Or should I try to figure out a way not to draw everything at once? Would the listview work for more than one type of object?
Thanks
Mateo

Why not make your galleries items of a listview? That way you won't have to inflate all of them immediately and can the advantage of the listview recyling mechanism. Some of the slowness you are seeing might be coming from very heavy memory usage. Galleries aren't exactly light widgets so you might be seeing pauses from heavy GC activity once you stop scrolling. ListView with an adapter would also allow you to lazily bind the Galleries to the list, such that during a fling you aren't doing the expensive binding of the galleries.

Related

How to make large 2d tilemap easier to load in Unity

I am creating a small game in the Unity game engine, and the map for the game is generated from a 2d tilemap. The tilemap contains so many tiles, though, is is very hard for a device like a phone to render them all, so the frame rate drops. The map is completely static in that the only moving thing in the game is a main character sprite and the camera following it. The map itself has no moving objects, it is very simple, there must be a way to render only the needed sections of it or perhaps just render the map in once. All I have discovered from researching the topic is that perhaps a good way to do it is buy using the Unity mesh class to turn the tilemap into a mesh. I could not figure out how to do this with a 2d tilemap, and I could not see how it would benefit the render time anyways, but if anyone could point me in the right direction for rendering large 2d tilemaps that would be fantastic. Thanks.
Tile system:
To make the tile map work I put every individual tile as a prefab in my prefab folder, with the attributes changed for 2d box colliders and scaled size. I attribute each individual prefab of the tile to a certain color on the RGB scale, and then import a png file that has the corresponding colors of the prefabs where I want them like this:
I then wrote a script which will place each prefab where its associated color is. It would look like this for one tile:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Map : MonoBehaviour {
private int levelWidth;
private int levelHeight;
public Transform block13;
private Color[] tileColors;
public Color block13Color;
public Texture2D levelTexture;
public PlayerMobility playerMobility;
// Use this for initialization
void Start () {
levelWidth = levelTexture.width;
levelHeight = levelTexture.height;
loadLevel ();
}
// Update is called once per frame
void Update () {
}
void loadLevel(){
tileColors = new Color[levelWidth * levelHeight];
tileColors = levelTexture.GetPixels ();
for (int y = 0; y < levelHeight; y++) {
for (int x = 0; x < levelWidth; x++) {
// if (tileColors [x + y * levelWidth] == block13Color) {
// Instantiate(block13, new Vector3(x, y), Quaternion.identity);
// }
//
}
}
}
}
This results in a map that looks like this when used with all the code (I took out all the code for the other prefabs to save space)
You can instantiate tiles that are in range of the camera and destroy tiles that are not. There are several ways to do this. But first make sure that what's consuming your resources is in fact the large number of tiles, not something else.
One way is to create an empty parent gameObject to every tile (right click in "Hierarchy" > Create Empty"
then attach a script to this parent. This script has a reference to the camera (tell me if you need help with that) and calculates the distance between it and the camera and instantiates the tile if the distance is less than a value, otherwise destroys the instance (if it's there).
It has to do this in the Update function to check for the distances every frame, or you can use "Coroutines" to do less checks (more efficient).
Another way is to attach a script to the camera that has an array with instances of all tiles and checks on their distances from the camera the same way. You can do this if you only have exactly one large tilemap because it would be hard to re-use this script if you have more than a large tilemap.
Also you can calculate the distance between the tile and the character sprite instead of the camera. Pick whichever is more convenient.
After doing the above and you still get frame-drops you can zoom-in the camera to include less tiles in its range but you'd have to recalculate the distances then.

adding textfield over movieclip images

I have several images, which are Symbols (movieClip) with Alpha parameter.
And i'm creating dynamic textfield from AS3 to be able change text every few seconds.
Problem is that everything worked good till i converted images to MovieClips. But after that my textfields are not visible.
Here is the code:
textFormat = new TextFormat();
textfield = new TextField();
textFormat.font = new customFonts().fontName;
textFormat.size = 16;
textFormat.align = "center";
textFormat.color = 0xFFFFFF;
textfield.defaultTextFormat = textFormat;
textfield.embedFonts = true;
textfield.width = 480;
textfield.height = 95;
textfield.x = 185;
textfield.y = 22;
textfield.wordWrap = true;
addChild (textfield);
So the question is - how to bring this textfield to the top so it would be visible?
You're adding your Text field after the movie clips are being initiated. Think of it as a layer, the text field is at the bottom layer, hence they will not be seen.
I would look at the container class
The Container class is an abstract base class for components that controls the layout characteristics of child components. You do not create an instance of Container in an application. Instead, you create an instance of one of Container's subclasses, such as Canvas or HBox.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/Container.html
You should be able to change what is displayed.
EDIT:
Anytime you add a clip it is added on top by default.
You should also look into Z-Index.
If you are coding with Flash Develop then it can get tricky, whilst using Flash Adobe CC can make your life so much easier!
Sorry if it's not that much of an answer.

Famo.us/Angular Sticky Background Position ScrollView Sync

I'm trying to create functionality very similar to most websites these days.
The concept is 3 sections the size of the browser, the background images are supposed to be fixed positioned and revealed by the div scrolling up and down.
We need this to function as beautifully on mobile as it does on desktop, and it looks like Famous/angular is the solution.
Here is a pen.
http://codepen.io/LAzzam2/pen/XJrwbo
I'm using famous' Scroll.sync, firing javascript that positions the background image on every start / update / end.
scrollObject.sync.on("update", function (event) {
console.log('update');
test(event);
});
here is the function positioning the backgrounds.
function test(data){
var scroller = document.getElementsByClassName('famous-group');
styles = window.getComputedStyle(scroller[0], null);
tr = styles.getPropertyValue("-webkit-transform").replace('matrix(1, 0, 0, 1, 0,','').replace(')','');
var distanceTop = -(parseInt(tr));
var sections = document.getElementsByClassName('section');
sections[3].style.backgroundPosition="50% "+distanceTop+"px";
sections[4].style.backgroundPosition="50% "+(-(window.innerHeight)+distanceTop)+"px";
sections[5].style.backgroundPosition="50% "+(-(window.innerHeight*2)+distanceTop)+"px";
};
Any input / suggestions / advice would be wonderful, really just looking for a proof of concept with these 3 background images scrolling nicely.
That jittery-ness is unfortunate, I can't tell what would be causing the issue, except maybe the order in which events are fired?
**There are known issues, only works in -webkit browsers as of now
I think your idea to use Famous is good, but probably what I would do, would be taking a different approach to the problem.
You are solving this by touching the DOM, that is exactly what both Angular and Famous are meant to avoid.
If I had to face the same goal, I would probably use a Famous surface for the background instead of changing the property of the main one and synchronize its position with the scrolling view.
So, in your code, it would be something like this:
function test(data){
var scrollViewPosition = scrollObject.getAbsolutePosition();
var newBackgroundPosition = // Calculate the new background position
var newForegroundPosition = // Calculate the new foreground position
var backgroundSurface = backgroundSurface.position.set(newBackgroundPosition);
var foregroundSurface = foregroundSurface.position.set(newForegroundPosition);
};

Create Backgroundthread Monogame

I made a game for Windows 8 in monogame but running into a problem. We finally got our hands on a Surface RT but we noticed that the loading times are really long on this device. We looked at several other games and noticed that this wasn't an uncommon issue. To fight the boredom of the user during the loading of the resources I want to draw a loading bar and some random facts onto the screen. The problem is that loading the resources blocks the rest of the game and doesn't allow me to draw anything because it stays stuck at the initializing part.
I searched for creating a lose Thread but found that Windows Store didn't support that so now my question to you how can I load my resources in the background or another way to not block the complete game and be able to call handle my Draw() function to draw a loading bar onto my screen.
I did something like this:
protected volatile bool ContentLoaded = false;
protected async override void LoadContent()
{
base.LoadContent();
Enabled = false;
await ThreadPool.RunAsync(new WorkItemHandler(LoadAllContent));
}
protected void LoadAllContent(Windows.Foundation.IAsyncAction action)
{
if (action.Status == Windows.Foundation.AsyncStatus.Error)
System.Diagnostics.Debug.WriteLine(action.ErrorCode);
// load your contents
ContentLoaded = true;
Enable = true;
}
And at the beginning of your Draw method:
if (!ContentLoaded)
{
// draw your loading screen
return;
}
If you want a progress bar you need a counter to increase every resource you've loaded, then in your Draw your bar has to relate to that counter.

Problems in my AS2 Game

Hey guys, I'm trying to make a 2D Platform style game similar to this game below:
http://www.gameshed.com/Puzzle-Games/Blockdude/play.html
I have finished making most of the graphic, and areas, and collision, but our character is still not able to carry things. I'm confused as to what code to use so that my character can carry the blocks. I need help as to how to make our character carry blocks that are in front of him, provided that the blocks that don't have anything on top of it. This has been confusing me for a week now, and any help would be highly appreciated. :D
I fondly remember my first AS2 game. The best approach is probably an object oriented approach, as I will explain.
In AS2, there is a hittest method automatically built into objects. There is a good tutorial on Kirupa here:
http://www.kirupa.com/developer/actionscript/hittest.htm
also
http://help.adobe.com/en_US/AS2LCR/Flash_10.0/help.html?content=00001314.html
First you'll want to generate your boxes using a Box class. Your class would need to look something like the following:
//Box.as pseudo-code
class Box {
var x_pos:Number;
var y_pos:Number;
var attachedToPlayer:Boolean;
function Box(_x:Number, _y:Number) {
this.x_pos = _x;
this.y_pos = _y;
}
//other code here
}
See this tutorial on how to attach a class to an object in the library:
http://www.articlesbase.com/videos/5min/86620312
To create a new Box, you'd then use something like
box1 = new Box(100,200);
// creates a box at position 100x,200y
However, you'll also want to store the blocks you want to pickup into some sort of array so you can loop through them. See http://www.tech-recipes.com/rx/1383/flash-actionscript-create-an-array-of-objects-from-a-unique-class/
Example:
//somewhere near the top of your main method, or whereever your main game loop is running from - note Box.as would need to be in the same folder
import Box;
//...then, somewhere before your game loop
//create an array to hold the objects
var boxArray:Array = new Array();
//create loop with i as the counter
for (var i=0; i<4; i++)
{
var _x:Number = 100 + i;
var _y:Number = 100 + i;
//create Box object
var box:Box = new Box();
//assign text to the first variable.
//push the object into the array
boxArray.push(box);
}
Similarly, you would need a class for your player, and to create a new Player object at the start of your game, e.g.
var player = new Player(0,0);
You could then run a hittest method for your player against the blocks in your array for the main game loop (i.e. the loop that updates your player's position and other game properties). There are probably more efficient ways of doing this, e.g. only looping for the blocks that are currently on the screen.
Once your array has been created, use a foreach loop to run a hittest against your player in your game's main loop, e.g.
//assuming you have an array called 'boxArray' and player object called 'player'
for(var box in boxArray){
if (player.hittest(box)) {
player.attachObjectMethod(box);
}
}
This is basically pseudo-code for "for every box that we have entered into the array, check if the player is touching the box. If the box is touching, use the box as the argument for a method in the player class (which I have arbitrarily called attachObjectMethod)".
In attachObjectMethod, you could then define some sort of behavior for attaching the box to the player. For example, you could create a get and set method(s) for the x and y position of your boxes inside the box class, along with a boolean called something useful like attachedToPlayer. When attachObjectMethod was called, it would set the box's boolean, e.g. in the Player class
//include Box.as at the top of the file
import Box;
//other methods, e.g. constructor
//somewhere is the Player.as class/file
public function attachObjectMethod (box:Box) {
box.setattachedToPlayer(true);
//you could also update fields on the player, but for now this is all we need
}
Now the attachedToPlayer boolean of the box the player has collided with would be true. Back in our game loop, we would then modify our loop to update the position of the boxes:
//assuming you have an array called 'boxArray' and player object called 'player'
for(var box in boxArray){
if (player.hittest(box)) {
player.attachObjectMethod(box);
}
box.updatePosition(player.get_Xpos, player.get_Ypos);
}
In our Box class, we now need to define 'updatePosition':
//Box.as pseudo-code
class Box {
var x_pos:Number;
var y_pos:Number;
var attachedToPlayer:Boolean;
function Box(box_x:Number, box_y:Number) {
this.x_pos = box_x;
this.y_pos = box_y;
}
public function updatePosition(_x:Number, _y:Number) {
if (this.attachedToPlayer) {
this.x_pos = _x;
this.y_pos = _y;
}
}
//other code here
}
As you can see we can pass the player's position, and update the box's position if the attachedToPlayer boolean has been set. Finally, we add a move method to the box:
public function move() {
if (this.attachedToPlayer) {
this._x = x_pos;
this._y = y_pos;
}
}
Examples of updating position:
http://www.swinburne.edu.au/design/tutorials/P-flash/T-How-to-smoothly-slide-objects-around-in-Flash/ID-17/
Finally, to make it all work we need to call the move method in the game loop:
//assuming you have an array called 'boxArray' and player object called 'player'
for(var box in boxArray){
if (player.hittest(box)) {
player.attachObjectMethod(box);
}
box.updatePosition(player.get_Xpos, player.get_Ypos);
box.move();
}
You have also specified that the blocks should only move with the player if they have nothing on top of them. When you call your attachedToPlayer method, you would also need to run a foreach loop inside the method between the box and the objects that might sit on top of the box. You should now have a fair idea from the above code how to do this.
I appreciate that this is quite a lengthy answer, and I haven't had an opportunity to test all the code (in fact I'm fairly positive I made a mistake somewhere) - don't hesitate to ask questions. My other advice is to understand the concepts thoroughly, and then write your own code one bit at a time.
Good luck!
The way I would do this is to design an individual hit test for each block he will be picking up, then code for the hit test to play a frame within the sprite's timeline of him carrying a block, and to play a frame within the block to be picked up's timeline of the block no longer at rest (disappeared?).
Good Luck if you're confused about what I've said just ask a little more about it and I'll try to help you if I can.