Doom-like angle based sprite changing - c#

So, i'm trying to make a first person game that used the same sprite mechanics as games like Doom, Duke Nukem and etc.
So far, i can identify the angle I'm at in relation to static objects, but not to rotating ones. I have some "enemies" that change rotation and start following me, but calculating the tangent angle (Mathf.Atan2) doesn't take the enemy's rotation in consideration.
Here's the code i'm using so far, which works perfectly for objects that dont rotate:
int GetAngleIndex()
{
var dir = cam.transform.position - transform.parent.forward;
var enemyAngle = Mathf.Atan2(dir.z, dir.x) * Mathf.Rad2Deg;
if (enemyAngle < 0.0f)
enemyAngle += 360;
Debug.Log("Angle from the player is: " + enemyAngle);
if (enemyAngle >= 292.5f && enemyAngle < 337.5f)
return 8;
else if (enemyAngle >= 22.5f && enemyAngle < 67.5f)
return 2;
else if (enemyAngle >= 67.5f && enemyAngle < 112.5f)
return 3;
else if (enemyAngle >= 112.5f && enemyAngle < 157.5f)
return 4;
else if (enemyAngle >= 157.5f && enemyAngle < 202.5f)
return 5;
else if (enemyAngle >= 202.5f && enemyAngle < 247.5f)
return 6;
else if (enemyAngle >= 247.5f && enemyAngle < 292.5f)
return 7;
else if (enemyAngle >= 337.5f || enemyAngle < 22.5f)
return 1;
else return 0;
}
I've searched for hours and I can't find a solution to this :(

You say your [only] problem is that it doesn't take their rotation into account - I'm guessing that means that you're not having trouble billboarding your sprites, and your rotation works when they're facing forward. To that end:
The dot product of vectors a and b is equal to cos(theta)*magnitude(a)*magnitude(b). So if a is the vector from the camera to the object:
var a = cam.transform.position - transform.parent.position
and b is the object's forward:
var b = transform.parent.forward
and we know that a and b both have magnitude 1
a.Normalize();
//b is already normalized
then we know that this is equal to cos(theta), where theta is the angle between them.
var theta = Mathf.Acos(Vector3.Dot(a, b)) * Mathf.Rad2Deg;
However. Theta is the shortest necessary angle - so it will be from 0 to 180. Given your switch table up there, we know that when we're hoping to go around the wrong way, we'll be in the wrong position. so to fix that:
if (a.x * a.z < 0)
theta = 360.0f - theta;
then we just plug it in and go. Here's the full file in my project:
using UnityEngine;
public class spriteAngler : MonoBehaviour
{
public Transform toFace;
public SpriteRenderer toManipulate;
public Sprite[] mySprites;
private float theta;
private Vector3 a;
void Update()
{
toManipulate.sprite = mySprites[GetAngleIndex()];
}
int GetAngleIndex()
{
a = toFace.position - transform.position;
a.Normalize();
var b = transform.forward;
theta = Mathf.Acos(Vector3.Dot(a, b)) * Mathf.Rad2Deg;
if (a.x * a.z < 0)
theta = 360.0f - theta;
if (theta >= 292.5f && theta < 337.5f)
return 7;
else if (theta >= 22.5f && theta < 67.5f)
return 1;
else if (theta >= 67.5f && theta < 112.5f)
return 2;
else if (theta >= 112.5f && theta < 157.5f)
return 3;
else if (theta >= 157.5f && theta < 202.5f)
return 4;
else if (theta >= 202.5f && theta < 247.5f)
return 5;
else if (theta >= 247.5f && theta < 292.5f)
return 6;
else if (theta >= 337.5f || theta < 22.5f)
return 0;
else return 0;
}
private Rect guiPos = new Rect(0, 0, 720, 30);
void OnGUI()
{
GUI.Label(guiPos, "Angle from the Player is: " + theta + " and forward=" + transform.forward + " and vectorToTarget=" + a);
}
}
and if that needs a little more context, here's my project: https://github.com/AdamRGrey/22623013
I'd recommend hitting play but watching the scene window instead of the game window.

Maybe I'm not understanding the exact effect you're trying to create here (And if so please provide more information such as screenshots in your post), but you should be able to simply use Transform.LookAt(). These are typically called Billboard Sprites.
Example:
Transform.LookAt(Camera.main.transform.position, Vector3.up)

I guess what you are mentioning is the concept of Billboards.
Here is a sample in unity wiki for creating Billboards that always face Camera, go ahead and give it a try.
http://wiki.unity3d.com/index.php?title=CameraFacingBillboard

Related

I need help on the math for detecting the "side" of collision on a rotating sprite

So I am making a 2D space shmup that handles combat in a naval way. So you shoot out the broadsides of the ship, your shields and hull are divided into 4 sections: Forward, Starboard, Port, and Rear. I am not the greatest with math, but I managed to find a script that detects the side of my polygon collider that was hit by say a collision or projectile. That all works great.
The problem is my sprite rotates to steer in 2D space. So when I collide with something say for example with the nose of my ship, if my ship's nose is up then the collision is detected properly. But if the ship is rotated and the nose is now on the left and I collide with something on the nose, the script will detect the nose collision as a port side collision instead. Could somebody help me with correcting the math to account for my ship's rotation?
Collision2DExtension.cs
using UnityEngine;
namespace PixelsoftGames
{
public static class Collision2DExtensions
{
public static Collision2DSideType GetContactSide(Vector2 max, Vector2 center, Vector2 contact)
{
Collision2DSideType side = Collision2DSideType.None;
float diagonalAngle = Mathf.Atan2(max.y - center.y, max.x - center.x) * 180 / Mathf.PI;
float contactAngle = Mathf.Atan2(contact.y - center.y, contact.x - center.x) * 180 / Mathf.PI;
if (contactAngle < 0)
{
contactAngle = 360 + contactAngle;
}
if (diagonalAngle < 0)
{
diagonalAngle = 360 + diagonalAngle;
}
if (
((contactAngle >= 360 - diagonalAngle) && (contactAngle <= 360)) ||
((contactAngle <= diagonalAngle) && (contactAngle >= 0))
)
{
side = Collision2DSideType.Starboard;
}
else if (
((contactAngle >= 180 - diagonalAngle) && (contactAngle <= 180)) ||
((contactAngle >= 180) && (contactAngle <= 180 + diagonalAngle))
)
{
side = Collision2DSideType.Port;
}
else if (
((contactAngle >= diagonalAngle) && (contactAngle <= 90)) ||
((contactAngle >= 90) && (contactAngle <= 180 - diagonalAngle))
)
{
side = Collision2DSideType.Forward;
}
else if (
((contactAngle >= 180 + diagonalAngle) && (contactAngle <= 270)) ||
((contactAngle >= 270) && (contactAngle <= 360 - diagonalAngle))
)
{
side = Collision2DSideType.Rear;
}
return side.Opposite();
}
static bool ranOnce = false;
public static Collision2DSideType GetContactSide(this Collision2D collision)
{
Vector2 max = collision.collider.bounds.max;
Vector2 center = collision.collider.bounds.center;
Vector2 contact = collision.GetContact(0).point;
if (!ranOnce)
{
ranOnce = true;
Debug.Log("Max: " + max);
Debug.Log("Center: " + center);
Debug.Log("Contact: " + contact);
}
return GetContactSide(max, center, contact);
}
}
}
Collision2DSideTypeExtensions.cs
namespace PixelsoftGames
{
public static class Collision2DSideTypeExtensions
{
public static Collision2DSideType Opposite(this Collision2DSideType sideType)
{
Collision2DSideType opposite;
if (sideType == Collision2DSideType.Port)
{
opposite = Collision2DSideType.Starboard;
}
else if (sideType == Collision2DSideType.Starboard)
{
opposite = Collision2DSideType.Port;
}
else if (sideType == Collision2DSideType.Forward)
{
opposite = Collision2DSideType.Rear;
}
else if (sideType == Collision2DSideType.Rear)
{
opposite = Collision2DSideType.Forward;
}
else
{
opposite = Collision2DSideType.None;
}
return opposite;
}
}
}
Collision2DSideType
public enum Collision2DSideType { None, Port, Starboard, Forward, Rear }
In the method GetContactSide you never get the rotation of your sprite, it is like your sprite angle is always 0
One solution for this is to add as a parameter the angle of your sprite to the method and add that angle to the the condition to determine wich side of the sprite it is
It can look like that :
public static class Collision2DExtensions
{
public static Collision2DSideType GetContactSide(Vector2 max, Vector2 center, Vector2 contact, float angle)
{
...
if (
((contactAngle >= (360 - diagonalAngle) + angle) && (contactAngle <= 360 + angle)) ||
((contactAngle <= diagonalAngle + angle) && (contactAngle >= 0 + angle))
)
...
`
I think you should do that for each of these conditions

Change animation based on mouse screen position in Unity 2D

I am developing an Isometric 2D game in Unity, using C# scripts. The character will be able to run in 8 different orientations.
I am trying to trigger a running animation depending on the mouse position.
My script is working fine but I don't think is the best way to face this problem.
First of all, I have an enum with the possible orientations:
public enum Orientations {N,NE,E,SE,S,SW,W,NW,NONE}
I wrote a method that returns an Orientations value based in a movement. This is because I want to trigger an animation based on the movement, so the Character will always be looking at the direction of the movement:
public static Orientations GetOrientation(Vector2 movement)
{
if (movement.x == 0 && movement.y == 1)
{
return Orientations.N;
}
else if (movement.x == 1 && movement.y == 0)
{
return Orientations.E;
}
else if (movement.x == 0 && movement.y == -1)
{
return Orientations.S;
}
else if (movement.x == -1 && movement.y == 0)
{
return Orientations.W;
}
else if (movement.x == -1 && movement.y == 1)
{
return Orientations.NW;
}
else if (movement.x == 1 && movement.y == 1)
{
return Orientations.NE;
}
else if (movement.x == -1 && movement.y == -1)
{
return Orientations.SW;
}
else if (movement.x == 1 && movement.y == -1)
{
return Orientations.SE;
}
return Orientations.NONE;
}
Next, I get the mouse angle between the character and the screen.
public static float GetMousePosition(Transform transform)
{
float cameraDistance = Camera.main.transform.position.y - transform.position.y;
Vector3 mousePosition = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, cameraDistance));
float angleRadius = Mathf.Atan2(mousePosition.y - transform.position.y, mousePosition.x - transform.position.x);
float angle = (180 / Mathf.PI) * angleRadius;
angle = (angle < 0) ? angle + 360 : angle;
return angle;
}
Then, I transform the angle in a Vector2, so I am able to switch between triggering animations by the character movement and mouse position:
public static Vector2 AngleToVectorDirection(Transform transform)
{
Vector2 direction = new Vector2(0,0);
float angle = GetMousePosition(transform);
if(angle >= 67.5 && angle < 112.5)
{
direction = new Vector2(0,1);
}
else if (angle >= 112.5 && angle < 157.5)
{
direction = new Vector2(-1,1);
}
else if (angle >= 157.5 && angle < 202.5)
{
direction = new Vector2(-1, 0);
}
else if (angle >= 202.5 && angle < 247.5)
{
direction = new Vector2(-1, -1);
}
else if (angle >= 247.5 && angle < 292.5)
{
direction = new Vector2(0, -1);
}
else if (angle >= 292.5 && angle < 337.5)
{
direction = new Vector2(1, -1);
}
else if (angle >= 337.5 || angle < 22.5)
{
direction = new Vector2(1, 0);
}
else if (angle >= 22.5 && angle < 67.5)
{
direction = new Vector2(1, 1);
}
return direction;
}
To finish, I return the Orientation as I mentioned:
public static Orientations GetOrientationByMovement(Transform transform, Vector2 movement)
{
Vector2 orientation;
if (!Input.GetButton("Fire1"))
{
orientation = movement;
}
else
{
orientation = AngleToVectorDirection(transform);
}
return GetOrientation(orientation);
}
This Orientation is received by an AnimationController script that triggers the animation.
I can not simply rotate the character, or flip sprite, or something like that because it is animation based.
Here you are doing the work twice. So in an optimisation point of view that not ideal but in a design point of view that can be good to separate the works. The question is where does the movement parameter come from in the GetOrientationByMovement method? can you use instead the orientation enum? if yes then that simplifies your code greatly!
You end up with :
public static Orientations AngleToVectorDirection(Transform transform)
{
float angle = GetMousePosition(transform);
if(angle >= 67.5 && angle < 112.5)
{
return Orientations.N;
}
else if (angle >= 112.5 && angle < 157.5)
{
return Orientations.NW;
}
else if (angle >= 157.5 && angle < 202.5)
{
return Orientations.W;
}
else if (angle >= 202.5 && angle < 247.5)
{
return Orientations.SW;
}
else if (angle >= 247.5 && angle < 292.5)
{
return Orientations.S;
}
else if (angle >= 292.5 && angle < 337.5)
{
return Orientations.SE;
}
else if (angle >= 337.5 || angle < 22.5)
{
return Orientations.E;
}
else if (angle >= 22.5 && angle < 67.5)
{
return Orientations.NE;
}
}
Also try to keep consistency in your code. if you use return value in the if statement do that for both function, in you use it outside do it everywhere.
Note that in your implementation of the AngleToVectorDirection you don't need to create a new vector in the beginning since you cover all the angle that can be.
Answering my own question:
With the just released unity's 3.8f1 patch, I've found in them demo project a way to trigger animations in a really simple way.
I am just using the code you can find in the official site:
https://blogs.unity3d.com/2019/03/18/isometric-2d-environments-with-tilemap/?_ga=2.120446600.1010886114.1552829987-288556513.1552829987
They use a IsometricCharacterRenderer script where use Animator.Play() passing as parameter a value of a string[], based on the player movement.
public static readonly string[] staticDirections = { "Static N", "Static NW", "Static W", "Static SW", "Static S", "Static SE", "Static E", "Static NE" };
public static readonly string[] runDirections = { "Run N", "Run NW", "Run W", "Run SW", "Run S", "Run SE", "Run E", "Run NE" };
public void SetDirection(Vector2 direction)
{
//use the Run states by default
string[] directionArray = null;
//measure the magnitude of the input.
if (direction.magnitude < .01f)
{
//if we are basically standing still, we'll use the Static states
//we won't be able to calculate a direction if the user isn't pressing one, anyway!
directionArray = staticDirections;
}
else
{
//we can calculate which direction we are going in
//use DirectionToIndex to get the index of the slice from the direction vector
//save the answer to lastDirection
directionArray = runDirections;
lastDirection = DirectionToIndex(direction, 8);
}
//tell the animator to play the requested state
animator.Play(directionArray[lastDirection]);
}
And to get the direction index, they convert the movement in an angle, just how I did, but in a smart way.
public static int DirectionToIndex(Vector2 dir, int sliceCount)
{
//get the normalized direction
Vector2 normDir = dir.normalized;
//calculate how many degrees one slice is
float step = 360f / sliceCount;
//calculate how many degress half a slice is.
//we need this to offset the pie, so that the North (UP) slice is aligned in the center
float halfstep = step / 2;
//get the angle from -180 to 180 of the direction vector relative to the Up vector.
//this will return the angle between dir and North.
float angle = Vector2.SignedAngle(Vector2.up, normDir);
//add the halfslice offset
angle += halfstep;
//if angle is negative, then let's make it positive by adding 360 to wrap it around.
if (angle < 0)
{
angle += 360;
}
//calculate the amount of steps required to reach this angle
float stepCount = angle / step;
//round it, and we have the answer!
return Mathf.FloorToInt(stepCount);
}

Separation Steering Algorithm

Ok so this site has helped me alot before i had an account, but now the net is not helping me so i'll post it myself :)
I am looking (i am yet another one) to do something like this:
tinykeep.com/dungen/
Now the first step(Generating the rooms , goes well), but this is the first time ever I encounter Flocking behaviour algorithms, and my maths really arent that terrific.
So i tried and came up with a non working algorithm, what i did is started from next standard separation algorithm: gamedevelopment.tutsplus.com/tutorials/the-three-simple-rules-of-flocking-behaviors-alignment-cohesion-and-separation--gamedev-3444 (sorry for this text but it wouldn't let me post more than 2 links without 10 rep), And changed it to my liking. Like i said before it's really not doing anything, if i find how i'll post some debug results.
Here's my code:
class Room {
Vector3 position;
Vector3 size;
int area;
public Room(Vector3 position, Vector3 size, int area) : this(position, size){
this.area = area;
}
public Room(Vector3 position, Vector3 size){
this.position = position;
this.size = size;
if(area != null)
this.area = (int)(size.x * size.z);
}
public Vector3 GetPosition(){
return position;
}
public Vector3 GetSize(){
return size;
}
public void SetPosition(Vector3 position){
this.position = position;
}
public Boolean TooCloseTo(Room room){
return position.x + size.x / 2 > room.GetPosition().x - room.GetSize().x / 2 || position.z + size.z / 2 > room.GetPosition().z - room.GetSize().z / 2 ||
position.x - size.x / 2 < room.GetPosition().x + room.GetSize().x / 2 || position.z - size.z / 2 < room.GetPosition().z + room.GetSize().z / 2;
}
public override string ToString ()
{
return string.Format ("[Room]\nPosition:{0}\nSize:{1}\nArea:{2}", position, size, area);
}
}
These are part of the Mapgenerator class, the rest of this class works fine and seems unimportant to me, but if you feel the need to see it, let me know and i'll post it.
void SeparateRooms(){
foreach (Room room in rooms) {
//Debug.Log (room);
Vector3 oldPos = room.GetPosition ();
Vector3 separation = computeSeparation (room);
//Debug.Log (separation);
Vector3 newPos = new Vector3 (oldPos.x += separation.x, oldPos.y, oldPos.z += separation.z);
room.SetPosition (newPos);
//Debug.Log (room);
}
}
Vector3 computeSeparation(Room agent) {
int neighbours = 0;
Vector3 v = new Vector3 ();
foreach (Room room in rooms) {
if (room != agent) {
if (agent.TooCloseTo (room)) {
v.x += Difference(room, agent, "x");
v.z += Difference(room, agent, "z");
neighbours++;
}
}
}
if (neighbours == 0)
return v;
v.x /= neighbours;
v.z /= neighbours;
v.x *= -1;
v.z *= -1;
v.Normalize ();
return v;
}
float Difference(Room room, Room agent, string type){
switch (type) {
case "x":
float xBottom = (room.GetPosition ().x + room.GetSize ().x / 2) - (agent.GetPosition ().x - agent.GetSize ().x / 2);
float xTop = (agent.GetPosition ().x + agent.GetSize ().x / 2) - (room.GetPosition ().x - room.GetSize ().x / 2);
return xBottom > 0 ? xBottom : xTop;
break;
case "z":
float xRight= (room.GetPosition ().z + room.GetSize ().z / 2) - (agent.GetPosition ().z - agent.GetSize ().z / 2);
float xLeft= (agent.GetPosition ().z + agent.GetSize ().z / 2) - (room.GetPosition ().z - room.GetSize ().z / 2);
return xRight > 0 ? xRight : xLeft;
default:
return 0;
break;
}
}
I was expecting the difference to be numbers like 4.0 and 8.0 and so on, instead i get 0.9 and 0.3 and so on, i'll copy an output:
Debug log
I hope that is readable.
Explanation: Each three lines are the info about the room:
1. the original room
2. the (what's supposed to be the) overlap between the room and the next
3. the new position of the room
EDIT: Ok thanks to the comments i'm getting pretty normal results for overlap now, but the rooms are still overlapping after i run the algorithm, i think this might have to do something with only iterating once over every room... Any comments on that?
I really hope some of you might be able to point me in the right direction, or tell me what is wrong in my reasoning.
Thank you!
EDIT: Filling up rooms:
public void Generate(int level) {
int levelModifier = (int)(Math.Round ((double)Mathf.Log (level, 2.5f),1) * 10);
int mean = 25;
int SD = 5;
for (int i = 0; i < 30 + levelModifier; i++) {
Vector3 position = getPInCircle (20);
int area = (int)SimpleRNG.GetNormal (mean, SD);
if (area < mean - SD)
continue;
Vector3 size = calculateSize (area);
Room room = new Room (position, size);
rooms.Add (room);
}
SeparateRooms ();
}
Vector3 calculateSize(int area) {
float k = UnityEngine.Random.Range (2.0f, area / 2.0f);
float l = area / k;
int shortSide;
int longSide;
if (Mathf.Round (k) > Mathf.Round (l)) {
shortSide = Mathf.RoundToInt (k);
longSide = Mathf.RoundToInt (l);
} else {
shortSide = Mathf.RoundToInt (l);
longSide = Mathf.RoundToInt (k);
}
//Debug.Log (shortSide);
//Debug.Log (longSide);
Vector3 size;
if (SimpleRNG.GetUniform () < 0.5) {
size = new Vector3 (Actualise(shortSide), 0, Actualise(longSide));
} else {
size = new Vector3 (Actualise(longSide), 0, Actualise(shortSide));
}
return size;
}
The SimpleRNG is John D. Cook's Namespace, open for download at www.codeproject.com/Articles/25172/Simple-Random-Number-Generation

Circle C# Mathematics

Ok...this question will get complicated for most...I'm trying to figure out a formula for 2 things so i can write all of this in nearly one line of code and have it go on for as long as I'd like..
formula for commented sections so i can get rid of the need for i > && i < by using ratio's in some way.
formula for angle 2.4f, 1f, 0.6f 0.5f(probably can be more precise but...how?!
Don't need help with radius it's perfect increment of 1.2f this is probably part of the formula needed to find out the other 2 in someway?
There is so much math going on here that it is just getting a little complicated for me and I just can't figure out how to reduce it down past this point...
pointNum = (i * 1.0f) / 7;
if (i > 0 && i <= 6) //cannot divide by 0
{
angle = pointNum * Mathf.PI * 2.4f;
radius = 1.2f;
}
else if(i > 6 && i <= 20) //3.3333~
{
angle = pointNum * Mathf.PI * 1f;
radius = 2.4f;
}
else if(i > 20 && i <= 43) //2.15
{
angle = pointNum * Mathf.PI * 0.6f;
radius = 3.6f;
}
else if(i > 43 && i <= 79) //1.837209302325581
{
angle = pointNum * Mathf.PI * 0.5f;
radius = 4.8f;
}
float x = Mathf.Sin(angle) * radius;//radiusX;
float z = Mathf.Cos(angle) * radius;//radiusZ;
pos = new Vector2(x, z);
The end result looks like:
The radius of concentric circles will be the small circle diameter plus a separation by a integer factor.
C1 Diameter = 1 * ((2*R) + S);
C2 Diameter = 2 * ((2*R) + S);
To know how many small circles can be created, you have to calculate the angle (green filled) that made yellow lines. This angle is easily calculated if you take the triangle made by yellow, green and blue lines.
cos = green line length / yellow line length;
green line length = C1 Diameter;
yellow line length = sqrt( blue line length * blue line length + green line length * green line length);
with the cosine you can calculate the angle with acos function.
later you can divide 360 by the angles and you get the number of circles.
of course it will not by exact, but the decimal part can by distributed among all circles.
Alright so...Here is both methods i got part of Blau's answer translated however...the performance was already far worse just from that it turns out my way is wayyyy faster so guess doing it manually and creating ranges is going to be my only choice thanks for the information though guys.
void CreateConcentricCircles(int i)
{
//Method1
pointNum = (float)i / 7;
if (angleCache != pointNum * Mathf.PI)
angleCache = pointNum * Mathf.PI;
if (i > 0 && i <= 7) //cannot divide by 0
{
angle = angleCache * 2f;
radius = 1.2f;
}
else if(i > 7 && i <= 21) //3.3333~
{
angle = angleCache * 1f;
radius = 2.4f;
}
else if(i > 21 && i <= 44) //2.15
{
angle = angleCache * 0.6f;
radius = 3.6f;
}
else if(i > 44 && i <= 72) //1.837209302325581
{
angle = angleCache * 0.5f;
radius = 4.8f;
}
else if(i > 72 && i <= 103)
{
angle = angleCache * 0.45f;
radius = 6f;
}
else if(i > 103 && i <= 138)
{
angle = angleCache * 0.4f;
radius = 7.2f;
}
else if(i > 138 && i <= 151)
{
angle = angleCache * 0.37f;
radius = 8.4f;
}
float x = Mathf.Sin(angle) * radius;//radiusX;
float z = Mathf.Cos(angle) * radius;//radiusZ;
pos = new Vector2(x, z);
//Method2
/*if (i > 0 && i <= 6) //cannot divide by 0
radius = 1.2f;
else if(i > 6 && i <= 20) //3.3333~
radius = 2.4f;
else if(i > 20 && i <= 43) //2.15
radius = 3.6f;
else if(i > 43 && i <= 71) //1.837209302325581
radius = 4.8f;
else if(i > 71 && i <= 102)
radius = 6f;
else if(i > 102 && i <= 150)
radius = 7.2f;
float C1 = 1 * ((2*radius) + i);
//float C2 = 2 * ((2*radius) + i);
//what's blue line? is it C2?
float anglex = Mathf.Sin(C1) * radius;
float anglez = Mathf.Cos(C1) * radius;
pos = new Vector2(anglex, anglez);*/
}

RotateFlipType helper functions?

I've repeatedly found myself wanting to deal with the RotateFlipType in a more modular manner.
For example, at any given time I want to store a single RotateFlipType enum, while giving the user access to buttons to allow flipping and rotating one click at a time. I need to store this later when I need to apply the RotateFlipType to the data.
So basically I need to store everything seperately across multiple variables. Or I need to have logic such as:
private RotateFlipType ApplyHorizontalFlip(RotateFlipType oldFlip)
{
switch (oldFlip)
{
case RotateFlipType.Rotate180FlipNone:
return RotateFlipType.RotateNoneFlipNone;
case RotateFlipType.Rotate180FlipX:
return RotateFlipType.RotateNoneFlipX;
case RotateFlipType.Rotate180FlipXY:
return RotateFlipType.RotateNoneFlipXY;
case RotateFlipType.Rotate180FlipY:
return RotateFlipType.RotateNoneFlipY;
case RotateFlipType.Rotate270FlipNone:
return RotateFlipType.Rotate90FlipNone;
// etc...
}
}
Are there any helper methods build into the framework, or that anyone knows of? Basically to take any existing RotateFlipType and modify it by rotating or flipping to give a new value.
My approach is to store flip and rotation separately until the moment of rendering. I uses RotateFlipType for the flip value, and a number for the degree. I use these methods to combine them into the appropriate RotateFlipType value.
I'd suggest using your own enum instead of RotateFlipType as I've done here, especially if this is exposed as an external API.
private double normalizeTo90Intervals(double d){
d = d % 360; //Coalesce multiples
if (d < 0) d += 360; //Force positive
//Use manual rounding
if (d >= 315 && d < 360) return 0;
if (d >= 0 && d < 45) return 0;
if (d >=45 && d < 135) return 90;
if (d >= 135 && d < 225) return 180;
if (d >= 225 && d < 315) return 270;
return 0; //to make compiler happy
}
private RotateFlipType combineFlipAndRotate(RotateFlipType flip, double angle) {
angle = normalizeTo90Intervals(angle);
if (flip == 0) return (RotateFlipType)(int)(angle / 90);
else if (flip == (RotateFlipType)4) return (RotateFlipType)(int)(4 + (angle / 90));
else if (flip == (RotateFlipType)6) {
if (angle == 0) return (RotateFlipType)6;
if (angle == 90) return (RotateFlipType)7;
if (angle == 180) return (RotateFlipType)4;
if (angle == 270) return (RotateFlipType)5;
} else if (flip == (RotateFlipType)2) {
if (angle == 0) return (RotateFlipType)2;
if (angle == 90) return (RotateFlipType)3;
if (angle == 180) return (RotateFlipType)0;
if (angle == 270) return (RotateFlipType)1;
}
throw new ArgumentException("Valid flip values are RotateNoneFlipNone, RotateNoneFlipX, RotateNoneFlipY, and RotateNoneFlipXY. Rotation must be specified with Rotate or srcRotate instead. Received: " + flip.ToString());
}
FYI, have you heard of http://imageresizing.net/?

Categories