I made a simulation in OpenSimulator. I changed the terrain to resemble that of Atlantis and used the OpenSimTide module to have the tide cause the disappearance of Atlantis.
Now the OpenSimTide module works, but for some reason I just can't find out how I make the terrain go lower whenever the tide reaches a specific level. How can I achieve this?
Here's what i have up until now:
using System;
using System.Net;
using System.IO;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using log4net;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using OpenMetaverse;
using Mono.Addins;
[assembly: Addin("OpenSimTide", "0.2")]
[assembly: AddinDependency("OpenSim.Region.Framework",
OpenSim.VersionInfo.VersionNumber)]
namespace TideModule
{
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "OpenSimTide")]
public class OpenSimTide : INonSharedRegionModule
{
#region Fields
private static readonly ILog m_log = LogManager.GetLogger (MethodBase.GetCurrentMethod ().DeclaringType);
public string Name { get { return m_name; } }
public Type ReplaceableInterface { get { return null; } }
private const int TICKS_PER_SECOND = 10000000;
public string m_name = "OpenSimTide";
private string m_regionConfigDir = "";
private uint m_frame = 0;
private int m_frameUpdateRate = 100;
private bool m_enabled = false;
private bool m_ready = false;
private float m_tideLevel = 20.0f; //current water level in m
private float m_lowTide = 18.0f; //low water level in m
private float m_highTide = 22.0f; //high water level in m
private ulong m_cycleTime = 3600; //low->high->low time in seconds
private DateTime m_lowTideTime = new DateTime(); // datetime indicating when next low tide will be
private DateTime m_highTideTime = new DateTime(); // datetime indicating when next hightide will be
private bool m_tideDirection = true; // which direction is the tide travelling, 'Coming In'(true) or 'Going Out'(false)
private bool m_lastTideDirection = true;
private bool m_tideInfoDebug = false; //do we chat the tide to the OpenSim console?
private bool m_tideInfoBroadcast = true; //do we chat the tide to the region?
private int m_tideInfoChannel = 5555; //chat channel for all tide info
private int m_tideLevelChannel = 5556; //chat channel for just the tide level in m
private int m_tideAnnounceCount = 5; //how many times do we announce the turning tide
private int m_tideAnnounceCounter = 0; //counter we use to count announcements of low or high tide
private string m_tideAnnounceMsg = "";
private ITerrainChannel m_channel;
public scene m_scene;
public IConfigSource m_config;
public RegionInfo m_regionInfo;
public Dictionary<string, Scene> mScene = new Dictionary<string, Scene> ();
public Vector3 m_shoutPos = new Vector3(128f, 128f, 30f);
#endregion
#region IRegionModuleBase implementation
public void Initialise (IConfigSource source)
{
m_config = source;
}
public void Close ()
{
if (m_enabled) {
m_scene.EventManager.OnFrame -= TideUpdate;
}
}
public void AddRegion (Scene scene)
{
IConfig cnf;
m_log.InfoFormat("[{0}]: Adding region '{1}' to this module", m_name, scene.RegionInfo.RegionName);
cnf = m_config.Configs["Startup"];
m_regionConfigDir = cnf.GetString("regionload_regionsdir", Path.Combine(Util.configDir(), "bin/Regions/"));
cnf = m_config.Configs[scene.RegionInfo.RegionName];
if(cnf == null)
{
m_log.InfoFormat("[{0}]: No region section [{1}] found in addon-modules/{2}/config/*.ini configuration files.", m_name, scene.RegionInfo.RegionName, m_name);
//string moduleConfigFile = Path.Combine(Util.configDir(),m_name + ".ini");
string moduleConfigFile = Path.Combine(m_regionConfigDir, "Regions.ini");
try
{
m_log.InfoFormat("[{0}]: Checking {1} for [{2}] section containing valid config keys", m_name, moduleConfigFile, scene.RegionInfo.RegionName);
m_config = new IniConfigSource(moduleConfigFile);
cnf = m_config.Configs[scene.RegionInfo.RegionName];
}
catch (Exception)
{
cnf = null;
}
if (cnf == null)
{
m_log.InfoFormat("[{0}]: No region section [{1}] found in configuration {2}. Tide in this region is set to Disabled", m_name, scene.RegionInfo.RegionName, moduleConfigFile);
m_enabled = false;
return;
}
}
m_enabled = cnf.GetBoolean("TideEnabled", false);
if (m_enabled)
{
m_frameUpdateRate = cnf.GetInt("TideUpdateRate", 150);
m_lowTide = cnf.GetFloat("TideLowWater", 18.0f);
m_highTide = cnf.GetFloat("TideHighWater", 22.0f);
m_cycleTime = (ulong)cnf.GetInt("TideCycleTime", 3600);
m_tideInfoDebug = cnf.GetBoolean("TideInfoDebug", false);
m_tideInfoBroadcast = cnf.GetBoolean("TideInfoBroadcast", true);
m_tideInfoChannel = cnf.GetInt("TideInfoChannel", 5555);
m_tideLevelChannel = cnf.GetInt("TideLevelChannel", 5556);
m_tideAnnounceCount = cnf.GetInt("TideAnnounceCount", 5);
m_log.InfoFormat("[{0}]: Enabled with an update rate every {1} frames, Low Water={2}m, High Water={3}m, Cycle Time={4} secs", m_name, m_frameUpdateRate, m_lowTide, m_highTide, m_cycleTime);
m_log.InfoFormat("[{0}]: Info Channel={1}, Water Level Channel={2}, Info Broadcast is {3}, Announce Count={4}", m_name, m_tideInfoChannel, m_tideLevelChannel, m_tideInfoBroadcast, m_tideAnnounceCounter);
m_frame = 0;
m_ready = true; // Mark Module Ready for duty
m_shoutPos = new Vector3(scene.RegionInfo.RegionSizeX / 2f, scene.RegionInfo.RegionSizeY / 2f, 30f);
scene.EventManager.OnFrame += TideUpdate;
m_scene = scene;
}
else
{
m_log.InfoFormat("[{0}]: Tide in this region is set to Disabled", m_name);
}
}
public void RemoveRegion (Scene scene)
{
m_log.InfoFormat("[{0}]: Removing region '{1}' from this module", m_name, scene.RegionInfo.RegionName);
if (m_enabled)
{
scene.EventManager.OnFrame -= TideUpdate;
}
}
public void RegionLoaded (Scene scene)
{
}
#endregion
#region TideModule
// Place your methods here
public void TideUpdate ()
{
ulong timeStamp;
double cyclePos; //cycles from 0.0000000001 to 0.999999999999
double cycleRadians;
double tideRange;
double tideMiddle;
string tideLevelMsg;
if (((m_frame++ % m_frameUpdateRate) != 0) || !m_ready) {
return;
}
timeStamp = (ulong) (DateTime.Now.Ticks);
cyclePos = (double)(timeStamp % (m_cycleTime * TICKS_PER_SECOND)) / (m_cycleTime * TICKS_PER_SECOND);
cycleRadians = cyclePos * Math.PI * 2;
if (cyclePos < 0.5) m_tideDirection = false; else m_tideDirection = true;
if (m_tideDirection != m_lastTideDirection)
{ //if the tide changes re-calculate the tide times
if (cyclePos < 0.5)
{ // tide just changed to be high->low
m_lowTideTime = DateTime.Now.AddSeconds((double)(m_cycleTime * (0.5 - cyclePos)));
m_highTideTime = m_lowTideTime.AddSeconds((double)(m_cycleTime / 2));
m_tideAnnounceMsg = "High Tide";
}
else
{ //tide just changed to be low->high
m_highTideTime = DateTime.Now.AddSeconds((double)(m_cycleTime * (1.0 - cyclePos)));
m_lowTideTime = m_highTideTime.AddSeconds((double)(m_cycleTime / 2));
m_tideAnnounceMsg = "Low Tide";
}
m_lastTideDirection = m_tideDirection;
}
tideRange = (double) (m_highTide - m_lowTide) / 2;
tideMiddle = (double) m_lowTide + tideRange;
m_tideLevel = (float) (Math.Cos(cycleRadians) * tideRange + tideMiddle);
tideLevelMsg = "Current Server Time: " + DateTime.Now.ToString("T") + "\n";
tideLevelMsg += "Current Tide Level: " + m_tideLevel.ToString() + "\n";
tideLevelMsg += "Low Tide Time: " + m_lowTideTime.ToString("T") + "\n";
tideLevelMsg += "Low Tide Level: " + m_lowTide.ToString() + "\n";
tideLevelMsg += "High Tide Time: " + m_highTideTime.ToString("T") + "\n";
tideLevelMsg += "High Tide Level: " + m_highTide.ToString() + "\n";
tideLevelMsg += "Tide Direction: " + ((m_tideDirection) ? "Coming In" : "Going Out") + "\n";
tideLevelMsg += "Cycle Position: " + cyclePos.ToString() + "\n";
if (m_tideAnnounceMsg != "")
{
if (m_tideAnnounceCounter++ > m_tideAnnounceCount)
{
m_tideAnnounceCounter = 0;
m_tideAnnounceMsg = "";
}
else
{
tideLevelMsg += "Tide Warning: " + m_tideAnnounceMsg + "\n";
}
}
if (m_tideInfoDebug) m_log.InfoFormat("[{0}]: Sea Level currently at {1}m in Region: {2}", m_name, m_tideLevel, m_scene.RegionInfo.RegionName);
if (m_tideInfoBroadcast && m_tideDirection)
{
m_scene.SimChatBroadcast(Utils.StringToBytes(tideLevelMsg), ChatTypeEnum.Region, m_tideInfoChannel, m_shoutPos, "TIDE", UUID.Zero, false);
m_scene.SimChatBroadcast(Utils.StringToBytes(m_tideLevel.ToString()), ChatTypeEnum.Region, m_tideLevelChannel, m_shoutPos, "TIDE", UUID.Zero, false);
}
if (m_tideInfoDebug) m_log.InfoFormat("[{0}]: Updating Region: {1}", m_name, m_scene.RegionInfo.RegionName);
m_scene.RegionInfo.RegionSettings.WaterHeight = m_tideLevel;
m_scene.EventManager.TriggerRequestChangeWaterHeight(m_tideLevel);
m_scene.EventManager.TriggerTerrainTick();
if (m_tideInfoBroadcast && !m_tideDirection)
{
m_scene.SimChatBroadcast(Utils.StringToBytes(tideLevelMsg), ChatTypeEnum.Region, m_tideInfoChannel, m_shoutPos, "TIDE", UUID.Zero, false);
m_scene.SimChatBroadcast(Utils.StringToBytes(m_tideLevel.ToString()), ChatTypeEnum.Region, m_tideLevelChannel, m_shoutPos, "TIDE", UUID.Zero, false);
}
}
private void InterfaceMultiplyTerrain(Object[] args)
{
int x, y;
for (x = 0; x < m_channel.Width; x++)
for (y = 0; y < m_channel.Height; y++)
m_channel[x, y] *= (double)args[0];
}
public void UpdateTerrainWithTide()
{
float terrain_scale = 0.75 * m_channel.Height;
float terrain_scale2 = 0.95 * m_channel.Height;
while (tideDirection == true)
{
if (m_tideLevel > terrain_scale && m_tideLevel < terrain_scale2)
{
InterfaceMultiplyTerrain(0.95);
}
}
}
#endregion
}
}
Related
I have the below code as a GPS controller and in Unity my map tiles are texturing fine... however, when I run in Xcode I get red question marks on all tiles. Is there something I'm not seeing here?
Have checked in Xcode debugger and my location coordinates are being found correctly but just not showing on tiles
Many thanks
{
RoadMap,
Satellite,
Terrain,
Hybrid
}
private const string GOOGLE_MAPS_URL = "http://maps.googleapis.com/maps/api/staticmap";
public int zoomLevel = 1;
public MapType mapType = MapType.RoadMap;
public int size = 640;
public bool doubleResolution = true;
public GPSLocationService gpsLocationService;
public MapLocation worldCenterLocation;
public MapLocation tileCenterLocation;
public Vector2 TileOffset;
public Vector2 TopLeftCorner;
public Vector2 BottomRightCorner;
private double lastGPSUpdate;
// Use this for initialization
void Start ()
{
RefreshMapTile ();
}
// Update is called once per frame
void Update ()
{
if (gpsLocationService != null &&
gpsLocationService.IsServiceStarted &&
lastGPSUpdate < gpsLocationService.Timestamp)
{
lastGPSUpdate = gpsLocationService.Timestamp;
worldCenterLocation.Latitude = gpsLocationService.Latitude;
worldCenterLocation.Longitude = gpsLocationService.Longitude;
print("GoogleMapTile refreshing map texture");
RefreshMapTile();
}
}
public void RefreshMapTile() {
StartCoroutine(_RefreshMapTile());
}
IEnumerator _RefreshMapTile ()
{
tileCenterLocation.Latitude = GoogleMapUtils.adjustLatByPixels(worldCenterLocation.Latitude, (int)(size * 1 * TileOffset.y), zoomLevel);
tileCenterLocation.Longitude = GoogleMapUtils.adjustLonByPixels(worldCenterLocation.Longitude, (int)(size * 1 * TileOffset.x), zoomLevel);
var url = GOOGLE_MAPS_URL;
var queryString = "";
queryString += "center=" + WWW.UnEscapeURL (string.Format ("{0},{1}", tileCenterLocation.Latitude, tileCenterLocation.Longitude));
queryString += "&zoom=" + zoomLevel.ToString ();
queryString += "&size=" + WWW.UnEscapeURL (string.Format ("{0}x{0}", size));
queryString += "&scale=" + (doubleResolution ? "2" : "1");
queryString += "&maptype=" + mapType.ToString ().ToLower ();
queryString += "&format=" + "png";
//styles
queryString += "&style=element:geometry|invert_lightness:true|weight:3.1|hue:0x00ffd5";
queryString += "&style=element:labels|visibility:off";
var usingSensor = false;
if MOBILE_INPUT
usingSensor = Input.location.isEnabledByUser && Input.location.status == LocationServiceStatus.Running;
endif
queryString += "&sensor=" + (usingSensor ? "true" : "false");
//set map bounds rect
TopLeftCorner.x = GoogleMapUtils.adjustLonByPixels(tileCenterLocation.Longitude, -size, zoomLevel);
TopLeftCorner.y = GoogleMapUtils.adjustLatByPixels(tileCenterLocation.Latitude, size, zoomLevel);
BottomRightCorner.x = GoogleMapUtils.adjustLonByPixels(tileCenterLocation.Longitude, size, zoomLevel);
BottomRightCorner.y = GoogleMapUtils.adjustLatByPixels(tileCenterLocation.Latitude, -size, zoomLevel);
print(string.Format("Tile {0}x{1} requested with {2}", TileOffset.x, TileOffset.y, queryString));
var req = new WWW(url + "?" + queryString);
//var req = new WWW("https://maps.googleapis.com/maps/api/staticmap?center=50.917316,-114.080923&zoom=17&format=png&sensor=false&size=640x640&scale=2&maptype=roadmap&style=feature:landscape.man_made|visibility:on|invert_lightness:true");
yield return req;
GetComponent<Renderer>().material.mainTexture = req.texture;
print(string.Format("Tile {0}x{1} textured", TileOffset.x, TileOffset.y));
}
}
At the top of the script i added the variable _birdscount:
public int _birdscount;
Then in a LoadSettings function i added the line:
res.boidSettings [0].BirdsCount = _birdscount;
So each time i change the value of _birdscount in the editor in the Inspector and then running the game it will take effect.
Settings LoadSettings()
{
TextAsset temp = (TextAsset)Resources.Load(SettingsFileName);
var str = new StringReader(temp.text);
Resources.UnloadAsset(temp);
res = (Settings)serializer.Deserialize(str);
while( res.boidSettings.Count < instancePoints.Length )
res.boidSettings.Add(new BoidSettingsEx());
res.boidSettings [0].BirdsCount = _birdscount;
return res;
}
But now i want to make that also when the game is running if i change the value of the _birdscount in the Inspector it will take effect.
So i tried in the Update function to do that if you click/press the button e it will make the changes while the game is running but it's not changing the birds count in real time. So i'm guessing just calling:
LoadSettings ();
Restart ();
Is not enough or not right.
void Update()
{
if (Input.GetKeyDown ("space"))
OnSettingsClick ();
if (Input.GetKeyDown ("e"))
{
LoadSettings ();
Restart ();
}
//We call it here to be sure that click on button desn't lead to camera target changing
if( !guiTools.MouseOverGUI && Input.GetMouseButtonDown(0) )
cameraControl.CheckForNewTarget( Input.mousePosition );
guiTools.ManualUpdate();
}
This is the complete script if it's needed:
using UnityEngine;
using System.Xml.Serialization;
using System.IO;
using System.Collections.Generic;
using UnityEngine.SceneManagement;
public class Main : MonoBehaviour
{
public CameraControl cameraControl;
public Object birdPrefab;
public Transform birdParent;
private Transform cameraObj;
public Transform[] instancePoints;
public int _birdscount;
private Settings res;
[System.Serializable]
public class BoidSettingsEx: Boid.Settings
{
public float BirdsCount = 100;
}
[System.Serializable]
public struct Size
{
public int width;
public int height;
public Size( int width, int height )
{
this.width = width;
this.height = height;
}
public bool IsValid { get{ return width > 0 && height > 0; } }
}
[System.Serializable]
public class Settings
{
public List<BoidSettingsEx> boidSettings = new List<BoidSettingsEx>();
public int instancePointNum = 0;
public Boid.DebugSettings debugSettings = new Boid.DebugSettings();
[System.Xml.Serialization.XmlIgnore]
public bool showSettingsWindow = false;
[System.Xml.Serialization.XmlIgnore]
public int settingsWindowTab = 0;
[System.Xml.Serialization.XmlIgnore]
public Size screenSize = new Size();
}
[SerializeField]
private Settings settings = new Settings();
//static is used to keep values after restart
static private Settings globalSettings;
void Start()
{
if( globalSettings == null )
{
settings = LoadSettings();
globalSettings = settings;
}
else
settings = globalSettings;
InstantiateBirds();
cameraControl.Enabled = !settings.showSettingsWindow;
}
void InstantiateBirds()
{
var ip = instancePoints[settings.instancePointNum];
var sts = settings.boidSettings[settings.instancePointNum];
sts.Trace = ip.GetComponent<Trace>();
const float size = 0.1f;
cameraObj = InstantiateBird( ip.position, ip.rotation, sts ).transform;
cameraControl.Target = cameraObj;
MathTools.FillSquareUniform( sts.BirdsCount, delegate ( int x, int y )
{
if( x != 0 || y != 0 )
InstantiateBird(
cameraObj.position + new Vector3( size * x, size * y, Random.Range(-size, size) ),
MathTools.RandomYawPitchRotation(),
sts
);
});
}
private readonly XmlSerializer serializer = new XmlSerializer(typeof(Settings));
private string SettingsFileName { get{ return "Settings"; } }
private string SettingsFilePath { get{ return Application.dataPath + Path.DirectorySeparatorChar + "Resources" + Path.DirectorySeparatorChar + SettingsFileName + ".xml";} }
Settings LoadSettings()
{
TextAsset temp = (TextAsset)Resources.Load(SettingsFileName);
var str = new StringReader(temp.text);
Resources.UnloadAsset(temp);
res = (Settings)serializer.Deserialize(str);
while( res.boidSettings.Count < instancePoints.Length )
res.boidSettings.Add(new BoidSettingsEx());
res.boidSettings [0].BirdsCount = _birdscount;
return res;
}
void SaveSettings()
{
if (Application.isEditor) {
using (var str = new FileStream (SettingsFilePath, FileMode.Create))
serializer.Serialize (str, settings);
}
}
private GameObject InstantiateBird( Vector3 position, Quaternion rotation, Boid.Settings boidSettings )
{
var obj = (GameObject)Instantiate( birdPrefab, position, rotation );
var boid = obj.GetComponent<Boid>();
obj.transform.parent = birdParent;
boid.SettingsRef = boidSettings;
boid.DebugSettingsRef = settings.debugSettings;
return obj;
}
public static Boid.Settings GetSettings( GameObject obj )
{
var main = Camera.main.GetComponent<Main>();
return main.settings.boidSettings[main.settings.instancePointNum];
}
private GuiTools guiTools = new GuiTools();
void GuiBoidSettings()
{
var sts = settings.boidSettings[settings.instancePointNum];
GUILayout.BeginHorizontal();
GUILayout.BeginVertical();
var newInstancePointNum = guiTools.Switcher( settings.instancePointNum, "Instance point", new string[]{ "WayPoints", "Box", "Freedom" } );
guiTools.FloatParam( ref sts.SpeedMultipliyer, "Speed", 20 );
guiTools.FloatParam( ref sts.ViewRadius, "Bird's view distance", 20 );
guiTools.FloatParam( ref sts.OptDistance, "Optimal distance between birds", 2 );
guiTools.FloatParam( ref sts.AligmentForcePart, "Fraction of flock aligment force", 0.01f );
GUILayout.EndVertical();
GUILayout.BeginVertical();
guiTools.FloatParam( ref sts.BirdsCount, "Number of birds (Restart Required)", 1000);
guiTools.FloatParam( ref sts.TotalForceMultipliyer, "Reaction speed", 50 );
guiTools.FloatParam( ref sts.Inertness, "Inertness", 1 );
guiTools.FloatParam( ref sts.VerticalPriority, "Flock's shape deformation", 3 );
guiTools.FloatParam( ref sts.AttractrionForce, "Waypoint's attraction force", 1.0f );
GUILayout.EndVertical();
GUILayout.EndHorizontal();
if( GUILayout.Button("Load default parameters") )
{
var defSt = LoadSettings();
settings.boidSettings[settings.instancePointNum] = defSt.boidSettings[settings.instancePointNum];
Restart();
}
if( newInstancePointNum != settings.instancePointNum )
{
settings.instancePointNum = newInstancePointNum;
cameraControl.ResetStoredSettings();
Restart();
}
}
void GuiDebugDrawSettings()
{
GUILayout.BeginVertical("box");
var newFullScreen = GUILayout.Toggle( Screen.fullScreen, "Fullscreen" );
GUILayout.EndVertical();
if( newFullScreen != Screen.fullScreen )
if( newFullScreen)
{
settings.screenSize = new Size( Screen.width, Screen.height );
Screen.SetResolution( Screen.currentResolution.width, Screen.currentResolution.height, true );
}
else if( settings.screenSize.IsValid )
Screen.SetResolution( settings.screenSize.width, settings.screenSize.height, false );
else
Screen.fullScreen = false;
GUILayout.BeginVertical("box");
guiTools.Toggle( ref settings.debugSettings.enableDrawing, "Algorithm Explanation Vectors" );
GUILayout.EndVertical();
if( settings.debugSettings.enableDrawing )
{
GUILayout.BeginVertical("box");
guiTools.Toggle( ref settings.debugSettings.velocityDraw, "Resulting velocity" );
guiTools.Toggle( ref settings.debugSettings.cohesionForceDraw, "Cohesion force" );
guiTools.Toggle( ref settings.debugSettings.collisionsAvoidanceForceDraw, "Collision Avoidance force" );
guiTools.Toggle( ref settings.debugSettings.positionForceDraw, "Cohesion + Collision Avoidance forces" );
guiTools.Toggle( ref settings.debugSettings.obstaclesAvoidanceDraw, "Obstacles Avoidance forces" );
guiTools.Toggle( ref settings.debugSettings.alignmentForceDraw, "Aligment force" );
guiTools.Toggle( ref settings.debugSettings.attractionForceDraw, "Attraction force" );
guiTools.Toggle( ref settings.debugSettings.totalForceDraw, "Resulting force" );
GUILayout.EndVertical();
}
}
void GuiInfo()
{
var text =
"<b><color=yellow>Bird Flocking Simulation</color></b>\n" +
" \n" +
" <b><color=orange>Dmitry Shesterkin 2013</color></b>\n" +
" http://black-square.github.io/BirdFlock/\n" +
" dfb#yandex.ru\n" +
" \n" +
"<b><color=yellow>Controls</color></b>\n" +
" \n" +
" <b><color=orange>Space</color></b> - Toggle settings\n" +
" <b><color=orange>Mouse</color></b> - Camera rotation\n" +
" <b><color=orange>Left Mouse Button Click</color></b> - Attach camera to target\n" +
" <b><color=orange>Tab</color></b> - Detach camera from target\n" +
" <b><color=orange>T</color></b> - Rotate camera with target\n" +
" <b><color=orange>Mouse ScrollWheel / Up / Down</color></b> - Zoom\n" +
" <b><color=orange>W/A/S/D/Q/E</color></b> - Manual camera movement\n" +
" <b><color=orange>Hold Right Mouse Button</color></b> - Disable camera rotation";
GUI.skin.box.richText = true;
GUI.skin.box.wordWrap = false;
GUI.skin.box.alignment = TextAnchor.MiddleLeft;
GUILayout.Box( text );
}
void SettingsWindow( int windowId )
{
GUILayout.BeginVertical();
settings.settingsWindowTab = GUILayout.Toolbar( settings.settingsWindowTab, new string[]{ "Birds Params", "Screen", "Info" } );
switch(settings.settingsWindowTab)
{
case 0:
GuiBoidSettings();
break;
case 1:
GuiDebugDrawSettings();
break;
case 2:
GuiInfo();
break;
}
GUILayout.EndVertical();
}
delegate void SimpleDlg();
void OnSettingsClick()
{
settings.showSettingsWindow = !settings.showSettingsWindow;
if (!settings.showSettingsWindow)
SaveSettings ();
cameraControl.Enabled = !settings.showSettingsWindow;
}
void Restart()
{
guiTools.ClearCache();
//Application.LoadLevel (Application.loadedLevelName);
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
void Update()
{
if (Input.GetKeyDown ("space"))
OnSettingsClick ();
if (Input.GetKeyDown ("e"))
{
LoadSettings ();
Restart ();
}
//We call it here to be sure that click on button desn't lead to camera target changing
if( !guiTools.MouseOverGUI && Input.GetMouseButtonDown(0) )
cameraControl.CheckForNewTarget( Input.mousePosition );
guiTools.ManualUpdate();
}
void OnGUI()
{
var tlbLabels = new string[] { "Restart", "Settings" };
var tlbActions = new SimpleDlg[] { Restart, OnSettingsClick };
var tlbResult = GUILayout.Toolbar( -1, tlbLabels );
guiTools.CheckMouseOverForLastControl();
if( tlbResult >= 0 )
tlbActions[tlbResult]();
if( settings.showSettingsWindow )
GUILayout.Window(0, new Rect(10, 30, 2, 2), SettingsWindow, "Settings");
}
}
I am making a twitch chat bot and for some reason I will sometimes get errors saying i am making cross-thread calls to an object, but I cant find anything that could be causing this, I have tried making a try-catch statement around the application.run statement but that doesn't fix it
Program.cs:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1()); // the error occurs here
}
Form1.cs:
#region variables
#region itunes variables
iTunesApp player = new iTunesApp();
#endregion
static Irc irc;
string nickname;
String message;
String rawMessage;
int dVolume = 100;
string fadeDir = "";
int fadeSpeed = 2;
#region banned_words
String[] bannedWords = { dont want to put these on this website :P};
#endregion
Thread Messages;
Form2 f2;
WebClient Client = new WebClient();
List<String> viewers;
#endregion
public Form1()
{
InitializeComponent();
player.OnPlayerPlayEvent += new _IiTunesEvents_OnPlayerPlayEventEventHandler(player_OnPlayerPlayingTrackChangedEvent);
irc = new Irc("irc.twitch.tv", 6667, "ZChembot", "oauth");
irc.joinRoom("zchem");
irc.send("Starting up...");
irc.sendIrc("CAP REQ :twitch.tv/membership");
Messages = new Thread(new ThreadStart(getMessages));
Messages.IsBackground = true;
Messages.Start();
fade.Enabled = true;
f2 = new Form2(this);
f2.Show();
getNames.Enabled = true;
}
public void player_OnPlayerPlayingTrackChangedEvent(object iTrack)
{
if (InvokeRequired)
{
this.Invoke(new Action<object>(player_OnPlayerPlayingTrackChangedEvent), new object[] { iTrack });
return;
}
IITTrack track = new iTunesApp().CurrentTrack;
if (String.IsNullOrEmpty(sound))
{
song.Text = "Song: " + track.Name;
StreamWriter file = new StreamWriter(#"c:\users\ben\desktop\twitch\Song.txt");
file.WriteLine(track.Name);
file.Close();
artist.Text = "Artist: " + track.Artist;
album.Text = "Album: " + track.Album;
}
f2.enableTimer();
f2.update();
}
public void Destroy()
{
player.OnPlayerPlayEvent -= player_OnPlayerPlayingTrackChangedEvent;
Marshal.ReleaseComObject(player);
}
#region threads
private void getMessages()
{
while (true)
{
message = irc.readMessage();
if (checkBox1.Checked)
{
updateChat("$NOTICE", message, Color.Purple);
}
rawMessage = message;
#region PRIVMSG
if (!String.IsNullOrEmpty(message))
{
if (message.Contains("PRIVMSG #zchem"))
{
nickname = rawMessage.Substring(1, message.IndexOf("!") - 1);
int start = message.IndexOf("#zchem") + 8;
String str = message.Substring(start);
message = str;
updateChat(nickname, message, Color.Black);
}
#endregion
#region notices
//successful connection
if (message.StartsWith(":tmi.twitch.tv 001 zchembot :Welcome, GLHF!"))
{
updateChat("$NOTICE", "successfully connected to the chat", Color.Green);
}
//the server pings the bot
if (message.StartsWith("PING tmi.twitch.tv"))
{
updateChat("$NOTICE", "Recieved a ping from the server", Color.Blue);
irc.sendIrc("PONG");
}
#endregion
#region play
if (message.StartsWith("!play"))
player.Play();
#endregion
#region volume up
if (message.StartsWith("!volume up"))
{
if (IsDigitsOnly(message.Substring(message.IndexOf(" ") + 1, message.Length)))
{
player.SoundVolume += int.Parse(message.Substring(message.IndexOf(" ") + 1, message.Length));
irc.send("The music volume has been changed to " + player.SoundVolume + "%");
}
}
#endregion
#region volume down
if (message.StartsWith("!volume down"))
{
if (IsDigitsOnly(message.Substring(message.IndexOf(" ", 10) + 1, message.Length)))
{
player.SoundVolume -= int.Parse(message.Substring(message.IndexOf(" ") + 1, message.Length));
irc.send("The music volume has been changed to " + player.SoundVolume + "%");
}
}
#endregion
#region vurrent volume
if (message.StartsWith("!current volume"))
{
irc.send("The current music volume is at " + player.SoundVolume + "%");
}
#endregion
#region join
if (rawMessage.EndsWith("JOIN #zchem"))
{
//detects when users join the channel
nickname = rawMessage.Substring(1, message.IndexOf("!") - 1);
irc.send("Hello, " + nickname + "!");
}
#endregion
#region part
if (rawMessage.EndsWith("PART #zchem"))
{
nickname = rawMessage.Substring(1, message.IndexOf("!") - 1);
irc.send(nickname + "has left the chat");
MessageBox.Show(nickname + "has left the chat");
}
#endregion
}
Thread.Sleep(100);
}
}
public void fade_Tick(object sender, EventArgs e)
{
if (this.Visible)
{
if (fadeDir.Equals("up"))
{
player.Play();
if (player.SoundVolume + fadeSpeed > dVolume)
player.SoundVolume = dVolume;
else
player.SoundVolume += fadeSpeed;
}
else if (fadeDir.Equals("down"))
{
if (player.SoundVolume - fadeSpeed < 0)
player.SoundVolume = 0;
else
player.SoundVolume -= fadeSpeed;
}
else if (player.SoundVolume == dVolume || player.SoundVolume == 0)
fadeDir = "";
if (player.SoundVolume == 0)
player.Pause();
}
}
#endregion
#region itunes events
private void playpause_Click(object sender, EventArgs e)
{
if (playpause.Text.Equals("❚❚"))
{
fadeDir = "down";
playpause.Text = "►";
}
else
{
fadeDir = "up";
playpause.Text = "❚❚";
}
}
private void nextSong_Click(object sender, EventArgs e)
{
player.NextTrack();
}
private void lastSong_Click(object sender, EventArgs e)
{
player.PreviousTrack();
}
private void showArt_CheckedChanged(object sender, EventArgs e)
{
if (showArt.Checked)
{
f2.Show();
}
else
{
f2.Hide();
}
}
private void soundDelay_TextChanged(object sender, EventArgs e)
{
if (!IsDigitsOnly(soundDelay.Text))
{
soundDelay.Text = "5";
}
}
#endregion
#region form events
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
Destroy();
}
#endregion
bool IsDigitsOnly(string str)
{
foreach (char c in str)
{
if (c < '0' || c > '9')
return false;
}
return true;
}
public void updateChat(string nickname, string message, Color color)
{
String text;
String time = DateTime.Now.ToShortTimeString();
time = time.Substring(0, time.Length - 3);
if (InvokeRequired)
{
this.Invoke(new Action<string, string, Color>(updateChat), new object[] { nickname, message, color });
return;
}
if (nickname.Equals("$NOTICE"))
nickname = "";
else
nickname += ": ";
text = ("[" + DateTime.Now.Hour + ":" + DateTime.Now.Minute + "] " + nickname + message + "\n");
chat.SelectionStart = chat.TextLength;
chat.SelectionLength = 0;
chat.SelectionColor = color;
chat.AppendText(text);
}
}
Irc.cs:
private string username;
public TcpClient tcpClient;
private StreamReader inputStream;
private StreamWriter outputStream;
public Irc(string ip, int port, string username, string password)
{
this.username = username;
tcpClient = new TcpClient(ip, port);
inputStream = new StreamReader(tcpClient.GetStream());
outputStream = new StreamWriter(tcpClient.GetStream());
outputStream.WriteLine("PASS " + password);
outputStream.WriteLine("NICK " + username);
outputStream.WriteLine("USER " + username + " 8 * :" + username);
outputStream.Flush();
}
public void joinRoom(string channel)
{
outputStream.WriteLine("JOIN #" + channel);
outputStream.Flush();
}
public void sendIrc(string message)
{
outputStream.WriteLine(message);
outputStream.Flush();
}
public void send(string message)
{
//sendIrc(":" + username + "!" + username + "#" + ".tmi.twitch.tv PRIVMSG #zchem :" + message);
}
public string readMessage()
{
string message = inputStream.ReadLine();
Console.WriteLine(message);
return message;
}
}
}
Form2.cs:
Form1 f1;
public Form2(Form1 f1)
{
InitializeComponent();
this.f1 = f1;
timer1.Enabled = true;
}
public void update()
{
IITTrack track = player.CurrentTrack;
IITArtworkCollection Art1 = track.Artwork;
IITArtwork Art2 = Art1[1];
Art2.SaveArtworkToFile(#"c:\users\ben\desktop\twitch\Album.png");
Stream s = File.Open(#"c:\users\ben\desktop\twitch\Album.png", FileMode.Open);
Image temp = Image.FromStream(s);
s.Close();
this.BackgroundImage = resize(temp);
if (!f1.Visible)
{
System.Environment.Exit(1);
}
}
static public Bitmap Copy(Bitmap srcBitmap, Rectangle section)
{
// Create the new bitmap and associated graphics object
Bitmap bmp = new Bitmap(section.Width, section.Height);
Graphics g = Graphics.FromImage(bmp);
// Draw the specified section of the source bitmap to the new one
g.DrawImage(srcBitmap, 0, 0, section, GraphicsUnit.Pixel);
// Clean up
g.Dispose();
// Return the bitmap
return bmp;
}
public static IEnumerable<Color> GetPixels(Bitmap bitmap)
{
for (int x = 0; x < bitmap.Width; x++)
{
for (int y = 0; y < bitmap.Height; y++)
{
Color pixel = bitmap.GetPixel(x, y);
yield return pixel;
}
}
}
#region enable click-through
public enum GWL
{
ExStyle = -20
}
public enum WS_EX
{
Transparent = 0x20,
Layered = 0x80000
}
public enum LWA
{
ColorKey = 0x1,
Alpha = 0x2
}
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
public static extern int GetWindowLong(IntPtr hWnd, GWL nIndex);
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
public static extern int SetWindowLong(IntPtr hWnd, GWL nIndex, int dwNewLong);
[DllImport("user32.dll", EntryPoint = "SetLayeredWindowAttributes")]
public static extern bool SetLayeredWindowAttributes(IntPtr hWnd, int crKey, byte alpha, LWA dwFlags);
protected void enable()
{
int wl = GetWindowLong(this.Handle, GWL.ExStyle);
wl = wl | 0x80000 | 0x20;
SetWindowLong(this.Handle, GWL.ExStyle, wl);
SetLayeredWindowAttributes(this.Handle, 0, 128, LWA.Alpha);
}
protected void disable()
{
SetWindowLong(this.Handle, GWL.ExStyle, 0);
SetLayeredWindowAttributes(this.Handle, 0, 128, LWA.Alpha);
}
#endregion
#region image stuph
public Size GenerateImageDimensions(int currW, int currH, int destW, int destH)
{
//double to hold the final multiplier to use when scaling the image
double multiplier = 0;
//string for holding layout
string layout;
//determine if it's Portrait or Landscape
if (currH > currW) layout = "portrait";
else layout = "landscape";
switch (layout.ToLower())
{
case "portrait":
//calculate multiplier on heights
if (destH > destW)
{
multiplier = (double)destW / (double)currW;
}
else
{
multiplier = (double)destH / (double)currH;
}
break;
case "landscape":
//calculate multiplier on widths
if (destH > destW)
{
multiplier = (double)destW / (double)currW;
}
else
{
multiplier = (double)destH / (double)currH;
}
break;
}
//return the new image dimensions
return new Size((int)(currW * multiplier), (int)(currH * multiplier));
}
private Image resize(Image img)
{
try
{
//calculate the size of the image
Size imgSize = GenerateImageDimensions(img.Width, img.Height, this.Width, this.Height);
//create a new Bitmap with the proper dimensions
Bitmap finalImg = new Bitmap(img, imgSize.Width, imgSize.Height);
//create a new Graphics object from the image
Graphics gfx = Graphics.FromImage(img);
//clean up the image (take care of any image loss from resizing)
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
//set the new image
return finalImg;
}
catch (System.Exception e)
{
MessageBox.Show(e.Message);
return null;
}
}
#endregion
private void timer1_Tick(object sender, EventArgs e)
{
this.Location = new Point(1920 - this.Width, 1080 - this.Height - 40);
if (Cursor.Position.X >= this.Location.X && Cursor.Position.X <= this.Location.X + this.Width && Cursor.Position.Y >= this.Location.Y && Cursor.Position.Y <= this.Location.Y + this.Height)
{
enable();
}
else
{
disable();
}
}
private void timer2_Tick(object sender, EventArgs e)
{
IITTrack track = player.CurrentTrack;
double max = track.Duration;
double val = player.PlayerPosition;
double prog = (int)(val/max * 100);
progressBar1.Value = (int)prog;
}
public void enableTimer()
{
timer2.Enabled = true;
}
}
As the debugger said, you're doing cross-thread calls.
The interface can only be updated from the main thread, and you're updating it from a secondary one.
You start a new thread on
Messages = new Thread(new ThreadStart(getMessages));
And in the getMessages function you are updating your form, so that are cross-thread calls.
If you Invoke your calls to updateChat and the MessageBox'es I think you will have enough, if no, then revise if some other function calls inside getMessages also update the interface.
Cheers.
Try this in constructor of form from which you are creating thread
Form1.CheckForIllegalCrossThreadCalls = false;
after this line InitializeComponent();
Note: This is dangerous
Try delegate methods for safe Thread calls.
I am trying to make an A* pathfinder for my game in C# XNA 4.0.
If the pathfinder executes once, then the monster moves correctly. But while the monster is moving the pathfinder executes again, and uses the current position of the enemy.
The pathfider takes about a half to one second to finish. So when the pathfinder is done and returns the new path, the monster have moved away from the position used meanwhile. So now the monster moves the whole way back to the position used, just to start the new path.
How do i solve this problem?
I dont know what you need. If it's the pathfinder code you'll need to see then i'll post it but here is the zombie class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.IO;
namespace *Private name*
{
class Zombie : Obj
{
ContentManager Content;
private Vector2 dest;
private bool[,] map;
private List<Note> path = new List<Note>();
private int PathIndex = 0;
private bool queued = false;
private int queTimer = 0;
private int queTime = 10;
private bool finding = false;
private bool walkable = false;
private Thread t;
public Zombie(Vector2 pos, string sprName, int MaxHP, int HP, int damage) : base(pos, sprName, MaxHP, HP)
{
position = pos;
spriteName = sprName;
maxHealth = MaxHP;
if (HP > maxHealth)
Health = maxHealth;
else if (HP < 0)
Health = 1;
else
Health = HP;
maxHealth = 10;
Health = 10;
solid = true;
speed = 1.0f;
dest = position;
this.damage = damage;
}
//Loads the content and sets some values
public override void LoadContent(ContentManager content)
{
spriteTexture = content.Load<Texture2D>(spriteName);
spriteRectangle = new Rectangle((int)position.X, (int)position.Y, spriteTexture.Width, spriteTexture.Height);
centerPosRec.X = (int)position.X + (spriteRectangle.Height / 2);
centerPosRec.Y = (int)position.Y + (spriteRectangle.Width / 2);
Content = content;
}
public override void Update()
{
if (!alive) return;
if (Health <= 0)
alive = false;
if (attackCoolDown > 0)
attackCoolDown--;
if (queTimer > queTime)
{
queTimer = 0;
NewSetPath();
}
else
{ queTimer++; }
MoveToDestination();
spriteRectangle.X = (int)position.X;
spriteRectangle.Y = (int)position.Y;
centerPosRec.X = (int)position.X + (spriteRectangle.Height / 2);
centerPosRec.Y = (int)position.Y + (spriteRectangle.Width / 2);
}
//Here the program finds the path
private void NewSetPath()
{
if (t != null)
if (t.IsAlive == true)
return;
dest = Player.player1.centerPosRec;
if (!finding)
{
finding = true;
t = new Thread(NewFindPath);
t.Start();
}
if (!t.IsAlive && finding)
{
t.Abort();
finding = false;
queued = false;
PathIndex = 0;
}
}
//Here it also finds the path
private void NewFindPath()
{
map = MyPathFinder.writeMap();
MyPathFinder finder;
finder = new MyPathFinder(map);
path = finder.findPath(this.centerPosRec, this.dest);
}
//Moves to the next point/note in the path list
private void MoveToDestination()
{
if (path == null)
{
return;
}
if (PathIndex < path.Count)
{
if (stepToPoint(path[PathIndex]))
{
PathIndex++;
}
else
{
PushTo(speed, rotation);
}
}
else if (path.Count >= 0)
{
path = null;
PathIndex = 0;
queued = false;
dest = Player.player1.position;
NewSetPath();
}
}
//Checkes for collition and distance to the point
private bool stepToPoint(Note note)
{
if (PointDist(centerPosRec.X, centerPosRec.Y, note.posRectangle.Y + (pathFinder.gridSize / 2), note.posRectangle.X + (pathFinder.gridSize / 2)) < pathFinder.gridSize / 2)
{
speed = 0;
return true;
}
rotation = Point_Direction(centerPosRec.X, centerPosRec.Y, note.posRectangle.Y + (pathFinder.gridSize / 2), note.posRectangle.X + (pathFinder.gridSize / 2));
speed = 2f;
return false;
}
public override void Draw(SpriteBatch spriteBatch)
{
try
{
Vector2 center = new Vector2(spriteTexture.Width / 2, spriteTexture.Height / 2);
foreach (Note n in path)
{
spriteBatch.Draw(Content.Load<Texture2D>("OfficeWall"), new Vector2(n.position.Y * 32, n.position.X * 32), null, Color.White, 0, center, scale, SpriteEffects.None, 0);
}
}
catch
{ }
base.Draw(spriteBatch);
try
{
spriteBatch.DrawString(Content.Load<SpriteFont>("HUDFont"), PathIndex + "/" + path.Count, new Vector2(500, 500), Color.White);
}
catch
{ }
}
//Gets distance between points
public static float PointDist(float x1, float y1, float x2, float y2)
{
float xRect = (x1 -x2) * (x1 - x2);
float yRect = (y1 - y2) * (y1 - y2);
double hRect = xRect + yRect;
float dist = (float)Math.Sqrt(hRect);
return dist;
}
//Movement
public override void PushTo(float pix, float dir)
{
float newX = (float)Math.Cos(MathHelper.ToRadians(dir));
float newY = (float)Math.Sin(MathHelper.ToRadians(dir));
newX *= pix;
newY *= pix;
if (!Collision(new Vector2(newX, newY)))
{
base.PushTo(pix, dir);
}
else if (!Collision(new Vector2(0, newY)))
{
this.position += new Vector2(0, newY);
}
else if (!Collision(new Vector2(newX, 0)))
{
this.position += new Vector2(newX, 0);
}
}
public override bool Collision(Vector2 pos)
{
Rectangle area = new Rectangle(spriteRectangle.X, spriteRectangle.Y, spriteRectangle.Width, spriteRectangle.Height);
area.X += (int)pos.X;
area.Y += (int)pos.Y;
foreach (Obj o in Items.objList)
{
if (o.solid && o.alive && o != this && o.GetType() != typeof(Zombie))
{
if (area.Intersects(Player.player1.spriteRectangle))
{
if (Player.player1.alive == true && attackCoolDown == 0)
{
this.attackCoolDown = 55;
Player.player1.Health -= damage;
Player.player1.regenAfterDamageTimer = 0;
Player.player1.PushTo(5f, rotation);
return true;
}
}
if (o.spriteRectangle.Intersects(area))
{
return true;
}
}
}
return false;
}
}
}
Ok, Here's the pathfinder, it is not completely done, and I know I have to move the if statement that checks if the end position is being checked. I made it faster by making it update each tick and it is working better now. Now it takes one milisecond But here it is :D
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.IO;
namespace *Private name*
{
class MyPathFinder
{
List<Note> path = new List<Note>();
List<Note> openList = new List<Note>();
List<Note> closedList = new List<Note>();
Note start;
Note endPos;
private Note[,] map;
public static int GridSize = 32;
bool NorthRight = false, NorthLeft = false, SouthRight = false, SouthLeft = false, EastRight = false, EastLeft = false, WestRight = false, WestLeft = false;
//string values = "";
public MyPathFinder(bool[,] cMap)
{
map = new Note[cMap.GetLength(0), cMap.GetLength(1)];
for (int x = 0; x < cMap.GetLength(0); x++)
{
for (int y = 0; y < cMap.GetLength(1); y++)
{
Rectangle rec = new Rectangle();
rec.Width = rec.Height = pathFinder.gridSize;
rec.X = x * pathFinder.gridSize;
rec.Y = y * pathFinder.gridSize;
map[x, y] = new Note();
map[x, y].walkable = cMap[x, y];
map[x, y].posRectangle = rec;
map[x, y].position = new Point(x, y);
}
}
}
public static bool[,] writeMap(params Obj[] objEx)
{
bool[,] cMap = new bool[Convert.ToInt16(Game1.room.Width / pathFinder.gridSize), Convert.ToInt16(Game1.room.Height / pathFinder.gridSize)];
//string output2 = "";
//loop through rows
for (int x = 0; x < cMap.GetLength(0); x++)
{
for (int y = 0; y < cMap.GetLength(1); y++)
{
Rectangle rec = new Rectangle();
rec.Width = rec.Height = pathFinder.gridSize;
rec.X = y * pathFinder.gridSize;
rec.Y = x * pathFinder.gridSize;
//output2 += Convert.ToString("{" + y + "," + x);
//If collision with grid then grid is unwalkable
foreach (Obj o in Items.objList)
{
if (o.spriteRectangle.Intersects(rec) && o.alive && o.solid && !objEx.Contains<Obj>(o) && o.GetType() != typeof(Zombie) && o.GetType() != typeof(Player))
{
cMap[x, y] = false;
break;
}
else
{
cMap[x, y] = true;
}
}
//output2 += " = " + cMap[x, y] + "} -- ";
}
//output2 += "\r\n";
}
//File.WriteAllText("DEBUG-Walkable.txt", output2);
return cMap;
}
public List<Note> findPath(Vector2 pos, Vector2 dest)
{
string wtf = "";
int num = 0;
path.Clear();
openList.Clear();
closedList.Clear();
Point startPos = new Point(Convert.ToInt16(Math.Floor((double)(pos.Y / GridSize))), Convert.ToInt16(Math.Floor((double)(pos.X / GridSize))));
Point end = new Point(Convert.ToInt16(Math.Floor((double)(dest.Y / GridSize))), Convert.ToInt16(Math.Floor((double)(dest.X / GridSize))));
start = map[startPos.X, startPos.Y];
endPos = (map[end.X, end.Y]);
openList.Add(map[startPos.X, startPos.Y]);
while (!endPos.closed)
{
num++;
openList = openList.OrderBy(p => p.F).ToList();
Note temp = null;
foreach (Note n in openList)
{
if (!closedList.Contains(n))
{
wtf += "number " + num + " = " + n.position.X + ", " + n.position.Y + "\r\n";
parenting(n.position, end);
n.closed = true;
temp = n;
break;
}
}
if (temp != null)
{
closedList.Add(temp);
openList.Remove(temp);
}
//File.WriteAllText("checking.txt", wtf);
//File.WriteAllText("listContent.txt", outp);
//File.WriteAllText("listCount.txt", openList.Count.ToString());
}
return path;
}
private void parenting(Point pos, Point dest)
{
checkNorth(pos, dest);
checkSouth(pos, dest);
checkEast(pos, dest);
checkWest(pos, dest);
//File.WriteAllText("DEBUGpos[" + pos.Y + ", " + pos.X + "].txt", values);
//if (NorthLeft && NorthRight && SouthLeft && SouthRight && EastLeft && EastRight && WestLeft && WestRight)
// Settings.exit = true;
}
private int GetH(Point v, Point endPos)
{
Point diff = new Point(v.X - endPos.X, v.Y - endPos.Y);
if (diff.X < 0) { diff.X *= 1; }
if (diff.Y < 0) { diff.Y *= 1; }
return Convert.ToInt16(diff.X + diff.Y);
}
private void checkNorth(Point pos, Point dest)
{
Point p = new Point(pos.X - 1, pos.Y);
if (map.XInRange(p.X))
{
if (map[p.X, p.Y].walkable && !map[p.X, p.Y].closed)
{
//values += p.X.ToString() + "," + p.Y.ToString() + " - " + map[p.X, p.Y].walkable + "\r\n";
if (map[p.X, p.Y] == endPos)
{
//File.WriteAllText("EndFound.txt", p.X + " - " + p.Y);
endPos.parent = pos;
endPos.closed = true;
closedList.Add(endPos);
path.Add(map[p.X, p.Y]);
while (!path.Contains(start))
{
path.Add(map[path[path.Count - 1].parent.X, path[path.Count - 1].parent.Y]);
}
path.Reverse();
}
else
{
if (map[p.X, p.Y].open == true)
{
if (map[pos.X, pos.Y].G + 10 < map[p.X, p.Y].G)
{
Settings.exit = true;
}
}
else
{
map[p.X, p.Y].open = true;
map[p.X, p.Y].parent = pos;
map[p.X, p.Y].H = GetH(p, dest);
map[p.X, p.Y].G = map[pos.X, pos.Y].G + 10;
map[p.X, p.Y].F = map[p.X, p.Y].G + map[p.X, p.Y].H;
NorthLeft = (map[p.X, p.Y - 1].walkable == true) ? true : false;
NorthRight = (map[p.X, p.Y + 1].walkable == true) ? true : false;
openList.Add(map[p.X, p.Y]);
}
}
}
else
{
NorthLeft = false;
NorthRight = false;
}
}
else
{
SouthLeft = false;
SouthRight = false;
}
//values += NorthLeft.ToString() + " " + NorthRight.ToString() + "\r\n";
}
private void checkSouth(Point pos, Point dest)
{
Point p = new Point(pos.X + 1, pos.Y);
if (p.X < 0)
{
SouthLeft = false;
SouthRight = false;
return;
}
//values += p.X.ToString() + "," + p.Y.ToString() + " - " + map[p.X, p.Y].walkable + "\r\n";
if (Enumerable.Range(0, map.GetLength(0)).Contains(p.X))
{
if (map[p.X, p.Y].walkable && !map[p.X, p.Y].closed)
{
if (map[p.X, p.Y] == endPos)
{
//File.WriteAllText("EndFound.txt", p.X + " - " + p.Y);
endPos.parent = pos;
endPos.closed = true;
closedList.Add(endPos);
path.Add(map[p.X, p.Y]);
while (!path.Contains(start))
{
path.Add(map[path[path.Count - 1].parent.X, path[path.Count - 1].parent.Y]);
}
path.Reverse();
}
else
{
if (map[p.X, p.Y].open == true)
{
if (map[pos.X, pos.Y].G + 10 < map[p.X, p.Y].G)
{
}
}
else
{
map[p.X, p.Y].open = true;
map[p.X, p.Y].parent = pos;
map[p.X, p.Y].H = GetH(p, dest);
map[p.X, p.Y].G = map[pos.X, pos.Y].G + 10;
map[p.X, p.Y].F = map[p.X, p.Y].G + map[p.X, p.Y].H;
if (Enumerable.Range(0, map.GetLength(1)).Contains(p.Y + 1))
SouthLeft = (map[p.X, p.Y + 1].walkable == true) ? true : false;
if (Enumerable.Range(0, map.GetLength(1)).Contains(p.Y - 1))
SouthRight = (map[p.X, p.Y - 1].walkable == true) ? true : false;
openList.Add(map[p.X, p.Y]);
}
}
}
else
{
SouthLeft = false;
SouthRight = false;
}
}
else
{
SouthLeft = false;
SouthRight = false;
}
//values += SouthLeft.ToString() + " " + SouthRight.ToString() + "\r\n";
}
private void checkEast(Point pos, Point dest)
{
Point p = new Point(pos.X, pos.Y + 1);
//File.WriteAllText("testEastpos.txt", p.X + " - " + p.Y + " -- " + map[p.X, p.Y].walkable);
//values += p.X.ToString() + "," + p.Y.ToString() + " - " + map[p.X, p.Y].walkable + "\r\n";
if (Enumerable.Range(0, map.GetLength(1)).Contains(p.Y))
{
if (map[p.X, p.Y].walkable && !map[p.X, p.Y].closed)
{
if (map[p.X, p.Y] == endPos)
{
//File.WriteAllText("EndFound.txt", p.X + " - " + p.Y);
endPos.parent = pos;
endPos.closed = true;
closedList.Add(endPos);
path.Add(map[p.X, p.Y]);
while (!path.Contains(start))
{
path.Add(map[path[path.Count - 1].parent.X, path[path.Count - 1].parent.Y]);
}
path.Reverse();
}
else
{
if (map[p.X, p.Y].open == true)
{
if (map[pos.X, pos.Y].G + 10 < map[p.X, p.Y].G)
{
}
}
else
{
map[p.X, p.Y].open = true;
map[p.X, p.Y].parent = pos;
map[p.X, p.Y].H = GetH(p, dest);
map[p.X, p.Y].G = map[pos.X, pos.Y].G + 10;
map[p.X, p.Y].F = map[p.X, p.Y].G + map[p.X, p.Y].H;
if (p.X - 1 >= 0)
EastLeft = (map[p.X - 1, p.Y].walkable == true) ? true : false;
else
EastLeft = false;
if (Enumerable.Range(0, map.GetLength(0)).Contains(p.Y))
{
EastRight = (map[p.X + 1, p.Y].walkable == true) ? true : false;
}
else
{ EastRight = false; }
openList.Add(map[p.X, p.Y]);
}
}
}
else
{
SouthLeft = false;
SouthRight = false;
}
}
else
{
EastLeft = false;
EastRight = false;
}
try
{
//File.WriteAllText("testEastSidepos.txt", (p.X - 1) + " - " + p.Y + " -- " + map[p.X - 1, p.Y].walkable + "\r\n" +
// (p.X + 1) + " - " + p.Y + " -- " + map[p.X + 1, p.Y].walkable);
}
catch
{ }
//values += EastLeft.ToString() + " " + EastRight.ToString() + "\r\n";
}
private void checkWest(Point pos, Point dest)
{
Point p = new Point(pos.X, pos.Y - 1);
if (Enumerable.Range(0, map.GetLength(1)).Contains(p.Y))
{
//values += p.X.ToString() + "," + p.Y.ToString() + " - " + map[p.X, p.Y].walkable + "\r\n";
if (map[p.X, p.Y].walkable && !map[p.X, p.Y].closed)
{
if (map[p.X, p.Y] == endPos)
{
//File.WriteAllText("EndFound.txt", p.X + " - " + p.Y);
endPos.parent = pos;
endPos.closed = true;
closedList.Add(endPos);
path.Add(map[p.X, p.Y]);
while (!path.Contains(start))
{
path.Add(map[path[path.Count - 1].parent.X, path[path.Count - 1].parent.Y]);
}
path.Reverse();
}
else
{
if (map[p.X, p.Y].open == true)
{
if (map[pos.X, pos.Y].G + 10 < map[p.X, p.Y].G)
{
}
}
else
{
map[p.X, p.Y].open = true;
map[p.X, p.Y].parent = pos;
map[p.X, p.Y].H = GetH(p, dest);
map[p.X, p.Y].G = map[pos.X, pos.Y].G + 10;
map[p.X, p.Y].F = map[p.X, p.Y].G + map[p.X, p.Y].H;
WestLeft = (map[p.X + 1, p.Y].walkable == true) ? true : false;
if (p.X - 1 >= 0)
WestRight = (map[p.X - 1, p.Y].walkable == true) ? true : false;
else
WestRight = false;
openList.Add(map[p.X, p.Y]);
}
}
}
else
{
WestLeft = false;
WestRight = false;
}
//values += WestLeft.ToString() + " " + WestRight.ToString() + "\r\n";
}
}
}
}
There is no need for the pathfinder to run while the monster is moving. It found a path, use that path.
A path must be recalculated, if the calculated path is blocked by an unpassable obstacle.
Then your zobie has to stop. The path is invalid anyway, it cannot move.
A path can be recalculated, if the environment changed in a way that suggests there will be a cheaper path available.
Only use the new path, if the full new path is cheaper then the remainder of the current path.
Edit:
Optimizing the pathfinder:
openList = openList.OrderBy(p => p.F).ToList();
This line is sorting the list every single time. You need a sorted list where it is sorted after inserting. As a quick fix, call openList.Sort() after inserting something. That may not be the best option though because it sorts the whole list while you already know that only a single element is unsorted.
The very same problem of finding a priority queue class in .NET is handled here
Your four north/east/south/west functions are code duplication. Check what they have in common and extract that into one common function. Your code will be just 25% of what it is now. That's not faster, but with less code, it's easier to see stuff.
Problem
I'm using a C# application to record keyboard and mouse movement, processing that movement and sending serial data out to a micro-controller that interpreters that data and moves a set of servos. In the past I had created a box or image that was the resolution(number of steps) my servos were capable of, clipped the mouse to that box or image, and processed where the cursor was in that box and sent data to my servos to move to that position.
This worked fine and dandy till I needed to move a greater amount of steps than my monitor has resolution.
So my question is what options are available to me for tracking mouse movement up to 10,000 steps/resolution in the X and Y axis?
Possible solution route
Thinking outside the box I think I could hide and center the mouse on the screen, record how much the mouse moved on mousemoved events, process that data, then recenter the mouse on the screen to give me unlimited movement in each axis.
Enclosed below is my PIC18F2420 code. Currently it is fed x and y positions via serial communications from my C# application. Data is stored in a ring buffer as it is received and processed as soon as possible.
PIC CODE
#include <p18f2420.h>
#include <cType.h>
#include <usart.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <timers.h>
#include <delays.h>
/**********************************************************************************************/
//DEFINES
#define switch_0 PORTCbits.RC4
#define switch_1 PORTCbits.RC5
#define bufferSize 48
/**********************************************************************************************/
/**********************************************************************************************/
//Function prototypes
void high_isr(void);
void int2ASCII(unsigned int output);
void UART_putChar(unsigned char value);
char readBuffer();
char emptyBuffer();
char peekBuffer();
void limitServo0(); //limit movement via predetermined min/max
void limitServo1();
/**********************************************************************************************/
unsigned char hertz = 75; //value to generate 5-=60 hertz wave default value 75
unsigned int timer0, servo0Min, servo0Max;
unsigned int timer1, servo1Min, servo1Max;
unsigned char servo0Rate = 10;
unsigned char ByteOut;
char array[bufferSize]; //input rs-232 buffer
char valueArray[bufferSize];
char dataArray[bufferSize];
char tempArray[bufferSize];
unsigned char tempIndex;
unsigned char head = 0;
unsigned char tail = 0;
//variables used to disect the comma delimited string
char CVdata; //do we have a command and value?
char CVvalue; //bool value like above
//BOOLEAN IF values
/**********************************************************************************************/
//Interrupt Service Routine
#pragma code high_vector=0x08
void interrupt_at_high_vector (void)
{
_asm GOTO high_isr _endasm
}
#pragma code /* return to the default code section */
#pragma interrupt high_isr
void high_isr (void)
{
if(PIR1bits.TMR2IF == 1)
{
//T0CONbits.TMR0ON = 0;
//T1CONbits.TMR1ON = 0;
INTCONbits.TMR0IF = 0; //Turn off Int Flag
PIR1bits.TMR1IF = 0;
PIR1bits.TMR2IF = 0; //Turn off Int Flag
LATCbits.LATC3 = 1; //Turn on data line
TMR0H = timer0/256; //Extract HIGH byte always do Hbyte first
TMR0L = timer0; //Extract LOW byte
}
if(PIR1bits.TMR1IF == 1)
{
PIR1bits.TMR1IF = 0;
//T1CONbits.TMR1ON = 0;
//PIR1bits.TMR2IF = 0; //Turn off Int Flag
INTCONbits.TMR0IF = 0; //Turn off Int Flag
LATCbits.LATC2 = 0;
PR2 = hertz; //Generate 50-60hertz pulse
}
if(INTCONbits.TMR0IF == 1)
{
LATCbits.LATC2 = 1;
//PIR1bits.TMR1IF = 0;
//PIR1bits.TMR2IF = 0; //Turn off Int Flag
//T0CONbits.TMR0ON = 0;
//T1CONbits.TMR1ON = 1;
INTCONbits.TMR0IF = 0; //Turn off Int Flag
LATCbits.LATC3 = 0;
TMR1H = timer1/256;
TMR1L = timer1;
}
if(PIR1bits.RCIF == 1)
{
PIR1bits.RCIF = 0;
array[tail] = RCREG;
//array[tail] = ReadUSART();
tail++;
if(tail == bufferSize)
{
tail = 0;
}
/* Clear the interrupt flag */
}
}
/**********************************************************************************************/
void main(void)
{
/**********************************************************************************************/
//Initialize
memset(array, '\0' , bufferSize);
memset(tempArray, '\0' , bufferSize);
memset(dataArray, '\0' , bufferSize);
memset(valueArray, '\0' , bufferSize);
TRISC = 0b10110000;//RC4 and RC5 inputs for switches
servo0Max = 65000; //Max value allowed PAN 65000
servo0Min = 62000; //Min value allowed 63500
servo1Max = 65000; //Tilt 64138
servo1Min = 62000; //TILT 63864
timer0 = 64250; //Initial position
timer1 = 64200;
CVdata = 0;
CVvalue = 0;
tempIndex = 0;
LATCbits.LATC0 = 0;
/**********************************************************************************************/
//USART
OpenUSART(USART_TX_INT_OFF &
USART_RX_INT_ON &
USART_CONT_RX &
USART_ASYNCH_MODE &
USART_EIGHT_BIT &
USART_BRGH_HIGH
, 16);//change back to 16 for 57.6 103 for 9.6
RCSTAbits.ADDEN = 0;//Testing this out might not help with overflow
TXSTAbits.SYNC = 0;
INTCONbits.GIE = 1;
INTCONbits.PEIE = 1;
TXSTAbits.BRGH = 1;
BAUDCONbits.BRG16 = 1;
/**********************************************************************************************/
//Initialize Timer0
OpenTimer0(TIMER_INT_ON &
T0_SOURCE_INT &
T0_16BIT);
T0CONbits.PSA = 1;
INTCONbits.TMR0IF = 0;
/**********************************************************************************************/
/**********************************************************************************************/
//Initialize Timer1
OpenTimer1(TIMER_INT_ON &
T1_16BIT_RW &
T1_SOURCE_INT &
T1_PS_1_1);
T1CONbits.T1CKPS1 = 0; // bits 5-4 Prescaler Rate Select bits
T1CONbits.T1CKPS0 = 0; // bit 4
T1CONbits.T1OSCEN = 1; // bit 3 Timer1 Oscillator Enable Control bit 1 = on
T1CONbits.T1SYNC = 1; // bit 2 Timer1 External Clock Input Synchronization Control bit...1 = Do not synchronize external clock input
T1CONbits.TMR1CS = 0; // bit 1 Timer1 Clock Source Select bit...0 = Internal clock (FOSC/4)
T1CONbits.TMR1ON = 1; // bit 0 enables timer
/**********************************************************************************************/
/**********************************************************************************************/
//Initialize Timer2
OpenTimer2( TIMER_INT_ON &
T2_PS_1_16 &
T2_POST_1_16);
PR2 = hertz;
PIE1bits.TMR2IE = 1;
IPR1bits.TMR2IP = 1;
INTCONbits.GIEH = 1; //enable global interrupts
INTCONbits.GIEL = 1;
/**********************************************************************************************/
while(1)
{
while(emptyBuffer());
if(CVdata == 0 && CVvalue == 1)
{
//ERROR THIS SHOULDN't HAPPEN! FLUSH BUFFER
CVdata = 0;
CVvalue = 0;
}
if(CVdata == 0 && CVvalue == 0)
{
if(peekBuffer() != ',')
{
tempArray[tempIndex] = readBuffer();
tempIndex++;
}
else
{
readBuffer();//if comma sent first read it and throw away
if(tempIndex > 0) //comma read and data in buffer
{
memcpy(dataArray, tempArray, tempIndex);
tempIndex = 0;
CVdata = 1;
memset(tempArray, 'a' , bufferSize);
}
}
}
if(CVdata ==1 && CVvalue == 0)
{
if(peekBuffer() != ',')
{
if(isdigit(peekBuffer()))
{
tempArray[tempIndex] = readBuffer();
tempIndex++;
}
else
readBuffer();
}
else
{
//readBuffer();
if(tempIndex > 0)
{
memcpy(valueArray, tempArray, tempIndex);
tempIndex = 0;
CVvalue = 1;
memset(tempArray, 'a', bufferSize);
}
}
}
if(CVdata == 1 && CVvalue == 1)
{
switch(dataArray[0])
{
case 'x':
case 'X':
{
//timer0 = current = atof(valueArray);//ISSUE HERE first char null
timer0 = (unsigned int)atoi(valueArray);
break;
}
case 'y':
case 'Y':
{
timer1 = (unsigned int)atoi(valueArray);
break;
}
}
CVdata = 0;
CVvalue = 0;
memset(dataArray, 'a' , bufferSize);
memset(valueArray, 'a' , bufferSize);
}
limitServo0();
limitServo1();
}
}
/**********************************************************************************************/
//Functions
void int2ASCII(unsigned int output)
{
unsigned char digit = 0;
while (output >= 10000) { output -= 10000; digit++; } UART_putChar(digit + 0x30); digit = 0;
while (output >= 1000) { output -= 1000; digit++; } UART_putChar(digit + 0x30); digit = 0;
while (output >= 100) { output -= 100; digit++; } UART_putChar(digit + 0x30); digit = 0;
while (output >= 10) { output -= 10; digit++; } UART_putChar(digit + 0x30); digit = 0;
while (output >= 1) { output -= 1; digit++; } UART_putChar(digit + 0x30);
}
void UART_putChar(unsigned char value)
{
while(PIR1bits.TXIF == 0);
TXREG = value;
}
char readBuffer()
{
if(tail != head)
{
ByteOut = array[head];
head++;
if(head == bufferSize)
{
head = 0;
}
return ByteOut;
}
//LATCbits.LATC0 = 1;
}
char peekBuffer()
{
return array[head];
}
char emptyBuffer()
{
if(tail == head)
return 1;
else
return 0;
}
void limitServo0()
{
if(timer0 > servo0Max)
{
timer0 = servo0Max;
}
if(timer0 < servo0Min)
{
timer0 = servo0Min;
}
}
void limitServo1()
{
if(timer1 > servo1Max)
{
timer1 = servo1Max;
}
if(timer1 < servo1Min)
{
timer1 = servo1Min;
}
}
An Example of my previous tracking via bitmap can be viewed on my youtube channel at: http://www.youtube.com/watch?v=rBhkV3dnyiU&list=UULGlw5rGZfETaiPs49JBEuA&index=41
UPDATE
After some research it seems I can write a XNA application, capture mouse movement, and output serial communications. I would really really like a windows forms solution but I do have XNA experience so guess I'll work on converting my application until another solution presents itself.
My initial purposed solution did the trick. On trackingEnabled I center the mouse and check how much it has moved every 100ms, after that I recenter it and send the data to my controller.
using System;
using System.Timers;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using PIC18F_Servo_Control_V2;
namespace FSI_Grid1
{
public partial class Form1 : Form
{
TabControl LeftControlTab;
System.Timers.Timer myTimer;
public delegate void UpdateStatusBarDelegate();
TabPage myTabPage;
Grid myGrid;
serialConnection myConnection;
int timerDelay = 100;
int initialX, initialY, currentX, currentY, minX, minY, maxX, maxY;
int MouseCurrentX, MouseCurrentY, MouseMovedX, MouseMovedY;//tracking mousemovement
int offsetX, offsetY;//how much each arrow click moves the servos
bool trackingActive;//are we in tracking mode?
bool MouseMovedFlag;
int YOffsetValue;//used to offset dynamically generated buttons in tab groups
int XCenter, YCenter;
enum States { Startup, MouseTracking, KeyboardTracking, Script, Idle };//state engine
States CurrentState;
public Form1()
{
currentX = initialX = 63503;
currentY = initialY = 64012;
minX = 62000;
maxX = 65000;
minY = 62000;
maxY = 65000;
offsetX = 10;
offsetY = 10;
trackingActive = false;
YOffsetValue = 0;
CurrentState = States.Startup;
MouseMovedFlag = false;
myTimer = new System.Timers.Timer(timerDelay);
myTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
myTimer.Elapsed += new ElapsedEventHandler(TrackMouse);
myTimer.Enabled = false;
InitializeComponent();
InitializeGrid();
InitializeLeftControlTab();
InitializeSerial();
//Initialize StatusBar
RadioButton button = (RadioButton)this.Controls.Find("SelectKeyboardRadioButton", true)[0];
button.Checked = true;
activeStatus.Text = "Keyboard Tracking DEACTIVATED";
activeStatus.BackColor = Color.Red;
ConnectionStatus.Text = "Disconnected!";
xOffsetStatus.Text = "X offset value " + offsetX.ToString();
yOffsetStatus.Text = "Y offset value " + offsetY.ToString();
//this.MouseMove += new MouseEventHandler(Form_MouseMove);
XCenter = this.Location.X + this.Width / 2;
YCenter = this.Location.Y + this.Height / 2;
}
~Form1()
{
if (myConnection.connected)
myConnection.disconnect();
}
private void widthTextBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = !char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar);
}
private void widthTextBox_KeyUp(object sender, KeyEventArgs e)
{
TextBox text = (TextBox)this.Controls.Find("widthTextBox", true)[0];
xOffsetStatus.Text = text.Text;
offsetX = Convert.ToInt16(text.Text);
}
private void heightTextBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = !char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar);
}
private void heightTextBox_KeyUp(object sender, KeyEventArgs e)
{
TextBox text = (TextBox)this.Controls.Find("heightTextBox", true)[0];
yOffsetStatus.Text = text.Text;
offsetY = Convert.ToInt16(text.Text);
}
private void LeftControlTab_DrawItem(object sender, DrawItemEventArgs e)
{
Graphics g = e.Graphics;
Brush _textBrush;
// Get the item from the collection.
TabPage _tabPage = LeftControlTab.TabPages[e.Index];
// Get the real bounds for the tab rectangle.
Rectangle _tabBounds = LeftControlTab.GetTabRect(e.Index);
if (e.State == DrawItemState.Selected)
{
// Draw a different background color, and don't paint a focus rectangle.
_textBrush = new SolidBrush(Color.Red);
g.FillRectangle(Brushes.White, e.Bounds);
}
else
{
_textBrush = new System.Drawing.SolidBrush(e.ForeColor);
g.FillRectangle(Brushes.LightGray, e.Bounds);
//e.DrawBackground();
}
// Use our own font.
Font _tabFont = new Font("Arial", (float)10.0, FontStyle.Bold, GraphicsUnit.Pixel);
// Draw string. Center the text.
StringFormat _stringFlags = new StringFormat();
_stringFlags.Alignment = StringAlignment.Center;
_stringFlags.LineAlignment = StringAlignment.Center;
g.DrawString(_tabPage.Text, _tabFont, _textBrush, _tabBounds, new StringFormat(_stringFlags));
}
private void InitializeLeftControlTab()
{
LeftControlTab = new TabControl();
LeftControlTab.Location = new Point(10, 30);
LeftControlTab.Size = new Size(300, 500);
LeftControlTab.Alignment = TabAlignment.Left;
LeftControlTab.SizeMode = TabSizeMode.Fixed;
LeftControlTab.ItemSize = new Size(30, 90);
LeftControlTab.DrawMode = TabDrawMode.OwnerDrawFixed;
/*EVENT HANDLER*/
LeftControlTab.DrawItem += new DrawItemEventHandler(LeftControlTab_DrawItem);
/*TABS*/
int offset = 100; //how far to the right the edit boxes are
myTabPage = new TabPage();
myTabPage.Text = "Appearance";
LeftControlTab.Controls.Add(myTabPage);
myTabPage = new TabPage();
myTabPage.Text = "Settings";
/*LABEL*/
Label OffsetLabel = new Label();
OffsetLabel.Text = "Step resolution";
OffsetLabel.Location = new Point(0,YOffset());
myTabPage.Controls.Add(OffsetLabel);
/*WIDTH LABEL*/
Label widthLabel = new Label();
widthLabel.Text = "Width";
widthLabel.Location = new Point(0, YOffset());
myTabPage.Controls.Add(widthLabel);
/*WIDTH TEXTBOX*/
TextBox widthTextBox = new TextBox();
widthTextBox.Name = "widthTextBox";
widthTextBox.Text = myGrid.Width.ToString();
widthTextBox.Location = new Point(widthLabel.Location.X + offset, widthLabel.Location.Y);
myTabPage.Controls.Add(widthTextBox);
widthTextBox.KeyPress += new KeyPressEventHandler(widthTextBox_KeyPress); //EVENT HANDLER
widthTextBox.KeyUp += new KeyEventHandler(widthTextBox_KeyUp); //EVENT HANDLER
/*HEIGHT LABEL*/
Label heightLabel = new Label();
heightLabel.Text = "Height";
heightLabel.Location = new Point(0, YOffset());
myTabPage.Controls.Add(heightLabel);
/*HEIGHT TEXTBOX*/
TextBox heightTextBox = new TextBox();
heightTextBox.Name = "heightTextBox";
heightTextBox.Text = myGrid.Height.ToString();
heightTextBox.Location = new Point(heightLabel.Location.X + offset, heightLabel.Location.Y);
myTabPage.Controls.Add(heightTextBox);
/*RADIOBUTTON LABEL*/
GroupBox RadioLabel = new GroupBox();
RadioLabel.Text = "Tracking Style";
RadioLabel.Location = new Point(0, YOffset());
myTabPage.Controls.Add(RadioLabel);
/*RADIO BUTTONS*/
RadioButton SelectMouse = new RadioButton();
SelectMouse.Location = new Point(10, 20);
SelectMouse.Text = "Mouse";
SelectMouse.Name = "SelectMouseRadioButton";
SelectMouse.CheckedChanged += new EventHandler(RadioButtons_CheckedChanged);
RadioLabel.Controls.Add(SelectMouse);
RadioButton SelectKeyboard = new RadioButton();
SelectKeyboard.Location = new Point(10, 42);
SelectKeyboard.Text = "Keyboard";
SelectKeyboard.Name = "SelectKeyboardRadioButton";
SelectKeyboard.CheckedChanged += new EventHandler(RadioButtons_CheckedChanged);
RadioLabel.Controls.Add(SelectKeyboard);
heightTextBox.KeyPress += new KeyPressEventHandler(heightTextBox_KeyPress); //EVENT HANDLER
heightTextBox.KeyUp += new KeyEventHandler(heightTextBox_KeyUp); //EVENT HANDLER
//EVENT HANDLER
LeftControlTab.Controls.Add(myTabPage);
Controls.Add(LeftControlTab);
}
private void InitializeGrid()
{
myGrid = new Grid(offsetX, offsetY);
}
private void connectToolStripMenuItem_Click(object sender, EventArgs e)
{
serialConnectionDialogBox serialBox = new serialConnectionDialogBox();
Point temp = this.Location;
temp.X += 30;
temp.Y += 70;
serialBox.Location = temp;
DialogResult results = serialBox.ShowDialog();
if (results == DialogResult.Yes && !myConnection.connected)
{
myConnection.setCOMMPort(serialBox.commPortComboBox.Text);
myConnection.setBaudRate(Convert.ToInt32(serialBox.baudRateComboBox.Text));
myConnection.connect();
}
if (myConnection.connected)
{
ConnectionStatus.Text = "X " + currentX.ToString() + "Y " + currentY.ToString();
}
}
private void InitializeSerial()
{
myConnection = new serialConnection();
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
bool updatePos = false;
switch (keyData)
{
case Keys.Left:
currentX += offsetX;
updatePos = true;
break;
case Keys.Right:
currentX -= offsetX;
updatePos = true;
break;
case Keys.Up:
currentY += offsetY;
updatePos = true;
break;
case Keys.Down:
currentY -= offsetY;
updatePos = true;
break;
case Keys.F5:
if (trackingActive)
{
trackingActive = false;
LeftControlTab.Enabled = true;
if(CurrentState == States.KeyboardTracking)
activeStatus.Text = "Keyboard Tracking DEACTIVATED";
if (CurrentState == States.MouseTracking)
activeStatus.Text = "Mouse Tracking DEACTIVATED";
activeStatus.BackColor = Color.Red;
myTimer.Enabled = false;
}
else
{
trackingActive = true;
LeftControlTab.Enabled = false;
if (CurrentState == States.KeyboardTracking)
activeStatus.Text = "Keyboard Tracking ACTIVATED";
if (CurrentState == States.MouseTracking)
activeStatus.Text = "Mouse Tracking ACTIVATED";
activeStatus.BackColor = Color.Green;
myTimer.Enabled = true;
}
break;
}
if (updatePos == true)
{
updatePos = false;
Point temp = new Point();
temp.X = currentX = clipX(currentX);
temp.Y = currentY = clipY(currentY);
String tx = "x," + Convert.ToString(temp.X) + ",y," + Convert.ToString(temp.Y) + ",";
myConnection.sendData(tx);
ConnectionStatus.Text = "X " + currentX.ToString() + "Y " + currentY.ToString();
}
return base.ProcessCmdKey(ref msg, keyData);
}
private void disconnectToolStripMenuItem_Click_1(object sender, EventArgs e)
{
if (myConnection.connected)
{
myConnection.disconnect();
ConnectionStatus.Text = "Disconnected!";
}
}
private void RadioButtons_CheckedChanged(object sender, EventArgs e)
{
if (sender == (RadioButton)this.Controls.Find("SelectMouseRadioButton", true)[0])
{
CurrentState = States.MouseTracking;
activeStatus.Text = "Mouse Tracking ";
}
if (sender == (RadioButton)this.Controls.Find("SelectKeyboardRadioButton", true)[0])
{
CurrentState = States.KeyboardTracking;
activeStatus.Text = "Keyboard Tracking ";
}
if (trackingActive)
activeStatus.Text += "ACTIVATED";
else
activeStatus.Text += "DEACTIVATED";
}
private void TrackMouse(object source, ElapsedEventArgs e)
{
if (trackingActive && CurrentState == States.MouseTracking)
{
MouseMovedFlag = true;
MouseMovedX = -1 * (Cursor.Position.X - XCenter);
MouseMovedY = -1 * (Cursor.Position.Y - YCenter);
currentX += MouseMovedX;
currentX = clipX(currentX);
currentY += MouseMovedY;
currentY = clipY(currentY);
statusStrip1.Invoke(new UpdateStatusBarDelegate(this.UpdateStatusBar), null);
Cursor.Position = new Point(XCenter, YCenter);
}
}
private int clipX(int tempX)
{
if(tempX < minX)
tempX = minX;
if(tempX > maxX)
tempX = maxX;
return tempX;
}
private int clipY(int tempY)
{
if(tempY < minY)
tempY = minY;
if (tempY > maxY)
tempY = maxY;
return tempY;
}
private int YOffset()
{
int tempValue = YOffsetValue;
if (tempValue == 0)
{
YOffsetValue += 22;
return tempValue;
}
else
{
YOffsetValue += 22;
return tempValue;
}
}
void OnTimedEvent(object source, ElapsedEventArgs e)
{
if (true)
{
if (MouseMovedFlag || trackingActive)
{
Point temp = new Point();
temp.X = currentX;
temp.Y = currentY;
String tx = "x," + Convert.ToString(temp.X) + ",y," + Convert.ToString(temp.Y) + ",";
myConnection.sendData(tx);
}
}
}
void UpdateStatusBar()
{
ConnectionStatus.Text = "X " + currentX.ToString() + "Y " + currentY.ToString();
ConnectionStatus.Invalidate();
this.Update();
}
}
}