How to select and deselect in a crossword game - c#

So, im doing a crossword game in Unity Engine, and when i select (with my left click button) a word, the white tiles should turn green (which occurs), but when i stop holding my left mouse click button, it does not turns white again as you can see on the print
And the code is here:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using System;
public class Selecionar : MonoBehaviour, ISelectHandler, IPointerClickHandler, IDeselectHandler {
private int acertos;
public static HashSet<Selecionar> todosMeusSelecionaveis = new HashSet<Selecionar>();
public static HashSet<Selecionar> selecionado = new HashSet<Selecionar>();
Renderer myRenderer;
[SerializeField]
Material materialNaoSelecionado;
[SerializeField]
Material materialSelecionado;
void Awake()
{
todosMeusSelecionaveis.Add(this);
myRenderer = GetComponent<Renderer>();
}
public void OnDeselect(BaseEventData eventData)
{
myRenderer.material = materialNaoSelecionado;
}
public void OnPointerClick(PointerEventData eventData)
{
if(Input.GetKeyDown(KeyCode.Mouse0)){
DeselectAll(eventData);
}
OnSelect(eventData);
}
public void OnSelect(BaseEventData eventData)
{
selecionado.Add(this);
myRenderer.material = materialSelecionado;
}
public static void DeselectAll (BaseEventData eventData){
foreach (Selecionar selecionavel in selecionado)
{
selecionavel.OnDeselect(eventData);
}
selecionado.Clear();
}
}

I think you should return inside the if statement on OnPointerClick. When it enters, it executes DeselectAll followed by OnSelect.
Either do:
public void OnPointerClick(PointerEventData eventData)
{
if(Input.GetKeyDown(KeyCode.Mouse0)){
DeselectAll(eventData);
return; // <----
}
OnSelect(eventData);
}
or:
public void OnPointerClick(PointerEventData eventData)
{
if(Input.GetKeyDown(KeyCode.Mouse0)){
DeselectAll(eventData);
} else {
OnSelect(eventData);
}
}

Related

OnTriggerEnter2D doesn't work after switching scenes

I have a game that is similar to "Flappy Bird" and I have main menu where I can start game and change skin of a pigeon. My skin collection is implemented with scroll rect and in the center there is a trigger which starts an animation of scaling a pigeon, it works fine until I click "start" and the scene changes to game and when I return to my main menu and click "skins" this trigger doesn't work anymore.
Script what is attached to all scroll rect elements to detect collisions with trigger:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ResizeFieldScript : MonoBehaviour
{
private Animator _anim;
private void Start()
{
_anim = GetComponent<Animator>();
}
public void OnTriggerEnter2D(Collider2D collider)
{
Debug.Log("Trigger is working");
if(collider.tag == "ResizeField")
{
Debug.Log("Condition is working");
_anim.SetBool("isInTrigger", true);
}
}
public void OnTriggerExit2D(Collider2D collider)
{
_anim.SetBool("isInTrigger", false);
}
}
Script what is attached to an empty object to change scenes:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
public class UIController : MonoBehaviour
{
[SerializeField] private List<string> sceneNameList;
private string sceneToFind;
private int index = 0;
public void SceneChanger()
{
sceneToFind = EventSystem.current.currentSelectedGameObject.name;
foreach(string str in sceneNameList)
{
if(str == sceneToFind)
{
SceneManager.LoadScene(index);
index = 0;
break;
}
index++;
}
}
public void Exit()
{
Application.Quit();
}
public void BackMenu()
{
SceneManager.LoadScene(4);
}
}
OnTriggerEnter2D doesn't work after switching scenes. We could use OnTriggerEnter2D to jump scenes.
code show as below:
private void Update() {
// If E is pressed
if (Input. GetKeyDown(KeyCode. E)) {
// scene switching
SceneManager.LoadScene(4);
}
}
private void OnTriggerEnter2D(Collider collision) {
if (collision. tag == "ResizeField") {
// The UI prompts the user to press E to jump
EnterDialog.SetActive(true);
Debug.Log("Condition is working");
// _anim.SetBool("isInTrigger", true);
}
}
Hope it helps you.

