Retrieving Multitouch Data in XNA - c#

I am having a problem retrieving touch input on my XNA game. Here is my starting code:
TouchCollection touchPositions;
List<Vector2> touchReleases = new List<Vector2>();
Then this is my update code:
protected override void Update(GameTime gameTime)
{
// Other update logic here
touchReleases.Clear();
foreach (TouchLocation tl in touchPositions)
{
if (tl.State == TouchLocationState.Released)
touchReleases.Add(tl.Position);
}
base.Update(gameTime);
}
The idea is to load all of the releases into a Vector2 list. Then (during the draw code) a function checks for a release to do stuff.
EDIT: I tested this using Guide.BeginShowMessageBox() during the foreach loop. It popped up every time I released.
bool released = false;
foreach (TouchLocation tl in touchPositions)
{
// checks to see if the button is being hovered on
}
foreach (Vector2 tr in touchReleases)
{
if (PointInArea(tr, new Rectangle((int)position.X, (int)position.Y, buttonimage[0].Width, buttonimage[0].Height)))
{
released = true;
break;
}
}
return released;
The PointInArea function checks to see if a Vector2 is in a Rectangle. I know this function is working right.
What's funny is that the buttons respond to releases about once every 4 taps. Does anyone know why this is?

Related

How can I get my camera to momentarily pause between different positions when using lerp in Unity3D?

I have an array of positions that I want my camera to move/lerp between. There are two buttons (button A and button B) that trigger the camera to move position. If the user presses button A, the camera will lerp to the previous position in the array. If the user presses button B, the camera will lerp to the next position in the array. However, before moving to a new position, I want the camera to lerp to an intermediate position, pause there for a couple of seconds, and then move. Here is the pseudocode for what I have at the moment:
void Update()
{
if (buttonPress == a) {
positionToMoveTo = positions[currentPosition--];
}
if (buttonpress == b) {
positionToMoveTo = positions[currentPosition++];
}
}
void LateUpdate()
{
camera.lerp(intermediatePosition);
StartCoroutine(pause());
}
IEnumerator pause()
{
yield return new WaitForSeconds(3f);
camera.lerp(positionToMoveTo);
}
This doesn't work though because I get strange jittering when switching camera positions and my intermediate position doesn't always occur. I think my problem has something to do with execution order but I can't figure it out. Any help would be great :)
You start a new Coroutine every frame since LateUpdate runs every frame after all Update calls are finished!
You could avoid this by a slightly different approach:
private bool isIntermediate;
private bool moveCamera;
private void LateUpdate ()
{
if(!moveCamera) return;
if(isIntermediate)
{
camera.lerp(intermediatePosition);
}
else
{
camera.lerp(positionToMoveTo);
}
}
private IEnumerator MoveCamera()
{
moveCamera = true;
isIntermediate=true;
yield return new WaitForSeconds(3f);
isIntermediate=false;
// Wait until the camera reaches the target
while(camera.transform.position == PositionToMoveTo){
yield return null;
}
// Stop moving
moveCamera = false;
// just to be sure your camera has exact the correct position in the end
camera.transform.position = PositionToMoveTo;
}
Alternatively you could do all the movement in the Coroutine without LateUpdate (but honestly I'm not sure if the Coroutines are done before or after Update)
private IEnumerator MoveCamera()
{
float timer = 3f;
while(timer>0)
{
timer -= Time.deltaTime;
camera.lerp(intermediatePosition);
yield return null;
}
// Wait until the camera reaches the target
while(camera.transform.position == PositionToMoveTo){
camera.lerp(PositionToMoveTo);
yield return null;
}
// just to be sure your camera has exact the correct position in the end
camera.transform.position = PositionToMoveTo;
}
This second one would be cleaner bjt as said I don't know if it is a requirement for you to have it run in LateUpdate
Note: the == operator of Vector3 has a precision of 0.00001. If you need a better or weaker precision you have to change to
if(Vector3.Distance(camera.transform.position, PositionToMoveTo) <= YOUR_DESIRED_THRESHOLD)
Now all you have to do is to call your Coroutine Everytime you want to change the camera position.
void Update()
{
if (buttonPress == a)
{
// Make sure the Coroutine only is running once
StopCoroutine(MoveCamera);
positionToMoveTo = positions[currentPosition--];
StartCoroutine (MoveCamera);
}
if (buttonpress == b)
{
// Make sure the Coroutine only is running once
StopCoroutine (MoveCamera);
positionToMoveTo = positions[currentPosition++];
StartCoroutine (MoveCamera);
}
}

Monogame/C# - Check if collision was present in previous frame

I have a working collision system in place in my Monogame/C# project that uses a quadtree to determine potential collisions, and test them accordingly. My problem is that I want to be able to send out a method to the entity (that has been collided with), either OnCollisionEnter() or OnCollisionStay() depending on if the collision was present in the previous frame.
In the following code, OnCollisionEnter() is never called:
public class Collision : iSystem
{
private List<Entity> currentCollisions; // Collisions occurring in the current frame
private List<Entity> previousCollisions; // Collisions from the previous frame
public override void Initialize(Entity caller)
{
currentCollisions = new List<Entity>();
previousCollisions = new List<Entity>();
base.Initialize(caller);
hasInitialized = true;
}
public override void Update(GameTime gameTime)
{
List<Entity> nearby = Global.QuadTree.GetNeighbours(parent);
for (int i = 0; i < nearby.Count; i++)
{
if (nearby[i] != parent)
if (parent.Collider.Intersects(nearby[i].Collider))
{
currentCollisions.Add(nearby[i]);
AlertEntity(nearby[i]);
}
}
previousCollisions = currentCollisions; // Ready for the next frame
currentCollisions.Clear();
base.Update(gameTime);
}
public void AlertEntity(Entity entity)
{
if (previousCollisions.Contains(entity))
parent.OnCollisionStay(entity.Collider);
else
parent.OnCollisionEnter(entity.Collider); // This is never called
}
}
('parent' refers to the entity that the component 'Collision' is attached to)
If you could suggest why this is happening, I'd be grateful. Thanks
Calling currentCollisions.Clear() will also clear previousCollisions because they are both referencing the same List object. Instead of calling currentCollisions.Clear(), you should set it to a new List<Entity>().
// . . .
previousCollisions = currentCollisions; // Ready for the next frame
currentCollisions = new List<Entity>(); // Now both lists are not clear
base.Update(gameTime);

XNA Point Counter

I am making a game where a player runs around collecting Kiwis. I want the point counter to increment by only one each time. What I have so far is that the pointer increments, but keeps incrementing. i.e. when the player touches a kiwi the counter keeps on increasing by 1.
Here is the Intersect method:
public void Intersect(Rectangle playerRect, SpriteBatch spriteBatch)
{
foreach (Rectangle kiwiRect in kiwiRectangle.Except(collectedKiwis))
{
if (kiwiRect.Intersects(playerRect))
{
collectedKiwis.Add(kiwiRect);
isCollected = true;
}
else
{
spriteBatch.Draw(kiwiTexture, kiwiRect, Color.White);
}
}
}
And here are the Update and Draw methods:
public void Update()
{
points = "Points: " + counter;
if (isCollected)
{
counter++;
}
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.DrawString(pointCounter, points, new Vector2(500, 10), Color.Red);
}
Well, you should check for 2 conditions at least:
If player is currently intersected with kiwi
If that kiwi hasn't already been collected (isCollected prop i suppose)
So if you are intersected and kiwi isn't yet collected, you set isCollected flag and increase counter. On the next Update() run you will skip that kiwi (if you haven't deleted it yet or want to perform some animation) as you've already set isCollected flag, like:
if (Intersect(...) && !isCollected)
{
counter++;
isCollected=true;
}
Though this approach answers your question, i advice you to think about the whole game logic you will want to implement, for ex. how are all of the kiwis will be managed and how to check only active kiwis for intersection to improve performance :)

