I am trying to implement a press and release button functionality and am getting a non-working result that I can't figure out why.
public class Button
{
public TouchLocation oldTouch, currentTouch;
public virtual void Update(GameTime gameTime)
{
TouchCollection touchCollection = TouchPanel.GetState ();
if (touchCollection.Count > 0) {
currentTouch = touchCollection [0];
if (currentTouch.Position.X > position.X && currentTouch.Position.X < position.X + width &&
currentTouch.Position.Y > position.Y && currentTouch.Position.Y < position.Y + height) {
if (currentTouch.State == TouchLocationState.Released && oldTouch.State == TouchLocationState.Pressed) {
buttonEvent.Invoke (this, new EventArgs ());
}
}
}
oldTouch = currentTouch;
}
}
First of all when I assign the below object:
currentTouch = touchCollection [0];
I get
"Incorrect number of types or arguments"
in red as the value in the locals debug window (no error, just red texted value).
It still however correctly passes through the position checking IF statement but it does not pass the Pressed/Release IF statement. If I replace currentTouch with touchCollection[0] then everything works as expected.
Am I using/assigning the TouchLocation object incorrectly?
Or am I maybe just overlooking an easy mistake?
I always use something like touchCollection.Last() or touchCollection.First() to get only one component of TouchCollection. Anyway I don't see any error in what you are doing there.
For your problem, I think you can't do only
oldTouch.State == TouchLocationState.Pressed
but you have to check:
oldTouch.State == TouchLocationState.Pressed || oldTouch.State == TouchLocationState.Moved
because you don't know how the last touch was detected by XNA.
And as a suggestion, why don't you use Rectangles for your button's collider? In this way you can simply call:
Rectangle.Contains(new Point(int)currentTouch.Position.X, (int)currentTouch.Position.Y))
instead of doing that if statement.
Related
I am working on a city builder game and trying to create a crop growing system. This issue is with 2 different scripts, a placement manager and a farm timer. The placement manager class detects mousedown events and will setTile to my farm tilemap based off of the click location and the selected tile. The farm timer class contains a method which is called when a farm tile is set in the placement manager which then starts the timer using the update method to countdown from 60.
3 if statements check for 45, 30, and 15 seconds and calls another method in the placement manager which will set the tile to its respective growth stage tile. This works when only placing a single crop, but when there are multiple it starts the timer over with whichever tile was placed last.
I am guessing I need to find a way to create new instances of the class but I am also wondering if there would be a better way???
PlacementManager.cs
public void Update()
{
if (Input.GetMouseButtonDown(0) && isIndexSet)
{
Vector3 pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Location = farmGround.WorldToCell(pos);
Location.z = 0;
//6 is a carrot crop
if(curIndex == 6 && isSpaceOpen())
{
PlacePlant();
CurrencyManager.Instance.currency -= 1;
//FarmTimer.instance.PlantPlaced("Carrot", Location);
timer.PlantPlaced("Carrot", Location);
}
if(curIndex < 6 && isSpaceOpen())
{
PlaceBuilding();
CurrencyManager.Instance.currency -= 5;
}
}
}
public void ChangePlantTile(int index, Vector3Int selectedLocation)
{
farmPlants.SetTile(selectedLocation, plants[index]);
}
FarmTimer.cs
private string carrotChk1 = "Farm_36 (UnityEngine.Tilemaps.Tile)";
private string carrotChk2 = "Farm_35 (UnityEngine.Tilemaps.Tile)";
private string carrotChk3 = "Farm_34 (UnityEngine.Tilemaps.Tile)";
private int curIndex;
private bool isIndexSet = false;
public Tile[] tiles;
public Tile[] plants;
void Update()
{
if (isTimerActive == true)
{
if(plant == "Carrot")
{
CarrotTimer();
}
}
}
public void CarrotTimer()
{
if (m_time < 45f && m_time > 30f
&& FarmMap.GetTile(selectedLocation).ToString() != carrotChk1)
{
curIndex = 0;
PlacementManager.Instance.ChangePlantTile(curIndex, selectedLocation);
curIndex++;
}
else if (m_time < 15f && m_time > 1
&& FarmMap.GetTile(selectedLocation).ToString() != carrotChk2)
{
PlacementManager.Instance.ChangePlantTile(curIndex, selectedLocation);
curIndex++;
}
else if (m_time < 1f
&& FarmMap.GetTile(selectedLocation).ToString() != carrotChk3)
{
PlacementManager.Instance.ChangePlantTile(curIndex, selectedLocation);
curIndex = 0;
isTimerActive = false;
}
}
For Testing purposes I am checking for the index of the carrot crop but I have 5 other crops which I plan to create the same functionality with.
Since i can't comment... i will write here directly. If you don't like the answer just comment it i will delete it.
I think the only way you can do this is either:
create a class and store yout imer there.
create a scriptable object
maybe use some sort of 2D list in your farmTimer class. This List could contain a reference to the cell you planted, and an int variable to store the timer of this cell.
maybe you can use an interface.
I never used the 3rd method in unity.
For me the best option is either 1 or 2. The class would be easier to manage.
I hope it answer your question, have a great day !
I'm no coder so I've spent a few days trying to figure out a way to stop the current slider from being dragged, but I can't figure out the syntax to get this to work.
I assume ExecuteEvents is what I'm looking for but I don't know how to.
void OnSceneGUI()
{
if (Event.current.type == EventType.MouseDown && Event.current.button == 1 && cancel)
{
cancel = false;
ExecuteEvents.Execute<IPointerUpHandler>(PointerEventData.pointerCurrentRaycast.gameObject, new PointerEventData(EventSystem.current), ExecuteEvents.pointerUpHandler);
slider = 0;
}
}
I am trying to get the slider with PointerEventData.pointerCurrentRaycast.gameObject
but it causes the following error,
An object reference is required for the non-static field, method, or
property 'PointerEventData.pointerCurrentRaycast'and I don't know
why. I am usingUnityEngine.EventSystems.
I'm also not sure if this is the right approach so. I don't mind some pointers.
Well because pointerCurrentRaycast is not a static member. It belongs to a specific instance of this type and you will need that instance's reference in order to access that value.
Don't know if this solves what you actually are trying to do but you probably can create your own PointerEventData instance at your mouse position and use a Raycast to get the object you are hovering. Something like
void OnSceneGUI()
{
if (Event.current.type == EventType.MouseDown && Event.current.button == 1 && cancel)
{
cancel = false;
var pointer = new PointerEventData(EventSystem.current);
pointer.position = Input.mousePosition;
List<RaycastResult> raycastResults = new List<RaycastResult>();
EventSystem.current.RaycastAll(pointer, raycastResults);
if(raycastResults.Count > 0)
{
var obj = raycastResults[0].gameObject;
ExecuteEvents.Execute<IPointerUpHandler>(obj, pointer, ExecuteEvents.pointerUpHandler);
slider = 0;
}
}
}
I was making a chess game, and all is well except that for example, a pawn, shows a move marker on a piece in front of it (pawns cant move like that). The game won't let you move there, since the move marker code is separate from the actual move code and check.
I have already tried many different approaches, such as iterating through every piece and checking if each piece is in front of the selected piece, as well as making sure that each piece iterated through is not the selected piece.
if (pieceSelected && !finishedPlacingMoveMarkers)
{
if (selectedPiece.GetComponent<BlackPawn>())
{
if (selectedPiece.transform.position.y + 1 <= 3.5)
{
foreach (Transform child in pieces.transform)
{
if (child.tag == "Piece")
{
if (obj.position == new Vector3(selectedPiece.transform.position.x, selectedPiece.transform.position.y + 1) && child.position != selectedPiece.transform.position)
{
if (child.position == new Vector3(selectedPiece.transform.position.x, selectedPiece.transform.position.y + 1))
{
noMoveHighlight = true;
break;
}
else
{
noMoveHighlight = false;
}
}
}
}
if (!noMoveHighlight)
{
GameObject move1 = Instantiate(tileMoveHighlight);
move1.transform.parent = moveTileHighlights.transform;
move1.transform.position = new Vector3(selectedPiece.transform.position.x, selectedPiece.transform.position.y + 1, -0.9f);
}
}
finishedPlacingMoveMarkers = true;
}
}
I expect the results to look like this when i select the pawn:
But they look like this:
Please help!
(Before you read, I'm very nervous about posting here since my previous question got a lot of negative responses... Please try and be nice. I am a student and can't write "Perfect" code yet)
I'm currently trying to figure out how to make a mosquito (Texture2D) swoop downwards and then come back up to it's original position.
Currently the mosquitoes simply move left and right within the screen bounds, with no Y movement.
I've stepped it through a debugger and observed it's Y coordinate. My mosquitoes are indeed swooping down and then back upwards again... However, they do it so quickly that it isn't visible to the human eye.
Therefore I need a way to smoothly swoop them down so that it's actually visible.
I am currently unable to embed images into my posts, however I have made a GIF demonstrating the effect that I want.
Here's a link to my GIF
Things I've tried:
Copied the first line of my movement code (seen below) and changed it so that it would only affect the Y coordinates.
Result: Mosquitoes were still swooping too fast to see.
Changing my mosquitoe's velocity.Y to include a Y that isn't 0, so that my movement code will also change the Y position instead of just the X position.
Result: Game was stuck in an infinite loop since my movement code is found in the Update() function, and the code never got out of the loop so that it could update the position...
Here's the movement code I have in my Update.
The mosquitoes move all the way to the right, then all the way to the left.
internal void Update(GameTime GameTime)
{
position += velocity * (float)GameTime.ElapsedGameTime.TotalSeconds;
// Reverses the direction of the mosquito if it hits the bounds
if (position.X <= gameBoundingBox.Left ||
position.X + animationSequence.CelWidth > gameBoundingBox.Right)
{
velocity.X *= -1;
}
}
And here's the actual Swoop() code that I have...
internal void Swoop(GameTime gameTime)
{
float originalYPosition = position.Y;
bool currentlySwooping = true;
while (currentlySwooping)
{
position.Y++;
if (this.BoundingBox.Bottom >= gameBoundingBox.Bottom)
{
currentlySwooping = false;
}
}
while (!currentlySwooping && position.Y > originalYPosition)
{
position.Y--;
}
}
I don't ask questions on here too often, so I'm sorry if I'm using an incorrect format or if I've given too little information.
If you need to know anything else then please let me know.
There are many ways of implementing this, but this should do it.
float originalYPosition = position.Y;
int swoopDirection = 0;
internal void Update(GameTime GameTime)
{
/* Same update code */
if (swoopDirection != 0)
{
position.Y += swoopDirection;
if (swoopDirection == 1 && this.BoundingBox.Bottom >= gameBoundingBox.Bottom)
{
swoopDirection = -1;
}
else if (swoopDirection == -1 && position.Y <= originalYPosition)
{
swoopDirection = 0;
}
}
}
internal void Swoop()
{
swoopDirection = 1;
}
Basically, we have a variable swoopDirection that changes depending on the state of the swoop (1 when going down and -1 when going up). In the update method we check that swoopDirection != 0 (we are swooping). If we are swooping we add the direction to the Y axis and check that we aren't out of bounds. If we touch the bottom we set swoopDirection to -1 so we go up. If we are at the original position swoopDirection is set to 0 and we stop swooping.
I have the following function to manage the reloading process of my player's gun in my game. I call the function from an AmmoCheck function and it runs, however the if statement is never run because the input doesn't get detected. The line:
Debug.Log("Reload function check");
will print to the console, but nothing further.
I have made sure the Input is set up under Edit>Project Settings>Input, and it is set to the r button. (Proof - http://i.imgur.com/u2aVNpU.png )
The function:
void gunReload()
{
Debug.Log("Reload function check");
if (Input.GetButtonDown("Reload")) {
Debug.Log("Reloading");
if(changeWeapon.currentGun == changeWeapon.gunPistol) {
aReload.SetActive(false);
// Incrementing the aClipPistolCurrent value by 1 so the current clip "should" progress one along? idk
aClipPistolCurrent += 1;
}
if(changeWeapon.currentGun == changeWeapon.gunAssault) {
aReload.SetActive(false);
// Incrementing the aClipPistolCurrent value by 1 so the current clip "should" progress one along? idk
aClipAssaultCurrent += 1;
}
}
}
Function calling gunReload();
gunAmmoCheck() is being called inside of Update()
void gunAmmoCheck()
{
if(changeWeapon.currentGun == changeWeapon.gunPistol && aClipPistol[aClipPistolCurrent] > 0) {
gunFire ();
// Reducing the ammo of the current clip by 1.
// ClipPistol is being used (say array, why array
aClipPistol[aClipPistolCurrent] -= 1;
}
if(changeWeapon.currentGun == changeWeapon.gunAssault && aClipAssault[aClipAssaultCurrent] > 0) {
gunFire ();
// Reducing the ammo of the current clip by 1.
// ClipPistol is being used (say array, why array
aClipAssault[aClipAssaultCurrent] -= 1;
}
if(aClipPistol[aClipPistolCurrent] == 0)
{
Debug.Log ("Reload");
// Activating the reload notification on the interface
aReload.SetActive(true);
gunReload();
}
if(aClipAssault[aClipAssaultCurrent] == 0)
{
Debug.Log ("Reload");
// Activating the reload notification on the interface
aReload.SetActive(true);
noAmmo = true;
gunReload();
}
}
I'm at a loss here, since all of my other inputs work flawlessly. Any help would be greatly appreciated.
I just tested this and it worked. I am starting to think that the problem is where you are calling the function from. Not sure yet but
Lets find the problem slowly. Can you comment out those things in your function and have only
void gunReload ()
{
//Debug.Log ("Reload function check");
if (Input.GetButtonDown ("Reload")) {
Debug.Log ("Reloading");
}
}
in your code. Then call gunReload () from the Update and tell me if it works.
It would also be good to pose the function you are calling gunReload () from.