Event Action Doesn't work in state Pattern

I'm using state pattern for my unity game. I have three states; HappyState, SurprisedState and SadState. HappyState is default state. I want the character to jump and enter surprised state by clicking left-mouse. Entering surprised state, a few jobs need to be done which I defined as a void to be subscribed to an event, But it doesn't work!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;
public class CapsuleScript : MonoBehaviour
{
public event Action SliderAction;
public Slider slider;
public Text stateText;
public GameObject hands;
public Rigidbody rb;
public CapsuleBasicStates currentstate;
public readonly HappyState happyState = new HappyState();
public readonly SadState sadState = new SadState();
public readonly SurprisedState surprisedState = new SurprisedState();
public SpriteRenderer renderer;
public Sprite happysprite, sadsprite, surprisedsprite;
// Start is called before the first frame update
void Start()
{
slider.value = 0;
renderer = GetComponentInChildren<SpriteRenderer>();
rb = GetComponent<Rigidbody>();
TransitionToState(happyState);
}
public void OnCollisionEnter(Collision other) {
currentstate.OnCollisionEnter(this);
}
// Update is called once per frame
void Update()
{
currentstate.Update(this);
}
public void SetSprite(Sprite sprite)
{
renderer.sprite = sprite;
}
public void TransitionToState(CapsuleBasicStates state)
{
currentstate = state;
currentstate.EnterState(this);
}
public IEnumerator SliderHandler()
{
yield return new WaitForSeconds(1f);
slider.value +=1;
StartCoroutine(SliderHandler());
}
public void IEHandler()
{
StartCoroutine(SliderHandler());
}
}
Here is SurprisedState script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SurprisedState : CapsuleBasicStates
{
public override void EnterState(CapsuleScript player)
{
player.SetSprite(player.surprisedsprite);
player.stateText.text = player.surprisedState.ToString();
player.slider.gameObject.SetActive(true);
player.SliderAction += player.IEHandler;
}
public override void OnCollisionEnter(CapsuleScript player)
{
//player.TransitionToState(player.happyState);
}
public override void Update(CapsuleScript player)
{
if(player.slider.value ==20)
{
player.SliderAction -= player.IEHandler;
player.TransitionToState(player.happyState);
}
}
}
HappyState script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HappyState : CapsuleBasicStates
{
public override void EnterState(CapsuleScript player)
{
player.SetSprite(player.happysprite);
player.stateText.text = player.happyState.ToString();
player.hands.SetActive(false);
}
public override void OnCollisionEnter(CapsuleScript player)
{
}
public override void Update(CapsuleScript player)
{
if(Input.GetButton("Fire1"))
{
player.rb.AddForce(Vector3.up * 150f);
player.TransitionToState(player.surprisedState);
}
if(Input.GetButton("Fire2"))
{
player.rb.AddForce(Vector3.up *250f);
player.TransitionToState(player.sadState);
}
}
}
Few points before I post my solution:
Try to post all scripts related to the question you are asking.
Comment your code or try to explain what each part of your script is doing.
BaseSate.cs
[System.Serializable]
public abstract class BaseState
{
public enum PlayerStates { HappyState = 0, SurprisedState = 1 }
public abstract PlayerStates PlayerState { get; }
public abstract void EnterState(PlayerScript playerScript);
public abstract void UpdateState();
public abstract void ExitState();
}
HappySate.cs
using UnityEngine;
[System.Serializable]
public class HappyState : BaseState
{
public override PlayerStates PlayerState => PlayerStates.HappyState;
private PlayerScript _playerScript;
public override void EnterState(PlayerScript playerScript)
{
_playerScript = playerScript;
Debug.Log($"Entered {PlayerState}");
}
public override void UpdateState()
{
if (Input.GetButtonDown("Fire1"))
{
_playerScript.ChangeState(new SurprisedState());
}
}
public override void ExitState()
{
Debug.Log($"Exited {PlayerState}");
}
}
SurprisedState.cs
using UnityEngine;
[System.Serializable]
public class SurprisedState : BaseState
{
public override PlayerStates PlayerState => PlayerStates.SurprisedState;
private PlayerScript _playerScript;
public override void EnterState(PlayerScript playerScript)
{
_playerScript = playerScript;
// subscribe to sliderAction on enter
playerScript.playerSliderAction += OnSliderChange;
Debug.Log($"Entered {PlayerState}");
}
private void OnSliderChange(float sliderValue)
{
// use Mathf.Approximately instead of == when comparing
// floating numbers.
if (Mathf.Approximately(sliderValue, 20f))
{
_playerScript.ChangeState(new HappyState());
}
}
public override void UpdateState() { }
public override void ExitState()
{
// unSubscribe to sliderAction on exit
_playerScript.playerSliderAction -= OnSliderChange;
Debug.Log($"Exited {PlayerState}");
}
}
PlayerScript.cs
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
public class PlayerScript : MonoBehaviour
{
[SerializeField]
private SpriteRenderer playerRenderer;
[SerializeField]
private Sprite[] playerStateSprites;
[SerializeField]
private Slider playerSlider;
public UnityAction<float> playerSliderAction;
private BaseState _currentState;
private void Awake()
{
Initialize();
}
private void Update()
{
_currentState.UpdateState();
}
private void Initialize()
{
ChangeState(new HappyState());
// use slider onValueChanged instead of checking slider
// value every frame.
// invoke unity action when the value has been changed.
playerSlider.onValueChanged.AddListener(sliderValue =>
{
playerSliderAction?.Invoke(sliderValue);
});
}
public void ChangeState(BaseState newState)
{
// change state only when it is different
// from previous state.
if (_currentState == newState)
{
return;
}
_currentState?.ExitState();
_currentState = newState;
_currentState.EnterState(this);
playerRenderer.sprite = playerStateSprites[(int)newState.PlayerState];
Debug.Log($"Current State : {_currentState.PlayerState}");
}
}
PlayerScript inspector view
Execution Overview gif:
https://gfycat.com/grimflowerycollardlizard