Mouse Click on XNA

I am trying to update my player by mouse click. I have tried different actions on player to update such as free drag. They work. But mouse click does not work. Can anybody help me?
For more detail, my player class holds animation texture and its position. I am trying to change another texture to current one.
It works. I mean: when I drag the player its animation changes. It means my class functionality has no problem. But when I try the same thing with mouse click, it does not work.
//initialize method
player.Initialize(player1, player1.Position);
//update method
protected override void Update(GameTime gameTime)
{
currentMouseState = Mouse.GetState();
UpdatePlayer(gameTime);
_bgLayer1.Update(gameTime);
_bgLayer2.Update(gameTime);
base.Update(gameTime);
}
//update player method
void UpdatePlayer(GameTime gameTime)
{
player.Update(gameTime);
// Touch inputs
while (TouchPanel.IsGestureAvailable)
{
GestureSample gesture = TouchPanel.ReadGesture();
if (gesture.GestureType == GestureType.FreeDrag)
player.Position += gesture.Delta;
player.PlayerAnimation = player2;
}
// Get Mouse State
if (previousMouseState.LeftButton == ButtonState.Released && currentMouseState.LeftButton == ButtonState.Pressed)
{
player.PlayerAnimation = player2;
}
previousMouseState = currentMouseState;
}

XNA for WP7 and multitouch update every frame

I'm having trouble with touch/multitouch input.
I want to draw a small rectangle, 100x100 in dimensions, wherever the user presses (mission accomplished) but I also want them to move as the user moves his fingers (that's not happening atm).
I'm also getting weird behaviour besides the not-moving part, let's say I touch first with my thumb, then with my middle finger. Two cubes appear bellow each finger, but if I remove the finger I place first (thumb in this scenario) the cube under the finger I placed second (middle finger) will disappear and the one where my thumb was will still be there. I guess this issue will solve itself once I get this to update correctly whenever there is movement.
This are the Draw and Update snippets. Any help appreciated:
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
TouchCollection touchLocations = TouchPanel.GetState();
i = 0;
foreach (TouchLocation touchLocation in touchLocations)
{
if (touchLocation.State == TouchLocationState.Pressed)
{
pos[i] = touchLocation.Position;
}
i++;
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
for (j = 0; j < i; j++)
{
spriteBatch.Draw(whiteRectangle, new Rectangle(((int)pos[j].X - 50), ((int)pos[j].Y - 50), 100, 100), Color.Chocolate);
}
spriteBatch.End();
base.Draw(gameTime);
}
I would recommend using a Dictionary assuming you want to associate touch locations to their position. The key should be the TouchLocation.Id
TouchLocation.Id will remain the same for a given interaction. There is no guarantee that the order of TouchLocations will be the same from one frame to another, so you have to use their ID and not the order they appear in the collection.
I'm a bit late on this, but well here is what was wrong and how I solve it...
foreach (TouchLocation touchLocation in touchLocations)
{
if (touchLocation.State == TouchLocationState.Pressed)
{
pos[i] = touchLocation.Position;
}
i++;
}
I guess I was sleepy when I wrote this part of the code (nothing good happens after 2 AM... not even good code) I don't know why I was checking if the location state was pressed... that's why it didn't move when I move... first frame it is indeed pressed but once you start moving it it's .Moved ... all in all, removed that if and it works like a charm...
foreach (TouchLocation touchLocation in touchLocations)
{
pos[i] = touchLocation.Position;
i++;
}
All in all now it behaves as intended.
Cheers!

Categories

Resources