static void ShowPrice(int num_chicken, int num_duck) {
float totalPrice = 0.00f;
float price_chicken = 10f;
float price_duck = 12.5f;
totalPrice = num_chicken * price_chicken + num_duck * price_duck;
Console.WriteLine(“总价钱为:{0:0.00}”, totalPrice);
}
已知点P(x,y),与直线上A(x1,y1),B(x2,y2)两点,通过向量AP与BP的叉乘返回的结果,即可确定点在直线的位置关系。
判断依据:1)等于0:点在直线上;2)小于0:点在直线的左侧;3)大于0:点在直线的右侧
///
/// 2D叉乘
///
public static float CrossProduct2D(Vector2 v1, Vector2 v2)
{
//叉乘运算公式 x1*y2 - x2*y1
return v1.x * v2.y - v2.x * v1.y;
}
///
/// 点与线的位置关系
///
/// ==0:点在线上 <0:点在线的左侧 >0:点在线的右侧
public static int IsPointToLinePosition(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
{
float crossValue = CrossProduct2D(point - lineStart, lineEnd - lineStart);
if (crossValue < 0) return -1;
if (crossValue > 0) return 1;
return 0;
}
已知点P(x,y),与直线上两点A(x1,y1),B(x2,2),求P点在直线AB上的投影
知识点:通过向量投影公式(点乘),即可获得点P在直线AB投影点。
///
/// 2D叉乘
///
public static float CrossProduct2D(Vector2 v1, Vector2 v2)
{
//叉乘运算公式 x1*y2 - x2*y1
return v1.x * v2.y - v2.x * v1.y;
}
///
/// 点是否在直线上
///
public static bool IsPointOnLine(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
{
float value = CrossProduct2D(point - lineStart, lineEnd - lineStart);
return Mathf.Abs(value) < 0.0003 /* 使用 Mathf.Approximately(value,0) 方式,在斜线上好像无法趋近为0*/;
}
///
/// 点到直线上的投影坐标
///
public static Vector2 Point2LineProject(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
{
if (IsPointOnLine(point, lineStart, lineEnd))
return point;
Vector2 v = point - lineStart;
Vector2 u = lineEnd - lineStart;
//求出长度
float u1Length = Vector2.Dot(u, v) / u.magnitude;
return u1Length * u.normalized + lineStart;
}
已知多边形的逆时针顶点序列,依次判断相邻两个线段走向是否一致即可。
(点与线段位置关系,因为规定为逆时针顶点序列,所以只要两个相邻线段的叉乘都小于0则该多边形为凸多边形)
///
/// 2D叉乘
///
public static float CrossProduct2D(Vector2 v1, Vector2 v2)
{
//叉乘运算公式 x1*y2 - x2*y1
return v1.x * v2.y - v2.x * v1.y;
}
///
/// 点与线的位置关系
///
/// ==0:点在线上 <0:点在线的左侧 >0:点在线的右侧
public static int IsPointToLinePosition(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
{
float crossValue = CrossProduct2D(point - lineStart, lineEnd - lineStart);
if (crossValue < 0) return -1;
if (crossValue > 0) return 1;
return 0;
}
///
/// 是否为凸多边形
///
/// 逆时针点序列
public static bool IsConvexPolygon(List<Vector2> points)
{
//计算每个顶点的转向,如果有不一致的转向,则表示该多边形不是凸多边形
if (points.Count < 3) return false;
bool isConvex = true;
for (int i = 1; i < points.Count; i++)
{
Vector2 point = points[i];
//上一个点
Vector2 point1 = points[i - 1];
//下一个点,如果超出当前点集合,则需要获取第一个点
int nextIndex = i + 1;
if (nextIndex >= points.Count) nextIndex = 0;
Vector2 point2 = points[nextIndex];
//计算朝向,因为点集合为逆时针点序列,如果点在线段右侧,则表示该角大于180 该多边形为凹多边形
float value = IsPointToLinePosition(point1, point, point2);
if (value > 0)
{
isConvex = false;
break;
}
}
return isConvex;
}
思路:
1)先判断两条线段是否平行,即两条线段的叉积等于0
2)在判断两条线段是否共线,即线段1一个点在线段2的延长线上
///
/// 线段与线段是否共线
///
public static bool IsSegmentCollineation(Vector2 segment1Start, Vector2 segment1End, Vector2 segment2Start,
Vector2 segment2End)
{
//1.判断两个向量是否平行
float value = CrossProduct2D(segment1End - segment1Start, segment2End - segment2Start);
if (Mathf.Abs(value) < 0.0003f)
{
// 平行,则判断一个线上的点是否在另一线上
if (IsPointOnLine(segment2Start, segment2End, segment2Start))
return true;
}
return false;
}
1)判断两条线段必须共线
2)然后片段判断线段A的起终点是否在线段B,以及线段B的起终点,是否在线段A上,只要有一个条件成立,则可以认为两条线段是重合的
或
1)判断两条线段是否共线
2)对两条线段的4个定点进行排序,如果1,3 或 1,4 为为同一条线段上的点,则可以任务两条线段是否重合的
///
/// 线段与线段是否重合(全部重合或局部重合)
///
public static bool IsSegmentCoincide(Vector2 segment1Start, Vector2 segment1End, Vector2 segment2Start,
Vector2 segment2End)
{
//先判断两条线段是否在同一条线上
if (!IsSegmentCollineation(segment1Start, segment1End, segment2Start, segment2End))
return false;
//如果是相同的起终点
if (segment1Start == segment2Start && segment1End == segment2End) return true;
//判断检测点是否在另一条线段上
if (IsPointOnSegment2(segment1Start, segment2Start, segment2End) ||
IsPointOnSegment2(segment1End, segment2Start, segment2End) ||
IsPointOnSegment2(segment2Start, segment1Start, segment1End) ||
IsPointOnSegment2(segment2End, segment1Start, segment1End))
return true;
return false;
}
///
/// 线段是否相交
///
public static bool IsSegmentIntersect(Vector2 segment1Start, Vector2 segment1End, Vector2 segment2Start,
Vector2 segment2End)
{
//快速排斥实验
if (Mathf.Min(segment1Start.x, segment1End.x) <= Mathf.Max(segment2Start.x, segment2End.x)
&& Mathf.Min(segment2Start.x, segment2End.x) <= Mathf.Max(segment2Start.x, segment2End.x)
&& Mathf.Min(segment1Start.y, segment1End.y) <= Mathf.Max(segment2Start.y, segment2End.y)
&& Mathf.Min(segment2Start.y, segment2End.y) <= Mathf.Max(segment1Start.y, segment1End.y))
{
//先判断线段是否重合,重合,则认为也是相交
if (IsSegmentCoincide(segment1Start, segment1End, segment2Start, segment2End))
return true;
//互为跨立的判断 一线的点相对另一线的位置关系,左右 -1 1,之和为 0
int state = IsPointToLinePosition(segment1Start, segment2Start, segment2End) +
IsPointToLinePosition(segment1End, segment2Start, segment2End) +
IsPointToLinePosition(segment2Start, segment1Start, segment1End) +
IsPointToLinePosition(segment2End, segment1Start, segment1End);
if (state == 0) return true;
}
return false;
}
///
/// 求直线的交点
///
public static Vector2 LineIntersectPoint(Vector2 line1Start, Vector2 line1End, Vector2 line2Start,
Vector2 line2End)
{
//两点式公式
//x0 = ((x3-x4) * (x2*y1 - x1*y2) - (x1-x2) * (x4*y3 - x3*y4)) / ((x3-x4) * (y1-y2) - (x1-x2) * (y3-y4));
//y0 = ((y3-y4) * (y2*x1 - y1*x2) - (y1-y2) * (y4*x3 - y3*x4)) / ((y3-y4) * (x1-x2) - (y1-y2) * (x3-x4));
float x1 = line1Start.x, x2 = line1End.x, x3 = line2Start.x, x4 = line2End.x;
float y1 = line1Start.y, y2 = line1End.y, y3 = line2Start.y, y4 = line2End.y;
Vector2 point = Vector2.zero;
point.x = ((x3 - x4) * (x2 * y1 - x1 * y2) - (x1 - x2) * (x4 * y3 - x3 * y4)) / ((x3 - x4) * (y1 - y2) - (x1 - x2) * (y3 - y4));
point.y = ((y3 - y4) * (y2 * x1 - y1 * x2) - (y1 - y2) * (y4 * x3 - y3 * x4)) / ((y3 - y4) * (x1 - x2) - (y1 - y2) * (x3 - x4));
return point;
}
///
/// 射线与线段是否相交
///
public static bool IsRaySegmentIntersect(Vector2 rayStart, Vector2 rayDir, Vector2 segmentStart, Vector2 segmentEnd, out Vector2 point)
{
//先计算两条直线是否相交
if (!LineIntersectPoint(rayStart, rayStart + rayDir * 1, segmentStart, segmentEnd, out point))
return false;
//判断交点的位置是否在射线上 方向相同可以确定点在射线上
if (Vector2.Dot((point - rayStart).normalized, rayDir.normalized) < 0) return false;
//点是否在线段上
if (!IsPointOnSegment2(point, segmentStart, segmentEnd)) return false;
return true;
}
///
/// 点绕另一个点进行旋转
///
public static Vector2 PointRoationOnPoint(Vector2 originPoint, Vector2 point, float angle)
{
if (originPoint == point) return originPoint;
Vector2 resultPoint = Vector2.zero;
Vector2 v = (point - originPoint).normalized;
angle *= Mathf.Deg2Rad;
resultPoint.x = v.x * Mathf.Cos(angle) - v.y * Mathf.Sin(angle);
resultPoint.y = v.x * Mathf.Sin(angle) + v.y * Mathf.Cos(angle);
return resultPoint * Vector2.Distance(originPoint, point) + originPoint;
}
///
/// 点集合绕点旋转
///
public static List<Vector2> PointsRoationOnPoint(List<Vector2> points, Vector2 point, float angle)
{
List<Vector2> resultPoints = new List<Vector2>();
if (points == null) return resultPoints;
for (int i = 0; i < points.Count; i++)
{
Vector2 nPoint = PointRoationOnPoint(point, points[i], angle);
resultPoints.Add(nPoint);
}
return resultPoints;
}
///
/// 点是否在任意多边形内部
///
/// -1:不在多边形内 0:在多边形上 1:多边形内
public static int IsPointInAnyPolygon(Vector2 point, List<Vector2> polygon)
{
//顶点数量小于3,则无法形成多边形
if (polygon.Count < 3) return -1;
//1.先获取多边形所在矩形范围内
Vector2 rectMin = polygon[0], rectMax = polygon[0];
for (int i = 1; i < polygon.Count; i++)
{
if (polygon[i].x < rectMin.x) rectMin.x = polygon[i].x;
if (polygon[i].y < rectMin.y) rectMin.y = polygon[i].y;
if (polygon[i].x > rectMax.x) rectMax.x = polygon[i].x;
if (polygon[i].y > rectMax.y) rectMax.y = polygon[i].y;
}
if (point.x < rectMin.x || point.y < rectMin.y || point.x > rectMax.x || point.y > rectMax.y) return -1;
//2.射线相交点计算
int intersectCount = 0;
for (int i = 0; i < polygon.Count; i++)
{
int nextIndex = i + 1;
if (nextIndex >= polygon.Count)
nextIndex = 0;
//目标在顶点上
if (polygon[i] == point || polygon[nextIndex] == point)
return 0;
//目标在线段上
if (IsPointOnSegment2(point, polygon[i], polygon[nextIndex]))
return 0;
Vector2 intersectPoint;
//射线与线段相交
if (IsRaySegmentIntersect(point, Vector2.right, polygon[i], polygon[nextIndex], out intersectPoint))
{
//如果相交为线段的顶点,则需要增加2,因为在同一点进入,又在同一个点出去
if (intersectPoint == polygon[i] || intersectPoint == polygon[nextIndex])
intersectCount += 2;
else
intersectCount += 1;
}
}
return intersectCount % 2 == 1 ? 1 : -1;
}
public class Timer: MonoBehaviour
{
private float timer = 0f;
private int h = 0;
private int m = 0;
private int s = 0;
private string timeStr = string.Empty;
Text time_text;
bool pause = true;
private void Start()
{
time_text = gameObject.GetComponent<Text>();
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
pause = !pause;
}
timer += Time.deltaTime;
if (!pause)
{
if (timer >= 1f)
{
s++;
timer = 0;
}
if (s >= 60)
{
m++;
s = 0;
}
if (m >= 60)
{
h++;
m = 0;
}
if (h >= 99)
{
h = 0;
}
}
if (Input.GetKeyDown(KeyCode.Keypad0))
{
s = 0; m = 0; h = 0;
}
timeStr = string.Format("{0:D2}:{1:D2}:{2:D2}", h, m, s);
time_text.text = timeStr;
}
}
public class DragObj : MonoBehaviour
{
private void OnMouseEnter()
{
gameObject.transform.localScale += new Vector3(0.1f, 0.1f, 0.1f);
}
private void OnMouseExit()
{
gameObject.transform.localScale -= new Vector3(0.1f, 0.1f, 0.1f);
}
private void OnMouseDrag()
{
Ray camRay = Camera.main.ScreenPointToRay(Input.mousePosition);//从屏幕鼠标点击的位置向场景内发出一条射线
RaycastHit floorHit;
if (Physics.Raycast(camRay, out floorHit, 1000f, 1))//1为过滤层
{
transform.position = new Vector3(floorHit.point.x, floorHit.point.y + 0.25f, floorHit.point.z);
}
}
}
//滚轮缩放
public class ViewCtrl : MonoBehaviour
{
public float wheelspeed;
void Update()
{
transform.Translate(0, 0, Input.GetAxis("Mouse ScrollWheel") * wheelspeed * Time.deltaTime, Space.Self);
}
}
public class Player : MonoBehaviour
{
public GameObject _prefabBullet;
private float _angleSpeed = 120f;
void Update()
{
float eularY = Input.GetAxis("Mouse X") * _angleSpeed * Time.deltaTime;
transform.Rotate(new Vector3(0, eularY, 0));
if (Input.GetMouseButtonDown(0))
{
Instantiate(_prefabBullet, transform.position, transform.rotation);
}
}
}
public class Timer : MonoBehaviour
{
public delegate void MyEventHandler(float currentTime);
#region 计时器的三种基础事件
public static event MyEventHandler onTimerStart;
public static event MyEventHandler onTimerPause;
public static event MyEventHandler onTimerStoped;
#endregion
private bool isStarted = false;
public bool IsStarted
{
get
{
return isStarted;
}
}
private bool isStoped = true;
public bool IsStoped
{
get
{
return isStoped;
}
}
private float totalTime = 0;
// Update is called once per frame
void Update()
{
//空格键当作“开始/暂停”键
if (Input.GetKeyDown(KeyCode.Space))
{
OnChangeState();
}
//回车键当作“停止”键
if (Input.GetKeyDown(KeyCode.Return))
{
OnSetStop();
}
if (isStarted)
{
isStoped = false;
totalTime += Time.deltaTime;
}
}
void OnChangeState()
{
var _startState = !isStarted;
isStarted = _startState;
if (isStarted)
{
//检查onTimerStart是否为空,防止报空 (废话了。。。下面不做赘述)
if (onTimerStart != null)
{
onTimerStart(totalTime);
}
else
{
Debug.Log("onTimerStart is Empty");
}
}
else
{
if (onTimerPause != null)
{
onTimerPause(totalTime);
}
else
{
Debug.Log("onTimerPause is Empty");
}
}
}
void OnSetStop()
{
if (onTimerStoped != null)
{
onTimerStoped(totalTime);
}
else
{
Debug.Log("onTimerStoped is Empty");
}
isStarted = false;
isStoped = true;
totalTime = 0;
}
}