Add Image dynamically in runtime - Unity 5 - unityscript

In my unity based Android game I wish to add the image dynamically based on the number of questions in each level. The image is shown for reference. Each correct answer will be marked in green and the wrong one in red. I am new to unity and trying hard to find steps to achieve this.
Any help with an example for this requirement will be a great help.

I once wrote a script for dynamically creating buttons based on each level. What I did was creating the first button on the scene and adding the other buttons based on the first one. Below is the shell of my code:
// tutorialButton and levelButtons are public variables which can be set from Inspector
RectTransform rect = tutorialButton.GetComponent<RectTransform> ();
for (int i = 1; i < levelSize; i++) {
// Instantiate the button dynamically
GameObject newButton = GameObject.Instantiate (tutorialButton);
// Set the parent of the new button (In my case, the parent of tutorialButton)
newButton.transform.SetParent (levelButtons.transform);
//Set the scale to be the same as the tutorialButton
newButton.transform.localScale = tutorialButton.transform.localScale;
//Set the position to the right of the tutorialButton
Vector3 position = tutorialButton.transform.localPosition;
position.x += rect.rect.width*i;
newButton.transform.localPosition = position;
}
I am not exactly sure if this is the right approach as it may or may not give unexpected results depending on different screen sizes and your canvas, but hopefully it gives you an idea about dynamically creating objects.

I'm not sure if this helps, but if you have all the images in the scene under a canvas, with this you just need to drag the canvas on the script and use
//level-1 is to keep the array notation
FindObjectOfType<NameOfScript>.ChangeColor(level-1,Color.green);
or you can do also
//level-1 is to keep the array notation
FindObjectOfType<NameOfScript>.RevertColor(level - 1);
This is the script:
//Keep it private but you still see it in inspector
//#Encapsulation :)
[SerializeField]
private Canvas _canvas;
private Image[] _images;
//keep the original colors in case you want to change back
private Color[] _origColors;
void Start () {
_images = GetComponentsInChildren<Image>();
_origColors = new Color[_images.Length];
for (int i = 0; i < _images.Length; i++)
{
_origColors[i] = _images[i].color;
}
}
//Reverts the color of the image back to the original
public void RevertToOriginal(int imageIndex)
{
_images[imageIndex].color = _origColors[imageIndex];
}
//Change to color to the coresponding index, starts from 0
public void ChangeColor(int imageIndex, Color color)
{
_images[imageIndex].color = color;
}
P.S If you want it visible only at the end you can make a method where you enable = (true or false) for the canvas. So you keep it false till the end of the level and you make it true when you want to show, while after every answer you call the ChangeColor depending on the result.
To make it easier you can use:
NameOfScript variableName = FindObjectOfType<NameOfScript>();
and after that you just call
variableName.ChangeColor(level - 1, Color.green);
Also it does not matter where you put the script. I would make some kind of manager(empty GameObject) in the scene and put it there.

Related

Unity3D Draggable GUI.Box with GUI controls

