This is NOT a solution to tree collissions (YET). I'm posting here to generate discussion/innovation from our C# coders about approaches to detecting tree collisions. My method in pseudo-code is ...
1. Define each forest areas as a polygon (a set of 2D points)
2. Make a list of each polygons forrest array (ie a list of 2D points that describe the perimeter of the forest)
3. Test (frequently) to see if an aircraft is inside a forest polygon & below tree height. (NOTE - This is probblematic as it would be processor intensive).
4. If so, destroy the aircraft.
Code:
using System;
using maddox.game;
using maddox.game.world;
using System.Collections.Generic;
using maddox.GP;
using System.Threading;
using System.ComponentModel;
using System.Diagnostics;
public class Mission : AMission
{
bool DEBUG = true; // turn on debugging messages in the console
BackgroundWorker BGworker;
Stopwatch WorkTimer = new Stopwatch();
List<Point2d[]> forests = new List<Point2d[]>(); // array of polygons around each forrest area on map
double TreeHeightMetres = 10; // notional tree height
public override void OnBattleStarted()
{
base.OnBattleStarted();
BGworker = new BackgroundWorker();
BGworker.DoWork += new DoWorkEventHandler(BGworker_DoWork);
BGworker.ProgressChanged += new ProgressChangedEventHandler
(BGworker_ProgressChanged);
BGworker.RunWorkerCompleted += new RunWorkerCompletedEventHandler
(BGworker_RunWorkerCompleted);
BGworker.WorkerReportsProgress = true;
BGworker.WorkerSupportsCancellation = true;
WorkTimer.Start();
if (DEBUG) Console.WriteLine("background worker started");
BGworker.RunWorkerAsync(GetAircraftsList());
}
public override void OnTickGame()
{
base.OnTickGame();
// check for tree collissions
if (WorkTimer.Elapsed.TotalSeconds > 30)
{
if (DEBUG) Console.WriteLine("checking if background worker is running");
if (!BGworker.IsBusy)
{ // restart the background worker
if (DEBUG) Console.WriteLine("background worker restarted");
BGworker.RunWorkerAsync(GetAircraftsList());
}
WorkTimer.Restart();
}
}
private bool IsPointInsidePolygon(Point2d[] polygon, Point3d point)
{
bool isInside = false;
for (int i = 0, j = polygon.Length - 1; i < polygon.Length; j = i++)
{
if (((polygon[i].y > point.y) != (polygon[j].y > point.y)) &&
(point.x < (polygon[j].x - polygon[i].x) * (point.y - polygon[i].y) / (polygon[j].y - polygon[i].y) + polygon[i].x))
{
isInside = !isInside;
}
}
return isInside;
}
public List<AiAircraft> GetAircraftsList()
{
// make a list of all aircraft in the game
List<AiAircraft> result = new List<AiAircraft>();
for (int army = 0; army < GamePlay.gpArmies().Length - 1; army++) // for all armies
{
List<AiAirGroup> airgroups = new List<AiAirGroup>(GamePlay.gpAirGroups(army));
for (int i = 0; i < airgroups.Count; i++) // for all airgroups
{
List<AiActor> aircrafts = new List<AiActor>(airgroups[i].GetItems());
for (int j = 0; j < aircrafts.Count; j++) // for all aircraft within an airgroup
{
result.Add(aircrafts[j] as AiAircraft);
}
}
}
return result;
}
public Point2d[] GetBoundingRectangle(Point2d[] points)
{
double xmax = double.MinValue;
double ymax = double.MinValue;
double xmin = double.MaxValue;
double ymin = double.MaxValue;
// get the maximum & minimum x y points
for (int i= 0; i < points.Length-1; i++)
{
if (points[i].x > xmax) xmax = points[i].x;
if (points[i].y > ymax) ymax = points[i].y;
if (points[i].x < xmin) xmin = points[i].x;
if (points[i].y < ymin) ymin = points[i].y;
}
return new Point2d[]{new Point2d(xmin, ymax),
new Point2d(xmax, ymax),
new Point2d(xmin, ymin),
new Point2d(xmax, ymin)};
}
// ------------------------
// background worker
// ------------------------
void BGworker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// The background process is complete. We need to inspect
// our response to see if an error occurred, a cancel was
// requested or if we completed successfully.
if (e.Cancelled)
{
//lblStatus.Text = "Task Cancelled.";
if (DEBUG) Console.WriteLine("background worker cancelled");
}
// Check to see if an error occurred in the background process.
else if (e.Error != null)
{
//lblStatus.Text = "Error while performing background operation.";
if (DEBUG) Console.WriteLine("background worker error " + e.Error.Message);
}
else
{
// Everything completed normally.
//lblStatus.Text = "Task Completed...";
if (DEBUG) Console.WriteLine("background worker done");
}
}
void BGworker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
}
void BGworker_DoWork(object sender, DoWorkEventArgs e)
{
// check for tree collissions
for (int army = 0; army < GamePlay.gpArmies().Length - 1; army++) // for all armies
{
if (DEBUG) Console.WriteLine("Processing army " + army.ToString());
List<AiAirGroup> airgroups = new List<AiAirGroup>(GamePlay.gpAirGroups(army));
for (int i = 0; i < airgroups.Count; i++ ) // for all airgroups
{
if (DEBUG) Console.WriteLine("Processing airgroup " + airgroups[i].Name().ToString());
List<AiActor> aircrafts = new List<AiActor>(airgroups[i].GetItems());
for (int j = 0; j < aircrafts.Count; j++) // for all aircraft within an airgroup
{
if (DEBUG) Console.WriteLine("Processing aircraft " + aircrafts[j].Name().ToString());
if (aircrafts[j].Pos().z < TreeHeightMetres && aircrafts[j].IsAlive() && (aircrafts[j] as AiAircraft).IsAirborne())
{ // aircraft is lower than tree height, alive & airborne
if (DEBUG) Console.WriteLine("Found collision candidate " + aircrafts[j].Name().ToString());
for (int k = 0; k < forests.Count; k++) // for all forest polygons
{
if (IsPointInsidePolygon(forests[k], aircrafts[j].Pos())) // plane inside a forrest?
{
(aircrafts[j] as AiAircraft).hitLimb(part.LimbNames.WingL0, 1); // tree collission occurred
if (DEBUG) Console.WriteLine("background worker aircraft hitnamedpart");
}
}
}
}
}
}
}
private static bool CircleEnclosesPoints(Point2d center, float radius2, List<Point2d> points,
int skip1, int skip2, int skip3)
{ // Return true if the indicated circle encloses all of the points.
for (int i = 0; i < points.Count; i++)
{
if ((i != skip1) && (i != skip2) && (i != skip3))
{
Point2d point = points[i];
float dx = (float)(center.x - point.x);
float dy = (float)(center.y - point.y);
float test_radius2 = dx * dx + dy * dy;
if (test_radius2 > radius2) return false;
}
}
return true;
}
}
Bookmarks