How can I use flag to change the mouse cursor to default or to other texture?

The first script that handle the mouse cursor :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HandleMouseCursor : MonoBehaviour
{
public bool useDefaultCursor = true;
public Texture2D mouse;
public Texture2D hand;
public Texture2D grab;
public CursorMode cursorMode = CursorMode.Auto;
public Vector2 hotSpot = Vector2.zero;
// Use this for initialization
void Start ()
{
if(useDefaultCursor == true)
{
mouse = Texture2D.def
}
setMouse();
}
// Update is called once per frame
void Update ()
{
}
public void setMouse()
{
Cursor.SetCursor(mouse, hotSpot, cursorMode);
}
public void setHand()
{
Cursor.SetCursor(hand, hotSpot, cursorMode);
}
public void setGrab()
{
Cursor.SetCursor(grab, hotSpot, cursorMode);
}
}
I added a flag : useDefaultCursor
and then tried to start using it :
if(useDefaultCursor == true)
{
mouse = Texture2D.def
}
but not sure how to continue Texture2D don't have default property.
The second script use the first one methods :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UpdateCursor : MonoBehaviour
{
HandleMouseCursor cursor;
bool carrying;
// Use this for initialization
void Start ()
{
cursor = GameObject.FindGameObjectWithTag("MainCamera").GetComponent<HandleMouseCursor>();
}
// Update is called once per frame
void Update ()
{
if (carrying)
cursor.setGrab();
}
private void OnMouseEnter()
{
cursor.setHand();
}
private void OnMouseExit()
{
cursor.setMouse();
}
private void OnMouseDown()
{
carrying = true;
}
private void OnMouseUp()
{
carrying = false;
cursor.setMouse();
}
}
What I want to do is to use the flag useDefaultCursor if it's true use the regular default mouse cursor
if it's false use the mouse textures from the public fields if there are any textures assigned to the fields. if not textures assigned at all then use again the default mouse cursor.
In your HandleMouseCursor::setMouse() just use the useDefaultCursor as you intended and write:
void setMouse()
{
if (useDefaultCursor)
Cursor.SetCursor(null, hotSpot, cursorMode);
else
Cursor.SetCursor(mouse, hotSpot, cursorMode);
}

