Unity swipe function using UI buttons and scrollview issue - c#

I'm trying to make a code that allows me to swipe pages in my level selection menĂº with a scrollview, using buttons that modify the scrollbar value. It works perfectly when I press the button to go right, but using the same principle on the left button it doesn't work and it even make Unity freeze completely without giving me any error message.
Here right function:
public void ScrollRight(Button button)
{
for (int i = 0; i < button.transform.parent.transform.parent.transform.childCount; i++)
{
if(button.transform.parent.transform.parent.transform.GetChild(i).transform.name == button.transform.parent.transform.name)
{
i++;
scrollPos = pos[i];
Swipe(pos, i);
}
}
}
This is the left:
public void ScrollLeft(Button button)
{
for (int i = 0; i < button.transform.parent.transform.parent.transform.childCount; i++)
{
if (button.transform.parent.transform.parent.transform.GetChild(i).transform.name == button.transform.parent.transform.name)
{
i--;
scrollPos = pos[i];
Swipe(pos, i);
}
}
}
Here the Swipe:
private void Swipe(float[] pos, int nextPosIndex)
{
for (int i = 0; i < pos.Length; i++)
{
if(scrollPos < pos[i] + (distance/2) && scrollPos > pos[i] - (distance / 2))
{
scrollbar.GetComponent<Scrollbar>().value = Mathf.Lerp(scrollbar.GetComponent<Scrollbar>().value, pos[nextPosIndex], 1f * Time.deltaTime);
}
}
}
Also the needed variables:
pos = new float[transform.childCount];
distance = 1f / (pos.Length - 1f);

In your code for left scroll, you increment i inside for statement, but then decrement it inside for body. As a result, your i is always equals 0, and for loop runs eternally.
In general, if you have unity freezed without error messages, and you dealing with loops, in most cases, it means that your loop set up not properly, and runs eternally.
Try something like this:
public void ScrollLeft(Button button)
{
for (int i = button.transform.parent.transform.parent.transform.childCount - 1; i > 0; i--)
{
if(button.transform.parent.transform.parent.transform.GetChild(i).transform.name == button.transform.parent.transform.name)
{
i--;
scrollPos = pos[i];
Swipe(pos, i);
}
}
}

Related

How to change GUI button highlighted color

I want to change GUI button highlighted color when I press the button. However, I do not find how can I change in my Script onGUI() method.
I did not show the whole code. The necessary part is below.
Here is onGUI() method;
if-else checks the button is clicked or not.
if(GUI.Button(new Rect(currentPart.DrawDepth * spacing + x + subPartsSpacing, y, 200, 20), currentPart.EnglishTitle,myStyle))
{
if (!currentPart.IsClicked)
{
currentPart.IsClicked = true;
HumanBodyVisualizer.ShowMode showModeFullBody = HumanBodyVisualizer.ShowMode.Invisible;
bodyVisualizer.ShowBody(showModeFullBody);
AllSubPartsAndRoot.Insert(AllSubPartsAndRoot.Count, currentPart);
addAllSubPartsOfClickButton(currentPart, AllSubPartsAndRoot, AllSubPartsAndRoot.Count - 1);
HumanBodyVisualizer.ShowMode showModeCurrentPart = HumanBodyVisualizer.ShowMode.LowTransparent;
for (int i = 0; i < AllSubPartsAndRoot.Count; i++)
{
bodyVisualizer.ShowBodyPart(showModeCurrentPart, AllSubPartsAndRoot[i]);
}
}
else
{
currentPart.IsClicked = false;
List<HumanBodyPart> RemoveBodyParts = new List<HumanBodyPart>();
RemoveBodyParts.Insert(0,currentPart);
addAllSubPartsOfClickButton(currentPart, RemoveBodyParts, 1);
for(int i = 0; i < RemoveBodyParts.Count; i++)
{
if (AllSubPartsAndRoot.Contains(RemoveBodyParts[i]))
{
bodyVisualizer.ShowBodyPart(HumanBodyVisualizer.ShowMode.Invisible, RemoveBodyParts[i]);
AllSubPartsAndRoot.Remove(RemoveBodyParts[i]);
}
}
if(AllSubPartsAndRoot.Count == 0)
{
bodyVisualizer.ShowBody(HumanBodyVisualizer.ShowMode.LowTransparent);
}
else
{
for (int ii = 0; ii < AllSubPartsAndRoot.Count; ii++)
{
bodyVisualizer.ShowBodyPart(HumanBodyVisualizer.ShowMode.LowTransparent, AllSubPartsAndRoot[ii]);
}
}
}
}
You are using a custom GUIStyle.
You can change the pressed style via the onActive
Rendering settings for when the element is turned on and pressed down.
and the active
Rendering settings for when the control is pressed down.
components of the GUIStyle
But you would need a Texture2D for it in
myStyle.onActive.background = SomeTexture2D;
unfortunately there is no way to directly change the color tint of a GUIStyle.
Note: In order to configure your GUIStyle more easely you can simply create an asset in the ProjectView &rightarrow; right click &rightarrow; Create &rightarrow; GUISkin
Do all your settings here via the Inspector and simply reference this GUISkin asset in your EditorScript and use GUI.skin = myReferencedGuiSkin;
Alternatively you can try and use the button to turn on a flag.
You could maybe use Event.current and check if it's type is EventType.MouseUp or the mousePosition is outside of the rect you use for the button in order to reset the flag. (Not sure if this will work though)
private bool pressed;
private bool hovered;
...
public void OnGUI()
{
var color = GUI.color;
var rect = new Rect(...);
var ev = Event.current;
hovered = ev.mousePosition.x > rect.x && ev.mousePosition.x < rect.x + rect.width && ev.mousePosition.y > rect.y && ev.mousePosition.y < rect.y + rect.height;
if (Event.current.type == EventType.MouseUp) pressed = false;
else if (ev.type == EventType.MouseDown) pressed = true;
if (hovered && pressed) GUI.color = Color.green;
if (GUI.Button(rect, ...))
{
...
}
GUI.color = color;
// in order to receive the mouse events
Repaint();
}
If this is an EditorWindow you have to make sure wantsMouseMove is set to true in order to receive mouse events.

