Plot very large number of box plots (range between 1 to 10,000) using Tee chart - boxplot

I need to allow user to select Start and End data. Once it is selected, i need to fetch all the group data between these dates and display box plot. The problem is box plots are overlaid if there are many box plot needs to be displayed. Tee chart does not automatically shrink the size of boxplot. Also, does not provide scroll to bar to adjust bottom axis to accommodate all the box plots. Any solution ?

I used your code in C# but it did not adjusted the width of box and they were overlapping.
private void button3_Click_1(object sender, EventArgs e)
{
tChart1.Aspect.View3D = false;
tChart1.Legend.Visible = false;
for(int i=0;i<100;i++)
{
Steema.TeeChart.Styles.Box b = new Steema.TeeChart.Styles.Box();
tChart1.Series.Add(b);
b.Position = i;
b.FillSampleValues();
}
tChart1.Panning.Allow = ScrollModes.Horizontal;
tChart1.Zoom.Direction = ZoomDirections.Horizontal;
ReCalculateBoxWidth();
}
public void ReCalculateBoxWidth()
{
int boxW;
double tmpW;
tChart1.Draw();
tmpW = (tChart1.Chart.ChartRect.Right - tChart1.Chart.ChartRect.Left) / (tChart1.Axes.Bottom.Maximum - tChart1.Axes.Bottom.Minimum) / 2;
tmpW = tmpW * 0.9;
boxW = (int)Math.Round(tmpW);
foreach (Steema.TeeChart.Styles.CustomBox b in tChart1.Series)
{
b.Box.SizeUnits = Steema.TeeChart.Styles.PointerSizeUnits.Pixels;
b.Box.SizeDouble = boxW;
}
tChart1.Draw();
}

You could calculate the appropriate box width according to your needs.
Here is is a simple example with 100 boxes that resizes them at Zoom & UnZoom events.
In C# using TeeChart .NET
Here the code:
private void testBoxPlotWidth()
{
tChart1.Aspect.View3D = false;
tChart1.Legend.Visible = false;
for (int i = 0; i < 100; i++)
{
Box b = new Box();
tChart1.Series.Add(b);
b.Position = i;
b.FillSampleValues();
b.ColorEach = true;
}
tChart1.Panning.Allow = ScrollModes.Horizontal;
tChart1.Zoom.Direction = ZoomDirections.Horizontal;
ReCalculateBoxWidth();
tChart1.Zoomed += TChart1_Zoomed;
tChart1.UndoneZoom += TChart1_UndoneZoom;
}
private void TChart1_UndoneZoom(object sender, EventArgs e)
{
ReCalculateBoxWidth();
}
private void TChart1_Zoomed(object sender, EventArgs e)
{
ReCalculateBoxWidth();
}
public void ReCalculateBoxWidth()
{
int boxW;
double tmpW;
tChart1.Draw();
tmpW = tChart1.Chart.ChartRect.Width / (tChart1.Axes.Bottom.Maximum - tChart1.Axes.Bottom.Minimum) / 2;
tmpW = tmpW * 0.7;
boxW = (int)Math.Round(tmpW);
foreach (CustomBox b in tChart1.Series)
{
b.Box.SizeUnits = PointerSizeUnits.Pixels;
b.Box.HorizSize = boxW;
}
}
In Delphi using TeeChart VCL/FMX
Here the code:
procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
Chart1.View3D:=False;
Chart1.Legend.Hide;
for i:=0 to 99 do
with Chart1.AddSeries(TBoxSeries) as TBoxSeries do
begin
Position:=i;
FillSampleValues;
end;
Chart1.AllowPanning:=pmHorizontal;
Chart1.Zoom.Direction:=tzdHorizontal;
RecalcBoxWidth;
end;
procedure TForm1.Chart1UndoZoom(Sender: TObject);
begin
RecalcBoxWidth;
end;
procedure TForm1.Chart1Zoom(Sender: TObject);
begin
RecalcBoxWidth;
end;
procedure TForm1.RecalcBoxWidth;
var i, boxW: Integer;
tmpW: Double;
begin
Chart1.Draw;
tmpW:=(Chart1.ChartRect.Right - Chart1.ChartRect.Left) / (Chart1.Axes.Bottom.Maximum - Chart1.Axes.Bottom.Minimum) / 2;
tmpW:=tmpW*0.9;
boxW:=Round(tmpW);
for i:=0 to 99 do
with Chart1[i] as TBoxSeries do
begin
Box.SizeUnits:=suPixels;
Box.Size:=boxW;
end;
Chart1.Draw;
end;

