How to generate a random Vector3 point inside a polygon - c#

I work on Unity3D and I have a Vector3 array, this array is the vertex of a polygon.
Now I try to Generate a random point inside the polygon and I don't know how many vertex I have.
e.g:
polygonBorders = new Vector3[3];
polygonBorders[0] = new Vector3(35.3f, 1.3f, -20.1f);
polygonBorders[1] = new Vector3(35.3f, 1.3f, -3.42f);
polygonBorders[2] = new Vector3(52.11f, 1.3f, -3.42f);
this is my polygon and I want a method like that:
Vector3 GeneratePointInsidePolygon(Vector3[] polyogn, Vector3 point)
I try to find a solution all over the Internet and there is no solution or libraey

I find a nice way to do that with the next snippet:
private Vector3 GeneratePointInsidePolygon(List<Vector3> polygon)
{
Vector3 MinVec = MinPointOnThePolygon(polygon);
Vector3 MaxVec = MaxPointOnThePolygon(polygon);
Vector3 GenVector;
float x = ((Random.value) * (MaxVec.x- MinVec.x)) + MinVec.x;
float z = ((Random.value) * (MaxVec.z - MinVec.z)) + MinVec.z;
GenVector = new Vector3(x, groundHight, z);
while(!InConfinedSpace.IsPointInPolygon(polygon,GenVector))
{
x = ((Random.value) * (MaxVec.x - MinVec.x)) + MinVec.x;
z = ((Random.value) * (MaxVec.z - MinVec.z)) + MinVec.z;
GenVector.x = x;
GenVector.z = z;
}
return GenVector;
}
private Vector3 MinPointOnThePolygon(List<Vector3> polygon)
{
float minX = polygon[0].x;
float minZ = polygon[0].z;
for (int i = 1; i<polygon.Count;i++)
{
if(minX > polygon[i].x)
{
minX = polygon[i].x;
}
if (minZ > polygon[i].z)
{
minZ = polygon[i].z;
}
}
return new Vector3(minX, groundHight, minZ);
}
private Vector3 MaxPointOnThePolygon(List<Vector3> polygon)
{
float maxX = polygon[0].x;
float maxZ = polygon[0].z;
for (int i = 1; i < polygon.Count; i++)
{
if (maxX < polygon[i].x)
{
maxX = polygon[i].x;
}
if (maxZ < polygon[i].z)
{
maxZ = polygon[i].z;
}
}
return new Vector3(maxX, groundHight, maxZ);
}
private bool IsPointInPolygon(List<Vector3> polygon, Vector3 point)
{
bool isInside = false;
for (int i = 0, j = polygon.Count - 1; i < polygon.Count; j = i++)
{
if (((polygon[i].x > point.x) != (polygon[j].x > point.x)) &&
(point.z < (polygon[j].z - polygon[i].z) * (point.x - polygon[i].x) / (polygon[j].x - polygon[i].x) + polygon[i].z))
{
isInside = !isInside;
}
}
return isInside;
}
The snippet finds the minimum and maximum polygon vertex and then generates a random number inside and checks if the point is inside the polygon every time, if it's not it generates another point.

Related

I need to apply a Vector3 to a Vector3[] with Vector3.up, Vector3.down, ecc.but I can't

I have this script and I need to assign a different value to vertices every frame but I can't convert Vector3 to Vector3[], I tried In many ways but I am not able to solve this
public Vector3 calculatePointOnPlanet(Vector3 directions)
{
float firstLayerValue = 0;
float elevation = 0;
directions = directions;
if (noiseFilters.Length > 0)
{
firstLayerValue = noiseFilters[0].Evaluate(directions);
if (settings.noiseLayers[0].enabled)
{
elevation = firstLayerValue;
}
}
for (int i = 0; i < noiseFilters.Length; i++)
{
if (settings.noiseLayers[i].enabled)
{
float mask = (settings.noiseLayers[i].useFirstLayerAsMask) ? firstLayerValue : 1;
elevation += noiseFilters[i].Evaluate(directions) * mask;
}
}
return directions * settings.radius * (1 + elevation);
}
public void a(Vector3[] vertices, Vector3[] directions)
{
for (int i = 0; i < noiseFilters.Length; i++)
{
vertices[i] = calculatePointOnPlanet(directions);
}
}
You probably forgot the index
// |
// V
vertices[i] = calculatePointOnPlanet(directions[i]);
Note btw that
directions = directions
does absolutely nothing

