I want to ask a question. How could I make a chat background similar like this link?
Link
With the auto text (the text will automatically typed one by one words per time).
The thing is, I already done the chat background similar to the image above, but with the transparent background, when I tried to fill the transparent background with the text in it, the text did not show.
Here is the image when it is on transparent background:
And here is the code that I have been using for this one (auto text):
using UnityEngine;
using System.Collections;
public class AutoText : MonoBehaviour
{
public float letterPause = 0.5f; // Define and set the pause for each letters
public AudioClip sound = null; // For the sound
public GUISkin customLabel = null; // For the label
public static string message = "Help...! Help...!" + "\n" + "Somebody...! Please Help Me...!"; // The message
private void Start()
{
StartCoroutine(TypedText());
}
private void OnGUI()
{
GUI.Label(new Rect((Screen.width / 2) - 250, (Screen.height / 2) - 200, 500, 500), message, customLabel.customStyles[0]);
}
IEnumerator TypedText()
{
// Loop through the message
foreach (char letter in message.ToCharArray())
{
// Set the gui text to be same with message
guiText.text += letter;
// If sound available
if (sound)
{
// Play it on each words
audio.PlayOneShot(sound);
// Go back to the if statement
yield return 0;
}
// Each letters will be shown for how many seconds delay
yield return new WaitForSeconds(letterPause);
}
}
}
For the text itself, I create a gui text and the gui skinin the unity editor and put the script on it, like the below image:
And also, when I tried to set the chat background to not be transparent, the text is on behind the chat background (so the text not been shown)
Thank you very much sir for answering this question and interest with it
Can't you just try and draw the Texture behind the Text :)?
Start by adding the texture as a variable in the script
public Texture2D Background;
Then change your OnGUI into
private void OnGUI()
{
GUI.DrawTexture(new Rect((Screen.width / 2) - 250, (Screen.height / 2) - 200, 500, 500), Background);
GUI.Label(new Rect((Screen.width / 2) - 250, (Screen.height / 2) - 200, 500, 500), message, customLabel.customStyles[0]);
}
Don't forget to assign the background texture in the editor first; Also on the imported texture. Set the Transparency to be from the alpha channel.
Without testing this I can ALMOST guarantee that it will work :-)
Related
I'm making a custom editor window and I want to draw EditorGUILayout.FloatField on it. if I write this:
EditorGUILayout.FloatField("change val", someFloatValue);
a label appears in front of the field. But I want it to appears behind the field. Also, I'd like to change simple text with a texture.
What I have now:
What I'd like to achieve:
UPD. I missed important information:
A mouse behavior over a texture must be the same as over a FloatField label, i.e. if I click on the texture and start dragging a cursor - the float value in the field must changes
I couldn't find an option to do it in a simple way. Maybe I miss something.
Is it possible not to create a lot of auxiliary classes for that simple action? If yes, then how?
Just put a label field after the floatfield
EditorGUILayout.BeginHorizontal();
someFloatValue = EditorGUILayout.FloatField(someFloatValue);
EditorGUILayout.LabelField("Change Val")
EditorGUILayout.EndHorizontal();
If you want to put a texture, then just create GUIStyle with the texture you want as background, and use the style for the label
GUIStyle myStyle = new GUIStyle();
myStyle.normal.background = myTexture;
EditorGUILayout.BeginHorizontal();
someFloatValue = EditorGUILayout.FloatField(someFloatValue);
EditorGUILayout.LabelField("", myStyle)
EditorGUILayout.EndHorizontal();
Now, to handle widths, just use GUILayout.Width()
GUIStyle myStyle = new GUIStyle();
myStyle.normal.background = myTexture;
EditorGUILayout.BeginHorizontal();
someFloatValue = EditorGUILayout.FloatField(someFloatValue, GUILayout.Width(150));
EditorGUILayout.LabelField("", myStyle)
EditorGUILayout.EndHorizontal();
It's very possible, but you shouldn't be GUILayout / EditorGUILayout classes. The Layout in the class names means that those variants handle positioning themselves, they each take up a default amount of space and move to the next row, its very conveinient but to do a little bit more advanced stuff, you should use versions of the GUI that take Rect as a position for a draw, so take from GUI/ EditorGUI classes (without Layout in the class name)
I recommend you start by doing a custom PropertyDrawer first, the API for a PropertyDrawer calls for manual element placement, so theres a ton of good examples. Once you start drawing using Rects instead of auto-Layouts there's no limit to how many layers of stuff to paint where, its actually trivial to start painting outside your own inspector (as long as its in the same window)
Well, I've made an UGLY workaround for the field (also for IntField).
If remove all redundant code that I used for content filling - it will be pretty short...
A simplified example looks like this:
using UnityEditor;
using UnityEngine;
public class MainWindow : EditorWindow {
private float floatFieldVal;
private Rect groupFloatFieldRect;
[MenuItem("Examples/Test")]
static void Init() {
MainWindow window = (MainWindow)GetWindow(typeof(MainWindow), false, "My Empty Window");
window.Show();
}
void OnGUI() {
EditorGUILayout.BeginHorizontal(); {
EditorGUILayout.BeginVertical(); {
GUILayout.Button("Button 1");
GUILayout.Button("Button 2");
GUILayout.Button("Button 3");
} EditorGUILayout.EndVertical();
EditorGUILayout.BeginVertical(GUILayout.Width(300)); {
// never load asset in the loop :)
string assetFullPath = "Assets/Editor/Test.guiskin";
var fakeFieldGUISkin = (GUISkin)AssetDatabase.LoadAssetAtPath(assetFullPath, typeof(GUISkin));
GUIStyle fakeFieldStyle = fakeFieldGUISkin.GetStyle("test");
// place fake floatField right over a real field texture button
Rect test = new Rect(groupFloatFieldRect);
test.position = new Vector2(test.x + groupFloatFieldRect.width - 20, test.y + 3);
test.size = new Vector2(20, 20);
floatFieldVal = EditorGUI.FloatField(test, "fake", floatFieldVal, fakeFieldStyle);
// Draw FloatField And Texture as a Group
Rect groupRect = EditorGUILayout.BeginHorizontal(); {
// never create GUIStyle in the loop :)
GUIStyle floatIconStyle = new GUIStyle(EditorStyles.toolbarButton) {
fixedWidth = 20f,
margin = new RectOffset(0, 0, 0, 0),
padding = new RectOffset(0, 0, 0, 0)
};
floatFieldVal = EditorGUILayout.FloatField("", floatFieldVal);
// It emulates a texture
GUILayout.Label("◀▶", floatIconStyle)
// save group rect in a variable
if (Event.current.type == EventType.Repaint)
groupFloatFieldRect = groupRect;
} EditorGUILayout.EndHorizontal();
} EditorGUILayout.EndVertical();
} EditorGUILayout.EndHorizontal();
}
void OnInspectorUpdate() {
Repaint();
}
}
Of course all magic numbers are just for a quick example. Also guiskin loading and a GUIStyle creating shouldn't be in a loop (in this case in OnGUI). It's for a quick example too.
Test.guiskinis for removing default skin data and regulating other params if needed.
That's how the code above looks:
screenshot of a window.jpg
animated demonstation of fake field.gif
In my chess game, I have a scene of pieces choice - black or white. After the user clicks on one of the pawns he/she gets a popup message/ It looks like this:
On Ok button click, the scene changes to the one with the board:
When the user chose black pieces he/she should see them closer to him/her, while if the user chose white pieces, they should be at the front. By default, in my scene pieces which are closer are black. I tried to achieve this by adding a texture change script on each figure (they will differ for white and black pieces):
void Start () {
GetComponent<Renderer>().material = Resources.Load<Material>)"Materials/Pieces/Marble/White Pawn");
}
However, how can I disable this script when I redirect to the scene if the user chose black pieces and the default view is needed.
Here is my code for popup window:
void OnGUI()
{
if (showPopUp)
{
GUI.Window(0, new Rect((Screen.width / 2) - 200, (Screen.height / 2) - 115
, 420, 180), ShowGUI, "Figures choice");
}
}
void ShowGUI(int windowID)
{
RedirectToMenu redirect = new RedirectToMenu();
guiStyle.fontSize = 22;
guiStyle.normal.textColor = Color.white;
GUI.Label(new Rect(80, 40, 200, 30), "You have chosen black pieces", guiStyle);
if (GUI.Button(new Rect(180, 110, 75, 35), "OK")){
showPopUp = false;
redirect.LoadAsset("UpgradedRoom");
SceneManager.LoadScene("UpgradedRoom");
}
}
I suppose I should access this script before loading the scene and disable if needed. But how can I access it outside of the scene with table, chessboard, and pieces? Or can I change the textures of game objects on another scene?
What I would do is use a static variable to remember whether the pieces are black or white. So, you'd set the variable before the scene loads and then check it after it is loaded. Therefore, if your class is called chess manager, your code for setting the variable might look like this:
public class ChessManager : Monobehavior {
public enum ChessColor { Black, White }
public static ChessColor playerColor
public void OnGUI() {
if(user chooses black) {
playerColor = ChessColor.Black;
//Load scene
}
else if(user chooses white) {
playerColor = ChessColor.White;
//Load scene
}
}
}
...And your code for enabling/disabling the script might be something like this, where ColorChanger is the script that sets the color:
public class ColorChanger : Monobehavior {
public void Start() {
if(ChessManager.playerColor == ChessManager.ChessColor.White) {
//Set texture
}
}
}
This would set the texture to something else when the user chooses white once the new scene is loaded. Don't forget to replace the if statements in ChessManager with the code that executes when a chess piece is selected (I'm assuming you're using legacy buttons for that, so you should replace if(user chooses color) with if(GUI.Button)). Hope I could help!
Also, as previously noted by someone else in the comments, it would probably be best if you used UnityEngine.UI instead of Unity's outdated legacy GUI system, but depending upon the project it might not be worth the effort.
I know that there are lot of different threads about horizontal text animation/text scrolling, but unfortunately none of them give smooth scrolling with repeatable text. I have tried double/thickness animation using various WPF controls containing text. Also tried animating with visual brush which gives me by far the most elegant scrolling compared to other approaches (for e.g. playing with Canvas.Left property etc.) but that too goes blur the text, if the text length or the animation speed is too high.
I'm over to a pure DirectX C# implementation using SharpDX library. Should also mention that I'm a beginner with DirectX programming. Here is the code:
public void RunMethod()
{
// Make window active and hide mouse cursor.
window.PointerCursor = null;
window.Activate();
var str = "This is an example of a moving TextLayout object with no snapped pixel boundaries.";
// Infinite loop to prevent the application from exiting.
while (true)
{
// Dispatch all pending events in the queue.
window.Dispatcher.ProcessEvents(CoreProcessEventsOption.ProcessAllIfPresent);
// Quit if the users presses Escape key.
if (window.GetAsyncKeyState(VirtualKey.Escape) == CoreVirtualKeyStates.Down)
{
return;
}
// Set the Direct2D drawing target.
d2dContext.Target = d2dTarget;
// Clear the target.
d2dContext.BeginDraw();
d2dContext.Clear(Color.CornflowerBlue);
//float layoutXOffset = 0;
float layoutXOffset = layoutX;
// Create the DirectWrite factory objet.
SharpDX.DirectWrite.Factory fontFactory = new SharpDX.DirectWrite.Factory();
// Create a TextFormat object that will use the Segoe UI font with a size of 24 DIPs.
textFormat = new TextFormat(fontFactory, "Verdana", 100.0f);
textLayout2 = new TextLayout(fontFactory, str, textFormat, 2000.0f, 100.0f);
// Draw moving text without pixel snapping, thus giving a smoother movement.
// d2dContext.FillRectangle(new RectangleF(layoutXOffset, 1000, 1000, 100), backgroundBrush);
d2dContext.DrawTextLayout(new Vector2(layoutXOffset, 0), textLayout2, textBrush, DrawTextOptions.NoSnap);
d2dContext.EndDraw();
//var character = str.Substring(0, 1);
//str = str.Remove(0, 1);
//str += character;
layoutX -= 3.0f;
if (layoutX <= -1000)
{
layoutX = 0;
}
// Present the current buffer to the screen.
swapChain.Present(1, PresentFlags.None);
}
}
Basically it creates an endless loop and subtracts the horizontal offset. Here are the challenges: I need repeatable text similar to HTML marquee without any gaps, Would probably need to extend it to multiple monitors.
Please suggest.
I don't know neither how to use DirectX nor sharpdx, but if you want you can consider this solution
I had a similar problem a while ago, but with the text inside a combobox. After a bounty i got what i was looking for. I'm posting the relevant piece of code as an example, but you can check the complete answer here
Basically, whenever you have a textblock/textbox that contain a string that cannot be displayed completely, cause the length exceed the textblock/box lenght you can use this kind of approach. You can define a custom usercontrol derived from the base you need (e.g. SlidingComboBox : Combobox) and define an animation for you storyboard like the following
_animation = new DoubleAnimation()
{
From = 0,
RepeatBehavior = SlideForever ? RepeatBehavior.Forever : new RepeatBehavior(1), //repeat only if slide-forever is true
AutoReverse = SlideForever
};
In my example i wanted this behaviour to be active only when the mouse was on the combobox, so in my custom OnMouse enter i had this piece of code
if (_parent.ActualWidth < textBlock.ActualWidth)
{
_animation.Duration = TimeSpan.FromMilliseconds(((int)textBlock.Text?.Length * 100));
_animation.To = _parent.ActualWidth - textBlock.ActualWidth;
_storyBoard.Begin(textBlock);
}
Where _parent represent the container of the selected item. After a check on the text lenght vs combobox lenght i start the animation and end it at the end of the text to be displayed
Note that in the question i mentioned there are also other soltions. I'm posting the one that worked for me
I'm developing an application in Unity with the Google CardbBoard Plugin, and I tried to fade in/out the screen when passing between scenes, I've worked with this example drawing a texture in the GUI object:
GUI.color = new Color (GUI.color.r, GUI.color.g, GUI.color.b, alpha);
Texture2D myTex;
myTex = new Texture2D (1, 1);
myTex.SetPixel (0, 0, fadeColor);
myTex.Apply ();
GUI.DrawTexture (new Rect (0, 0, Screen.width, Screen.height), myTex);
if (isFadeIn)
alpha = Mathf.Lerp (alpha, -0.1f, fadeDamp * Time.deltaTime);
else
alpha = Mathf.Lerp (alpha, 1.1f, fadeDamp * Time.deltaTime);
if (alpha >= 1 && !isFadeIn) {
Application.LoadLevel (fadeScene);
DontDestroyOnLoad(gameObject);
} else if (alpha <= 0 && isFadeIn) {
Destroy(gameObject);
}
The code I worked with is from this page: Video Tutorial, Example downloads, and it worked fine in a Unity game without the Cardboard plugin, but in my current project the same way to use this code is not working. The only difference is the use of the Cardboard plugin.
Is there any specific Cardboard object I must use instead of GUI or another way to draw a texture?
As per the Google Cardboard docs, You need to have GUI elements exist in 3D space infront of the camera so they are replicated in each eye.
I'll share my solution of how I did it. Note that What I've done is have a single instance of the Cardboard Player Prefab spawn when my game starts and persist throughout all my levels via DontDestoryOnLoad(), rather than have a seperate instance in each level.
This allows for settings to be carried over to each loaded level and Fade out and Fade in the screen.
I accomplished a screen fader by creating a World Space Canvas that is parented to the Cardboard prefab's "Head" object so it follows gaze, And put a Black Sprite image that covers the entire Canvas which blocks the players view when the Black Sprite is visible.
This script attached to my Player Prefab allows me to first fade out the screen (call FadeOut()), Load a new level (set LevelToLoad to the level index you want to load), then Fade in the screen after the new level is loaded.
By default it uses the Async way of loading levels, To allow for loading Bars, But you can set UseAsync to false to load levels via Application.LoadLevel()
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class LoadOperations: MonoBehaviour {
public Image myImage;
// Use this for initialization
public bool UseAsync;
private AsyncOperation async = null;
public int LevelToLoad;
public float FadeoutTime;
public float fadeSpeed = 1.5f;
private bool fadeout;
private bool fadein;
public void FadeOut(){
fadein= false;
fadeout = true;
Debug.Log("Fading Out");
}
public void FadeIn(){
fadeout = false;
fadein = true;
Debug.Log("Fading In");
}
void Update(){
if(async != null){
Debug.Log(async.progress);
//When the Async is finished, the level is done loading, fade in the screen
if(async.progress >= 1.0){
async = null;
FadeIn();
}
}
//Fade Out the screen to black
if(fadeout){
myImage.color = Color.Lerp(myImage.color, Color.black, fadeSpeed * Time.deltaTime);
//Once the Black image is visible enough, Start loading the next level
if(myImage.color.a >= 0.999){
StartCoroutine("LoadALevel");
fadeout = false;
}
}
if(fadein){
myImage.color = Color.Lerp(myImage.color, new Color(0,0,0,0), fadeSpeed * Time.deltaTime);
if(myImage.color.a <= 0.01){
fadein = false;
}
}
}
public void LoadLevel(int index){
if(UseAsync){
LevelToLoad= index;
}else{
Application.LoadLevel(index);
}
}
public IEnumerator LoadALevel() {
async = Application.LoadLevelAsync(LevelToLoad);
yield return async;
}
}
The GUI, GUILayout and Graphics do not work in VR. No 2d direct to screen will work properly.
You should render in 3d, easiest thing to do is to put a sphere around the camera (or even better, two spheres around each eye) and animate their opacity.
I am working on a game in the engine Unity, and am trying to make the skybox change color based on the time of day, but I can't seem to find out how to get it working.. What I want to do, I think, is to change the color of the material I use for the skybox in render settings, and be able to set it using one variable for red, one for green and one for blue.
I am using C#.
Thanks in advance for all answers :)
From the code you displayed in the comment:
RenderSettings.skybox.SetColor("_Tint", 0, 0, blue)
I think you mean
RenderSettings.skybox.SetColor("_Tint", Color.blue)
no need for extra zeros and remember that the color "blue" is a member variable of the Color class.
Next you would have to develop a time system and based on the time var you pass to the script controlling the skybox renderer you would then use a Lerp function to smoothly transition from one color to the next... like this
using UnityEngine;
using System.Collections;
public class example : MonoBehaviour {
public Color colorStart = Color.blue;
public Color colorEnd = Color.green;
public float duration = 1.0F;
void Update() {
float lerp = Mathf.PingPong(Time.time, duration) / duration;
RenderSettings.skybox.SetColor("_Tint", Color.Lerp(colorStart, colorEnd, lerp));
}
}
Then you could write a function to change the colorStart and colorEnd...
Hope this helps...
We can change Skybox color using the _Tint property. RenderSettings is the base class used to change the render properties at run time. For ensuring the attribute is existing in the skybox is done by the HasProperty(). SetColor() is used to set the color of the skybox.
if (RenderSettings.skybox.HasProperty("_Tint"))
RenderSettings.skybox.SetColor("_Tint", Color.red);
else if (RenderSettings.skybox.HasProperty("_SkyTint"))
RenderSettings.skybox.SetColor("_SkyTint", Color.red);
you can make your own skybox too in unity by changing texture shape into a cube one then apply for those changes it will create a cube mesh which you can simply drop it into your unity editor scree.
and if you want to load multiple skybox materials on run time by click on button
I have that code for that i hope it will help you for building a project in which you want to change skybox by some time or by using other input method.
enter code here
public class skybox : MonoBehaviour {
enter code here
public Material[] secondSkybox;
public static int i = 0;
public void skyboxOn()
{
if (i == 0) {
RenderSettings.skybox = secondSkybox[0];
i++;
}
else if(i==1)
{
RenderSettings.skybox = secondSkybox[1];
i++;
}else if(i==2)
{
RenderSettings.skybox = secondSkybox[2];
i=0;
}
}
}
and if you want too change the color of skybox which can be done by using this line of code
RenderSettings.skybox.SetFloat ("_Exposure", Mathf.Sin (Time.time * Mathf.Deg2Rad * 100) + 2);