Related

How can I scale a unity sprite programmatically to a fractional number of units?

I've spawned a tile as follows:
private GameObject SpawnTile(int col, int row, Color color, GameObject parent, string label)
{
GameObject g = new GameObject("C: " + col + " R: " + row);
g.transform.position = world_grid.GetWorldPosition(col, row);
g.transform.localScale = new Vector3(world_grid.cell_size, world_grid.cell_size);
g.transform.parent = parent.transform;
return g;
}
I then add a spriterenderer, and display a sprite of a given color.
tile.game_object = SpawnTile(col, row, color, parent, label);
tile.sprite_renderer = tile.game_object.AddComponent<SpriteRenderer>();
tile.sprite_renderer.sprite = tile_sprite;
//Bounds bounds = tile.sprite_renderer.bounds;
tile.sprite_renderer.color = color;
I have the ability to display grids using this mechanism. I can scale the size of a tile up by an integer amount. However when I try to scale the object down, the sprite does not scale down with it.
In the following, I have 3 1x1 grids. The grid on the right has a cell_size of 2. The grid in the middle has a cell_size of 1. The grid on the left has a cell_size of 0.5.
The "tile" object is of an appropriate size. As we see this object is shown as half size in Unity's Scene View. However in the game view on the right, it shows as the same size as the pink grid in the middle.
Further details, I have spent quite a bit of time trying to figure this out, and though I see a variety of posts that seem to relate to sprite sizing, none of them are clear for a relative unity beginner.
Some of the posts I've found seem to suggest that I need to use the sprite renderer bounds to ensure that the sprite is proeprly sized. But its not clear to me how.
This is my grid class. Notice that it is constructed with a cell_size (in units). Notice that when I create the object of a given size, I size the object, but not the sprite.
public class WorldGrid<TGridObject> : Grid<TGridObject>
{
public float cell_size { get; private set; }
// Defines the center point in world coordinates
public Vector3 center_point { get; private set; }
public WorldGrid(Vector3 _center_point, int _columns, int _rows, float _cell_size) : base(_columns, _rows)
{
cell_size = _cell_size;
center_point = _center_point;
}
public Vector3 GetWorldPosition(int col, int row)
{
float x_pos = col * cell_size + cell_size / 2f;
float y_pos = row * cell_size + cell_size / 2f;
// wp = cp + gp
return center_point + new Vector3(x_pos, y_pos);
}
public void GetGridPosition(Vector3 world_position, out int col, out int row)
{
// gp = wp - cp
// position in grid-centered reference frame
Vector3 gp = world_position - center_point;
row = Mathf.FloorToInt(gp.y / cell_size);
col = Mathf.FloorToInt(gp.x / cell_size);
}
public void SetValue(Vector3 world_position, TGridObject value)
{
int row, col;
GetGridPosition(world_position, out row, out col);
SetValue(row, col, value);
}
}
This references a lower level grid class (that is not in world units):
public class Grid<TGridObject>
{
public int columns { get; private set; }
public int rows { get; private set; }
public TGridObject[,] grid { get; private set; }
private int cnt = 0;
public event EventHandler<OnGridCellValueChangedEventArgs> OnGridCellValueChanged;
public class OnGridCellValueChangedEventArgs : EventArgs
{
public int cnt;
public int row;
public int column;
}
public Grid(int _columns, int _rows)
{
columns = _columns;
rows = _rows;
grid = new TGridObject[columns, rows];
}
public void SetValue(int col, int row, TGridObject value)
{
if((row >= 0 && row < rows) &&
(col >= 0 && col < columns))
{
grid[col, row] = value;
if(OnGridCellValueChanged != null)
{
cnt += 1;
Debug.LogError("Triggering [" + col + "," + row + "] of [" + columns + "," + rows + "]");
OnGridCellValueChanged(this,
new OnGridCellValueChangedEventArgs { row = row, column = col, cnt = cnt }
);
}
}
}
public TGridObject GetValue(int col, int row)
{
if ((row >= 0 && row < rows) &&
(col >= 0 && col < columns))
{
return grid[col, row];
} else
{
return default(TGridObject);
}
}
}
I instantiate grids using a GridManager class:
public class GridManager : MonoBehaviour
{
[System.Serializable]
private struct WorldGridDescriptor
{
public int rows;
public int columns;
public float cell_size;
public Vector3 center_point;
public bool randomize_start;
}
public Sprite tile_sprite;
public int world_size_factor = 1;
private int columns, rows;
private float unit_step_size = 1.0f;
private List<WorldGrid<float>> world_grids = new List<WorldGrid<float>>();
private List<GridView> world_grid_views = new List<GridView>();
[SerializeField] private List<WorldGridDescriptor> world_grid_descriptors;
// Start is called before the first frame update
void Start()
{
// The orthographic size specifies the camera units from
// the horizontal centerline to the top of screen
// The vertical_units are then the number of tile rows
// from the centerline to the top of screen
rows = (int)Camera.main.orthographicSize * world_size_factor * 2;
float aspect_ratio = ((float)Screen.width / (float)Screen.height);
columns = (int)(rows * aspect_ratio);
// Will parent the tiles in the empty Grid.
// Perhaps this container should be public.
// For now it is a hard-coded assumption, that it exists.
GameObject grid_container = this.gameObject.transform.Find("Grid").gameObject;
if (world_grid_descriptors != null)
{
foreach (WorldGridDescriptor wgd in world_grid_descriptors)
{
WorldGrid<float> wg = new WorldGrid<float>(wgd.center_point, wgd.columns, wgd.rows, wgd.cell_size);
if(wgd.randomize_start)
{
RandomizeState(wg);
}
GridView grid_view = new GridView(wg, tile_sprite, grid_container);
world_grids.Add(wg);
world_grid_views.Add(grid_view);
}
}
}
private void RandomizeState(WorldGrid<float> g)
{
for (int col = 0; col < g.columns; col++)
{
for (int row = 0; row < g.rows; row++)
{
g.SetValue(col, row, Random.Range(0.0f, 1.0f));
}
}
}
private void Update()
{
if (Input.GetMouseButtonDown(0)) {
Vector3 worldPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
foreach (WorldGrid<float> wg in world_grids)
{
int c, r;
wg.GetGridPosition(worldPosition, out c, out r);
wg.SetValue(c, r, Random.Range(0.0f, 1.0f));
}
}
}
}
Lastly, the view into the grids are created as follows (this shows you exactly how I create the grid representation that uses a sprite renderer component to render sprites for each cell in the grid):
public class GridView
{
public struct Tile
{
public GameObject game_object;
public SpriteRenderer sprite_renderer;
public TextMesh text_mesh;
}
private Tile[,] tiles;
private WorldGrid<float> world_grid;
protected Sprite tile_sprite { get; private set; }
public GridView(WorldGrid<float> wg, Sprite ts, GameObject parent)
{
world_grid = wg;
tile_sprite = ts;
tiles = new Tile[wg.columns, wg.rows];
wg.OnGridCellValueChanged += OnGridCellValueChanged;
Create(parent);
}
private void Create(GameObject parent)
{
for (int col = 0; col < world_grid.columns; col++)
{
for (int row = 0; row < world_grid.rows; row++)
{
Tile tile = new Tile();
float r, g, b;
r = g = b = world_grid.grid[col, row];
float a = 1f;
Color color = new Color(r, g, b, a);
string label = (string)((int)(255 * world_grid.grid[col, row])).ToString("x");
tile.game_object = SpawnTile(col, row, color, parent, label);
tile.sprite_renderer = tile.game_object.AddComponent<SpriteRenderer>();
tile.sprite_renderer.sprite = tile_sprite;
//Bounds bounds = tile.sprite_renderer.bounds;
tile.sprite_renderer.color = color;
tile.text_mesh = UtilsClass.CreateWorldText(label, parent.transform,
tile.game_object.transform.position, 7, Color.red, TextAnchor.MiddleCenter);
tiles[col, row] = tile;
}
}
}
// Update is called once per frame
private GameObject SpawnTile(int col, int row, Color color, GameObject parent, string label)
{
GameObject g = new GameObject("C: " + col + " R: " + row);
g.transform.position = world_grid.GetWorldPosition(col, row);
g.transform.localScale = new Vector3(world_grid.cell_size, world_grid.cell_size);
g.transform.parent = parent.transform;
return g;
}
private void OnGridCellValueChanged(object sender, Grid<float>.OnGridCellValueChangedEventArgs e)
{
Debug.LogError(e.cnt + " - Updating [" + e.column + "," + e.row + "]");
Update(e.row, e.column);
}
private void Update(int row, int col)
{
if (row >= 0 && row < world_grid.rows && col >= 0 && col < world_grid.columns)
{
Tile tile = tiles[col, row];
float r, g, b;
r = g = b = world_grid.grid[col, row];
float a = 1f;
Color color = new Color(r, g, b, a);
string label = (string)((int)(255 * world_grid.grid[col, row])).ToString("x");
tile.text_mesh.text = label;
tile.sprite_renderer.color = color;
}
}
}
My sprites are a simple blank image that is 256 x 256 pixels in size. I then set the pixels per unit (in the unity editor) to 256.
How can I scale the sprite so that it aligns properly with the spawned tile?
Looks like my only issue was in the Display setting.
I had been using a 10x10 display.
When I changed it to something more reasonable, I realized that my gameobjects were being displayed and selected as expected.

