How to process multiple touch swipes unity - c#

I am a fairly new programmer and after learning my c# basics i am trying to get into game development with Unity. Right now i am coding a small mobile game. I want to add an one screen multiplayer to it. I had an easy script set up which gathered the starting and ending position of the swipe and calculated the path between the two points. then it compared the absolute of Δx with the absolute of Δy and finally it testet whether the coordinate is below or above 0. this works quite nicely but obviously it would not work for my planned one screen multiplayer. first i tried just testing whether the starting point of a swipe is located to the left or right of the screen center. this also worked quite nicely but it could obviously not track two swipes at the same time. then i tried changing the variables to arrays and adding a for (later a foreach loop). now whenever i swipe in one direction it repeats the signal every frame even if i clear the slot in the array at the beginning of the loop... after literally one and a half days of trying stuff out and searching for answers i now came around to adding my own question. thank you in advance.
public class HopefullyWorkingSwipeDetector
{
Vector2[] av2_TouchPos1L = new Vector2[5];
Vector2[] av2_TouchPos2L = new Vector2[5];
Vector2[] av2_TouchPathL = new Vector2[5];
public int[] aint_TouchDirectionL = new int[5]; // Up: 0; Down: 1; Right: 2; Left: 3; n/a: 4;
public int int_SwipePendingL;
public int int_CountTouchesL = 0;
public void ListenForSwipeP1()
{
int_CountTouchesL = 0;
int_SwipePendingL = 0;
foreach (Touch touch in Input.touches)
{
if (Input.touchCount > 0 && Input.GetTouch(int_CountTouchesL).phase == TouchPhase.Began && Input.GetTouch(int_CountTouchesL).position.x < Screen.width / 2)
{
int_SwipePendingL = int_CountTouchesL;
av2_TouchPos1L[int_SwipePendingL] = Input.GetTouch(int_SwipePendingL).position;
}
else if (Input.touchCount > 0 && Input.GetTouch(int_SwipePendingL).phase == TouchPhase.Ended && Input.GetTouch(int_SwipePendingL).position.x < Screen.width / 2)
{
av2_TouchPos2L[int_SwipePendingL] = Input.GetTouch(int_SwipePendingL).position;
av2_TouchPathL[int_SwipePendingL] = av2_TouchPos2L[int_SwipePendingL] - av2_TouchPos1L[int_SwipePendingL];
if (Mathf.Abs(av2_TouchPathL[int_SwipePendingL].x) < Mathf.Abs(av2_TouchPathL[int_SwipePendingL].y)) //Vertical
{
if (av2_TouchPathL[int_SwipePendingL].y > 0) //up
{
aint_TouchDirectionL[int_SwipePendingL] = 0;
}
else if (av2_TouchPathL[int_SwipePendingL].y < 0) //Down
{
aint_TouchDirectionL[int_SwipePendingL] = 1;
}
}
else if (Mathf.Abs(av2_TouchPathL[int_SwipePendingL].x) > Mathf.Abs(av2_TouchPathL[int_SwipePendingL].y)) //horizontal
{
if (av2_TouchPathL[int_SwipePendingL].x > 0) //Right
{
aint_TouchDirectionL[int_SwipePendingL] = 2;
}
else if (av2_TouchPathL[int_SwipePendingL].x < 0) //left
{
aint_TouchDirectionL[int_SwipePendingL] = 3;
}
}
}
else
{
aint_TouchDirectionL[int_CountTouchesL] = 4;
}
int_CountTouchesL++;
}
}
}

Related

Separation steering algorithm for separationg set of Rectangles