Did I declare this array properly? [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
I was trying to translate something from C++ to C#, now the translation is completely done, however I'm getting an error when compiling that says index of array is out of bounds so I want to know if I declared the array properly.
[Entire Code]
using System;
using SFML.Graphics;
using SFML.Window;
using SFML.Audio;
using SFML.System;
namespace Pruebas_Algoritmia
{
class Program
{
const int num = 8;
static int[,] points = new int[num, 2] {{300, 610},
{ 1270, 430},
{1380,2380},
{1900,2460},
{1970,1700},
{2550,1680},
{2560,3150},
{500, 3300}};
public struct Car
{
public float x;
public float y;
public float speed;
public float angle;
public int n;
public Car(float speed,float angle, int n)
: this()
{
speed = 2;
angle = 0;
n = 0;
}
public void move()
{
x += MathF.Sin(angle) * speed;
y -= MathF.Cos(angle) * speed;
}
public void findTarget()
{
float tx = points[n, 0];
float ty = points[n, 1];
float beta = angle - MathF.Atan2(tx - x, -ty + y);
if (Math.Sin(beta) < 0)
{
angle += 0.005f * speed;
}
else
{
angle -= 0.005f * speed;
}
if ((x - tx) * (x - tx) + (y - ty) * (y - ty) < 25 * 25)
{
n = (n + 1) % num;
}
}
};
static void OnClose(object sender, EventArgs e)
{
RenderWindow window = (RenderWindow)sender;
window.Close();
}
static void Main(string[] args)
{
RenderWindow app = new RenderWindow(new VideoMode(640, 480), "Car Racing Game", Styles.Default);
app.SetFramerateLimit(60);
app.SetVerticalSyncEnabled(true);
app.DispatchEvents();
app.Clear();
Texture t1 = new Texture("c://images/background.png");
Texture t2 = new Texture("c://images/car.png");
t1.Smooth = true;
t2.Smooth = true;
Sprite sBackground = new Sprite(t1);
Sprite sCar = new Sprite(t2);
sBackground.Scale = new Vector2f(2, 2);
sCar.Origin = new Vector2f(22, 22);
float R = 22f;
const int N = 5;
Car[] car = new Car[N];
for (int i = 0; 0 < N; i++)
{
car[i].x = 300 + i * 50;
car[i].y = 1700 + i * 80;
car[i].speed = 7 + i;
}
float speed = 0f;
float angle = 0f;
float maxSpeed = 12.0f;
float acc = 0.2f;
float dec = 0.03f;
float turnSpeed = 0.08f;
float offsetX = 0;
float offsetY = 0;
while (app.IsOpen)
{
Event e;
app.Closed += new EventHandler(OnClose);
app.Display();
}
bool up = false;
bool down = false;
bool right = false;
bool left = false;
if (Keyboard.IsKeyPressed(Keyboard.Key.Up))
{
up = true;
}
if (Keyboard.IsKeyPressed(Keyboard.Key.Right))
{
right = true;
}
if (Keyboard.IsKeyPressed(Keyboard.Key.Down))
{
down = true;
}
if (Keyboard.IsKeyPressed(Keyboard.Key.Left))
{
left = true;
}
//movement
if (up && speed < maxSpeed)
{
if (speed < 0)
{
speed += dec;
}
else
{
speed -= acc;
}
}
if (down && speed >- maxSpeed)
{
if (speed > 0)
{
speed -= dec;
}
else
{
speed -= acc;
}
}
if (!up && !down)
{
if (speed - dec > 0)
{
speed -= dec;
}
else if(speed + dec < 0)
{
speed += dec;
}
else
{
speed = 0;
}
}
if (right && speed != 0)
{
angle += turnSpeed * speed / maxSpeed;
}
if (left && speed != 0)
{
angle -= turnSpeed * speed / maxSpeed;
}
car[0].speed = speed;
car[0].angle = angle;
for (int i = 0; i < N; ++i)
{
car[i].move();
}
for (int i = 0; i < N; ++i)
{
car[i].findTarget();
}
for (int i = 0; i < N; ++i)
{
for(int j = 0; i < N; ++j)
{
float dx = 0;
float dy = 0;
while (dx * dx + dy * dy < 4 * R * R)
{
car[i].x += dx / 10.0f;
car[i].x += dy / 10.0f;
car[j].x += dx / 10.0f;
car[j].x += dy / 10.0f;
dx = car[i].x - car[j].x;
dy = car[i].y - car[j].y;
}
}
}
app.Clear(Color.White);
if (car[0].x > 320) offsetX = car[0].x - 320;
if (car[0].y > 240) offsetY = car[0].y - 240;
//sBackground
sBackground.Position = new Vector2f(-offsetX, -offsetY);
app.Draw(sBackground);
Color[] colors = new Color[] { Color.Red, Color.Green, Color.Magenta, Color.Blue, Color.White};
for (int i = 0; i < N; ++i)
{
sCar.Position = new Vector2f(car[i].x - offsetX, car[i].y - offsetY);
sCar.Rotation = car[i].angle * 180 / 3.141593f;
sCar.Color = colors[i];
app.Draw(sCar);
}
app.Display();
}
}
}
I'm getting the error around line 88 where I have this.
const int N = 5;
Car[] car = new Car[N];
for (int i = 0; 0 < N; i++)
{
car[i].x = 300 + i * 50;
car[i].y = 1700 + i * 80;
car[i].speed = 7 + i;
}
Originally this looked like this in C++
const int N=5;
Car car[N];
for(int i=0;i<N;i++)
{
car[i].x=300+i*50;
car[i].y=1700+i*80;
car[i].speed=7+i;
}
The error I get literally says the index is out of bounds, also I'm getting an exception after this for loop saying that there's unreachable code for every line below the loop
You made a typo in your C# code. You wrote 0 < N instead of i < N.

Drawing a Turkey in unity2d using Verlet method

This is a homework problem(Do not copy, copy is not smart): We need to draw a 2d turkey in unity 2d using Verlet method to update the positions of the vertices. However, We don't know the forces involved to trace the Turkey. Here is a picture of the Turkey. Is there a trick?
Here is the codes that we started:
public class GenerateTurkeys : MonoBehaviour
{
LineRenderer lineRenderer = gameObject.AddComponent<LineRenderer>();
// Start is called before the first frame update
int numberOfTurkeys;
int NUM_PARTICLES;
float fTimeStep;
Vector3[] m_position = new Vector3[NUM_PARTICLES];
Vector3[] m_acceleration = new Vector3[NUM_PARTICLES];
Vector3[] m_oldPosition = new Vector3[NUM_PARTICLES];
void Start()
{
NUM_PARTICLES = 100;
numberOfTurkeys = 0;
}
// Verlet integration step void ParticleSystem::
Verlet()
{
for (int i=0; i<NUM_PARTICLES; i++)
{
Vector3 x = m_position[i];
Vector3 temp = x;
Vector3 oldx = m_oldPosition[i];
Vector3 a = m_acceleration[i];
x += x-oldx+a* fTimeStep*fTimeStep;
oldx = temp;
}
}
void DrawLine(float[] heights)
{
LineRenderer lineRenderer = GetComponent<LineRenderer>();
var t = Time.time;
for (int i = 0; i < NUM_PARTICLES; i++)
{
lineRenderer.SetPosition(i, );
}
}
// Update is called once per frame
void Update()
{
}
}
I'm not sure that I correctly decided, due to the fact that the contour does not match, but in the solution the speed is exactly iterative. I think this is a small error of physics in Unity, Because if you use the resulting accelerations, you can draw the graph very accurately.
Here is code:
public class Drawer : MonoBehaviour
{
[SerializeField]
private Transform[] m_Dots;
private Rigidbody2D m_Dot;
private Vector2[] m_Acceler;
float deltaT = 0.5f;//for example
private void Start()
{
m_Acceler = GetAcceler();
var go = new GameObject("Tracer");
var tr = go.AddComponent<TrailRenderer>();
tr.widthMultiplier = 0.1f;
tr.time = 50f;
m_Dot = go.AddComponent<Rigidbody2D>();
m_Dot.bodyType = RigidbodyType2D.Kinematic;
m_Dot.gravityScale = 0;
StartCoroutine(VerletCoroutine());
}
private Vector2[] GetAcceler()
{
Vector2[] result = new Vector2[m_Dots.Length];
float T = deltaT;
int len = m_Dots.Length;
result[0] = An(m_Dots[1].position, m_Dots[0].position, m_Dots[0].position, T);
for (int i = 1 ; i < len - 1 ; i++, T += deltaT)
{
result[i] = An(m_Dots[i + 1].position, m_Dots[i].position, m_Dots[i].position, T);
}
result[len - 1] = An(m_Dots[0].position, m_Dots[len - 1].position, m_Dots[len - 1].position, T);
return result;
}
private Vector2 An(Vector2 Xnext, Vector2 Xn, Vector2 Xprev, float t)
{// a[n] = (x[n+1] - 2*x[n]+x[n-1])/t^2
return (Xnext - 2 * Xn + Xprev) / t * t;
}
private IEnumerator VerletCoroutine()
{
m_Dot.transform.position = m_Dots[0].position;
Vector2 Vprev = Vector2.zero;
int len = m_Acceler.Length - 1;
float t = 0;
int i = 0;
while (true)
{
t += Time.deltaTime;
if (t >= deltaT)
{
i++;
if (i > len)
{
break;
}
t = 0;
Vprev = Vector2.zero;
}
Vprev = Vnext(Vprev, m_Acceler[i], m_Acceler[i], t);
m_Dot.velocity = Vprev;
yield return new WaitForEndOfFrame();
}
m_Dot.velocity = Vector3.zero;
yield return null;
}
private Vector2 Vnext(Vector2 Vn, Vector2 Anext, Vector2 An, float t)
{//v[n+1]= v[n]+0,5(a[n+1] +a[n]) * t
var v = Vn + 0.5f * (Anext + An) * t;
return v;
}
}

For some reason when I reactivate objects in my object pool they are static?

I'm currently working on a game and I ran into a small issue. I'm currently trying to create an object pool for objects that will reappear constantly in my game in order to improve the framerate of my game. However when creating this object pool whenever the game starts and the pool of objects is created and then activated and then deactivated and then reactivated again the game objects always get reactivated in a static state. I've tried going through my code to find out where this problem might be coming from but I have no Idea. All the reactivated game objects have rigidbodys and the proper tags.
Ive tried going trough all the different classes which might be creating this problem but I haven't found anything out of the ordinary myself.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnPoint: MonoBehaviour
{
public Transform SpawnPoints;
public GameObject[] interact;
List<float> StarPositions = new List<float>();
int Interact;
int index = 1;
public int pooledAmount = 40;
List<GameObject> colouredBalls;
public static bool spawnAllowed;
public static int count = 0;
public void Start()
{
colouredBalls = new List<GameObject>();
for (int c = 0; c < pooledAmount; c++)
{
GameObject obj = (GameObject)Instantiate(interact[0]);
obj.SetActive(false);
colouredBalls.Add(obj);
}
if (ScoreScript.scoreValue < 5)
{
Vector2 pos = Camera.main.WorldToViewportPoint(transform.position);
for (int x = 1; x < 5; x++)
{
//Vector3 SpawnPos = spawnPoints[d].position;
int NrSpawnpoints = 4;
int NrSpaces = NrSpawnpoints + 1;
double Xlegnth = 1.0;
double spawnPosX = x * Xlegnth / NrSpaces;
pos.x = (float)spawnPosX;
pos.y = 1.3f;
Vector2 Posi = Camera.main.ViewportToWorldPoint(pos);
Instantiate(SpawnPoints, Posi, Quaternion.identity);
//Debug.Log(Posi);
}
}
spawnAllowed = true;
InvokeRepeating("SpawnAInteract", 0f, 1f);
}
void SpawnAInteract()
{
if (spawnAllowed)
{
int randomSpawnPoint;
Vector2 pos = Camera.main.WorldToViewportPoint(transform.position);
//Vector2 starpos = Camera.main.WorldToViewportPoint(transform.position);
if (index % 10 != 0)
{
for (int d = 1; d < 5; d++)
{
//Vector3 SpawnPos = spawnPoints[d].position;
int NrSpawnpoints = 4;
int NrSpaces = NrSpawnpoints + 1;
double Xlegnth = 1.0;
double spawnPosX = d * Xlegnth / NrSpaces;
pos.x = (float)spawnPosX;
pos.y = 1.3f;
Vector2 Posi = Camera.main.ViewportToWorldPoint(pos);
if (!colouredBalls[d].activeInHierarchy)
{
colouredBalls[d].transform.position = Posi;
colouredBalls[d].transform.rotation = transform.rotation;
colouredBalls[d].SetActive(true);
//Debug.Log("Nr active Balls:" + f + colouredBalls[f].activeInHierarchy);
Debug.Log("Nr active Balls:" + d + colouredBalls[d].activeInHierarchy);
count++;
break;
}
}
index++;
}
else
{
for (int d = 1; d < 5; d++)
{
int NrSpawnpoints = 4;
int NrSpaces = NrSpawnpoints + 1;
double Xlegnth = 1.0;
double spawnPosX = d * Xlegnth / NrSpaces;
pos.x = (float)spawnPosX;
pos.y = 1.3f;
Vector2 Posi = Camera.main.ViewportToWorldPoint(pos);
StarPositions.Add((float)spawnPosX);
//Debug.Log("Starpositions " + StarPositions.ToString());
//edit this
double StarPos = spawnPosX - Xlegnth / NrSpaces / 2;
//Change to a list
//Debug.Log("Star " + d);
StarPositions[d - 1] = (float)StarPos;
}
//edit this to make the star appear at the StarPosition directly to the left or to the right of the WhiteBall
Vector2 Start = new Vector2(0, 0);
Vector2 StartCon = Camera.main.ViewportToWorldPoint(Start);
float whiteBallX = GameObject.FindWithTag("White Ball").transform.position.x;
for (int d = 1; d < 5; d++)
{
if (whiteBallX >= StartCon.x && whiteBallX <= StarPositions[d - 1])
{
int[] potentialStarPositions = { d, d + 2 };
int positionIndex = Random.Range(0, 2);
int randomSpawnPoin = potentialStarPositions[positionIndex];
pos.x = StarPositions[randomSpawnPoin];
pos.y = 1.3f;
Vector2 StarPosi = Camera.main.ViewportToWorldPoint(pos);
Interact = 1;
Instantiate(interact[Interact], StarPosi, Quaternion.identity);
break;
}
}
index++;
}
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectDestroy: MonoBehaviour
{
public Transform CameraCollider;
int NonActive = 0;
void Start()
{
Vector3 ScreenSize = new Vector3(1.5f, 1.5f, 1.5f);
Vector3 ScreenSizeAdj = Camera.main.ViewportToWorldPoint(ScreenSize);
CameraCollider.localScale = ScreenSizeAdj;
Vector3 ScreenPos = new Vector3(0.5f, 0.5f, 0);
Vector3 ScreenPosAdj = Camera.main.ViewportToWorldPoint(ScreenPos);
Instantiate(CameraCollider, ScreenPosAdj, Quaternion.identity);
}
private void OnTriggerExit2D(Collider2D other)
{
if (other.gameObject.CompareTag("ColouredBall Highress") || other.gameObject.CompareTag("Star"))
{
other.gameObject.SetActive(false);
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InteractControl : MonoBehaviour
{
Rigidbody2D rb;
GameObject target;
float moveSpeed;
Vector3 directionToTarget;
Renderer m_Renderer;
void Start()
{
target = GameObject.Find("White Ball");
rb = GetComponent<Rigidbody2D>();
moveSpeed = 3f; //Movement speed of all the obstacles and powerups
MoveInteract(); //Method responsable for the movement of the obstacles and powerups, gets called at start
}
void MoveInteract() //Method responsable for the movement of the obstacles and stars
{
if (target != null)
{
if(ScoreScript.scoreValue > 5) //Determine when RedBall goes from going down in a straigh line to following white ball
{
directionToTarget = (target.transform.position - transform.position).normalized;
rb.velocity = new Vector2(directionToTarget.x * moveSpeed,
directionToTarget.y * moveSpeed);
}
else //Red Ball goes down in a straigh line
{
directionToTarget = new Vector3(0, -1, 0);
rb.velocity = new Vector2(0, directionToTarget.y * moveSpeed);
}
}
else
rb.velocity = Vector3.zero;
}
}
This is normal, when you deactivate an object the velocity resets. You must save their velocity before deactivating then set it again when reactivated.
I would look for other kind of optimization, this makes code more complex and probably there are better ways of optimizing it.
Edit: A quick solution would be to deactivate the sprite renderer, instead of the whole game object. This would optimize gpu load which I guess is the problem.

Collision Detection in C# XNA

Collision detection has been a huge issue for me lately, been breaking my mind over this particular problem.
After I got a reasonable collision detection for my Super Mario World remake in C# (XNA) I have the following problem: I keep getting sort of stuck in blocks when I jump against them...
Example: https://gyazo.com/0f1ac6f4894f41aa4bcbdc73e572e36d
This is my current code than handles the collision: http://pastebin.com/iWsnffWQ
If anyone knows anything that could help my problem, I have been searching high and low for the solution but I to no avail...
EDIT:
This problem has been fixed though a new one arised with object collision on the infamous mario "Mystery Blocks". Whenever I stand on them (not moving) either mario or the world starts to vibrate up and down by about one pixel.
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
namespace PlatFormer
{
public abstract class Entity
{
protected ContentManager _Content;
protected Texture2D _Image;
protected Texture2D _Outline;
protected SpriteSheetAnimation _MoveAnimation;
protected FileManager _FileManager;
protected List<List<string>> _Attributes;
protected List<List<string>> _Contents;
protected Vector2 _Velocity;
protected Vector2 _PrevPosition;
protected Vector2 _Frames;
protected Rectangle _Collbox;
private Rectangle _TileBounds;
protected int _Health;
protected float _MoveSpeed;
protected float _Gravity;
protected float _PreviousBottom;
protected bool _ActivateGravity;
protected bool _TilePositionSync;
protected bool _FacingRight;
protected const float _Friction = 0.9f;
protected const float _Grav = 10f;
protected const float _TerminalVelocity = 10f;
protected Vector2 _Acceleration;
public bool _OnGround;
protected bool _IsJumping;
protected int collisiondeny;
public Vector2 Position;
public SpriteSheetAnimation Animation
{
get { return _MoveAnimation; }
}
public virtual void LoadContent(ContentManager content)
{
_Content = new ContentManager(content.ServiceProvider, "Content");
_Attributes = new List<List<string>>();
_Contents = new List<List<string>>();
}
public virtual void LoadContent(ContentManager content, InputManager input)
{
_Content = new ContentManager(content.ServiceProvider, "Content");
_Attributes = new List<List<string>>();
_Contents = new List<List<string>>();
}
public virtual void UnloadContent()
{
_Content.Unload();
}
public virtual void Update(GameTime gameTime, List<List<WorldTile>> TileMap, List<Enemy> EntList)
{
_PrevPosition = Position;
Position.X = _FacingRight ? Position.X + _MoveSpeed : Position.X - _MoveSpeed;
_Velocity.Y += _Gravity;
if (!_OnGround) { }
else
_Velocity.Y = 0;
UpdatePhysics(gameTime, TileMap, EntList);
_MoveAnimation.Position = Position;
_MoveAnimation.Update(gameTime);
}
public virtual void Update(GameTime gameTime, InputManager input, List<List<WorldTile>> TileMap)
{
}
public virtual void Draw(SpriteBatch spriteBatch)
{
_MoveAnimation.Draw(spriteBatch);
}
protected virtual void UpdatePhysics(GameTime gameTime, List<List<WorldTile>> TileMap, List<Enemy> EntList)
{
_Acceleration *= _Friction;
_Velocity *= _Friction;
_Velocity += _Acceleration;
Position.X = _FacingRight ? Position.X + _Velocity.X : Position.X - _Velocity.X;
Position.Y += _Velocity.Y;
if (Math.Abs(_Acceleration.X) < 0.001f)
{
_MoveAnimation.IsActive = false;
}
UpdateCollBox();
CollisionHandle(TileMap);
EntCollisionHandle(EntList);
if (Position.X == _PrevPosition.X)
_Velocity.X = 0;
if (Position.Y == _PrevPosition.Y)
_Velocity.Y = 0;
}
protected virtual void UpdatePhysics(GameTime gameTime, InputManager input, List<List<WorldTile>> TileMap)
{
float totalSecElapsed = gameTime.ElapsedGameTime.Milliseconds / 1000f;
_Acceleration.X *= _Friction;
_Velocity.X *= _Friction;
_Acceleration.Y = _Grav;
_Velocity.Y += _Acceleration.Y * totalSecElapsed;
_Velocity.X += _Acceleration.X;
if (_Velocity.Y >= _TerminalVelocity)
{
_Velocity.Y = _TerminalVelocity;
}
Position += _Velocity;
if (Math.Abs(_Acceleration.X) < 0.001f)
{
_MoveAnimation.IsActive = false;
}
UpdateCollBox();
CollisionHandle(TileMap); //replace with horizontal collision first then vertical collision
//TestCollisionHandle(TileMap);
if (Position.X == _PrevPosition.X)
_Velocity.X = 0;
if (Position.Y == _PrevPosition.Y)
_Velocity.Y = 0;
}
public void ObjectCollision(List<LevelObject> obj)
{
//OnThisNiceMysteryBox = false;
for (int i = 0; i < obj.Count; i++)
{
if (_Collbox.Intersects(obj[i].Bounds))
{
if (obj[i].Collision != TileCollision.Empty)
{
Vector2 depth = IntersectDepth(_Collbox, obj[i].Bounds);
if (depth != Vector2.Zero)
{
float absDepthX = Math.Abs(depth.X);
float absDepthY = Math.Abs(depth.Y);
if (absDepthY < absDepthX)
{
if (_Collbox.Top <= obj[i].Bounds.Bottom && _Collbox.Top >= obj[i].Bounds.Top)
{
Vector2 tempPos = obj[i].Position;
if (obj[i] is MysteryBox)
{
obj.Remove(obj[i]);
obj.Insert(i, new MysteryBox(tempPos));
}
}
if (_PreviousBottom <= obj[i].Bounds.Top)
{
_OnGround = true;
}
if (obj[i].Collision == TileCollision.Solid || _OnGround)
{
Position = new Vector2((float)Math.Round(Position.X), (float)Math.Round(Position.Y + depth.Y));
_Velocity.Y = 0;
UpdateCollBox();
}
}
else if (obj[i].Collision == TileCollision.Solid)
{
Position = new Vector2((float)Math.Round(Position.X + depth.X), (float)Math.Round(Position.Y));
UpdateCollBox();
}
}
}
}
_PreviousBottom = _Collbox.Bottom;
}
}
protected void EntCollisionHandle(List<Enemy> EntList)
{
for (int i = 0; i < EntList.Count; i++)
{
if (!(EntList[i] == this))
{
Vector2 intersection = IntersectDepth(this._Collbox, EntList[i]._Collbox);
if (intersection != Vector2.Zero)
{
if (collisiondeny == 0)
{
_FacingRight = !_FacingRight;
Position.X = _FacingRight ? Position.X - intersection.X : Position.X + intersection.X;
collisiondeny = 1;
}
else
{
collisiondeny--;
}
//if intersection has occured call both collision handles in colliding classes
}
}
}
}
protected void CollisionHandle(List<List<WorldTile>> TileMap)
{
int leftTile = (int)Math.Floor((float)_Collbox.Left / WorldTile.Width);
int rightTile = (int)Math.Ceiling(((float)_Collbox.Right / WorldTile.Width)) - 1;
int topTile = (int)Math.Floor((float)_Collbox.Top / WorldTile.Height);
int bottomTile = (int)Math.Ceiling(((float)_Collbox.Bottom / WorldTile.Height)) - 1;
_OnGround = false;
for (int y = topTile; y <= bottomTile; y++)
{
for (int x = leftTile; x <= rightTile; x++)
{
TileCollision collision = TileCollision.Empty;
if (y >= 0)
{
if (x >= 0)
{
if (y < TileMap.Count && x < TileMap[y].Count)
collision = TileMap[y][x].Collision;
}
else
{
collision = TileCollision.Solid;
}
}
if (collision != TileCollision.Empty)
{
_TileBounds = new Rectangle(x * WorldTile.Width, y * WorldTile.Height, WorldTile.Width, WorldTile.Height);
Vector2 depth = IntersectDepth(_Collbox, _TileBounds);
if (depth != Vector2.Zero)
{
float absDepthX = Math.Abs(depth.X);
float absDepthY = Math.Abs(depth.Y);
if (absDepthY <= absDepthX || collision == TileCollision.OneWay)
{
if (_PreviousBottom <= _TileBounds.Top)
_OnGround = true;
if ((collision == TileCollision.Solid) || _OnGround)
{
Position = new Vector2((int)Math.Round(Position.X), (int)Math.Round(Position.Y + depth.Y));
UpdateCollBox();
}
}
else if (collision == TileCollision.Solid)
{
Position = new Vector2((int)Math.Round(Position.X + depth.X), (int)Math.Round(Position.Y));
_FacingRight = !_FacingRight;
//_Velocity.Y = 0;
UpdateCollBox();
}
}
}
}
}
_PreviousBottom = _Collbox.Bottom;
}
protected void TestCollisionHandle(List<List<WorldTile>> TileMap)
{
int leftTile = (int)Math.Floor((float)_Collbox.Left / WorldTile.Width);
int rightTile = (int)Math.Ceiling(((float)_Collbox.Right / WorldTile.Width)) - 1;
int topTile = (int)Math.Floor((float)_Collbox.Top / WorldTile.Height);
int bottomTile = (int)Math.Ceiling(((float)_Collbox.Bottom / WorldTile.Height)) - 1;
_OnGround = false;
for (int y = topTile; y <= bottomTile; y++)
{
for (int x = leftTile; x <= rightTile; x++)
{
TileCollision collision = TileCollision.Empty;
if (y >= 0)
{
if (x >= 0)
{
if (y < TileMap.Count && x < TileMap[y].Count)
collision = TileMap[y][x].Collision;
}
}
if(collision != TileCollision.Empty)
{
//if collision can occor, get tilecollisionbox for horizontal
_TileBounds = new Rectangle(x * WorldTile.Width, y * WorldTile.Height, WorldTile.Width, WorldTile.Height);
//get the horizontal collision depth, will return zero if none is found
GetHorizontalIntersectionDepth(_Collbox, _TileBounds);
}
}
}
_PreviousBottom = _Collbox.Bottom;
}
private void UpdateCollBox()
{
_Collbox = new Rectangle((int)Math.Round(Position.X), (int)Math.Round(Position.Y), Animation.FrameWidth, Animation.FrameHeight);
}
private Vector2 IntersectDepth(Rectangle rectangleA, Rectangle rectangleB)
{
float halfWidthA = rectangleA.Width / 2.0f;
float halfHeightA = rectangleA.Height / 2.0f;
float halfWidthB = rectangleB.Width / 2.0f;
float halfHeightB = rectangleB.Height / 2.0f;
Vector2 centerA = new Vector2(rectangleA.Left + halfWidthA, rectangleA.Top + halfHeightA);
Vector2 centerB = new Vector2(rectangleB.Left + halfWidthB, rectangleB.Top + halfHeightB);
float distanceX = centerA.X - centerB.X;
float distanceY = centerA.Y - centerB.Y;
float minDistanceX = halfWidthA + halfWidthB;
float minDistanceY = halfHeightA + halfHeightB;
// If no intersection is happening, return Vector2.Zero
if (Math.Abs(distanceX) >= minDistanceX || Math.Abs(distanceY) >= minDistanceY)
return Vector2.Zero;
// Calculate instersection depth
float depthX = distanceX > 0 ? minDistanceX - distanceX : -minDistanceX - distanceX;
float depthY = distanceY > 0 ? minDistanceY - distanceY : -minDistanceY - distanceY;
return new Vector2(depthX, depthY);
}
private float GetHorizontalIntersectionDepth(Rectangle rectA, Rectangle rectB)
{
// Calculate half sizes.
float halfWidthA = rectA.Width / 2.0f;
float halfWidthB = rectB.Width / 2.0f;
// Calculate centers.
float centerA = rectA.Left + halfWidthA;
float centerB = rectB.Left + halfWidthB;
// Calculate current and minimum-non-intersecting distances between centers.
float distanceX = centerA - centerB;
float minDistanceX = halfWidthA + halfWidthB;
// If we are not intersecting at all, return (0, 0).
if (Math.Abs(distanceX) >= minDistanceX)
return 0f;
// Calculate and return intersection depths.
return distanceX > 0 ? minDistanceX - distanceX : -minDistanceX - distanceX;
}
private float GetVerticalIntersectionDepth(Rectangle rectA, Rectangle rectB)
{
// Calculate half sizes.
float halfHeightA = rectA.Height / 2.0f;
float halfHeightB = rectB.Height / 2.0f;
// Calculate centers.
float centerA = rectA.Top + halfHeightA;
float centerB = rectB.Top + halfHeightB;
// Calculate current and minimum-non-intersecting distances between centers.
float distanceY = centerA - centerB;
float minDistanceY = halfHeightA + halfHeightB;
// If we are not intersecting at all, return (0, 0).
if (Math.Abs(distanceY) >= minDistanceY)
return 0f;
// Calculate and return intersection depths.
return distanceY > 0 ? minDistanceY - distanceY : -minDistanceY - distanceY;
}
public enum Direction
{
Horizontal,
Vertical
}
private bool TileIntersectsPlayer(Rectangle player, Rectangle block, Direction direction, out Vector2 depth)
{
depth = direction == Direction.Vertical ? new Vector2(0, GetVerticalIntersectionDepth(player, block)) : new Vector2(GetHorizontalIntersectionDepth(player, block), 0);
return depth.Y != 0 || depth.X != 0;
}
}
}
Consider using or just compare your code to the libraries that exist already: see GeoLib which is very simple to use and/or clipper lib. 'Do not reinvent...'

Categories

Resources