Floating origin and visual effect graph in Unity

I am sure that everybody knows about this script, http://wiki.unity3d.com/index.php/Floating_Origin, that fixes problems with floating origin easily.
The problem is that the script is outdated and does not move the particle effects created by visual effect graph.
I was trying to rewrite it but I cant seem to make an array to store all the particles, like with the previous one, thus I can't continue from there.
Here is my code:
// Based on the Unity Wiki FloatingOrigin script by Peter Stirling
// URL: http://wiki.unity3d.com/index.php/Floating_Origin
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.VFX;
using UnityEngine.Experimental.VFX;
public class FloatingOrigin : MonoBehaviour
{
[Tooltip("Point of reference from which to check the distance to origin.")]
public Transform ReferenceObject = null;
[Tooltip("Distance from the origin the reference object must be in order to trigger an origin shift.")]
public float Threshold = 5000f;
[Header("Options")]
[Tooltip("When true, origin shifts are considered only from the horizontal distance to orign.")]
public bool Use2DDistance = false;
[Tooltip("When true, updates ALL open scenes. When false, updates only the active scene.")]
public bool UpdateAllScenes = true;
[Tooltip("Should ParticleSystems be moved with an origin shift.")]
public bool UpdateParticles = true;
[Tooltip("Should TrailRenderers be moved with an origin shift.")]
public bool UpdateTrailRenderers = true;
[Tooltip("Should LineRenderers be moved with an origin shift.")]
public bool UpdateLineRenderers = true;
private ParticleSystem.Particle[] parts = null;
VisualEffect[] visualEffect = null;
void LateUpdate()
{
if (ReferenceObject == null)
return;
Vector3 referencePosition = ReferenceObject.position;
if (Use2DDistance)
referencePosition.y = 0f;
if (referencePosition.magnitude > Threshold)
{
MoveRootTransforms(referencePosition);
if (UpdateParticles)
MoveParticles(referencePosition);
if (UpdateTrailRenderers)
MoveTrailRenderers(referencePosition);
if (UpdateLineRenderers)
MoveLineRenderers(referencePosition);
}
}
private void MoveRootTransforms(Vector3 offset)
{
if (UpdateAllScenes)
{
for (int z = 0; z < SceneManager.sceneCount; z++)
{
foreach (GameObject g in SceneManager.GetSceneAt(z).GetRootGameObjects())
g.transform.position -= offset;
}
}
else
{
foreach (GameObject g in SceneManager.GetActiveScene().GetRootGameObjects())
g.transform.position -= offset;
}
}
private void MoveTrailRenderers(Vector3 offset)
{
var trails = FindObjectsOfType<TrailRenderer>() as TrailRenderer[];
foreach (var trail in trails)
{
Vector3[] positions = new Vector3[trail.positionCount];
int positionCount = trail.GetPositions(positions);
for (int i = 0; i < positionCount; ++i)
positions[i] -= offset;
trail.SetPositions(positions);
}
}
private void MoveLineRenderers(Vector3 offset)
{
var lines = FindObjectsOfType<LineRenderer>() as LineRenderer[];
foreach (var line in lines)
{
Vector3[] positions = new Vector3[line.positionCount];
int positionCount = line.GetPositions(positions);
for (int i = 0; i < positionCount; ++i)
positions[i] -= offset;
line.SetPositions(positions);
}
}
private void MoveParticles(Vector3 offset)
{
var particles = FindObjectsOfType<ParticleSystem>() as ParticleSystem[];
foreach (ParticleSystem system in particles)
{
if (system.main.simulationSpace != ParticleSystemSimulationSpace.World)
continue;
int particlesNeeded = system.main.maxParticles;
if (particlesNeeded <= 0)
continue;
bool wasPaused = system.isPaused;
bool wasPlaying = system.isPlaying;
if (!wasPaused)
system.Pause();
// ensure a sufficiently large array in which to store the particles
if (parts == null || parts.Length < particlesNeeded)
{
parts = new ParticleSystem.Particle[particlesNeeded];
}
// now get the particles
int num = system.GetParticles(parts);
for (int i = 0; i < num; i++)
{
parts[i].position -= offset;
}
system.SetParticles(parts, num);
if (wasPlaying)
system.Play();
}
var particles2 = FindObjectsOfType<VisualEffect>() as VisualEffect[];
foreach (VisualEffect system in particles2)
{
int particlesNeeded = system.aliveParticleCount;
if (particlesNeeded <= 0)
continue;
bool wasPaused = !system.isActiveAndEnabled;
bool wasPlaying = system.isActiveAndEnabled;
if (!wasPaused)
system.Stop();
// ensure a sufficiently large array in which to store the particles
if (visualEffect == null || visualEffect.Length < particlesNeeded)
{
visualEffect = new VisualEffect().visualEffectAsset[particlesNeeded];
}
// now get the particles
int num = system.GetParticles(parts);
for (int i = 0; i < num; i++)
{
parts[i].position -= offset;
}
system.SetParticles(parts, num);
if (wasPlaying)
system.Play();
}
}
}
On the line(this is a wrong line and everything below it too)
visualEffect = new VisualEffect().visualEffectAsset[particlesNeeded];
, I need to create a similar array to the line (correct one, but for the old particle system)
parts = new ParticleSystem.Particle[particlesNeeded];
that creates array full of particles (but with VisualEffect class).
If I can fix this one, there should not be any problem with the rest.
I think that solving this problem will help literally thousands of people now and in the future, since limitation for floating origin in unity are horrible and majority of people working in unity will need floating origin for their game worlds, with VFX graph particles.
Thanks for the help.
My question has been answered here:
https://forum.unity.com/threads/floating-origin-and-visual-effect-graph.962646/#post-6270837