Unity2D: Fixing colliding for inventory

My goal was to make my character pickup item on collider (2D) didn't work.
So here is what I've tried:
Player Controller Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float moveSpeed = 2f;
public Inventory inventory;
void Start()
{
}
public bool isGrounded;
public LayerMask groundLayers;
void Update()
{
// isgrounded?
isGrounded = Physics2D.OverlapArea(new Vector2(transform.position.x -
0.2f, transform.position.y - 0.2f),
new Vector2(transform.position.x + 0.2f, transform.position.y -
0.21f), groundLayers);
Jump();
Vector3 movement = new Vector3(Input.GetAxis("Horizontal"), 0f, 0f);
transform.position += movement * Time.deltaTime * moveSpeed;
}
void Jump()
{
if(Input.GetButtonDown("Jump") && isGrounded)
{
gameObject.GetComponent<Rigidbody2D>().AddForce(new Vector2(0f,
2.5f), ForceMode2D.Impulse);
}
}
private void OnCollisionEnter2D(ControllerColliderHit hit)
{
IInventoryItem item = hit.collider.GetComponent<IInventoryItem>();
if (item != null)
{
inventory.AddItem(item);
}
}
}
HUD SCRIPT:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class HUD : MonoBehaviour
{
public Inventory Inventory;
void Start ()
{
Inventory.ItemAdded += InventoryScript_ItemAdded;
}
private void InventoryScript_ItemAdded(object sender, InventoryEventArgs
e)
{
Transform inventoryPanel = transform.Find("InventoryPanel");
foreach(Transform slot in inventoryPanel)
{
// Border... Image
Image image = slot.GetChild(0).GetChild(0).GetComponent<Image>();
// We found empty slot!
if (!image.enabled)
{
image.enabled = true;
image.sprite = e.Item.Image;
// Todo store a reference;
break;
}
}
}
}
Inventory Script:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
private const int SLOTS = 7;
private List<IInventoryItem> mItems = new List<IInventoryItem>();
public event EventHandler<InventoryEventArgs> ItemAdded;
public void AddItem(IInventoryItem item)
{
if(mItems.Count < SLOTS)
{
Collider collider = (item as MonoBehaviour).GetComponent<Collider>
();
if (collider.enabled)
{
collider.enabled = false;
mItems.Add(item);
item.OnPickup();
if (ItemAdded != null)
{
ItemAdded(this, new InventoryEventArgs(item));
}
}
}
}
}
Inventory Item Script:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface IInventoryItem
{
string Name { get; }
Sprite Image { get; }
void OnPickup();
}
public class InventoryEventArgs : EventArgs
{
public InventoryEventArgs(IInventoryItem item)
{
Item = item;
}
public IInventoryItem Item;
}
Rock Script (The object):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rock : MonoBehaviour, IInventoryItem
{
public string Name
{
get
{
return "Rock";
}
}
public Sprite _Image = null;
public Sprite Image
{
get
{
return _Image;
}
}
public void OnPickup()
{
// TODO: ADD LOGIC THAT WILL MAKE THE ROCK A 'WEAPON' TO CUT DOWN THE
TREE
gameObject.SetActive(false);
}
}
All of those scripts work, but whenever I join my game and Collide the player with the object (all 2d, 2D Box colliders, etc.) the character wont pick the item up and put it in it's inventory?
The scripts are referenced to each other.
What did I do wrong?
Physics 2D Screenshot:
Player inspector screenshot:
Rock (Object that needs to join his inventory)
One thing I noticed is that you are mixing the syntax of two events to create one that doesn't exist. void OnCollisionEnter2D(ControllerColliderHit hit) is not a built-in event in Unity. You probably mean to use void OnCollisionEnter2D(Collision2D hit):
private void OnCollisionEnter2D(Collision2D hit)
{
IInventoryItem item = hit.collider.GetComponent<IInventoryItem>();
if (item != null)
{
inventory.AddItem(item);
}
}
Another thing is that BoxCollider2D does not inherit from Collider. So, in AddItem, you should look for a Collider2D component instead:
public void AddItem(IInventoryItem item)
{
if(mItems.Count < SLOTS)
{
Collider2D collider = (item as MonoBehaviour).GetComponent<Collider2D>();
if (collider.enabled)
{
collider.enabled = false;
mItems.Add(item);
item.OnPickup();
if (ItemAdded != null)
{
ItemAdded(this, new InventoryEventArgs(item));
}
}
}
}
Consider this to be a partial solution because this may not capture all the changes needed... Let me know if this alone doesn't fix the problem in the comments below.