How to stop tile animation in Unity TileSystem?

I'm trying to understand tileSystem build in Unity, and i don't know how to stop animation in AnimatedTiles.
Once animation is started, there is no way i can think of to stop this. I'm working on Unity 2018.3.2f1, but i think that TileSystem is similar in next versions.
Only code in AnimatedTile handling animation is:
public override void GetTileData(Vector3Int location, ITilemap tileMap, ref TileData tileData)
{
tileData.transform = Matrix4x4.identity;
tileData.color = Color.white;
if (m_AnimatedSprites != null && m_AnimatedSprites.Length > 0)
{
tileData.sprite = m_AnimatedSprites[0];
tileData.colliderType = m_TileColliderType;
}
}
public override bool GetTileAnimationData(Vector3Int location, ITilemap tileMap, ref TileAnimationData tileAnimationData)
{
if (m_AnimatedSprites.Length > 0)
{
tileAnimationData.animatedSprites = m_AnimatedSprites;
tileAnimationData.animationSpeed = Random.Range(m_MinSpeed, m_MaxSpeed);
tileAnimationData.animationStartTime = m_AnimationStartTime;
return true;
}
return false;
}
I want to stop animation after some time (like 3 seconds) or after last frame. Any help would be appritiated!
So after some time a got workaround and it looks like this :
public class TileBump : MonoBehaviour
{
public Transform m_GridParent;
public GameObject m_TileMap_Prefab;
public AnimatedTile m_tilePrefabAnimated;
public Tile m_tilePrefabStatic;
private Tilemap map;
void Start()
{
StartCoroutine(EStart());
}
public IEnumerator EStart()
{
GameObject t = Instantiate(m_TileMap_Prefab, m_GridParent);
map = t.GetComponent<Tilemap>();
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
map.SetTile(new Vector3Int(i, j, 0), m_tilePrefabAnimated);
StartCoroutine(Operation(new Vector3Int(i, j, 0)));
yield return new WaitForSeconds(0.3f);
}
}
}
public IEnumerator Operation(Vector3Int x)
{
yield return new WaitForSeconds(m_tilePrefabAnimated.m_AnimatedSprites.Length / m_tilePrefabAnimated.m_AnimationSpeed);
map.SetTile(x, m_tilePrefabStatic);
}
}
BUT. What i understood here is that tiles are not for that. Every tile in TileMap refer to ScriptableObject, so every animation will be same in every frame.
However if someone need this kind of effect, its one way to do it.

Playing sprite animation sequence slow on first loop