Microphone, gain value and spectrum values do not sync using Unity

I am making a simple voice visualization program. My goals are:
Playback microphone input
Visualize voice spectrum and gain in real time
Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class VisualizeVoice : MonoBehaviour
{
private const int NUM_SPECTRUM_SAMPLES = 256;
private const int NUM_SPECTRUM_BARS = 32;
private const int NUM_PCM_SAMPLES = 16000;
private const float BAR_DROP_SPEED = 1e-3f;
private const int NUM_SAMPLES_TO_AVERAGE = 8;
private string _deviceName;
private float[] _spectrumData = new float[NUM_SPECTRUM_SAMPLES];
private float[] _fPCMData = new float[NUM_PCM_SAMPLES];
private float _gain = 0;
private AudioClip _audio; // Audio from microphone
private AudioSource _playback; // To play the audio from microphone
// For visualization
private GameObject[] _spectrumBars = new GameObject[NUM_SPECTRUM_BARS];
private GameObject _gainBar;
// Start is called before the first frame update
void Start()
{
if (Microphone.devices.Length == 0) {
Debug.LogError("No Microphone");
return;
}
_deviceName = Microphone.devices[0];
Debug.Log("Current microphone is " + _deviceName);
if ((_playback = this.GetComponent<AudioSource>()) == null) {
_playback = this.gameObject.AddComponent<AudioSource>();
}
_playback.loop = true;
_playback.bypassEffects = true;
_playback.bypassListenerEffects = true;
_playback.bypassReverbZones = true;
_playback.priority = 0;
_playback.pitch = 1;
_playback.clip = _audio = Microphone.Start(_deviceName, true, 1, AudioSettings.outputSampleRate);
// Sync microphone and playback, but it always fails
float waitTime = 0;
while (!(Microphone.GetPosition(_deviceName) > 0) && waitTime <= 2)
waitTime += Time.deltaTime;
if (waitTime > 2) {
Debug.LogError("time out waiting for microphone");
}
_playback.Play();
InitVisualization();
}
// Update is called once per frame
void Update()
{
// Get PCM data and calculate gain
var audioPosition = Microphone.GetPosition(_deviceName);
_audio.GetData(_fPCMData, audioPosition);
UpdateGain();
// Get spectrum data
_playback.GetSpectrumData(_spectrumData, 0, FFTWindow.BlackmanHarris);
// Update visualization
UpdateVisualization();
}
private void InitVisualization()
{
// Initialize spectrum bars
for (int ibar = 0; ibar < NUM_SPECTRUM_BARS; ibar++) {
_spectrumBars[ibar] = GameObject.CreatePrimitive(PrimitiveType.Cube);
_spectrumBars[ibar].transform.parent = this.transform;
_spectrumBars[ibar].transform.localPosition = new Vector3(ibar, 0, 0);
_spectrumBars[ibar].transform.localScale = new Vector3(1, 0, 1);
}
// Initialize gain bar
_gainBar = GameObject.CreatePrimitive(PrimitiveType.Cube);
_gainBar.transform.parent = this.transform;
_gainBar.transform.localPosition = new Vector3(-5, 0, 0);
_gainBar.transform.localScale = new Vector3(4, 0, 1);
// Overall dimension
this.transform.localScale = new Vector3(0.2f, 10.0f, 0.2f);
}
private void UpdateVisualization()
{
// Update spectrum bars
int nSamplesPerBar = NUM_SPECTRUM_SAMPLES / NUM_SPECTRUM_BARS;
for (int ibar = 0; ibar < NUM_SPECTRUM_BARS; ibar++) {
// Calculate value of each bar
float value = 0;
for (int isample = 0; isample < nSamplesPerBar; isample++) {
value += _spectrumData[ibar * nSamplesPerBar + isample];
}
value /= nSamplesPerBar;
// Use current value if increasing, or slowly drop previous value if decreasing
float prevValue = _spectrumBars[ibar].transform.localScale.y;
if (value < prevValue)
value = prevValue - BAR_DROP_SPEED;
// Y scale is set to value
_spectrumBars[ibar].transform.localScale = new Vector3(1, value, 1);
}
// Update gain bar
_gainBar.transform.localScale = new Vector3(4, _gain, 1);
}
private void UpdateGain()
{
_gain = 0;
for(int i = 0; i < NUM_SAMPLES_TO_AVERAGE; i++) {
_gain += Mathf.Abs(_fPCMData[NUM_PCM_SAMPLES - i - 1]);
}
_gain /= NUM_SAMPLES_TO_AVERAGE;
}
}
Here are my questions:
I can't use while (!Microphone.GetPosition(_deviceName) > 0)); to avoid latency from microphone to speaker. If I use it, my application just freezes. If I add code to allow time-out, it has time-out every time.
The gain bar seems irrelevant with my voice. I don't know if my calculation is right.
I'm not sure if I need to average over multiple samples calculating gains, and how many samples I need to average over. I need this gain value later to detect silent moments and cut audio data.
To 1.
You can. Unity allows to define Start as a Coroutine
private IEnumerator Start()
{
...
}
On this way you can use a non blocking
while (!Microphone.GetPosition(_deviceName) > 0))
{
yield return null;
}

