Xna Intersect is to slow - c#

Hello i have a problem with this code:
for (int i = 0; i < map.collision_rects.Count(); i++)
{
if (player.collision_rect.Intersects(map.collision_rects[i]))
{
Debug.WriteLine("INTERSERCTED:" + player.velocity.Y);
player.velocity.Y = 0;
player.has_jumped = false;
}
}
player.Update(gameTime);
The problem is that it Detects that it intersected but the velocity is set to zero a frame later than it detected
if (has_jumped == true)
{
float i = 1;
velocity.Y += 0.15f*i;
}
The code that sets the velocity

Related

Unity Multiplayer Server Client desync due to rotation from mouse input

I am currently working on implementing my first multiplayer system with server authority and client side prediction with server reconciliation. But I am running into a problem that I just don't know how other's have solved. I've implemented a fixed timestep system according to a tutorial I found: https://github.com/Ajackster/ClientPredictionTutorial/blob/master/Assets/Scripts/Client.cs and in each timestep I process user keypresses and change the velocity accordingly. Which works great until I start changing my rotation with mouse input. User input and mouse input are read in the Update() function which I think is the source of my desync problems. My client is changing its rotation with each frame. but the server is only changing its input when it receives the rotation from the client in the fixed timestep "handleTick()" method. I believe this is causing a desync in the velocity of my client object and the velocity of the server object. because the velocity of my client is updating with each render (potentially, if we are receiving new mouse input in each update frame) but the velocity of my server only changes in the fixed time step call which could be called less frequently or more frequently than update()
I hope this makes some sense to you brilliant people out there. Is there anyway to handle this?? Please excuse this trash code but this is a snippet from my project
void Update()
{
timer += Time.deltaTime;
if (!isServer)
{
verticalAxisInput = 0;
horizonalAxisInput = 0;
if (inputManager.getKeyManager().getKey("w"))
{
verticalAxisInput = 1;
}
else if (inputManager.getKeyManager().getKey("s"))
{
verticalAxisInput = -1;
}
if (inputManager.getKeyManager().getKey("d"))
{
horizonalAxisInput = 1;
}
if (inputManager.getKeyManager().getKey("a"))
{
horizonalAxisInput = -1;
}
EDIT: The below line was the source of the bug. needs to be moved after transform.localRotation update
playerInput = (transform.forward * verticalAxisInput) + (transform.right * horizonalAxisInput);
pressJump = inputManager.getSingleKeyInput("space") > 0;
pressSprint = inputManager.getSingleKeyInput("left shift") > 0;
mouseX = Input.GetAxis(InputKeys.MOUSE_X_AXIS);
mouseY = Input.GetAxis(InputKeys.MOUSE_Y_AXIS);
playerCam.transform.localRotation = lookY(mouseY);
transform.localRotation = lookX(mouseX);
}
while (timer >= MIN_TIME_BETWEEN_TICKS)
{
timer -= MIN_TIME_BETWEEN_TICKS;
handleTick();
currentTick++;
}
private void handleTick()
{
if (isServer)
{
PlayerInputPacket packet = RemoteDataConnection.instance.getData();
pressJump = inputManager.getSingleKeyInput("space") > 0;
transform.localRotation = packet.playerRot;
inputManager.getKeyManager().setKeyMap(packet.keyMap);
verticalAxisInput = 0;
horizonalAxisInput = 0;
if (inputManager.getKeyManager().getKey("w"))
{
verticalAxisInput = 1;
}
else if (inputManager.getKeyManager().getKey("s"))
{
verticalAxisInput = -1;
}
if (inputManager.getKeyManager().getKey("d"))
{
horizonalAxisInput = 1;
}
if (inputManager.getKeyManager().getKey("a"))
{
horizonalAxisInput = -1;
}
playerInput = (transform.forward * verticalAxisInput) + (transform.right * horizonalAxisInput);
}
else
{
ClientDataConnection.instance.writeData(new PlayerInputPacket(inputManager.getKeyManager().getKeyMap(), transform.localRotation));
}
if (currentJumpCoolDown > 0)
{
currentJumpCoolDown--;
}
move(playerInput, pressJump, pressSprint);
}
Found the problem. The client was calculating input velocity in the update() loop but the server was doing that in the fixed timestep tick method. when made the client calculate this in the fixed timestep method my problem was fixed. I don't entirely understand how this fixes the problem because when the client was processing input it was also sending the server its rotation value so I thought the server and client would get the same result but that must of not of been the case. if anyone understands why this is I would really appreciate an answer
playerInput = (transform.forward * verticalAxisInput) + (transform.right * horizonalAxisInput);
move(playerInput, pressJump, pressSprint);
full code after fix:
void Update()
{
timer += Time.deltaTime;
if (!isServer)
{
verticalAxisInput = 0;
horizonalAxisInput = 0;
if (inputManager.getKeyManager().getKey("w"))
{
verticalAxisInput = 1;
}
else if (inputManager.getKeyManager().getKey("s"))
{
verticalAxisInput = -1;
}
if (inputManager.getKeyManager().getKey("d"))
{
horizonalAxisInput = 1;
}
if (inputManager.getKeyManager().getKey("a"))
{
horizonalAxisInput = -1;
}
pressJump = inputManager.getSingleKeyInput("space") > 0;
pressSprint = inputManager.getSingleKeyInput("left shift") > 0;
mouseX = Input.GetAxis(InputKeys.MOUSE_X_AXIS);
mouseY = Input.GetAxis(InputKeys.MOUSE_Y_AXIS);
playerCam.transform.localRotation = lookY(mouseY);
transform.localRotation = lookX(mouseX);
Debug.Log(characterController.velocity);
}
while (timer >= MIN_TIME_BETWEEN_TICKS)
{
timer -= MIN_TIME_BETWEEN_TICKS;
handleTick();
currentTick++;
}
doWeaponBounce();
}
private void handleTick()
{
if (isServer)
{
PlayerInputPacket packet = RemoteDataConnection.instance.getData();
pressJump = inputManager.getSingleKeyInput("space") > 0;
transform.localRotation = packet.playerRot;
inputManager.getKeyManager().setKeyMap(packet.keyMap);
verticalAxisInput = 0;
horizonalAxisInput = 0;
if (inputManager.getKeyManager().getKey("w"))
{
verticalAxisInput = 1;
}
else if (inputManager.getKeyManager().getKey("s"))
{
verticalAxisInput = -1;
}
if (inputManager.getKeyManager().getKey("d"))
{
horizonalAxisInput = 1;
}
if (inputManager.getKeyManager().getKey("a"))
{
horizonalAxisInput = -1;
}
}
else
{
ClientDataConnection.instance.writeData(new PlayerInputPacket(inputManager.getKeyManager().getKeyMap(), transform.localRotation));
}
if (currentJumpCoolDown > 0)
{
currentJumpCoolDown--;
}
playerInput = (transform.forward * verticalAxisInput) + (transform.right * horizonalAxisInput);
move(playerInput, pressJump, pressSprint);
}

Cannot Connect Path Points with Line Renderer in Unity

I am trying to generate a pathway system where a line is being rendered with time. My code is:
public IEnumerator DrawPath(List<Vector3> pathWay)
{
lineRenderer.positionCount = 0;
points = new Vector3[pathWay.Count];
for (int i = 0; i < pathWay.Count; i++)
{
Vector3 checkpointpos = pathWay[i];
points[i] = new Vector3(checkpointpos.x, checkpointpos.y, checkpointpos.z);
}
lineRenderer.startWidth = 1f;
lineRenderer.endWidth = 1f;
lineRenderer.positionCount = points.Length;
for (int i = 0; i < points.Length; i++)
{
//Mathf.Lerp
yield return new WaitForSeconds(0.1f);
lineRenderer.SetPosition(i, points[i]);
}
}
Output:
I am getting List<Vector3> from A* Pathfinding free version plugin.
Any kind of help would be appreciated. Thanks in advance.
Okay I resolved the issue.
The problem was setting the counts of lines all at once so whenever I was setting a new vector it starts from position 0 that's why I had problem.
Solution:
public IEnumerator DrawPath(List<Vector3> pathWay)
{
lineRenderer.positionCount = 0;
points = new Vector3[pathWay.Count];
lineRenderer.startWidth = 1f;
lineRenderer.endWidth = 1f;
for (int i = 0; i < pathWay.Count; i++)
{
Vector3 checkpointpos = pathWay[i];
points[i] = new Vector3(checkpointpos.x, checkpointpos.y, checkpointpos.z);
yield return new WaitForSeconds(0.1f);
lineRenderer.positionCount++;
lineRenderer.SetPosition(i, points[i]);
}
}
Output:

Unity freezes on Play

I've been making this enemy generator, which is called on Start() and it freezes most of the time. Sometimes it let's to play once but as soon as I hit play second time, it freezes, unity needs to be restarted. Standalone version doesn't fix the problem. Logs last lines:
UnityEngine.DebugLogHandler:Internal_Log(LogType, LogOption, String, Object)
UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])
UnityEngine.Logger:Log(LogType, Object)
UnityEngine.Debug:Log(Object)
EnemyGenerator:Start() (at Assets\Scripts\Utils\EnemyGenerator.cs:23)
(Filename: Assets/Scripts/Utils/EnemyGenerator.cs Line: 23)
Here is my script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyGenerator : MonoBehaviour
{
public List<GameObject> camps;
public List<GameObject> enemies;
int threshold;
public List<GameObject> campAreas;
public List<GameObject> enemyAreas;
public int campsToSpawn;
public int enemiesPerAreaMin;
public int enemiesPerAreaMax;
void Start()
{
for (int i = 0; i < campsToSpawn; i++)
{
threshold = Random.Range(0, camps.Count - 1);
Debug.Log(threshold);
var campPlace = Random.Range(0, campAreas.Count - 1);
var camp = Instantiate(camps[threshold], campAreas[campPlace].transform.position, Quaternion.identity);
if (camp != null)
{
campAreas.RemoveAt(campPlace);
}
}
Debug.Break();
bool canSpawn = true;
for (int i = 0; i < enemyAreas.Count; i++)
{
threshold = Random.Range(0, enemies.Count - 1);
List<GameObject> enemiesSpawned = new List<GameObject>();
var enemyCount = Random.Range(enemiesPerAreaMin, enemiesPerAreaMax);
for (int j = 0; j < enemyCount; j++)
{
var pos = new Vector3(Random.Range(enemyAreas[i].GetComponent<BoxCollider>().bounds.min.x, enemyAreas[i].GetComponent<BoxCollider>().bounds.max.x), enemyAreas[i].transform.position.y,
Random.Range(enemyAreas[i].GetComponent<BoxCollider>().bounds.min.z, enemyAreas[i].GetComponent<BoxCollider>().bounds.max.z));
if (enemiesSpawned.Count == 0)
{
GameObject en = null;
enemiesSpawned.Add(en = Instantiate(enemies[threshold], pos, Quaternion.identity));
}
else
{
for (int x = 0; x < enemiesSpawned.Count; x++)
{
if (Vector3.Distance(enemiesSpawned[x].transform.position, pos) < 3f)
{
canSpawn = false;
}
}
if (!canSpawn)
{
j--;
}
else
{
enemiesSpawned.Add(Instantiate(enemies[threshold], pos, Quaternion.identity));
}
}
}
Debug.Break();
}
}
}
I tried to find something that would actually loop forever, but I don't think that's the problem. Wondering if it could be performance leak?
Thank you in advance.
Sry I though it was an issue with Debug.Break();
this is probably the problem
{
for (int x = 0; x < enemiesSpawned.Count; x++)
{
if (Vector3.Distance(enemiesSpawned[x].transform.position, pos) < 3f)
{
canSpawn = false;
}
}
if (!canSpawn)
{
j--;
}
else
{
enemiesSpawned.Add(Instantiate(enemies[threshold], pos, Quaternion.identity));
}
}
You getting a random position inside a certain bounds. If the position is too close u don't spawn and --j; to retry a new position. So if for some reason the bounds are wrong or barely engouth you might be running that function for a very long time.
A quick test is to add a counter before your j for loop.
int debugCounter = 0;
for (int j = 0; j < enemyCount; j++)
{
//at the very top
++debugCounter;
if(debugCounter > 100)//or a bigger number
{
Debug.Log("Too many attemps");
break;
}
...

Enemies in a list: issue with colliding the enemies with the other enemies

I'm currently working on a game in which a list of enemies is spawned into the level randomly on the x-axis using a list up to the point of the maximum number to spawn (currently set at 10) I have a large portion of the game working however I currently have the problem that the enemies can overlap/stack on top of each other.
What I want is if the collision box of the enemy is intersecting another enemy in the list, for it to no overlap. (if that makes sense) this is the code I have for it so far.
foreach (EnemyClass enemy1 in enemies)
{
if (enemy1.position.X < myPlayer.position.X - 10 && !enemy1.stopMoving)
{
enemy1.position.X += enemy1.amountToMove;
}
if (enemy1.position.X > myPlayer.position.X - 50 && !enemy1.stopMoving)
{
enemy1.position.X -= enemy1.amountToMove;
}
foreach (EnemyClass enemy2 in enemies)
{
if (enemy1 != enemy2 && enemy1.collisionBox.Intersects(enemy2.collisionBox))
{
System.Console.WriteLine("Collision Detected");
}
}
enemy1.collisionX = (int)enemy1.position.X;
enemy1.Update(graphics.GraphicsDevice);
}
Any help would be greatly appreciated.
EDIT: What I missed off was that they technically do collide, however they collide when they are 1000 pixels apart, when the sprite is actually 50 pixels wide.
EDIT: This is the changed collision code..
foreach (EnemyClass enemy in enemies)
{
enemy.collisionX = (int)enemy.position.X;
if (enemy.position.X < myPlayer.position.X - 10 && !enemy.stopMoving)
{
enemy.position.X += enemy.amountToMove;
}
if (enemy.position.X > myPlayer.position.X - 50 && !enemy.stopMoving)
{
enemy.position.X -= enemy.amountToMove;
}
for (int i = 0; i < enemies.Count; i++)
{
for (int j = i + 1; j < enemies.Count; j++)
{
if (enemies[i].collisionBox.Intersects(enemies[i].collisionBox))
{
System.Console.WriteLine("Collision Detected");
}
}
}
enemy.Update(graphics.GraphicsDevice);
}
EDIT: Here is the EnemyClass, which is where the collisionBox is contained:
public EnemyClass(Texture2D newTexture, Vector2 newPosition)
{
texture = newTexture;
position = newPosition;
collisionBox = new Rectangle((int)position.X, (int)position.Y, texture.Width, texture.Height);
randX = random.Next(1, 3);
speed = new Vector2(randX, 0);
}
public void Update(GraphicsDevice graphics)
{
collisionBox = new Rectangle((int)position.X, (int)position.Y, texture.Width, texture.Height);
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, Color.White);
}
It seems that the collision is being detected before all of the collision boxes have been updated.
My suggestions for how to order things:
Define the collision box in terms of position.X and position.Y so
that it always accurately reflects the correct position.
Update all the enemies x- and y-positions.
Execute the snippet below after all the enemy positions have been updated.
foreach (EnemyClass enemy in enemies)
{
if (enemy.position.X < myPlayer.position.X - 10 && !enemy.stopMoving)
{
enemy.position.X += enemy.amountToMove;
}
if (enemy.position.X > myPlayer.position.X - 50 && !enemy.stopMoving)
{
enemy.position.X -= enemy.amountToMove;
}
enemy.Update(graphics.GraphicsDevice);
}
for (int i = 0; i < enemies.Count; i++)
{
for (int j = i + 1; j < enemies.Count; j++)
{
if (enemies[i].collisionBox.Intersects(enemies[j].collisionBox))
{
System.Console.WriteLine("Collision Detected");
}
}
}
The above code also has an advantage in not detecting the same collision twice (i.e. enemy1/enemy2 and enemy2/enemy1).

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;
// }
// }
}

Categories

Resources