In few last days trying to implement TinyKeep's dungeon generation algorithm myself.
Link to TinyKeep's dungeon generation algorithm
I don't understand it perfectly by 100%, because of it here am I :)
Firstly I generated set of rooms in circle
Going for each room in set. Pick it and going with another for loop again in set to compare every room intersection.
If room intersects, I added force, in which I will be apply separation. After that nested loop ended, I move current room, from first loop, according to that force vector. And so on. It happening until every room is not overlapped with others.
Also I picked center(Middle) point of rects ( x+width/2f, y+height/2f) to calculate that force vector
If vector is normalized, then rooms tighly packed, but if no - rooms have much space between them...
I wanna just recreate and understand TinyKeep's algorithm, but results not the same...
Also I getting weird results, then tall/wide rooms or always going in corners, tall go upper-left corner of map, wide - bottom-right corner. And all sometimes have overall diagonal separate direction
// Main method
private void Separate()
{
do
{
for (int i = 0; i < rooms.Count; i++)
{
Vector2 force = Vector2.zero;
int overlapCounter = 0;
for (int j = 0; j < rooms.Count; j++)
{
if (i == j) continue;
if (!rooms[i].IsOverlapped(rooms[j])) continue;
force += rooms[j].Middle - rooms[i].Middle;
overlapCounter++;
}
if (overlapCounter == 0) continue;
force /= overlapCounter;
force.Normalize();
force *= -1f;
rooms[i].Move(force);
}
} while (IsAnyRoomOverlapped());
StopTimer(true);
}
// Room.Move()
public void Move(Vector2 move)
{
x += Mathf.CeilToInt(move.x)* TILE_SIZE;
y += Mathf.CeilToInt(move.y)* TILE_SIZE;
}
// Constructor
public Dungeon(int roomAmount, int seed,float radius)
{
StartTimer();
this.roomAmount = roomAmount;
this.radius = radius;
Seed = seed;
InitializeRandom();
PopulateDungeonWithRooms();
}
While trying to figure out how solve this problem I read some questions and look their source code. I find that they not only move room after every overlapped neighbour found but also move neighbour in other direction!
What about directional behaviour of separation? It's my mistake or misunderstanding of rounding to integer
What about perfomance? Generating 512 rooms inside circle with radius of 128 units using normal distribution give 1100 ms
Now, code looks like:
private void SeparateRooms()
{
do
{
for (int current = 0; current < rooms.Count; current++)
{
for (int other = 0; other < rooms.Count; other++)
{
if (current == other || !rooms[current].IsOverlapping(rooms[other])) continue;
var direction = (rooms[other].Middle - rooms[current].Middle).normalized;
rooms[current].Move(-direction, TILE_SIZE);
rooms[other].Move(direction, TILE_SIZE);
}
}
}
while (IsAnyRoomOverlapped());
StopTimer(true);
}
And Room's Move() method:
public void Move(Vector2 move,int tileSize=1)
{
x += Mathf.RoundToInt(move.x)*tileSize;
y += Mathf.RoundToInt(move.y)*tileSize;
}

Can I build an AI that is more human beatable than this?

I've been building an AI and currently I'm to the point where it mostly works as it should. I hit a few hitches at first, and had something that.. spazzed out. Now that is fixed, but there's a problem - this AI catches the ball 90% of the time and returns it, although somewhat slowly at times. I have yet to build the Attract mode of the game, but I can imagine... when that is in, the two AI will almost never score on eachother.
The game takes place on a 2D plane. The AI moves purely on X, locked into Z and Y while the ball moves on X and Y.
The playing field is set up like tennis, a 'net' in the center - 0,0,0, denotes the middle and the ball moves like a tennis ball does.
The AI (and player) uses two controls - 'Direction' to go either left or right, 1 for left, -1 for right, and a bool to trigger the ball return.
At the moment I just want it to 'miss' the ball every so often, not nearly perfectly every time. I'm programming in C#, with the game engine being Unity3D - here's my code for the AI engine thus far:
void AIHandle()
{
DetectBalls();
if (GameController.Instance.Balls.Count < 1) {
GetFlipperButton = false;
}
if (BallPosition) {
BallPosit = BallPosition.position;
BallX = BallPosit.x;
//BallVelPosit = BallPosition.gameObject.rigidbody.velocity;
//BallPosit.x += BallVelPosit.x;
//BallPosit.y += BallVelPosit.y;
//BallVelPosit.y -= Physics.gravity.y;
//BallHitPredictor = new Vector3 (BallPosit.x, 0, 0);
transformPoint = transform.InverseTransformPoint(BallPosit);
//////////////////
Vector3 Heading = BallPosit - transform.position;
if (BallX > 0) {
Debug.Log(Heading.sqrMagnitude);
// THe ball is to the left //
if (transformPoint.z < 0f)
{
Direction = 1;
}
// The ball is to the right //
if (transformPoint.z > 0f)
{
Direction = -1;
}
if (Heading.sqrMagnitude < 30.0f)
{
Direction = 0;
}
} else {
Retreat();
}
} else {
Retreat();
}
MovementDirection = Mathf.Lerp(MovementDirection, Direction, 2.0f);
}
private void Retreat()
{
float DistanceToCenter = Vector3.Distance(transform.position, PlayerStartPosition);
Vector3 CenterPointOrient = transform.InverseTransformPoint(PlayerStartPosition);
if (DistanceToCenter >= 1f) {
if (CenterPointOrient.z > 0) {
Direction = -1;
} else {
Direction = 1;
}
} else {
Direction = 0;
}
}

