I'm failing to understand how to decouple business logic of a controller and view for Unity3D GUI controls.
For example, if I have a GUI.Box, how would I implement a controller to fade in or out from the OnGUI lifecycle stage of the view?
View
using UnityEngine;
public class ExampleView : MonoBehaviour {
protected void OnGUI () {
GUI.Box(new Rect(0, 0, 100, 100), "Title");
}
}
If I instantiate a controller to change alpha of GUI.color it would need notification of Update() from the main view thread.
To roughly encapsulate functionality, if this were a single script it could be implemented as:
using UnityEngine;
public class ExampleView : MonoBehaviour {
private Color color;
protected void Start () {
color = Color.white;
}
protected void OnGUI () {
GUI.color = color;
GUI.Box(new Rect(0, 0, 100, 100), "Title");
}
protected void Update () {
if(color.a > 0)
color.a -= Time.deltaTime / 3;
}
}
Akin to how iTween animates changes to properties using iTween.fadeTo(gameObject, ... how can this be implemented for Unity3d GUI controls using statements like FadeOut()?
There's probably no way to target individual GUI controls unless multiple controller instances are specified OnGUI(). However, it would be cool to control isolated GUI instances such as fading in a GUI.Box followed by GUI.Label.
Are you looking for something like this?:
using UnityEngine;
public class ExampleView : MonoBehaviour {
private Color color;
private bool bFadeIn = false;
private bool bFadeOut = false;
protected void Start () {
color = Color.white;
}
public void FadeOut(){
bFadeOut = true;
bFadeIn = false;
}
public void FadeIn(){
bFadeIn = true;
bFadeOut = false;
}
protected void OnGUI () {
GUI.color = color;
GUI.Box(new Rect(0, 0, 100, 100), "Title");
}
protected void Update () {
if(bFadeOut && color.a > 0.0)color.a -= Time.deltaTime / 3;
if(bFadeIn && color.a < 1.0)color.a += Time.deltaTime / 3;
}
}
You might also want to include a flag to determine when the control is invisible and, if invisible, skip the full GuiRender function.
Dont know if this is what you are looking for, but its a simple way to add fade effect to gui..
using UnityEngine;
using System.Collections;
/**Fade In/Out Instructions:
* 1.Create bool fadeIn. Create float alpha.
* 2.Call Fade() method at start of OnGUI().
* 3.Put 'GUI.color = new Color(1,1,1,alpha)' above the elements you want to fade'.
* 4.To fade in, fadeIn = true.
* 5.To fade out, fadeIn = false.
* 6.To deactivate buttons on fade out, wrap gui in 'if(alpha > 0)'
**/
public class MainMenuGUI : MonoBehaviour {
int buttonWidth;
int buttonHeight;
public float alpha;
public bool fadeIn;
// Use this for initialization
void Start () {
buttonWidth = 100;
buttonHeight = 50;
fadeIn = true;
}
void OnGUI(){
Fade();
GUI.color = new Color(1,1,1,alpha);
if(alpha > 0)
{
if (GUI.Button (new Rect ((Screen.width/2)-50, (Screen.height/2)-(buttonHeight*4/2), 100, 50), "PLAY"))
{
fadeIn = false;
Debug.Log("Play pressed");
}
if (GUI.Button (new Rect ((Screen.width/2)-50, ((Screen.height/2)-(buttonHeight*4/2)+ buttonHeight), 100, 50), "SCORES"))
{
Debug.Log("Scores pressed");
}
if (GUI.Button (new Rect ((Screen.width/2)-50, ((Screen.height/2)-(buttonHeight*4/2)+ buttonHeight*2), 100, 50), "OPTIONS"))
{
Debug.Log("Options pressed");
}
if (GUI.Button (new Rect ((Screen.width/2)-50, ((Screen.height/2)-(buttonHeight*4/2)+ buttonHeight*3), 100, 50), "EXIT"))
{
Debug.Log("Exit pressed");
}
}
}
void Fade(){
if(fadeIn){
alpha = Mathf.Clamp(alpha+0.01f,0,1);
}else{
alpha = Mathf.Clamp(alpha-0.01f,0,1);
}
}
}
Good luck on your game :)
Related
i'm trying to make a board, that have 12 site. i tried to detect one of them with Overlapsphere, but i'm looking for a method to check the 12 site at the same time. so i can know how many object are in each site. anyone can help ? maybe its possible to create an array of overlapSphere ?
here is the code:enter code here
public int count;
[SerializeField]Vector3 position = new Vector3 (0,0,0);
float radius = 2f;
[SerializeField] public Text counter;
// Start is called before the first frame update
void Start()
{
//detectedball();
}
// Update is called once per frame
void Update()
{
detectedball();
}
void detectedball()
{
Collider[] hitColliders = Physics.OverlapSphere(position, radius);
foreach (var hitCollider in hitColliders)
{
// hitCollider.SendMessage("Detected");
if(gameObject.tag == "Ball")
{
count++;
}
Debug.Log(count);
// counter.text = hitCollider.ToString();
}
}
void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere( position , radius);
}
}
I am calling JUMP function from a UI Button but unable to jump using Character Collider provided by Unity. Can someone please help me where am i going wrong?
PlayerMovement Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class PlayerControllerCC : MonoBehaviour
{
public FixedJoystick moveJoystick;
CharacterController _charController;
private Vector3 v_movement;
private Animator _animator;
public float moveSpeed = 0.1f;
public float gravity = 0.5f;
public float jumpForce = 0.5F;
private float originalstepOffset;
private float InputX;
private float InputZ;
// Start is called before the first frame update
void Start()
{
moveSpeed = 0.1f;
gravity = 0.5f;
jumpForce = 0.5F;
_charController = GetComponent<CharacterController>();
originalstepOffset = _charController.stepOffset;
_animator = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
InputX = moveJoystick.Horizontal;
InputZ = moveJoystick.Vertical;
isWalking();
}
private void FixedUpdate()
{
playerMovement();
}
void playerMovement()
{
//Check Gravity
if (_charController.isGrounded)
{
_charController.stepOffset = originalstepOffset;
v_movement.y = -0.5f;
}
else
{
_charController.stepOffset = 0;
v_movement.y -= gravity * Time.deltaTime;
}
//player movement
v_movement = new Vector3(InputX * moveSpeed, v_movement.y, InputZ * moveSpeed);
float magnitute = Mathf.Clamp01(v_movement.magnitude);
v_movement.Normalize();
_charController.Move(v_movement * magnitute);
Vector3 lookDir = new Vector3(v_movement.x, 0, v_movement.z);
//Set rotation facing after player movement
if ((lookDir.x != 0) && (lookDir.z != 0))
{
transform.rotation = Quaternion.LookRotation(lookDir);
}
}
void isWalking()
{
if (InputX == 0 && InputZ == 0)
{
_animator.SetBool("isWalking", false);
}
else
{
_animator.SetBool("isWalking", true);
}
}
public void Attack()
{
_animator.SetTrigger("isAttacking");
}
public void Jump()
{
if (_charController.isGrounded)
{
v_movement.y = jumpForce * Time.deltaTime;
}
}
}
When button is clicked in UI it called the JUMP function. I am not using keyboard but FixedJoyStick hence using button to jump.
My Game looks like this and the UI. The up arrow key is the jump button.
The Game button Up Arrow Jump
Calling Jump Function in Button
Your problem lays on the OnClick() function of the button, it is interacting with the script but the script itself is not attached to any character in this case. What you did works when the script works by itself no matter where is attached (e.g. when you call all the objects with a tag).
What you need to do is to link the object which has the script to the OnClick() in the editor, then select from the dropdown menu the script component and then call the function you want.
Like This.
Image link since I'm new
Notice how what is linked are the Game Objects and then the script is selected.
I am creating a voice controlled game. One game I'm creating is a "shoot the targets" cannon game which will fire a cannon ball when the word "shoot" is said.
I am trying to use Unity's speech recogniser in conjunction with an if statement in order to move the Slider UI's fill area with my voice.
However, my initial method is drawing a few errors such as "Cannot convert Method group 'Up' to non-delegate type bool. Did you intent to invoke the method?"
P.S This is my first time using StackOverflow, please be nice.
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Windows.Speech;
using UnityEngine;
using UnityEngine.UI;
public class SliderControls : MonoBehaviour
{
//Voice Controls Setup
private KeywordRecognizer keywordRecognizer;
private Dictionary<string, Action> actions = new Dictionary<string, Action>();
float sliderValue;
// Start is called before the first frame update
void Start()
{
actions.Add("Up", Up);
actions.Add("Down", Down);
keywordRecognizer = new KeywordRecognizer(actions.Keys.ToArray());
keywordRecognizer.OnPhraseRecognized += Recognization;
keywordRecognizer.Start();
}
private void Recognization(PhraseRecognizedEventArgs speech)
{
Debug.Log(speech.text);
actions[speech.text].Invoke();
}
private void Up()
{
ControlGUI();
}
private void Down()
{
ControlGUI();
}
public void ControlGUI ()
{
if (Up)
{
sliderValue = sliderValue + 0.1F;
}
else if(Down)
{
sliderValue = sliderValue - 0.1F;
}
sliderValue = GUI.HorizontalSlider(new Rect(25F, 25F, 600F, 30F), sliderValue, 0.0F, 10.0F);
return;
}
}
As the error says, you trying to use method as a bool. You can't do that. Moreover, your logic in ControlGUI method is strange - where these Up and Down should come from?
I think you need to pass and argument to ControlGUI method, so your code will look like:
private void Up()
{
ControlGUI("Up");
}
private void Down()
{
ControlGUI("Down");
}
// You can also define enum Direction { Up, Down } or use int or any other approach
public void ControlGUI (string direction)
{
if (direction == "Up")
{
sliderValue = sliderValue + 0.1F;
}
else if(direction == "Down")
{
sliderValue = sliderValue - 0.1F;
}
sliderValue = GUI.HorizontalSlider(new Rect(25F, 25F, 600F, 30F), sliderValue, 0.0F, 10.0F);
return; // this return statement is redundant
}
I am new in Unity.
There is one cube. I want to make cube go right and left continuously.
Right now it only work when i lift my finger from the pressed button (it is 3d game).
Here is my code:
public class PlayerMovement : MonoBehaviour
{
public Rigidbody rb;
public float sidewaysforceand = 150f;
public void rightforce()
{
rb.AddForce(sidewaysforceand * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
}
public void leftforce()
{
rb.AddForce(-sidewaysforceand * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
}
}
You need to place them both in the same script / Update that tracks if the buttons have been pressed.
public void Update()
{
float xChange = 0;
if(Input.GetKey(rightButton))
xChange ++;
if(Input.GetKey(leftButton))
xChange --;
rb.AddForce(sidewaysforceand * Time.deltaTime * xChange, 0, 0, ForceMode.VelocityChange);
}
If you are using UI Buttons you will have to use a flagging system such as:
bool rightFlag = false;
bool leftFlag = false;
public void Update()
{
float xChange = 0;
if(rightFlag)
xChange ++;
if(leftFlag)
xChange --;
rb.AddForce(sidewaysforceand * Time.deltaTime * xChange, 0, 0, ForceMode.VelocityChange);
}
public void EnableRightFlag() //put on button down press.
{
rightFlag = true;
}
public void EnableLeftFlag() //put on button down press.
{
leftFlag = true;
}
Then you just have to add a trigger for when the button is not pressed to set the flags back to false.
I have script called PlayerCharacter to control a player on the Unity 2D Platform. It's perfect, working as usual.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[RequireComponent(typeof (Rigidbody2D))]
[RequireComponent(typeof(BoxCollider2D))]
public class PlayerCharacter : MonoBehaviour
{
public float speed = 1.0f;
public string axisName = "Horizontal";
private Animator anim;
public string jumpButton = "Fire1";
public float jumpPower = 10.0f;
public float minJumpDelay = 0.5f;
public Transform[] groundChecks;
private float jumpTime = 0.0f;
private Transform currentPlatform = null;
private Vector3 lastPlatformPosition = Vector3.zero;
private Vector3 currentPlatformDelta = Vector3.zero;
// Use this for initialization
void Start ()
{
anim = gameObject.GetComponent<Animator>();
}
// Update is called once per frame
void Update ()
{
//Left and right movement
anim.SetFloat("Speed", Mathf.Abs(Input.GetAxis(axisName)));
if(Input.GetAxis(axisName) < 0)
{
Vector3 newScale = transform.localScale;
newScale.x = -1.0f;
transform.localScale = newScale;
Debug.Log("Move to left");
}
else if(Input.GetAxis(axisName) > 0)
{
Vector3 newScale = transform.localScale;
newScale.x = 1.0f;
transform.localScale = newScale;
Debug.Log ("Move to Right");
}
transform.position += transform.right*Input.GetAxis(axisName)*speed*Time.deltaTime;
//Jump logic
bool grounded = false;
foreach(Transform groundCheck in groundChecks)
{
grounded |= Physics2D.Linecast(transform.position, groundCheck.position, 1 << LayerMask.NameToLayer("Ground"));
}
anim.SetBool("Grounded", grounded);
if(jumpTime > 0)
{
jumpTime -= Time.deltaTime;
}
if(Input.GetButton("jumpButton") && anim.GetBool("Grounded") )
{
anim.SetBool("Jump",true);
rigidbody2D.AddForce(transform.up*jumpPower);
jumpTime = minJumpDelay;
}
if(anim.GetBool("Grounded") && jumpTime <= 0)
{
anim.SetBool("Jump",false);
}
//Moving platform logic
//Check what platform we are on
List<Transform> platforms = new List<Transform>();
bool onSamePlatform = false;
foreach(Transform groundCheck in groundChecks)
{
RaycastHit2D hit = Physics2D.Linecast(transform.position, groundCheck.position, 1 << LayerMask.NameToLayer("Ground"));
if(hit.transform != null)
{
platforms.Add(hit.transform);
if(currentPlatform == hit.transform)
{
onSamePlatform = true;
}
}
}
if(!onSamePlatform)
{
foreach(Transform platform in platforms)
{
currentPlatform = platform;
lastPlatformPosition = currentPlatform.position;
}
}
}
void LateUpdate()
{
if(currentPlatform != null)
{
//Determine how far platform has moved
currentPlatformDelta = currentPlatform.position - lastPlatformPosition;
lastPlatformPosition = currentPlatform.position;
}
if(currentPlatform != null)
{
//Move with the platform
transform.position += currentPlatformDelta;
}
}
}
A problem arises when I try to modify the script with a touchable controller. I have googled many times and modified the script as I could, and still it gives me no result (btw, I'm new to Unity). Then I found a tutorial from a website about making a touch controller with a GUI Texture (TouchControls). I think that tutorial is easy to learn. Here is the script
using UnityEngine;
using System.Collections;
[RequireComponent(typeof (Rigidbody2D))]
[RequireComponent(typeof(BoxCollider2D))]
public class TouchControls : MonoBehaviour {
// GUI textures
public GUITexture guiLeft;
public GUITexture guiRight;
public GUITexture guiJump;
private Animator anim;
// Movement variables
public float moveSpeed = 5f;
public float jumpForce = 50f;
public float maxJumpVelocity = 2f;
// Movement flags
private bool moveLeft, moveRight, doJump = false;
void Start ()
{
anim = gameObject.GetComponent<Animator>();
}
// Update is called once per frame
void Update () {
// Check to see if the screen is being touched
if (Input.touchCount > 0)
{
// Get the touch info
Touch t = Input.GetTouch(0);
// Did the touch action just begin?
if (t.phase == TouchPhase.Began)
{
// Are we touching the left arrow?
if (guiLeft.HitTest(t.position, Camera.main))
{
Debug.Log("Touching Left Control");
moveLeft = true;
}
// Are we touching the right arrow?
if (guiRight.HitTest(t.position, Camera.main))
{
Debug.Log("Touching Right Control");
moveRight = true;
}
// Are we touching the jump button?
if (guiJump.HitTest(t.position, Camera.main))
{
Debug.Log("Touching Jump Control");
doJump = true;
}
}
// Did the touch end?
if (t.phase == TouchPhase.Ended)
{
// Stop all movement
doJump = moveLeft = moveRight = false;
}
}
// Is the left mouse button down?
if (Input.GetMouseButtonDown(0))
{
// Are we clicking the left arrow?
if (guiLeft.HitTest(Input.mousePosition, Camera.main))
{
Debug.Log("Touching Left Control");
moveLeft = true;
}
// Are we clicking the right arrow?
if (guiRight.HitTest(Input.mousePosition, Camera.main))
{
Debug.Log("Touching Right Control");
moveRight = true;
}
// Are we clicking the jump button?
if (guiJump.HitTest(Input.mousePosition, Camera.main))
{
Debug.Log("Touching Jump Control");
doJump = true;
}
}
if (Input.GetMouseButtonUp(0))
{
// Stop all movement on left mouse button up
doJump = moveLeft = moveRight = false;
}
}
void FixedUpdate()
{
//anim.SetFloat("Speed", Mathf.Abs);
// Set velocity based on our movement flags.
if (moveLeft)
{
rigidbody2D.velocity = -Vector2.right * moveSpeed;
}
if (moveRight)
{
rigidbody2D.velocity = Vector2.right * moveSpeed;
}
if (doJump)
{
// If we have not reached the maximum jump velocity, keep applying force.
if (rigidbody2D.velocity.y < maxJumpVelocity)
{
rigidbody2D.AddForce(Vector2.up * jumpForce);
} else {
// Otherwise stop jumping
doJump = false;
}
}
}
}
But I have no idea how to implement the script from the tutorial (TouchControls) and assign that to my player control script (PlayerCharacter). How can I combine both scripts so that a player can control it with a touchable control?
The best thing you can do is not to drag the touch controls from the touchcontrols tutorial to the playercontroller but the other way around, use the touchcontrols tutorial script as your template.
Since your playercontroller uses floats in its input such as moveleft = 50.0f; and the touchcontrols uses moveleft = true;
the scripts are very different from each other to just merge and work.
so from that in the touchcontrols leave the update function as it is,
and only update the fixedupate function with your controls logic since
the update void, is the condition controller for right, left, up & down so to speak.
and it will also handle the actual input of the touch.
the fixed update could then control some things that the playercontroller has such as
apply force when touching a tagged object or stuff like that.
and the update only does the input condition, good advice would be to wrap the update touch code in its own function so the update is not only touch but also other game logic related code.
You should search use copy the touch control script inside the player controller while changing the right parts. For example, instead of using Input.GetKeyDown you should use the Input.GetTouch but it depends on the game you are creating. You should pay attention to that code and change some parts