I'm making a game using monogame and trying to use a controller manager to manage user input.
I've created a class ControllerManager to do this. Because I'm trying to take input from 2 controllers, I create three instances of ControllerManager: controllerManager, controller1Manager and controller2Manager.
Now, in my player object I have a local variable, localManager to which I need to assign to either controller1Manager or controller2Manager depending on which player it is.
I've been trying to assign it like:
this.localManager = Controller1Manager;
This results in the localManager variable being set to controllerManager.
So does anyone see what I'm doing wrong? I have no idea other than maybe it has something to do with pointers/references/singleton but I've checked the component list and each individual manager is in there.
Edit:
As requested, here are the constructor, class creation and where I'm trying to change values
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using GDApp;
namespace GDLibrary
{
public class ControllerManager : GameComponent, IService
{
public GamePadState newState, oldState;
public PlayerIndex player;
public ControllerManager(Main game, PlayerIndex index)
: base(game)
{
this.player = index;
}
public override void Update(GameTime gameTime)
{
oldState = newState;
newState = GamePad.GetState(player);
base.Update(gameTime);
}
public bool IsFirstButtonPress(Buttons button)
{
if (oldState.IsButtonUp(button) && newState.IsButtonDown(button))
return true;
return false;
}
public bool IsButtonDown(Buttons button)
{
return newState.IsButtonDown(button);
}
public bool IsButtonUp(Buttons button)
{
return newState.IsButtonUp(button);
}
#region Thumbsticks
//Right
//Magnitude of right stick in right direction
public float RightStickRight()
{
if (newState.ThumbSticks.Right.X <= 0)
return 0;
else
return newState.ThumbSticks.Right.X;
}
//Magnitude of right stick in left direction
public float RightStickLeft()
{
if (newState.ThumbSticks.Right.X >= 0)
return 0;
else
return System.Math.Abs(newState.ThumbSticks.Right.X);
}
//Magnitude of right stick in upward direction
public float RightStickUp()
{
if (newState.ThumbSticks.Right.Y >= 0)
return 0;
else
return System.Math.Abs(newState.ThumbSticks.Right.Y);
}
//Magnitude or right stick in downward direction
public float RightStickDown()
{
if (newState.ThumbSticks.Right.Y <= 0)
return 0;
else
return newState.ThumbSticks.Right.Y;
}
//Left
//Magnitude of left stick in right direction
public float LeftStickRight()
{
if (newState.ThumbSticks.Left.X <= 0)
return 0;
else
return newState.ThumbSticks.Left.X;
}
//Magnitude of left stick in left direction
public float LeftStickLeft()
{
if (newState.ThumbSticks.Left.X >= 0)
return 0;
else
return System.Math.Abs(newState.ThumbSticks.Left.X);
}
//Magnitude of left stick in upward direction
public float LeftStickUp()
{
if (newState.ThumbSticks.Left.Y >= 0)
return 0;
else
return System.Math.Abs(newState.ThumbSticks.Left.Y);
}
//Magnitude or right stick in downward direction
public float LeftStickDown()
{
if (newState.ThumbSticks.Left.Y <= 0)
return 0;
else
return newState.ThumbSticks.Left.Y;
}
#endregion
public bool RightStickCentered()
{
if (newState.ThumbSticks.Right.X.Equals(0) && newState.ThumbSticks.Right.Y.Equals(0))
{
return true;
}
return false;
}
public bool LeftStickCentered()
{
if (newState.ThumbSticks.Left.X.Equals(0) && newState.ThumbSticks.Left.Y.Equals(0))
{
return true;
}
return false;
}
public Vector2 RightStick()
{
return this.newState.ThumbSticks.Right;
}
public Vector2 LeftStick()
{
return this.newState.ThumbSticks.Left;
}
public bool LeftStickMoved()
{
if (!oldState.ThumbSticks.Left.X.Equals(newState.ThumbSticks.Left.X) || !oldState.ThumbSticks.Left.Y.Equals(newState.ThumbSticks.Left.Y))
{
return true;
}
return false;
}
public bool RightStickMoved()
{
if (!oldState.ThumbSticks.Right.X.Equals(newState.ThumbSticks.Right.X) || !oldState.ThumbSticks.Right.Y.Equals(newState.ThumbSticks.Right.Y))
{
return true;
}
return false;
}
}
}
Creating managers:
this.controller1Manager = new ControllerManager(this, PlayerIndex.One);
Components.Add(controller1Manager);
IServiceContainer.AddService(typeof(ControllerManager), controller1Manager);
this.controller2Manager = new ControllerManager(this, PlayerIndex.Two);
Components.Add(controller2Manager);
IServiceContainer.AddService(typeof(ControllerManager), controller2Manager);
Changing values:
if (this.index.Equals(PlayerIndex.One))
{
this.localManager = Controller1Manager;
}
else if (this.index.Equals(PlayerIndex.Two))
{
this.localManager = Controller2Manager;
Controller2Manager.player = index;
}
This issue has been resolved by passing a ControllerManager into the PlayerObject in place of a PlayerIndex. The reason all of the controllerManagers seemed to have their variables changed at once was their inclusion in the IServiceContainer shown in the edits above. IServiceContainer stores only one instance of a given type (It's a Dictionary) so only the most recent addition was being saved.
Related
I don't know what else to do. I've done everything from disabling the character controller, then changing the position, then re-enabling the character controller. I have Auto Sync Transforms turned on. I've tried changing transform.position, I've tried changing the character controller position, I've tried everything and nothing works. I'm at my wits end here just trying to move my character from one point to another. Why is this the hardest thing I've done?
The code instantiates my characters correctly when it wants to. Sometimes they spawn off the map or in some random position way off from my spawn point.
public string spawnPointName;
public GameObject malePlayerSystems;
public GameObject femalePlayerSystems;
public GameObject playerInScene;
public Transform spawnPoint;
private Transform playerObject;
public Vector3 spawnPointPosition;
public bool inGame = false;
public bool maleKnight = false;
public bool femaleKnight = false;
public bool spawnRunning;
public bool moveRunning;
public IEnumerator SpawnPlayer()
{
spawnRunning = true;
yield return new WaitForSecondsRealtime(0.5f);
if (spawnRunning)
{
spawnPoint = GameObject.Find(spawnPointName).transform;
//playerInScene = GameObject.FindGameObjectWithTag("Gameplay Systems");
if (playerInScene != null)
{
spawnRunning = false;
yield return null;
}
else
{
if (maleKnight && !femaleKnight)
{
Instantiate(malePlayerSystems, spawnPoint.position, Quaternion.identity);
playerInScene = malePlayerSystems;
playerObject = malePlayerSystems.transform.Find("Player1/Player Base");
playerObjectCC = playerObject.GetComponent<CharacterController>();
}
if (femaleKnight && !maleKnight)
{
Instantiate(femalePlayerSystems, spawnPoint.position, Quaternion.identity);
playerInScene = femalePlayerSystems;
playerObject = femalePlayerSystems.transform.Find("Player1/Player Base");
playerObjectCC = playerObject.GetComponent<CharacterController>();
}
if (maleKnight && femaleKnight)
{
Debug.LogError("Error: Both gender switches active. Choose one gender to play as.");
}
}
spawnRunning = false;
}
}
public void DestroyPlayer()
{
playerInScene = GameObject.FindGameObjectWithTag("Gameplay Systems");
if (playerInScene != null)
{
Destroy(playerInScene);
} else
{
Debug.LogError("Error: Cannot find player to delete");
}
}
public IEnumerator movePlayer(){
moveRunning = true;
yield return new WaitForSecondsRealtime(0.5f);
if (moveRunning){
spawnPoint = GameObject.Find(spawnPointName).transform;
spawnPointPosition = spawnPoint.transform.position;
playerObjectCC.enabled = false;
Debug.Log("Disabled CC");
yield return new WaitForSecondsRealtime(0.5f);
playerObject.transform.position = new Vector3(spawnPointPosition.x, spawnPointPosition.y, spawnPointPosition.z);
Debug.Log("New Position is " + playerObject.transform.position);
yield return new WaitForSecondsRealtime(0.5f);
playerObjectCC.enabled = true;
Debug.Log("Re enabled CC");
}
moveRunning = false;
}
I have this issue with double clicking in-game. I wrote this code that checks for input and returns the type of input it received.
In editor it works just fine, but when I export the game it always returns double click type. Even if I click just once. Not sure what's causing this issue..
Below is the mouse input script and other is how I use it in other scripts.
Mouse Input script:
using System.Collections;
using UnityEngine.EventSystems;
public class MouseInput : MonoBehaviour
{
#region Variables
private enum ClickType { None, Single, Double }
private static ClickType currentClick = ClickType.None;
readonly float clickdelay = 0.25f;
#endregion
void OnEnable()
{
StartCoroutine(InputListener());
}
void OnDisable()
{
StopAllCoroutines();
}
public static bool SingleMouseClick()
{
if (currentClick == ClickType.Single)
{
currentClick = ClickType.None;
return true;
}
return false;
}
public static bool DoubleMouseClick()
{
if (currentClick == ClickType.Double)
{
currentClick = ClickType.None;
return true;
}
return false;
}
private IEnumerator InputListener()
{
while (enabled)
{
if (Input.GetMouseButtonDown(0))
{ yield return ClickEvent(); }
yield return null;
}
}
private IEnumerator ClickEvent()
{
if (EventSystem.current.IsPointerOverGameObject()) yield break;
yield return new WaitForEndOfFrame();
currentClick = ClickType.Single;
float count = 0f;
while (count < clickdelay)
{
if (Input.GetMouseButtonDown(0))
{
currentClick = ClickType.Double;
yield break;
}
count += Time.deltaTime;
yield return null;
}
}
}
Usage:
if (MouseInput.SingleMouseClick())
{
Debug.Log("Single click");
Select(true);
}
else if (MouseInput.DoubleMouseClick())
{
Debug.Log("Double click");
Select(false);
}
So on the frame Input.GetMouseButtonDown(0) evaluates to true you call into ClickEvent() which then yields on WaitForEndOfFrame(); then eventually gets back to another Input.GetMouseButtonDown(0)).
You problem is that WaitForEndOfFrame() waits until the end of the current frame:
Waits until the end of the frame after all cameras and GUI is
rendered, just before displaying the frame on screen.
It doesn't wait until the next frame. Because of this, all values returned by the Input API are still going to be the same. You want a yield return null instead of WaitForEndOfFrame().
What I have
Scenario where a sphere moves towards a cube. There are multiple cubes. I want it to go to 1 cube that is within sight, and when it reached the cube, I want it to search for the next one. I know this should be easy but I've tried to fix this for several hours.
Code
WithinSight.cs
using UnityEngine;
using BehaviorDesigner.Runtime;
using BehaviorDesigner.Runtime.Tasks;
public class WithinSight : Conditional {
public float fieldOfViewAngle;
public string targetTag;
public SharedTransform target;
private Transform[] possibleTargets;
public override void OnAwake() {
var targets = GameObject.FindGameObjectsWithTag (targetTag);
possibleTargets = new Transform[targets.Length];
for (int i = 0; i < targets.Length; ++i) {
possibleTargets [i] = targets [i].transform;
}
}
public override TaskStatus OnUpdate() {
for (int i = 0; i < possibleTargets.Length; ++i) {
if (withinSight(possibleTargets [i], fieldOfViewAngle)) {
target.Value = possibleTargets [i];
return TaskStatus.Success;
gameObject.tag = "Untagged";
}
}
return TaskStatus.Failure;
}
public bool withinSight(Transform targetTransform, float fieldOfViewAngle) {
Vector3 direction = targetTransform.position - transform.position;
return Vector3.Angle(direction, transform.forward) < fieldOfViewAngle;
}
}
MoveTowards.cs
using UnityEngine;
using BehaviorDesigner.Runtime;
using BehaviorDesigner.Runtime.Tasks;
public class MoveTowards : Action {
public float speed = 0;
public SharedTransform target;
private bool pietje;
void PrintMessage (string message) {
Debug.Log(message);
}
void Start() {
pietje = false;
}
public override TaskStatus OnUpdate() {
if (Vector3.SqrMagnitude (transform.position - target.Value.position) < 0.1f && !pietje) {
PrintMessage ("Found the cube.");
pietje = true;
if (pietje) {
PrintMessage ("Searching...");
pietje = false;
}
return TaskStatus.Success;
}
transform.position = Vector3.MoveTowards (transform.position, target.Value.position, speed * Time.deltaTime);
transform.LookAt (target.Value.position);
return TaskStatus.Running;
}
}
Anyone that can help me will get a virtual cookie! (hmmm...)
I think the error is OnUpdate() in WithinSight class. When you do the return it never does this gameObject.tag = "Untagged";
Change the order of the lines like this.
public override TaskStatus OnUpdate() {
for (int i = 0; i < possibleTargets.Length; ++i) {
if (withinSight(possibleTargets [i], fieldOfViewAngle)) {
target.Value = possibleTargets [i];
gameObject.tag = "Untagged";
return TaskStatus.Success;
}
}
return TaskStatus.Failure;
}
I can't reproduce this scenario, but this code won´t go back to a previuos cube. In case you want that you should save a reference of the last cube the sphere moved towards and do the comparisons in OnUpdate() of WithinSight.
Just want to know if the get property code in this script(on the end) is a shorthand code, which says, if the shootCooldown is less than or equal to 0 then return true?
if it is, then is this another way of writing an if condition?For me, the code seems to be returning a float value and not a boolean.
the whole code is posted below:
public class WeaponScript : MonoBehaviour
{
public Transform shotPrefab;
public float shootingRate = 0.25f;
private float shootCooldown;
void Start()
{
shootCooldown = 0f;
}
void Update()
{
if (shootCooldown > 0)
{
shootCooldown -= Time.deltaTime;
}
}
public void Attack(bool isEnemy)
{
if (CanAttack)
{
shootCooldown = shootingRate;
// Create a new shot
var shotTransform = Instantiate(shotPrefab) as Transform;
// Assign position
shotTransform.position = transform.position;
// The is enemy property
ShotScript shot = shotTransform.gameObject.GetComponent<ShotScript>();
if (shot != null)
{
shot.isEnemyShot = isEnemy;
}
// Make the weapon shot always towards it
MoveScript move = shotTransform.gameObject.GetComponent<MoveScript>();
if (move != null)
{
move.direction = this.transform.right; // towards in 2D space is the right of the sprite
}
}
}
public bool CanAttack
{
get
{
return shootCooldown <= 0f;
}
}
}
The code of the property does not return the value of
shootCooldown
But the result of the expression
shootCooldown <= 0f;
which is resolved to boolean.
It is equivalent to writing
if (shootCooldown <= 0f)
{
return true;
}
else
{
return false;
}
I've finally found a script that can be used with a GUI Button in an IOS project. I am using Unity3d game engine. I'm a little familiar with JavaScript buttons and animation but am not familiar at all with C#. My problem is not knowing were to write the function that will play a queued animation in the C# button script when the button is touched. Below is copy of the IOS Button Script and then the code I have to play the queued animation.
using UnityEngine;
using System.Collections;
public enum Btn
{
normal,
hover,
armed
}
[System.Serializable] // Required so it shows up in the inspector
public class ButtonTextures
{
public Texture normal=null;
public Texture hover=null;
public Texture armed=null;
public ButtonTextures() {}
public Texture this [ButtonState state]
{
get
{
switch(state)
{
case ButtonState.normal:
return normal;
case ButtonState.hover:
return hover;
case ButtonState.armed:
return armed;
default:
return null;
}
}
}
}
[RequireComponent(typeof(GUITexture))]
[AddComponentMenu ("GUI/Button")]
public class GuiButton : MonoBehaviour
{
public GameObject messagee;
public string message = "";
public string messageDoubleClick = "";
public ButtonTextures textures;
protected int state = 0;
protected GUITexture myGUITexture;
private int clickCount = 1;
private float lastClickTime = 0.0f;
static private float doubleClickSensitivity = 0.5f;
protected virtual void SetButtonTexture(ButtonState state)
{
if (textures[state] != null)
{
myGUITexture.texture = textures[state];
}
}
public virtual void Reset()
{
messagee = gameObject;
message = "";
messageDoubleClick = "";
}
public bool HitTest(Vector2 pos)
{
return myGUITexture.HitTest(new Vector3(pos.x, pos.y, 0));
}
public virtual void Start()
{
myGUITexture = GetComponent(typeof(GUITexture)) as GUITexture;
SetButtonTexture(ButtonState.normal);
}
public virtual void OnMouseEnter()
{
state++;
if (state == 1)
SetButtonTexture(ButtonState.hover);
}
public virtual void OnMouseDown()
{
state++;
if (state == 2)
SetButtonTexture(ButtonState.armed);
}
public virtual void OnMouseUp()
{
if (Time.time - lastClickTime <= doubleClickSensitivity)
{
++clickCount;
}
else
{
clickCount = 1;
}
if (state == 2)
{
state--;
if (clickCount == 1)
{
if (messagee != null && message != "")
{
messagee.SendMessage(message, this);
}
}
else
{
if (messagee != null && messageDoubleClick != "")
{
messagee.SendMessage(messageDoubleClick, this);
}
}
}
else
{
state --;
if (state < 0)
state = 0;
}
SetButtonTexture(ButtonState.normal);
lastClickTime = Time.time;
}
public virtual void OnMouseExit()
{
if (state > 0)
state--;
if (state == 0)
SetButtonTexture(ButtonState.normal);
}
#if (UNITY_IPHONE || UNITY_ANDROID)
void Update()
{
int count = Input.touchCount;
for (int i = 0; i < count; i++)
{
Touch touch = Input.GetTouch(i);
if (HitTest(touch.position))
{
if (touch.phase == TouchPhase.Ended || touch.phase == TouchPhase.Canceled)
{
SetButtonTexture(ButtonState.normal);
}
else
{
SetButtonTexture(ButtonState.armed);
}
if (touch.phase == TouchPhase.Began)
{
if (touch.tapCount == 1)
{
if (messagee != null && message != "")
{
messagee.SendMessage(message, this);
}
}
else if (touch.tapCount == 2)
{
if (messagee != null && messageDoubleClick != "")
{
messagee.SendMessage(messageDoubleClick, this);
}
}
}
break;
}
}
}
#endif
}
Most of this seems to deal with button states, where my touch button only has one state, which is 'normal'. Should references to 'hover' and armed just be deleted? I also get an error in the console saying; "the type or namespace "Button State" could not be found. Are you missing a using directive or an assembly reference?"
The code for C# GUI Button play queued animation I want to insert reads like this:
using UnityEngine;
using System.Collections;
public class example : MonoBehaviour {
void Update() {
if (Input.GetButtonDown("Btn"))
animation.PlayQueued("shoot", QueueMode.PlayNow);
}
}
I suppose of queued animation script snippet; Input.GetButtondown....would change to
void Update() {
if(Input.GetTouch("Btn"))
animation.PlayQueued("shoot", QueueMode.PlayNow);
}
and be inserted at about line 148 of the GUI Button script. Please help me if you can, I'm
feeling down. Seriously! Any help in reformatting this script would be greatly appreciated
and used as a template as I have two other GUI buttons to setup. It maybe asking a lot or what's a heaven for?
Respectfully,
Digital D
an analog man,
in a digital world
Okay, there's a lot going on in the script, but it appears to be designed so you don't have to modify it.
What you need to do is go to the object that will be playing the animation, and create a function on it that you wish to be called when the button is clicked.
So something like (you can do this in JS if you like):
public class ShootyMan : MonoBehaviour {
public void Shoot() {
animation.PlayQueued("shoot", QueueMode.PlayNow);
}
}
Now, look at the button in the inspector. I'm not sure if you're familiar with how messaging works in Unity, but basically the button will send a "message" to a "messagee". (ie. it will call a function of name message on any script attached to the messagee).
Set the "messagee" to the GameObject with the "Shoot" function. And set the message to the string "Shoot".