Dynamically adding tiles to a grid based map

I want to have an infinitely explorable map. The plan is to create categories of game tiles (roads, obstacles, buildings), and randomly choose a category of game tile to be added when the player approaches the edge of the existing set of tiles. Tiles will also be destroyed once the player is 2 grid squares away from that tile. Currently I am using a multidimensional array that requires a size initializer.
What I have so far:
public class GameManager : MonoBehaviour
{
private GameObject[,] tileArray;
public GameObject groundTile;
public GameObject player;
private int tileSize = 80;
private int nextFarX = 1;
private int nextFarZ = 1;
private int nextNearX = -1;
private int nextNearZ = -1;
private float padding = .1f;
private int arrayOffset;
private int arrayDimension;
// Use this for initialization
void Start ()
{
arrayDimension = 200;
arrayOffset = arrayDimension / 2;
tileArray = new GameObject[,];
this.AddCubeAt(0, 0);
}
// Update is called once per frame
void Update () {
var x = Convert.ToInt32(player.transform.position.x / tileSize);
var z = Convert.ToInt32(player.transform.position.z / tileSize);
for (int i = -1; i < 2; i++)
{
for (int j = -1; j < 2; j++)
{
var checkX = x + i;
var checkZ = z + j;
if (tileArray[checkX + arrayOffset, checkZ + arrayOffset] == null)
{
//player is less than 2 tiles away from this grid, add a tile
this.AddCubeAt(checkX, checkZ);
}
}
}
// feels like a hack, but it will remove tiles that are not touching the tile that the player occupies
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 6; j++)
{
if (i == 0 | i == 5 | j == 0 | j == 5)
{
if (tileArray[x + (i-2) + arrayOffset, z + (j-2) + arrayOffset] != null)
{
Destroy(tileArray[x + (i - 2) + arrayOffset, z + (j - 2) + arrayOffset]);
tileArray[x + (i - 2) + arrayOffset, z + (j - 2) + arrayOffset] = null;
}
}
}
}
}
private void AddCubeAt(int x, int z)
{
var pos = new Vector3(x * tileSize, 0, z * tileSize);
var rot = Quaternion.identity;
GameObject newCube = (GameObject)Instantiate(groundTile, pos, rot);
tileArray[x + arrayOffset, z + arrayOffset] = newCube;
}
}
What is a better way to approach this?
You should familiarize yourself with Graph Data Structure (not adjacency matrix implementation). It's much more appropriate for this task. And, I would solve this
Tiles will also be destroyed once the player is 2 grid squares away from that tile
in another way: Every time player changed his position I would start DFS on target depth (in your case it's 2) and remove found tiles.
Decided to go with a simple Dictionary and methods to query/update it:
private GameObject RetrieveTileAt(int x, int z)
{
string key = string.Format("{0}.{1}", x, z);
if (tileDictionary.ContainsKey(key))
{
return tileDictionary[key];
}
else
{
return null;
}
}
private void InsertTileAt(int x, int z, GameObject tile)
{
string key = string.Format("{0}.{1}", x, z);
tileDictionary[key] = tile;
}
It is not an infinitely sized grid, (int min + int max)squared, but it should be far more than I need.

Processing.js: Won't track mouseMoved()?

I'm having an issue with tracking the movement of a mouse in a Processing sketch when its ported to Javascript. As far as I can tell, the program runs fine except that it wont activate mouseMoved, either as an event or as a logical operation. I also tried pMousex != mouseX and that also didn't work. Any help?
color[] palette = new color[5];
color c1;
color c2;
color c3;
color c4;
color c5;
color bgColor;
int swarmSize;
int xVariance;
int yVariance;
int maxSize;
int maxOpacity;
int maxStroke;
//Non-definables for swarm gen
int sideMod;
int sSize;
int opacity;
int stroke;
void setup() {
size(600, 400);
c1= #BF2633;
c2= #A6242F;
c3= #D9CEAD;
c4= #C0B18F;
c5= #011C26;
bgColor = color(23, 76, 79);
palette[0] = c1;
palette[1] = c2;
palette[2] = c3;
palette[3] = c4;
palette[4] = c5;
swarmSize = 1;
xVariance = 60;
yVariance = 60;
maxSize = 30;
maxOpacity = 255;
maxStroke = 4;
}
void draw() { //tried tracking pMouse != mouse here, no dice
}
void drawSwarm() {
for (int i = 0; i < swarmSize; i++)
{
if (random(1, 10) < 5) {
sideMod = -1;
}
else {
sideMod = 1;
}
stroke = int(random(1, maxStroke));
sSize = int(random(1, maxSize));
opacity = int(random(0, maxOpacity));
strokeWeight(stroke);
stroke(palette[int(random(1, 5))], opacity);
fill(palette[int(random(1, 5))], opacity);
// strokeWeight(int(random(1, 7)));
ellipse(mouseX + int(random(1, xVariance)) * sideMod, mouseY+ int(random(1, yVariance)), sSize, sSize);
}
}
void mouseMoved() { //Doesn't work in processing.js
drawSwarm();
}
void keyPressed() {
background(bgColor);
}
The following code works just fine (see http://jsfiddle.net/qPpRQ/)
int x,y;
void draw() {
point(x,y);
}
void mouseMoved() {
x = mouseX;
y = mouseY;
redraw();
}
usually, draw instructions in a mouse handler don't work all that well, you generally want to set up your state based on the mouse position, and then call redraw(), with the code that actually draws things to the screen being called from draw, not from your event handler.