I just made a png animation sequence that fires when the object is found but on the first loop it takes a lot to load, is there a way to load it faster?
The animation consist of 500 pngs loaded in a sprite the total size of all is about 180Mb, and the code that I am using is very simple:
DefaultTrackableEventHandler.cs:
public SpriteRenderer sr;
public int i = 0;
void Update ()
{
i++;
i = (i > 100) ? 0 : i;
sr.sprite = Resources.Load<Sprite> ("fractal/03_" + i.ToString ("D5"));
}
btw i'm a complete noob on unity programming so please forgive me if i'm missing something obvious, thanks
The problem is that you are loading sprite every frame. It will effect performance. Do the loading once in the Start function and store the result in an array. You can then use that array in the Update function.
const int ANIM_SIZE = 500;
Sprite[] animSprites;
public SpriteRenderer sr;
public int i = 0;
void Start()
{
for (int i = 0; i < ANIM_SIZE; i++)
{
animSprites[i] = Resources.Load<Sprite>("fractal/03_" + i.ToString("D5")) as Sprite;
}
}
void Update()
{
i++;
i = (i > 100) ? 0 : i;
sr.sprite = animSprites[i];
}
Since you are loading many files, you should use Resources.LoadAsync instead. That will let you load the data over frame and prevent any possible freezing when loading the sprites.
const int ANIM_SIZE = 500;
Sprite[] animSprites;
public SpriteRenderer sr;
public int i = 0;
bool isDoneLoading = false;
IEnumerable Start()
{
for (int i = 0; i < ANIM_SIZE; i++)
{
ResourceRequest rs = Resources.LoadAsync<Sprite>("fractal/03_" + i.ToString("D5"));
yield return rs;
animSprites[i] = rs.asset as Sprite;
}
isDoneLoading = true;
}
void Update()
{
if (isDoneLoading)
{
i++;
i = (i > 100) ? 0 : i;
sr.sprite = animSprites[i];
}
}
Finally, don't use any of these solutions mentioned above. They are just there because that's what you asked for. Use the Unity's Animation/Animator's tool to do this. You can learn more about this here.

Movement Loop in Unity

I have 4 objects each located in a corner of a square. I wish to move these objects clockwise, 1 position per method call.
With the code I have atm, they all just complete the entire loop on 1 method call instead of moving only one position...
My code so far:
void SwitchPositions()
{
tempPosition1 = parent.transform.GetChild(0).GetComponent<Transform>().position;
tempPosition2 = parent.transform.GetChild(1).GetComponent<Transform>().position;
tempPosition3 = parent.transform.GetChild(2).GetComponent<Transform>().position;
tempPosition4 = parent.transform.GetChild(3).GetComponent<Transform>().position;
parent.transform.GetChild (0).GetComponent<Transform> ().position = tempPosition2;
parent.transform.GetChild (1).GetComponent<Transform> ().position = tempPosition3;
parent.transform.GetChild (2).GetComponent<Transform> ().position = tempPosition4;
parent.transform.GetChild (3).GetComponent<Transform> ().position = tempPosition1;
Debug.Log (tempPosition1);
}
If anyone has any ideas how to fix this or at least explain to me why it-s completing the entire loop in 1 method call...
Thank you!
I am really not sure how your timer works or for that matter anything wrong with your code. But I have used the coroutine where after every two seconds the blocks get switched and it happens continuously. I think this should be somewhere close to what you need.
//Predefined positions where objects to place
public Transform[] Position;
//The objects that will will be swapped in coroutines
public Transform[] ObjectsToMove;
private int ObjectIndex = 0;
private bool startupdate = true;
void Update () {
if(startupdate)
StartCoroutine(SwitchBlocks());
}
IEnumerator SwitchBlocks() {
startupdate = false;
int tempIndex = ObjectIndex;
for(int i = 0; i < ObjectsToMove.Length; i++) {
tempIndex = ObjectIndex + i;
if(tempIndex > ObjectsToMove.Length - 1)
tempIndex -= ObjectsToMove.Length;
ObjectsToMove[i].position = Position[tempIndex].position;
}
ObjectIndex++;
if(ObjectIndex > ObjectsToMove.Length - 1) {
ObjectIndex = 0;
}
yield return new WaitForSeconds(2.0f);
startupdate = true;
yield return null;
}
Hope this helps.

Adding a timer to the Kinect Click function C#

I have created a click function for Kinect without using any gestures.. its simple and it works.. however i want the function to wait.. my counter isnt seem to be working .. what I want to do is.. IF my hand is on the button for lets say more than 3 seconds.. then return true ..any method to do it? Counter doesnt seem to be working
public bool KinectClick(int x,int y)
{
if ((x >= position.X && x <= position.X +position.Width) && (y >= position.Y && y <= position.Y + position.Height))
{
// time.Start();
int counter = 0;
while (true)
{
counter++;
if (counter >= 8000)
{
return true;
counter = 0;
}
}
}
I use a DispatcherTimer to accomplish the same thing you are trying to do. A simple form could look something like this:
private DispatcherTimer hitTestTimer = new DispatcherTimer();
private int timerCount = 5;
public MyConstructor() {
hitTestTimer.Tick += OnHitTestTimerTick;
hitTestTimer.Interval = new TimeSpan(0, 0, 1);
}
private void OnHitTestTimerTick(object sender, EventArgs e)
{
if (timerCount > 1)
{
timerCount--;
}
else
{
// CLICK!
}
}
You can add flags that toggle when you first enter your object, and check that to verify if you have (or haven't) left the object since the last timer tick.

Categories

Resources