I'm constructing a custom node editor window in Unity, and I've had a look at various resources such as this one, which uses GUI.Box to construct node windows.
This works great, and I'm able to drag these windows around the way I want, however once I add controls to the GUI.Box, I want them to override the Drag() function I've written.
Here's an example of the issue - When I move the vertical slider up, the entire box drags with it.
Is there a way to fix this behavior using GUI.Box, or should I go back to GUI.Window with its built-in GUI.DragWindow()?
Here's a simplified version of the code I'm using:
EditorMouseInput.cs:
private bool ActionLeftMouseDown()
{
mouseDownNode = editor.GetSelectedNode(Input.current.mousePosition);
if (mouseDownNode == null)
editor.StartMovingEditorCanvas();
else
mouseDownNode.IsSelected = true;
}
BaseNodeEditor.cs:
public BaseNode GetSelectedNode(Vector2 mousePos)
{
foreach (BaseNode node in Nodes)
{
if (node.WindowRect.Contains(mousePos))
return node;
}
return null;
}
public void Drag(Vector2 delta)
{
if (!MoveEditorMode && !ConnectionMode)
{
foreach (BaseNode node in Nodes)
{
node.Drag(delta);
}
}
BaseNode.cs:
public void Drag(Vector2 delta)
{
if (IsSelected)
draggedDistance += delta;
}
The vertical slider is added in the derived JumpNode class. Extract of the helper class that constructs the slider:
Vector2 pos = node.WindowRect.position + rect.position * GridSpacing;
value = GUI.VerticalSlider(new Rect(pos, rect.size * GridSpacing), value, maxValue, minValue);
I can see why this doesn't do what I want, but I don't know how to go about it given the GUI controls aren't part of the GUI.Box.
Any help or suggestions, even a nudge towards another source would be greatly appreciated - I feel I've used all the search terms that exist in my head!
Edit - Solved: Thanks to Kleber for solving this one for me. In case anyone else runs into this or a similar issue, the solution for me was in realising that GUI controls consume left mousedown events automatically, so clicking a slider means there's no propagation to the Box to check if it was clicked.
What I needed to do was separate the IsSelected and IsDragged flags in the Node class, and clear IsDragged on mouseUp. I originally used IsSelected to flag both drag enabled, and selected (multiple nodes could be selected and dragged at once).
It's quite a complex tutorial so I didn't read it entirely, but the problem seems to be the MouseDrag detection. Well, basically you want to stop the event propagation when you click on a GUI element inside the Box, right? To do so, you call:
Event.current.Use()
every time the user drags the mouse on one of your components.
Using the resource you've mentioned, I altered the Node class and added a slider inside the Draw() method, ending like this:
public void Draw() {
inPoint.Draw();
outPoint.Draw();
GUI.Box(rect, title, style);
GUI.BeginGroup(rect);
_value = GUI.HorizontalSlider(new Rect(20, 0, 50, 20), _value, 100, -100);
GUI.EndGroup();
}
Another thing you can do is change how you draw your window. Here it's a simple example that I've tested on the latest Unity version (5.6):
private void OnGUI() {
GUI.Box(_rect, string.Empty);
GUI.BeginGroup(_rect);
_value = GUI.VerticalSlider(new Rect(145, 100, 20, 100), _value, 100, -100);
GUI.EndGroup();
var e = Event.current;
if (e.type == EventType.MouseDrag && _rect.Contains(e.mousePosition)) {
_rect.x += e.delta.x;
_rect.y += e.delta.y;
Repaint();
}
}
As you can see, this example doesn't need an Event.current.Use() to work properly.

Stop rotating for a click right on the game object

I have a unity game and in it, a rotating game object, which increases its speed when it is clicked.
My problem is that the game does not work as I want it to. Right now, if I click any part of the screen, it increases the game object's speed of rotation. On the other hand, if I keep my finger on the screen, the game object starts to slow down and then starts rotating in the opposite direction.
I want the rotation of the object to increase when I click on it, not just if I click on any part of the screen. Furthermore, I don't know why holding down reverses the direction of rotation.
var speed = 1;
var click = 0;
Screen.orientation = ScreenOrientation.LandscapeLeft;
function Update (){
{
transform.Rotate(0,0,speed);
}
if(Input.GetMouseButton(0))
{
if(speed != 0)
{
speed = 0;
} else {
click++;
speed = click;
}
You must use Input.GetMouseButtonUp or Input.GetMouseButtonDown, NOT A Input.GetMouseButton, this method used for clamping.
Try use this code:
var speed = 1;
var click = 0;
Screen.orientation = ScreenOrientation.LandscapeLeft;
function Update (){
{
transform.Rotate(0,0,speed);
}
if(Input.GetMouseButtonDown(0))
{
if(speed != 0)
{
speed = 0;
} else {
click++;
speed = click;
}
A few issues here:
Firstly:
To increase speed upon clicking on the object only, use raycasting from camera, and check if it hits your object. Your object needs need a collider component on it for this to work.
RaycastHit hit;
Ray ray = camera.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
Transform objectHit = hit.transform;
objectHit.Rotate(0,0,speed);
}
Refer to https://docs.unity3d.com/Manual/CameraRays.html -> Raycasting section, for more information.
Secondly:
Input.GetMouseButtonDown(..) // returns true at the instance your mouse button transits from up to down
Input.GetMouseButton(..) // returns true as long as your mouse button is held down
Use Input.GetMouseButtonDown(..) in your Update() method if you want to to do something when you click on it.

Xamarin Forms fade to hidden?

In my current app, I have a bunch of buttons which can hide or show their corresponding stackLayout.
First, i tried using IsVisble property, but this causes a flash,
now im at using LayoutTo() which also flashes?
My code is as below:
async void btnStrike_Clicked(object sender, EventArgs args)
{
var layout = this.FindByName<StackLayout>("stkStrikeInfo");
var rect = new Rectangle(layout.X, layout.Y, layout.Width, layout.Height - layout.Height);
await layout.LayoutTo(rect, 2500, Easing.Linear);
}
Id like to animate the height!
Edit:
I found the following piece of code, which removes the Stacklayout from the page.
The issue now is that the view isnt updating?
I think you'll have better luck with just a default animation that reduces the height of the layout you want to hide to zero.
void btnStrike_Clicked(object sender, EventArgs args)
{
// get reference to the layout to animate
var layout = this.FindByName<StackLayout>("stkStrikeInfo");
// setup information for animation
Action<double> callback = input => { layout.HeightRequest = input; }; // update the height of the layout with this callback
double startingHeight = layout.Height; // the layout's height when we begin animation
double endingHeight = 0; // final desired height of the layout
uint rate = 16; // pace at which aniation proceeds
uint length = 1000; // one second animation
Easing easing = Easing.CubicOut; // There are a couple easing types, just tried this one for effect
// now start animation with all the setup information
layout.Animate("invis", callback, startingHeight, endingHeight, rate, length, easing);
}
If the layout is already hidden and you want to show it, you would replace
double startingHeight = layout.Height;
double endingHeight = 0;
with
double startingHeight = 0;
double endingHeight = 55;
The 55 is just an arbitrary height, if you want it to go back to the height from before, you would save the previous height to a variable before you hide it and use that saved height instead of 55.

Changing alpha of Text's CanvasGroup in OnTriggerEnter Unity

I'm currently working on a game that pays hommage to Marble Blast Gold/Ultra.
At this point I have text that is positioned with the marble. The text is a child of a canvas and I have a canvas group added to the text. I initially set the alpha of the canvas group to 0 so that you can't see the text.
What I'm trying to do is have it so that when you pick up a power up the text reappears by changing the canvas group's alpha back to 1 and then once the power up is used set it back to 0.
I'm not seeming to have any luck with my current code.
// Super Jump pickup
if (col.gameObject.tag == "Spring")
{
superJumpText.GetComponent<CanvasGroup>().alpha = 1;
canSuperJump = true;
canSuperSpeed = false;
col.gameObject.SetActive(false);
hitSuperJump = true;
Invoke("Display", 20);
}
void Update()
{
//super jump
if (canSuperJump)
{
if (Input.GetKeyDown(KeyCode.Mouse0))
{
Vector3 jump = new Vector3(0, superJumpForce, 0);
GetComponent<Rigidbody>().AddForce(jump);
canSuperJump = false;
superJumpText.GetComponent<CanvasGroup>().alpha = 0;
}
}
}
The only reason this would not work for you is that somewhere in your parent hierarchy you have a gameobject with another canvas group. That would ALWAYS override the child canvas group settings UNLESS you select the 'Ignore Parent Groups' checkbox in the child canvas

Use parameters for variable animation

I'd like to animate my Score-GUI text counting up to a variable value but there are two things in my way:
1: How can I animate to a variable instead of a fixed value?
2: Why can't I add own properties (like int) to my script and animate them?
For #2 I created a property in my script. Yet the editor won't show it in the AddProperty-dialog (as shown below):
public int currentScore = 0;
public int score {
get { return currentScore; }
set { this.currentScore += value; }
}
EDIT: The animator is set up in the most basic way:
Since you only have 1 Animation. An Animator is irrelevant to the solution. This is tested and working. Now you need to make the Animation a Legacy type to get this working because we are not going to use the Animator.
Click the Animation on the Project -> look at the upper right section of the Inspector view, there is a little button there which will drop down a selection. "Debug" then Check the Legacy.
Set your Animation to whatever you want. I force the WrapMode in the script to be wrap mode once. So it will only play once.
Now in the Animation Component make sure you select the Animation that you want by default or it wont work. Cause we only use anim.Play(); Without parameters meaning, run the default animation that is set.
I created a Text UI and added an Animation that alpha is 0 from the start and at the end point making it 1. You have to do that on your own.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class MyScore : MonoBehaviour {
// Use this for initialization
public int currentScore = 0;
public GameObject Myscore; // Drag the GameObject that has the Animation for your score.
public Text myScoreText; //Drag in the Inspector the Text object to reference
public Animation anim;
public int score
{
get { return currentScore; }
set { this.currentScore += value; }
}
void Start()
{
anim = Myscore.GetComponent<Animation>(); // Reference the Animation Component.
anim.wrapMode = WrapMode.Once; // Legacy animation Set to play once
AddScore();
}
public void AddScore()
{
score += 10;
myScoreText.text = score.ToString();
anim.Play();
Debug.Log("Current Score is "+ score);
Invoke("AddScore", 2);
}
}
Good luck.

Resources