Space Invaders stick to wall

So I have to develop an XNA game for school and I thought Space Invaders was a nice thing to make. But now I'm stuck with a problem. I have a List filled with 'Aliens' from another class. And every second it moves 20 px to the right and I want it to descend when it touches the right side of the screen (not the problem). But I want it to move the opposite direction (to the left) as soon as it touches the wall. Here lies the problem.
As soon as it touches the wall it still moves 20px once, changes direction, moves 20px back and changes direction again. This keeps repeating.
So where lies the problem. I think it has to check earlier if one of the aliens touches the screen but don't know how to accomplish that and thought maybe one of you could help me out because it is very frustrating!
I included the update method
if (xPos % step == 0)
{
if (!isDescending)
{
for (int k = 0; k < sprites.Count; k++)
{
Sprite sprite = sprites[k];
if (touchedRight) sprite.position.X += step;
else sprite.position.X -= step;
}
for (int k = 0; k < sprites.Count; k++)
{
Sprite sprite = sprites[k];
bool hitLeft = sprite.position.X == 0;
bool hitRight = sprite.rect.Right == screenWidth;
if ((hitLeft) || (hitRight))
{
touchedRight = !touchedRight;
isDescending = true;
}
}
}
else
{
isDescending = false;
for (int k = 0; k < sprites.Count; k++)
{
sprites[k].position.Y += sprites[k].rect.Height;
}
}
}
// CheckCollision(alienBounds, k-1);
// sprite.rect = new Rectangle((int)sprite.position.X, (int)sprite.position.Y, 20, 20);
// alienBounds = sprite.rect;
xPos += 1;
Well, this is wrong:
if ((hitLeft) || (hitRight))
When moving right, you only care about hitRight. And when moving left, you care only about hitLeft.
So try
if (touchedRight? hitLeft: hitRight)
This will also fix the issue where multiple aliens can hit the wall at the same time.
Im not sure but I bellieve in Space invaders, if you kill all columns but the most left, it doesnt move completely to the right side of the screen before switching its direction.
So what I suggest is you create a derivate of a Sprite called Invader:
class Invader : Sprite
{
readonly float distanceFromCenterHorizontal;
public Invader(float distanceFromCenterHorizontal)
{
this.distanceFromCenterHorizontal= distanceFromCenterHorizontal;
}
public void UpdatePosition(Point center)
{
this.Position.X = center.X + distanceFromCenterHorizontal;
this.Position.Y = center.Y;
}
}
// global variables:
Point center = ....
bool moveLeft = false;
void createInvaders()
{
int invaderWidth = 20; // whatever your value is
float columnCenter = ((float) columnMax) / 2 * invaderWidth;
for(var column = 0; column < columnMax ; column++)
{
float invaderX = (column * invaderWidth);
float distanceFromCenterHorizontal = invaderX - columnCenter;
for(var row = 0; row < rowMax; row ++)
{
Invader invader = new Invader(distanceFromCenterHorizontal);
invader.Position.Y = row * invaderHeight // Needs adjustment here!
}
}
}
void update()
{
if(center.X == screenWidth) moveLeft = true;
else if(center.X <= 0) moveLeft = false;
center.X += moveLeft? -step : step;
foreach(var invader in invaders) invader.UpdatePosition(center);
}
You want to move the "centerPoint" and all Invaders update According to the new Center.
Im not sure if XNA uses double or float values, so youmight need to adjust this.
You can then easily expand this to create some up / down wobbling.
So i made a new rectangle called 'bounds' which is as wide as the aliens and moves the same as the aliens do. And got it working! (half of it). It moves to the right until it touches the right side, then it goes to the left but keeps going to the left and never goes back to the right. So where am i going wrong this time?
if (xPos % step == 0)
{
if (!isDescending)
{
for (int k = 0; k < sprites.Count; k++)
{
Sprite sprite = sprites[k];
sprite.position.X += step;
}
if (bounds.Right == screenWidth || bounds.Left == 0)
{
touchedRight = !touchedRight;
step *= -1;
}
if (!touchedRight) bounds.X += step;
if (touchedRight) bounds.X -= step;
// for (int k = 0; k < sprites.Count; k++)
// {
// Sprite sprite = sprites[k];
// bool hitLeft = sprite.position.X == 0;
// bool hitRight = sprite.rect.Right == screenWidth;
// if ((hitLeft) || (hitRight))
// {
// touchedRight = !touchedRight;
// isDescending = true;
// }
// }
}

Platform jumping problems with AABB collisions

When my AABB physics engine resolves an intersection, it does so by finding the axis where the penetration is smaller, then "push out" the entity on that axis.
Considering the "jumping moving left" example:
If velocityX is bigger than velocityY, AABB pushes the entity out on the Y axis, effectively stopping the jump (result: the player stops in mid-air).
If velocityX is smaller than velocitY (not shown in diagram), the program works as intended, because AABB pushes the entity out on the X axis.
How can I solve this problem?
Source code:
public void Update()
{
Position += Velocity;
Velocity += World.Gravity;
List<SSSPBody> toCheck = World.SpatialHash.GetNearbyItems(this);
for (int i = 0; i < toCheck.Count; i++)
{
SSSPBody body = toCheck[i];
body.Test.Color = Color.White;
if (body != this && body.Static)
{
float left = (body.CornerMin.X - CornerMax.X);
float right = (body.CornerMax.X - CornerMin.X);
float top = (body.CornerMin.Y - CornerMax.Y);
float bottom = (body.CornerMax.Y - CornerMin.Y);
if (SSSPUtils.AABBIsOverlapping(this, body))
{
body.Test.Color = Color.Yellow;
Vector2 overlapVector = SSSPUtils.AABBGetOverlapVector(left, right, top, bottom);
Position += overlapVector;
}
if (SSSPUtils.AABBIsCollidingTop(this, body))
{
if ((Position.X >= body.CornerMin.X && Position.X <= body.CornerMax.X) &&
(Position.Y + Height/2f == body.Position.Y - body.Height/2f))
{
body.Test.Color = Color.Red;
Velocity = new Vector2(Velocity.X, 0);
}
}
}
}
}
public static bool AABBIsOverlapping(SSSPBody mBody1, SSSPBody mBody2)
{
if(mBody1.CornerMax.X <= mBody2.CornerMin.X || mBody1.CornerMin.X >= mBody2.CornerMax.X)
return false;
if (mBody1.CornerMax.Y <= mBody2.CornerMin.Y || mBody1.CornerMin.Y >= mBody2.CornerMax.Y)
return false;
return true;
}
public static bool AABBIsColliding(SSSPBody mBody1, SSSPBody mBody2)
{
if (mBody1.CornerMax.X < mBody2.CornerMin.X || mBody1.CornerMin.X > mBody2.CornerMax.X)
return false;
if (mBody1.CornerMax.Y < mBody2.CornerMin.Y || mBody1.CornerMin.Y > mBody2.CornerMax.Y)
return false;
return true;
}
public static bool AABBIsCollidingTop(SSSPBody mBody1, SSSPBody mBody2)
{
if (mBody1.CornerMax.X < mBody2.CornerMin.X || mBody1.CornerMin.X > mBody2.CornerMax.X)
return false;
if (mBody1.CornerMax.Y < mBody2.CornerMin.Y || mBody1.CornerMin.Y > mBody2.CornerMax.Y)
return false;
if(mBody1.CornerMax.Y == mBody2.CornerMin.Y)
return true;
return false;
}
public static Vector2 AABBGetOverlapVector(float mLeft, float mRight, float mTop, float mBottom)
{
Vector2 result = new Vector2(0, 0);
if ((mLeft > 0 || mRight < 0) || (mTop > 0 || mBottom < 0))
return result;
if (Math.Abs(mLeft) < mRight)
result.X = mLeft;
else
result.X = mRight;
if (Math.Abs(mTop) < mBottom)
result.Y = mTop;
else
result.Y = mBottom;
if (Math.Abs(result.X) < Math.Abs(result.Y))
result.Y = 0;
else
result.X = 0;
return result;
}
It's hard to read code of other people, but I think this is one possible (purely brainstormed) workaround, although of course I'm not able to test it:
Before the collision detection happens, save the players velocity to some temporary variable.
After you've done your collision response, check if the players X or Y position has been corrected
If X position has been changed, manually reset (as a kind of "safety reset") the players Y velocity to the one that he had before the response.
By the way, what happens with your current code when your players hits the roof while jumping?
I had that same problem. Even the Microsoft platformer starterskit seems to have that bug.
The solution I found so far is to either use multisampling (argh) or to use the movedirection of the object: only move the distance between those 2 objects and no further when a collision is detected (and do that for each axis).
One possible solution I found is sorting the objects before resolving based on the velocity of the player.

Area constraint blows up my physics simulation if a body slams into it too fast

I have a physics simulation and it allows you to place area constraints, so that the bodies within will not exit that area. However if an atom goes past one of the "walls" of the area constraint it blows up the physics simulation. Why does it do this?
Update method:
if (!atom.IsStatic)
{
Vector2 force = Vector2.Zero;
bool x = false, y = false;
if (atom.Position.X - atom.Radius < _min.X)
{
force = new Vector2(-(_min.X - atom.Position.X), 0);
if (atom.Velocity.X < 0)
x = true;
}
if (atom.Position.X + atom.Radius > _max.X)
{
force = new Vector2(atom.Position.X - _max.X, 0);
if (atom.Velocity.X > 0)
x = true;
}
if (atom.Position.Y - atom.Radius < _min.Y)
{
force = new Vector2(0, -(_min.Y - atom.Position.Y));
if (atom.Velocity.Y < 0)
y = true;
}
if (atom.Position.Y + atom.Radius > _max.Y)
{
force = new Vector2(0, atom.Position.Y - _max.Y);
if (atom.Velocity.Y > 0)
y = true;
}
atom.ReverseVelocityDirection(x, y);
if (!atom.IsStatic)
{
atom.Position += force;
}
}
I see you're doing calculation with a constant time step T. When modeling collisions though on every step you should use time step equal to minimal time before any of atoms reach any obstacle.
Make time step variable, and atoms will never "tunnel" obstacles.
P.S. There are a lot of optimizations in collision detection, please read gamedev papers for information on those.
P.S. A bug?
force = new Vector2(-(_min.X - atom.Position.X), 0);
Force is created separately for X and Y reflection. What happens when the atom gets into a corner? Only second force will be applied.
P.P.S: Use epsilon
One more important note: if you use floating point, the error is accumulated, and you should use eps:
abs(atom.Position.Y + atom.Radium - _max.Y) < eps
where eps is a number much smaller than normal sizes in your task, e.g. 0.000001.
You seem to have solved the problem already, but I notice that "force" seems to be wrong. It moves the atom away from the boundary, even if it's on the wrong side. Suppose an atom has shot past _max.X:
if (atom.Position.X + atom.Radius > _max.X)
{
force = new Vector2(atom.Position.X - _max.X, 0);
...
}
Now "force" will be in the +x direction, and the atom's distance from the wall will double with every iteration. Boom!
Wouldn't you know, after about half an hour of mindless hacking at it, i thought of simply not applying the position correction. That fixed it like a charm. For any interested, here's the updated code:
if (!atom.IsStatic)
{
if (atom.Position.X - atom.Radius < _min.X && atom.Velocity.X < 0)
{
atom.ReverseVelocityDirection(true, false);
}
if (atom.Position.X + atom.Radius > _max.X && atom.Velocity.X > 0)
{
atom.ReverseVelocityDirection(true, false);
}
if (atom.Position.Y - atom.Radius < _min.Y && atom.Velocity.Y < 0)
{
atom.ReverseVelocityDirection(false, true);
}
if (atom.Position.Y + atom.Radius > _max.Y && atom.Velocity.Y > 0)
{
atom.ReverseVelocityDirection(false, true);
}
}

Categories

Resources