Can anyone point me in the right direction as to what am I doing wrong here. My line does get created but but when I move the cursor up to create an angle in the line created to form an arc, simply nothin happens.
private void CreateArc(PlaneEx plane, Vector2 p0, Vector2 p1, Vector2 p2)
{
this.spots_.Clear();
ArcToolProperties arcToolProperties = this.Properties<ArcToolProperties>();
List<Vector2> outPoints;
if (!MathUtil.CreateArc(new Edge2D(p0, p1), p2, arcToolProperties.segment, out outPoints, out Vector2 _))
{
this.spots_.Add(this.first_);
this.spots_.Add(this.second_);
this.arcCenter_ = (this.first_.pos + this.second_.pos) / 2f;
}
else
{
for (int index = 0; index < outPoints.Count; ++index)
{
this.spots_.Add(this.first_);
first_.pos = plane.FromPlaneCoord(outPoints[index]);
first_.snapStatus = ESnapStatus.None;
}
this.arcCenter_ = outPoints.Count % 2 != 0 ? plane.FromPlaneCoord(outPoints[outPoints.Count / 2]) : plane.FromPlaneCoord((outPoints[outPoints.Count / 2] + outPoints[outPoints.Count / 2 - 1]) / 2f);
if (this.spots_.Count <= 0)
return;
this.spots_[0] = this.first_;
this.spots_[this.spots_.Count - 1] = this.second_;
}
I want to scale a rectangle made of 4 vertexes in a list simply with the value 0.5. So I mean by that, just make it 0.5 units bigger. The new values should be stored in another list which I named list2 here.
My first thought was trying this:
foreach (Vector3 element in list)
{
if(element.x < 0 && element.z < 0)
{
list2.Add(new Vector3(element.x - 0.5f, 0, element.z - 0.5f));
}
else if(element.x > 0 && element.z > 0)
{
list2.Add(new Vector3(element.x + 0.5f, 0, element.z + 0.5f));
}
else if (element.x < 0 && element.z > 0)
{
list2.Add(new Vector3(element.x - 0.5f, 0, element.z + 0.5f));
}
else if (element.x > 0 && element.z < 0)
{
list2.Add(new Vector3(element.x + 0.5f, 0, element.z - 0.5f));
}
}
I firstly thought that's the way to go, but I realised it would be a problem if the elements are partially equal to 0.
My question now is, is there any way to scale Vector3 points and simply make them bigger or smaller, independing where they are in the coordinate system?
I googled already but only found a given function which helps to scale a Vector but its only scaling by multiplication with a factor and I want to scale it only with 0.5 units.
Maybe you guys can help a noob out. :D
Thanks in advance.
If you already know the order of vertices e.g. in your case counter-clockwise starting at bottom-left I wouldn't use a loop with conditions but rather directly do
public List<Vector3> ScaleRectangleByStep(List<Vector3> vertices, float step)
{
// copy the given list
var output = new List<Vector3>(vertices);
output[0] = output[0] - Vector3.right * step - Vector3.forward * step;
output[1] = output[1] + Vector3.right * step - Vector3.forward * step;
output[2] = output[2] + Vector3.right * step + Vector3.forward * step;
output[3] = output[3] - Vector3.right * step + Vector3.forward * step;
return output;
}
If you don't know the order you would rather somehow get center position in order to check
public List<Vector3> ScaleRectangleByStep(List<Vector3> vertices, float step)
{
// copy the given list
var output = new List<Vector3>(vertices);
// Get the center of the rectangle
var center = Vector3.zero;
foreach(var vertex in output)
{
center += vertex;
}
center /= output.Count;
// in a second run use the center for your conditions
for(var i = 0; i < output.Count; i++)
{
var vertex = output[i];
if(vertex.x < center.x)
{
vertex.x -= step;
}
else if(vertex.x > center.x)
{
vertex.x += step;
}
if(vertex.z < center.z)
{
vertex.z -= step;
}
else if(vertex.z > center.z)
{
vertex.z += step;
}
// the else cases would basically mean that the vertices
// are equal to the center ...
output[i] = vertex;
}
return output;
}
Or as a complete alternative if instead of moving the borders by certain units you rather want to scale by a certain factor I would rather do it like
public List<Vector3> ScaleRectangleByFactor(List<Vector3> vertices, float multiplicationFactor)
{
// copy the given list
var output = new List<Vector3>(vertices);
// first find the center position
var center = Vector3.zero;
foreach(var vertex in output)
{
center += vertex;
}
center /= list.Count;
// Now scale every vertex relative to the center position with the given factor
for(var i = 0; i < output.Count; i++)
{
// Get the position relative to the center
var relativePosition = (output[i] - center);
// scale it up by the given factor
relativePosition *= multiplicationFactor;
// assign it back to the list
output[i] = center + relativePosition;
}
return output;
}
I'm trying to create a Line of Sight method for an enemy class. However, it always returns false, no matter how close the player is to the enemy or whether the ray passes through any blocks to get to the player.
public virtual bool PlayerInLOS()
{
Vector3 middleOfPlayer = new Vector3(Level.Player.Position.X, Level.Player.Position.Y - Level.Player.BoundingRectangle.Height / 2, 0);
Vector3 middleOfEnemy = new Vector3(Position.X, Position.Y - localBounds.Height / 2, 0);
Vector3 direction = middleOfPlayer - middleOfEnemy;
float distanceToPlayer = Vector3.Distance(middleOfEnemy, middleOfPlayer);
if (direction != Vector3.Zero)
direction.Normalize();
Ray lineOfSight = new Ray(middleOfEnemy, direction);
float? lineToPlayer = lineOfSight.Intersects(Level.Player.BoundingBox);
foreach (BoundingBox box in Level.boundingBoxes)
{
float? distanceToIntersect = lineOfSight.Intersects(box);
if (distanceToIntersect == null)
continue;
else if (distanceToIntersect < visionLength && distanceToIntersect < distanceToPlayer && distanceToIntersect != null)
return false;
}
// Never gets to this part because it always returns before it exits the for loop
if (lineToPlayer < visionLength)
return true;
else return false;
}
Any ideas? Thanks.
I ended up fixing the problem by implementing an entirely different solution: checking every Vector2 along the distance between the enemy and the player. Works perfectly.
public bool CanSeePlayer()
{
Vector2 middleOfPlayer = new Vector2(Level.Player.Position.X, Level.Player.Position.Y - Level.Player.BoundingRectangle.Height / 2);
Vector2 middleOfEnemy = new Vector2(Position.X, Position.Y - localBounds.Height / 2);
Vector2 direction = middleOfPlayer - middleOfEnemy;
float distanceToPlayer = Vector2.Distance(middleOfEnemy, middleOfPlayer);
if (visionLength > distanceToPlayer) // If the enemy can see farther than the player's distance,
{
if (direction != Vector2.Zero)
direction.Normalize();
for (int y = 0; y < Level.tiles.GetLength(1); ++y) // loop through every tile,
{
for (int x = 0; x < Level.tiles.GetLength(0); ++x)
{
if (Level.GetCollision(x, y) != TileCollision.Passable) // and if the block is solid,
{
Vector2 currentPos = middleOfEnemy;
float lengthOfLine = 0.0f;
Rectangle tileRect = new Rectangle(x * Tile.Width, y * Tile.Height, Tile.Width, Tile.Height);
while (lengthOfLine < distanceToPlayer + 1.0f) // check every point along the line
{
currentPos += direction;
if (tileRect.Contains(currentPos)) // to see if the tile contains it.
{
return false;
}
lengthOfLine = Vector2.Distance(middleOfEnemy, currentPos);
}
}
}
}
// If every tile does not contain a single point along the line from the enemy to the player,
return true;
}
return false;
}
If you need to check if enemy is within angle of sight, and in some distance you could try this code.
public static bool InLOS(float AngleDistance, float PositionDistance, Vector2 PositionA, Vector2 PositionB, float AngleB)
{
float AngleBetween = (float)Math.Atan2((PositionA.Y - PositionB.Y), (PositionA.X - PositionB.X));
if ((AngleBetween <= (AngleB + (AngleDistance / 2f / 100f))) && (AngleBetween >= (AngleB - (AngleDistance / 2f / 100f))) && (Vector2.Distance(PositionA, PositionB) <= PositionDistance)) return true;
else return false;
}
credits: https://gamedev.stackexchange.com/questions/26813/xna-2d-line-of-sight-check
I am making a video-game in unity, and decided to use ray-tracing. I have the code, But as you will see in a second. It isn't exactly rendering frame by frame.
Here is my raytracing code, this is the main script attached to the main camera.
using UnityEngine;
using System.Collections;
public class RayTracer : MonoBehaviour
{
public Color backgroundColor = Color.black;
public float RenderResolution = 1f;
public float maxDist = 100f;
public int maxRecursion = 4;
private Light[] lights;
private Texture2D renderTexture;
void Awake()
{
renderTexture = new Texture2D((int)(Screen.width * RenderResolution), (int)(Screen.height * RenderResolution));
lights = FindObjectsOfType(typeof(Light)) as Light[];
}
void Start()
{
RayTrace();
}
void OnGUI()
{
GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), renderTexture);
}
void RayTrace()
{
for (int x = 0; x < renderTexture.width; x++)
{
for (int y = 0; y < renderTexture.height; y++)
{
Color color = Color.black;
Ray ray = GetComponent<Camera>().ScreenPointToRay(new Vector3(x / RenderResolution, y / RenderResolution, 0));
renderTexture.SetPixel(x, y, TraceRay(ray, color, 0));
}
}
renderTexture.Apply();
}
Color TraceRay(Ray ray, Color color, int recursiveLevel)
{
if (recursiveLevel < maxRecursion)
{
RaycastHit hit;
if (Physics.Raycast(ray, out hit, maxDist))
{
Vector3 viewVector = ray.direction;
Vector3 pos = hit.point + hit.normal * 0.0001f;
Vector3 normal = hit.normal;
RayTracerObject rto = hit.collider.gameObject.GetComponent<RayTracerObject>();
//Does the object we hit have that script?
if (rto == null)
{
var GO = hit.collider.gameObject;
Debug.Log("Raycast hit failure! On " + GO.name + " position " + GO.transform.position.ToString());
return color; //exit out
}
Material mat = hit.collider.GetComponent<Renderer>().material;
if (mat.mainTexture)
{
color += (mat.mainTexture as Texture2D).GetPixelBilinear(hit.textureCoord.x, hit.textureCoord.y);
}
else
{
color += mat.color;
}
color *= TraceLight(rto, viewVector, pos, normal);
if (rto.reflectiveCoeff > 0)
{
float reflet = 2.0f * Vector3.Dot(viewVector, normal);
Ray newRay = new Ray(pos, viewVector - reflet * normal);
color += rto.reflectiveCoeff * TraceRay(newRay, color, recursiveLevel + 1);
}
if (rto.transparentCoeff > 0)
{
Ray newRay = new Ray(hit.point - hit.normal * 0.0001f, viewVector);
color += rto.transparentCoeff * TraceRay(newRay, color, recursiveLevel + 1);
}
}
}
return color;
}
Color TraceLight(RayTracerObject rto, Vector3 viewVector, Vector3 pos, Vector3 normal)
{
Color c = RenderSettings.ambientLight;
foreach (Light light in lights)
{
if (light.enabled)
{
c += LightTrace(rto, light, viewVector, pos, normal);
}
}
return c;
}
Color LightTrace(RayTracerObject rto, Light light, Vector3 viewVector, Vector3 pos, Vector3 normal)
{
float dot, distance, contribution;
Vector3 direction;
switch (light.type)
{
case LightType.Directional:
contribution = 0;
direction = -light.transform.forward;
dot = Vector3.Dot(direction, normal);
if (dot > 0)
{
if (Physics.Raycast(pos, direction, maxDist))
{
return Color.black;
}
if (rto.lambertCoeff > 0)
{
contribution += dot * rto.lambertCoeff;
}
if (rto.reflectiveCoeff > 0)
{
if (rto.phongCoeff > 0)
{
float reflet = 2.0f * Vector3.Dot(viewVector, normal);
Vector3 phongDir = viewVector - reflet * normal;
float phongTerm = max(Vector3.Dot(phongDir, viewVector), 0.0f);
phongTerm = rto.reflectiveCoeff * Mathf.Pow(phongTerm, rto.phongPower) * rto.phongCoeff;
contribution += phongTerm;
}
if (rto.blinnPhongCoeff > 0)
{
Vector3 blinnDir = -light.transform.forward - viewVector;
float temp = Mathf.Sqrt(Vector3.Dot(blinnDir, blinnDir));
if (temp != 0.0f)
{
blinnDir = (1.0f / temp) * blinnDir;
float blinnTerm = max(Vector3.Dot(blinnDir, normal), 0.0f);
blinnTerm = rto.reflectiveCoeff * Mathf.Pow(blinnTerm, rto.blinnPhongPower) * rto.blinnPhongCoeff;
contribution += blinnTerm;
}
}
}
}
return light.color * light.intensity * contribution;
case LightType.Point:
contribution = 0;
direction = (light.transform.position - pos).normalized;
dot = Vector3.Dot(normal, direction);
distance = Vector3.Distance(pos, light.transform.position);
if ((distance < light.range) && (dot > 0))
{
if (Physics.Raycast(pos, direction, distance))
{
return Color.black;
}
if (rto.lambertCoeff > 0)
{
contribution += dot * rto.lambertCoeff;
}
if (rto.reflectiveCoeff > 0)
{
if (rto.phongCoeff > 0)
{
float reflet = 2.0f * Vector3.Dot(viewVector, normal);
Vector3 phongDir = viewVector - reflet * normal;
float phongTerm = max(Vector3.Dot(phongDir, viewVector), 0.0f);
phongTerm = rto.reflectiveCoeff * Mathf.Pow(phongTerm, rto.phongPower) * rto.phongCoeff;
contribution += phongTerm;
}
if (rto.blinnPhongCoeff > 0)
{
Vector3 blinnDir = -light.transform.forward - viewVector;
float temp = Mathf.Sqrt(Vector3.Dot(blinnDir, blinnDir));
if (temp != 0.0f)
{
blinnDir = (1.0f / temp) * blinnDir;
float blinnTerm = max(Vector3.Dot(blinnDir, normal), 0.0f);
blinnTerm = rto.reflectiveCoeff * Mathf.Pow(blinnTerm, rto.blinnPhongPower) * rto.blinnPhongCoeff;
contribution += blinnTerm;
}
}
}
}
if (contribution == 0)
{
return Color.black;
}
return light.color * light.intensity * contribution;
case LightType.Spot:
contribution = 0;
direction = (light.transform.position - pos).normalized;
dot = Vector3.Dot(normal, direction);
distance = Vector3.Distance(pos, light.transform.position);
if (distance < light.range && dot > 0)
{
float dot2 = Vector3.Dot(-light.transform.forward, direction);
if (dot2 > (1 - light.spotAngle / 180))
{
if (Physics.Raycast(pos, direction, distance))
{
return Color.black;
}
if (rto.lambertCoeff > 0)
{
contribution += dot * rto.lambertCoeff;
}
if (rto.reflectiveCoeff > 0)
{
if (rto.phongCoeff > 0)
{
float reflet = 2.0f * Vector3.Dot(viewVector, normal);
Vector3 phongDir = viewVector - reflet * normal;
float phongTerm = max(Vector3.Dot(phongDir, viewVector), 0.0f);
phongTerm = rto.reflectiveCoeff * Mathf.Pow(phongTerm, rto.phongPower) * rto.phongCoeff;
contribution += phongTerm;
}
if (rto.blinnPhongCoeff > 0)
{
Vector3 blinnDir = -light.transform.forward - viewVector;
float temp = Mathf.Sqrt(Vector3.Dot(blinnDir, blinnDir));
if (temp != 0.0f)
{
blinnDir = (1.0f / temp) * blinnDir;
float blinnTerm = max(Vector3.Dot(blinnDir, normal), 0.0f);
blinnTerm = rto.reflectiveCoeff * Mathf.Pow(blinnTerm, rto.blinnPhongPower) * rto.blinnPhongCoeff;
contribution += blinnTerm;
}
}
}
}
}
if (contribution == 0)
{
return Color.black;
}
return light.color * light.intensity * contribution;
}
return Color.black;
}
float max(float x0, float x1)
{
return x0 > x1 ? x0 : x1;
}
}
And this is the code attached to the Objects in the scene
using UnityEngine;
using System.Collections;
public class RayTracerObject : MonoBehaviour
{
public float lambertCoeff = 1f;
public float reflectiveCoeff = 0f;
public float phongCoeff = 1f;
public float phongPower = 2f;
public float blinnPhongCoeff = 1f;
public float blinnPhongPower = 2f;
public float transparentCoeff = 0f;
public Color baseColor = Color.gray;
void Awake()
{
if (!GetComponent<Renderer>().material.mainTexture)
{
GetComponent<Renderer>().material.color = baseColor;
}
}
}
How would I go about doing this? And what would the code be?
Though raytracing in the primary thread is a perfectly acceptable design, it's probably not what you want in Unity as it blocks everything else.
Now you could arguably spawn a child thread to perform the raytracing and having the primary thread render the results. The problem though is that neither approach makes use of the GPU which sort of defeats the point using Unity in the first place.
How to do real time Raytracing in unity with C#
It all depends on what your scene consists of and how you intend to render it. You could arguably render something simple in real-time at low resolution, however rendering with a reasonable screen resolution and with reasonable levels of ray bouncing i.e. the number of recursive light rays cast with reflective or transmissive materials would perhaps be much more difficult.
Instead I would urge you to follow the changing trend in raytracing where realtime raytracing is now being performed on the GPU using techniques known as General Purpose GPU or GPGPU. nVidia has some talks on this subject and are available on YouTube. Here is my sample Unity GPGPU galaxy simulation that might prove useful as a background to GPGPU.
Sample GPGPU kernel merely to show you what GPGPU is about:
// File: Galaxy1Compute.compute
// Each #kernel tells which function to compile; you can have many kernels
#pragma kernel UpdateStars
#include "Galaxy.cginc"
// blackmagic
#define BLOCKSIZE 128
RWStructuredBuffer<Star> stars;
Texture2D HueTexture;
// refer to http://forum.unity3d.com/threads/163591-Compute-Shader-SamplerState-confusion
SamplerState samplerHueTexture;
// time ellapsed since last frame
float deltaTime;
const float Softening=3e4f;
#define Softening2 Softening * Softening
static float G = 6.67300e-11f;
static float DefaultMass = 1000000.0f;
// Do a pre-calculation assuming all the stars have the same mass
static float GMM = G*DefaultMass*DefaultMass;
[numthreads(BLOCKSIZE,1,1)]
void UpdateStars (uint3 id : SV_DispatchThreadID)
{
uint i = id.x;
uint numStars, stride;
stars.GetDimensions(numStars, stride);
float3 position = stars[i].position;
float3 velocity = stars[i].velocity;
float3 A=float3(0,0,0);
[loop]
for (uint j = 0; j < numStars; j++)
{
if (i != j)
{
float3 D = stars[j].position - stars[i].position;
float r = length(D);
float f = GMM / (r * r + Softening2);
A += f * normalize(D);
}
}
velocity += A * deltaTime;
position += velocity * deltaTime;
if (i < numStars)
{
stars[i].velocity = velocity;
stars[i].position = position;
stars[i].accelMagnitude = length(A);
}
}
Additionally there are some fine books on the subject. Real-time Volume Graphics, though it covers volumes, it does cover casting rays - the essence of ray-tracing. The hardest paradigm shift is the writing for GPGPU, once you understand it, writing a GPGPU raytracer is an easy step from GPGPU volume shaders.
A marvellous tome to accompany any raytrace author is Matt Pharr's Physically Based Rendering book (there is a 2nd edition but I have not read that)
More
GPU Ray Tracing in Unity – Part 1
Nvidia announced NVIDIA RTX™, a ray-tracing technology that brings real-time, cinematic-quality rendering to content creators and game developers.
It consists of a ray-tracing engine running on NVIDIA Volta architecture GPUs. It’s designed to support ray tracing through a variety of interfaces.
And these results in bringing the game developers to do raycasting in their work to get a movie quality output.
https://nvidianews.nvidia.com/news/nvidia-rtx-technology-realizes-dream-of-real-time-cinematic-rendering
Unity in the future update would support this new DirectX Raytracing API. Then the game developers can enjoy the photorealistic quality output in their unity rendering pipeline.
So after we all saw a hype around RTX cards, we need to answer a question, what is it actually doing? Well, basically it is hardware accelerated raycaster, which is well optimized to do its job at it.
But nobody said you can't do hardware accelerated raycasting on let's say any other graphics card. In Unity, you have access to hardware acceleration in the form of shaders. you can write your own raycaster with the power of compute shaders. which will be much slower then very very optimized RTX cards but give you an advantage in some areas.
But hey man, since it is slower then RTX why would I need to do so. Well, in general, you can enhance your rendring with this method. For example softening shadows, attempting Global illumination, all sorts of stuff. But to answer your question, you won't be able to do a full-blown raytracing without RTX cards.
Hi and thanks for reading.
I need to change this void I wrote so that it can work with negative angles.
The goal of this function is to rotate an ANGLE towards the DIRECTION by adding INCREMENT to either clockwise or counterclockwise (+ or -).
However the problem as I said is that it does not work with numbers less than 0 or greater than 360 (2pi). I need to be able to use negative angles as well.
I tried several stuff but couldn't get it to work for a while. Can anyone lend me a hand? I'll be grateful. :D
public void ToDirection(float Increment, float Direction)
{
if (CurrentAngle != Direction)
{
float ClockwiseDifference;
float CounterClockwiseDifference;
//Clockwise
if (Direction < CurrentAngle)
{
ClockwiseDifference = CurrentAngle - Direction;
}
else
{
ClockwiseDifference = Constants.Rotation_360 - (Direction - CurrentAngle);
}
//CounterClockwise
if (Direction > CurrentAngle)
{
CounterClockwiseDifference = Direction - CurrentAngle;
}
else
{
CounterClockwiseDifference = Constants.Rotation_360 - (CurrentAngle - Direction);
}
float CurrentFaceSpeed = Increment;
if (ClockwiseDifference == CounterClockwiseDifference)
{
if (Globals.Randomizer.Next(0, 2) == 0)
{
if (ClockwiseDifference < CurrentFaceSpeed)
{
CurrentAngle = Direction;
}
else
{
CurrentAngle -= CurrentFaceSpeed;
}
}
else
{
if (CounterClockwiseDifference < CurrentFaceSpeed)
{
CurrentAngle = Direction;
}
else
{
CurrentAngle += CurrentFaceSpeed;
}
}
}
else if (ClockwiseDifference < CounterClockwiseDifference)
{
if (ClockwiseDifference < CurrentFaceSpeed)
{
CurrentAngle = Direction;
}
else
{
CurrentAngle -= CurrentFaceSpeed;
}
}
else
{
if (CounterClockwiseDifference < CurrentFaceSpeed)
{
CurrentAngle = Direction;
}
else
{
CurrentAngle += CurrentFaceSpeed;
}
}
}
if (CurrentAngle >= Constants.Rotation_360)
{
CurrentAngle -= Constants.Rotation_360;
}
else if (CurrentAngle < 0)
{
CurrentAngle += Constants.Rotation_360;
}
}
Simply unwrap the angle. Then you'll always have angles from 0 to 360. Unwrap the starting angle and the target angle, then perform your turn. Here's a working example (the only method you really need is UnwrapAngle()).
internal class Program {
private static object UnwrapAngle(double angle) {
if (angle >= 0) {
var tempAngle = angle % 360;
return tempAngle == 360 ? 0 : tempAngle;
}
else
return 360 - (-1 * angle) % 360;
}
private static void TestUnwrap(double angle, double expected) {
Console.WriteLine(String.Format("{0} unwrapped = {1}, expected {2}", angle, UnwrapAngle(angle), expected));
}
private static void Main(string[] args) {
TestUnwrap(0, 0);
TestUnwrap(360, 0);
TestUnwrap(180, 180);
TestUnwrap(360 + 180, 180);
TestUnwrap(-270, 90);
TestUnwrap(-270 - 720, 90);
TestUnwrap(-725, 355);
Console.ReadLine();
}
}
This answer seems to cover the topic quite well:
Work out whether to turn clockwise or anticlockwise from two angles
RE: angles that are less than 0 or greater than 360. Basically, -10 is the same as 350. 720 is the same as 360. So if you translate the incoming angle so that it lies between 0 and 360, all your problems are solved (presuming your code works for values between 0 & 360 as you suggest).
This is something I've done myself (in a different language before):
var wantDir;
var currDir;
var directiondiff;
var maxTurn;
// want - this is your target direction \\
wantDir = argument0;
// max turn - this is the max number of degrees to turn \\
maxTurn = argument1;
// current - this is your current direction \\
currDir = direction;
if (wantDir >= (currDir + 180))
{
currDir += 360;
}
else
{
if (wantDir < (currDir - 180))
{
wantDir += 360;
}
}
directiondiff = wantDir - currDir;
if (directiondiff < -maxTurn)
{
directiondiff = -maxTurn
}
if (directiondiff > maxTurn)
{
directiondiff = maxTurn
}
// return the resultant directional change \\
return directiondiff