
1.制作障碍系统 (1.制作几种类型的障碍物的预制体 ((*.编写障碍物基类,以下几种均继承自基类,含碰撞体,RememberY(生成障碍物时该有多大的Y) ((1.矮障碍,仅碰撞体 ((2.高障碍,仅碰撞体 ((3.可冲破障碍 (((1.除基本碰撞体外,额外包含一个触发器,比碰撞体先检测到马,同时获取马的x速度,大于阈值则给障碍做破碎,用马的力度决定破碎力,关闭碎块和马的碰撞 (((*.导入某2D破碎插件 ((4.人马分离障碍 (((WAIT,需要等待人马分离系统先搭建 (2.编写障碍物生成系统 ((1.每若干时间,生成一个随机一种障碍,若干的范围可控 (((1.设计协程,从预制体列表中随机出一种,并在计算好的位置实例化,随后等待范围内的若干时间,然后检查马的存活情况,若马仍存活,重新调用本协程 ((2.生成的位置:x在相机右侧若干不变距离,y根据障碍物的不同而不同,需要计算保存。 (3.编写障碍物消亡系统 ((1.每个障碍物和碎片都会在离开镜头后被删除
389 lines
9.1 KiB
C#
389 lines
9.1 KiB
C#
using UnityEngine;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using Delaunay.Geo;
|
|
using Delaunay.LR;
|
|
|
|
namespace Delaunay
|
|
{
|
|
// import com.nodename.geom.LineSegment;
|
|
//
|
|
// import flash.display.BitmapData;
|
|
// import flash.display.CapsStyle;
|
|
// import flash.display.Graphics;
|
|
// import flash.display.LineScaleMode;
|
|
// import flash.display.Sprite;
|
|
// import flash.geom.Point;
|
|
// import flash.geom.Rectangle;
|
|
// import flash.utils.Dictionary;
|
|
|
|
/**
|
|
* The line segment connecting the two Sites is part of the Delaunay triangulation;
|
|
* the line segment connecting the two Vertices is part of the Voronoi diagram
|
|
* @author ashaw
|
|
*
|
|
*/
|
|
public sealed class Edge
|
|
{
|
|
private static Stack<Edge> _pool = new Stack<Edge> ();
|
|
|
|
/**
|
|
* This is the only way to create a new Edge
|
|
* @param site0
|
|
* @param site1
|
|
* @return
|
|
*
|
|
*/
|
|
public static Edge CreateBisectingEdge (Site site0, Site site1)
|
|
{
|
|
float dx, dy, absdx, absdy;
|
|
float a, b, c;
|
|
|
|
dx = site1.x - site0.x;
|
|
dy = site1.y - site0.y;
|
|
absdx = dx > 0 ? dx : -dx;
|
|
absdy = dy > 0 ? dy : -dy;
|
|
c = site0.x * dx + site0.y * dy + (dx * dx + dy * dy) * 0.5f;
|
|
if (absdx > absdy) {
|
|
a = 1.0f;
|
|
b = dy / dx;
|
|
c /= dx;
|
|
} else {
|
|
b = 1.0f;
|
|
a = dx / dy;
|
|
c /= dy;
|
|
}
|
|
|
|
Edge edge = Edge.Create ();
|
|
|
|
edge.leftSite = site0;
|
|
edge.rightSite = site1;
|
|
site0.AddEdge (edge);
|
|
site1.AddEdge (edge);
|
|
|
|
edge._leftVertex = null;
|
|
edge._rightVertex = null;
|
|
|
|
edge.a = a;
|
|
edge.b = b;
|
|
edge.c = c;
|
|
//trace("createBisectingEdge: a ", edge.a, "b", edge.b, "c", edge.c);
|
|
|
|
return edge;
|
|
}
|
|
|
|
private static Edge Create ()
|
|
{
|
|
Edge edge;
|
|
if (_pool.Count > 0) {
|
|
edge = _pool.Pop ();
|
|
edge.Init ();
|
|
} else {
|
|
edge = new Edge ();
|
|
}
|
|
return edge;
|
|
}
|
|
|
|
// private static const LINESPRITE:Sprite = new Sprite();
|
|
// private static const GRAPHICS:Graphics = LINESPRITE.graphics;
|
|
//
|
|
// private var _delaunayLineBmp:BitmapData;
|
|
// internal function get delaunayLineBmp():BitmapData
|
|
// {
|
|
// if (!_delaunayLineBmp)
|
|
// {
|
|
// _delaunayLineBmp = makeDelaunayLineBmp();
|
|
// }
|
|
// return _delaunayLineBmp;
|
|
// }
|
|
//
|
|
// // making this available to Voronoi; running out of memory in AIR so I cannot cache the bmp
|
|
// internal function makeDelaunayLineBmp():BitmapData
|
|
// {
|
|
// var p0:Point = leftSite.coord;
|
|
// var p1:Point = rightSite.coord;
|
|
//
|
|
// GRAPHICS.clear();
|
|
// // clear() resets line style back to undefined!
|
|
// GRAPHICS.lineStyle(0, 0, 1.0, false, LineScaleMode.NONE, CapsStyle.NONE);
|
|
// GRAPHICS.moveTo(p0.x, p0.y);
|
|
// GRAPHICS.lineTo(p1.x, p1.y);
|
|
//
|
|
// var w:int = int(Math.ceil(Math.max(p0.x, p1.x)));
|
|
// if (w < 1)
|
|
// {
|
|
// w = 1;
|
|
// }
|
|
// var h:int = int(Math.ceil(Math.max(p0.y, p1.y)));
|
|
// if (h < 1)
|
|
// {
|
|
// h = 1;
|
|
// }
|
|
// var bmp:BitmapData = new BitmapData(w, h, true, 0);
|
|
// bmp.draw(LINESPRITE);
|
|
// return bmp;
|
|
// }
|
|
|
|
public LineSegment DelaunayLine ()
|
|
{
|
|
// draw a line connecting the input Sites for which the edge is a bisector:
|
|
return new LineSegment (leftSite.Coord, rightSite.Coord);
|
|
}
|
|
|
|
public LineSegment VoronoiEdge ()
|
|
{
|
|
if (!visible)
|
|
return new LineSegment (null, null);
|
|
return new LineSegment (_clippedVertices [Side.LEFT],
|
|
_clippedVertices [Side.RIGHT]);
|
|
}
|
|
|
|
private static int _nedges = 0;
|
|
|
|
public static readonly Edge DELETED = new Edge ();
|
|
|
|
// the equation of the edge: ax + by = c
|
|
public float a, b, c;
|
|
|
|
// the two Voronoi vertices that the edge connects
|
|
// (if one of them is null, the edge extends to infinity)
|
|
private Vertex _leftVertex;
|
|
public Vertex leftVertex {
|
|
get { return _leftVertex;}
|
|
}
|
|
private Vertex _rightVertex;
|
|
public Vertex rightVertex {
|
|
get { return _rightVertex;}
|
|
}
|
|
public Vertex Vertex (Side leftRight)
|
|
{
|
|
return (leftRight == Side.LEFT) ? _leftVertex : _rightVertex;
|
|
}
|
|
public void SetVertex (Side leftRight, Vertex v)
|
|
{
|
|
if (leftRight == Side.LEFT) {
|
|
_leftVertex = v;
|
|
} else {
|
|
_rightVertex = v;
|
|
}
|
|
}
|
|
|
|
public bool IsPartOfConvexHull ()
|
|
{
|
|
return (_leftVertex == null || _rightVertex == null);
|
|
}
|
|
|
|
public float SitesDistance ()
|
|
{
|
|
return Vector2.Distance (leftSite.Coord, rightSite.Coord);
|
|
}
|
|
|
|
public static int CompareSitesDistances_MAX (Edge edge0, Edge edge1)
|
|
{
|
|
float length0 = edge0.SitesDistance ();
|
|
float length1 = edge1.SitesDistance ();
|
|
if (length0 < length1) {
|
|
return 1;
|
|
}
|
|
if (length0 > length1) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public static int CompareSitesDistances (Edge edge0, Edge edge1)
|
|
{
|
|
return - CompareSitesDistances_MAX (edge0, edge1);
|
|
}
|
|
|
|
// Once clipVertices() is called, this Dictionary will hold two Points
|
|
// representing the clipped coordinates of the left and right ends...
|
|
private Dictionary<Side,Nullable<Vector2>> _clippedVertices;
|
|
public Dictionary<Side,Nullable<Vector2>> clippedEnds {
|
|
get { return _clippedVertices;}
|
|
}
|
|
// unless the entire Edge is outside the bounds.
|
|
// In that case visible will be false:
|
|
public bool visible {
|
|
get { return _clippedVertices != null;}
|
|
}
|
|
|
|
// the two input Sites for which this Edge is a bisector:
|
|
private Dictionary<Side,Site> _sites;
|
|
public Site leftSite {
|
|
get{ return _sites [Side.LEFT];}
|
|
set{ _sites [Side.LEFT] = value;}
|
|
|
|
}
|
|
public Site rightSite {
|
|
get { return _sites [Side.RIGHT];}
|
|
set { _sites [Side.RIGHT] = value;}
|
|
}
|
|
|
|
public Site Site (Side leftRight)
|
|
{
|
|
return _sites [leftRight];
|
|
}
|
|
|
|
private int _edgeIndex;
|
|
|
|
public void Dispose ()
|
|
{
|
|
// if (_delaunayLineBmp) {
|
|
// _delaunayLineBmp.Dispose ();
|
|
// _delaunayLineBmp = null;
|
|
// }
|
|
_leftVertex = null;
|
|
_rightVertex = null;
|
|
if (_clippedVertices != null) {
|
|
_clippedVertices [Side.LEFT] = null;
|
|
_clippedVertices [Side.RIGHT] = null;
|
|
_clippedVertices = null;
|
|
}
|
|
_sites [Side.LEFT] = null;
|
|
_sites [Side.RIGHT] = null;
|
|
_sites = null;
|
|
|
|
_pool.Push (this);
|
|
}
|
|
|
|
private Edge ()
|
|
{
|
|
// if (lock != PrivateConstructorEnforcer)
|
|
// {
|
|
// throw new Error("Edge: constructor is private");
|
|
// }
|
|
|
|
_edgeIndex = _nedges++;
|
|
Init ();
|
|
}
|
|
|
|
private void Init ()
|
|
{
|
|
_sites = new Dictionary<Side,Site> ();
|
|
}
|
|
|
|
public override string ToString ()
|
|
{
|
|
return "Edge " + _edgeIndex.ToString () + "; sites " + _sites [Side.LEFT].ToString () + ", " + _sites [Side.RIGHT].ToString ()
|
|
+ "; endVertices " + ((_leftVertex != null) ? _leftVertex.vertexIndex.ToString () : "null") + ", "
|
|
+ ((_rightVertex != null) ? _rightVertex.vertexIndex.ToString () : "null") + "::";
|
|
}
|
|
|
|
/**
|
|
* Set _clippedVertices to contain the two ends of the portion of the Voronoi edge that is visible
|
|
* within the bounds. If no part of the Edge falls within the bounds, leave _clippedVertices null.
|
|
* @param bounds
|
|
*
|
|
*/
|
|
public void ClipVertices (Rect bounds)
|
|
{
|
|
float xmin = bounds.xMin;
|
|
float ymin = bounds.yMin;
|
|
float xmax = bounds.xMax;
|
|
float ymax = bounds.yMax;
|
|
|
|
Vertex vertex0, vertex1;
|
|
float x0, x1, y0, y1;
|
|
|
|
if (a == 1.0 && b >= 0.0) {
|
|
vertex0 = _rightVertex;
|
|
vertex1 = _leftVertex;
|
|
} else {
|
|
vertex0 = _leftVertex;
|
|
vertex1 = _rightVertex;
|
|
}
|
|
|
|
if (a == 1.0) {
|
|
y0 = ymin;
|
|
if (vertex0 != null && vertex0.y > ymin) {
|
|
y0 = vertex0.y;
|
|
}
|
|
if (y0 > ymax) {
|
|
return;
|
|
}
|
|
x0 = c - b * y0;
|
|
|
|
y1 = ymax;
|
|
if (vertex1 != null && vertex1.y < ymax) {
|
|
y1 = vertex1.y;
|
|
}
|
|
if (y1 < ymin) {
|
|
return;
|
|
}
|
|
x1 = c - b * y1;
|
|
|
|
if ((x0 > xmax && x1 > xmax) || (x0 < xmin && x1 < xmin)) {
|
|
return;
|
|
}
|
|
|
|
if (x0 > xmax) {
|
|
x0 = xmax;
|
|
y0 = (c - x0) / b;
|
|
} else if (x0 < xmin) {
|
|
x0 = xmin;
|
|
y0 = (c - x0) / b;
|
|
}
|
|
|
|
if (x1 > xmax) {
|
|
x1 = xmax;
|
|
y1 = (c - x1) / b;
|
|
} else if (x1 < xmin) {
|
|
x1 = xmin;
|
|
y1 = (c - x1) / b;
|
|
}
|
|
} else {
|
|
x0 = xmin;
|
|
if (vertex0 != null && vertex0.x > xmin) {
|
|
x0 = vertex0.x;
|
|
}
|
|
if (x0 > xmax) {
|
|
return;
|
|
}
|
|
y0 = c - a * x0;
|
|
|
|
x1 = xmax;
|
|
if (vertex1 != null && vertex1.x < xmax) {
|
|
x1 = vertex1.x;
|
|
}
|
|
if (x1 < xmin) {
|
|
return;
|
|
}
|
|
y1 = c - a * x1;
|
|
|
|
if ((y0 > ymax && y1 > ymax) || (y0 < ymin && y1 < ymin)) {
|
|
return;
|
|
}
|
|
|
|
if (y0 > ymax) {
|
|
y0 = ymax;
|
|
x0 = (c - y0) / a;
|
|
} else if (y0 < ymin) {
|
|
y0 = ymin;
|
|
x0 = (c - y0) / a;
|
|
}
|
|
|
|
if (y1 > ymax) {
|
|
y1 = ymax;
|
|
x1 = (c - y1) / a;
|
|
} else if (y1 < ymin) {
|
|
y1 = ymin;
|
|
x1 = (c - y1) / a;
|
|
}
|
|
}
|
|
|
|
// _clippedVertices = new Dictionary(true); // XXX: Weak ref'd dict might be a problem to use standard
|
|
_clippedVertices = new Dictionary<Side,Nullable<Vector2>> ();
|
|
if (vertex0 == _leftVertex) {
|
|
_clippedVertices [Side.LEFT] = new Vector2 (x0, y0);
|
|
_clippedVertices [Side.RIGHT] = new Vector2 (x1, y1);
|
|
} else {
|
|
_clippedVertices [Side.RIGHT] = new Vector2 (x0, y0);
|
|
_clippedVertices [Side.LEFT] = new Vector2 (x1, y1);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//class PrivateConstructorEnforcer {} |