Buttons in Unity, without using UI?

Is there a way in Unity to create a simple 2D button without using the UI layer. I have a game with a lot of buttons and I don't want to make the whole app in the UI. Some more controls are welcome too: switches, sliders etc.
PS. I saw NGUI and I don't like it so far. Anything else?
Is there a way in Unity to create a simple 2D button without using the
UI layer
You can use Sprite/Sprite Render as a Button.First Create a GameObject and attach EventSystem and StandaloneInputModule to it. Attach Physics2DRaycaster to the Camera, implement IPointerClickHandler and override OnPointerClick function. Create a 2D Sprite by going to GameObject->2D Object->Sprite then attach your script to the Sprite. Here is a complete code to do that:
using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections;
public class SPRITEBUTTON: MonoBehaviour, IPointerClickHandler,
IPointerDownHandler, IPointerEnterHandler,
IPointerUpHandler, IPointerExitHandler
{
void Start()
{
//Attach Physics2DRaycaster to the Camera
Camera.main.gameObject.AddComponent<Physics2DRaycaster>();
addEventSystem();
}
public void OnPointerClick(PointerEventData eventData)
{
Debug.Log("Mouse Clicked!");
}
public void OnPointerDown(PointerEventData eventData)
{
Debug.Log("Mouse Down!");
}
public void OnPointerEnter(PointerEventData eventData)
{
Debug.Log("Mouse Enter!");
}
public void OnPointerUp(PointerEventData eventData)
{
Debug.Log("Mouse Up!");
}
public void OnPointerExit(PointerEventData eventData)
{
Debug.Log("Mouse Exit!");
}
//Add Event System to the Camera
void addEventSystem()
{
GameObject eventSystem = null;
GameObject tempObj = GameObject.Find("EventSystem");
if (tempObj == null)
{
eventSystem = new GameObject("EventSystem");
eventSystem.AddComponent<EventSystem>();
eventSystem.AddComponent<StandaloneInputModule>();
}
else
{
if ((tempObj.GetComponent<EventSystem>()) == null)
{
tempObj.AddComponent<EventSystem>();
}
if ((tempObj.GetComponent<StandaloneInputModule>()) == null)
{
tempObj.AddComponent<StandaloneInputModule>();
}
}
}
}
EDIT:
If this is a 3D GameObject/Mesh, then you need to add a simple collider to it. If it is just Sprite then you must add a 2D collider to the sprite.
Another approach that is even simpler, is to just add a BoxCollider2D component, then add the following methods to the a new componenent, say UIButton, where you will to perform the button actions :
void OnMouseOver()
void OnMouseDown()
void OnMouseUp()
This avoids the use of an EventSystem, StandaloneInputModule and Physics2DRaycaster.
Example :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class UIButton : MonoBehaviour {
public Sprite regular;
public Sprite mouseOver;
public Sprite mouseClicked;
public TextMeshPro buttonText;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
private void OnMouseDown()
{
}
private void OnMouseEnter()
{
}
private void OnMouseExit()
{
}
private void OnMouseUpAsButton()
{
}
}
Tested in unity 2018.1. One difference I initially noticed to this and the above approach is that the right mouse button click is not detected in this model, but is detected in the EventSystemModel.

Categories