Ho realizzato in Xna un programma fantascientifico che permette la navigazione in un sistema planetario. Gli oggetti sono costruiti tramite moltissime strutture, alcune molto leggere che descrivono un pianeta "in lontananza" (modelli "Far", le cui istanze sono semplici sfere nude), ed altre molto pesanti per i grossi pianeti da sorvolare o da esplorare al suolo (modelli "Near", con milioni di primitive modellati da heightmaps e ricoperti da textures). E' impossibile postare il codice ma il riassunto del Main è qui:
codice:
//Namespaces
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections;
using System.Windows.Forms;
using System.Collections.Generic;
namespace Progetto_Albireo
{
public class My : Microsoft.Xna.Framework.Game
{
//Generals
public static GraphicsDeviceManager Graphicsdevicemanager;
.............
public static string StarType = "Progetto_Albireo.Star"; MODELLO STELLA 'FAR' (leggero)
public static string TStarType = "Progetto_Albireo.TStar"; MODELLO STELLA 'NEAR' (leggero)
//Worlds
public static string SphType = "Progetto_Albireo.SphWorld"; MODELLO PIANETA 'FAR' (leggero)
public static string SphHType = "Progetto_Albireo.SphHWorld"; MODELLO PIANETA 'NEAR' (molto pesante)
..... ecc.
//FUNZIONI DI UTILITY
public static float VelocityAt(float G, float M, float d)
{
return (float)Math.Sqrt(G * M / d);
}
.......... ecc.
//METODO CHE INIZIALIZZA IL SISTEMA
public void InitSystem()
{
Planets.Add("A", new Star(...);
Planets.Add("B", new SphWorld(....);
................ ecc.
}
public My()
{
//costruiamo un nostro GraphicsDeviceManager
//la sua proprietà più importante è il GraphicsDevice
Graphicsdevicemanager = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
Spritebatch = new SpriteBatch(GraphicsDevice);
........... ecc.
base.Initialize();
}
protected override void LoadContent()
{
Background = Content.Load<Texture2D>("back");
............. ecc.
InitSystem();
}
protected override void Update(GameTime gametime)
{
My.Discovery.Depthlist.Clear(); LISTA DEGLI OGGETTI
IN ORDINE DI DISTANZA DALLA CAMERA (astronave)
TStar.H1("A"); METODO STATICO CHE TRASFORMA "A" DA 'Sta'r IN 'TStar'
SE CI SI AVVICINA TROPPO E LO RIPORTA A 'Star' SE CI SI ALLONTANA;
AGGIORNA LA Dephtlist
SphHWorld.H1("B", 0f, Vector3.Zero); METODO STATICO CHE TRASFORMA "B" DA 'SphWorld' IN 'SphHWorld'
SE CI SI AVVICINA TROPPO E LO RIPORTA A 'SphWorld' SE CI SI ALLONTANA;
AGGIORNA LA Dephtlist
.......... ecc.
}
protected override void Draw(GameTime gametime)
{
GraphicsDevice.Clear(Color.Black);
string T;
foreach (KeyValuePair<double, string> item in Discovery.Depthlist)
{
double d = item.Key;
string k = item.Value;
T = My.Planets[k].GetType().ToString();
if (T == My.StarType)
{
Star x = (Star)Planets[k];
x.Draw(GraphicsDevice);
}
else if (T == My.TStarType)
{
TStar x = (TStar)Planets[k];
x.Draw(GraphicsDevice);
}
else if (T == My.SphType)
{
SphWorld x = (SphWorld)Planets[k];
x.Draw(GraphicsDevice);
}
else if (T == My.SphHType)
{
SphHWorld x = (SphHWorld)Planets[k];
x.Draw(GraphicsDevice);
}
else if ........... ecc.
}
}
}
}
Il cuore del programma è il metodo statico H1 che opera la trasformazione da "Far" a "Near" e viceversa. Questo è il riassunto:
codice:
public static void H1(string k, float FM, Vector3 L)
{
if (My.Planets[k].GetType().ToString() == My.SphType)
{
SphWorld x = (SphWorld)My.Planets[k];
Vector3 d = My.Discovery.Position - x.Location;
//costruisce la collection di profondità
double D = Math.Sqrt((Math.Pow(d.X, 2) + Math.Pow(d.Y, 2) + Math.Pow(d.Z, 2)));
My.Discovery.Depthlist.Add(-D, k);
...
//Solving
if (d.Length() < x.Ehorizon)
SphHWorld.Solve(k); 'TRASFORMA x NEL TIPO 'SphHWorld'
}
else
{
SphHWorld x = (SphHWorld)My.Planets[k];
Vector3 d = My.Discovery.Position - x.Location;
//costruisce la collection di profondità
double D = Math.Sqrt((Math.Pow(d.X, 2) + Math.Pow(d.Y, 2) + Math.Pow(d.Z, 2)));
My.Discovery.Depthlist.Add(-D, k);
...
//Unsolving
if (d.Length() > x.Ehorizon)
SphHWorld.Unsolve(k);'RIPORTA x IN AL TIPO 'SphWorld'
}
}
Ecco in dettaglio i due metodi "decisivi" richiamati da H1:
codice:
public static void Solve(string k)
{
.........
My.Planets.Remove(k);
My.Planets.Add(k, new SphHWorld(...);
}
public static void Unsolve(string k)
{
..........
My.Planets.Remove(k);
My.Planets.Add(k, new SphWorld(...);
}
Per avere la piena padronanza di questo programma mi manca solo di capire bene cosa succede QUI e QUI, ma soprattutto QUI:
codice:
public static void Solve(string k)
{
My.Planets.Remove(k);<<<<<------------------- QUI
My.Planets.Add(k, new SphHWorld(...);
}
public static void Unsolve(string k)
{
My.Planets.Remove(k);<<<<<-------------------- QUI
My.Planets.Add(k, new SphWorld(...);
}
Non capisco un tubo di Garbage Collection. Vorrei capire se l'oggetto k in hastable viene rimosso anche dalla memoria oltre che dall'hash, e se navigando negli spazi aperti lontano dal sistema non ci sono in memoria oggetti "Near" residenti. Un oggetto SphHWorld è veramente ingombrante....
Spero di essere stato chiaro. Grazie