Dieser Beitrag gibt die eine Chance deinen Boss zu beeindrucken, deine Verwandten zu überraschen, jedem zu zeigen , dass man dich ernst nehmen sollte, macht die Welt zu einem besserem Platz und so weiter.
Dieser Code liest die Daten in einer Textdatei und stellt sie als 3D Graph dar. Schauen wir mal was in dieser Textdatei war, die mit diesem Beitrag kam:
data1,
100
data2,
50
data3,
35
data4,
75
data5,
58
end
Beginnen wir mit der Funktion, die die Daten liest:
function
read_data()
{
data_handle = file_open_read("data.txt"); // open the file
while (str_cmp (temp_string, "end") == 0) // read until you have reached
"end"
Wir öffnen die Datei data.txt zum lesen und lesen ihren Inhalt bis wir am Ende angelangt sind ("end").
{
file_str_read(data_handle, temp_string);
str_cpy(data_name.string[i], temp_string);
if (str_cmp (temp_string, "end") == 0) // don't try to read inexistent
data numbers after "end" -> this can create trouble
{
data_value[i] = file_var_read(data_handle);
if ((data_value[i] < 0) || (data_value[i] > 100)) // data_value must
be in the 0..100 interval
{
error_text.visible = on; // make the error text visible
sleep (5); // for 5 seconds
exit; // and then shut down the engine
}
}
else
{
break; // get out of the loop -> don't increase "i" because it would be
wrong and we need its correct value in main
}
i += 1;
}
ready = 1; // all the data was read
}
Wir haben 2 Spalten in der data.txt: eine für strings und die andere für die damit verknüpften Werte. Die strings werden in den temporären string temp_string gelesen und ihr Inhalt wird nach data_name kopiert, ein array von strings. Die Werte werden direkt im array namens data_value gespeichert. Wenn die Werte, die aus der data.txt gelesen werden, unter 0 oder über 100 liegen, zeigen wir für 5 sek. Eine Fehlermeldung und beenden die engine. Die Variable namens i (Index) wird 1 sein für die erste Aufnahme (data + value), 2 für die zweite und so weiter. Wenn wir aus der Whileschleife austreten, beträgt i = 5 wenn data.txt 5 aufnahmen hat, i = 2 bei 2 Aufnahmen und so weiter.
Sobald wir ans Ende der Datei gelangen ("end") treten wir aus der Whileschleife aus und setzen ready auf 1; dies ist die Variable die in der main-function verwendet wird. An diesem Punkt haben wir alle strings in data_name und alle Werte in data_value gespeichert.
function
main()
{
camera.arc = 75; // set the field of view
read_data(); // read the data stored in data.txt
level_load (dummy_wmb);
while (ready == 0) {wait (1);} // wait until all the data is read
temp.x = 270;
temp.y = 100 - (5 - i) * 25;
Wir setzen den Sichtbereich auf 75 Grad, wir rufen die Funktion auf, die die data.txt liest, wir laden ein Dummy-Level und wir warten bis die Daten fertig sind (ready = 1).
Lass mich dir einige Dinge über das Dummy-Level sagen – es ist ein spezielles Level . Wenn du es in WED öffnest wirst du sehen, dass es einen einzigen block enthält, der als Ursprung für den 3D Graph benutzt wird, aber es hat keine ausgehöhlte box herum. Wenn an „vergisst“ sein Level in einen ausgehöhlten block oder eine Sphäre zu setzen, wird die engine unendliche Abstände rendern (die grenze wird von clip_range festgelegt). So wird Etwas, das für einige Frames im Level ist für immer sichtbar sein, auch wenn man die Entity, das Panel , den Text etc entfernt. Ich habe diese Methode angewandt, weil ich ein einziges Panel verwenden will um die Werte für alle Balken anzuzeigen. Falls meine data.txt 50 Aufnahmen enthalten hätte, hatte ich 50 Panels definieren müssen, stimmt`s? Mit meinem Trick benötige ich ein einziges Panel für alle Werte die über den 3D Balken erscheinen; Ich erhalte den ersten Wert und zeige ihn über dem ersten Balken an für ein paar Frames, dann lese ich den nächsten Wert und bewege das Panel über den 2ten Balken für einige Frames etc.
Der einzige Nachteil ist, dass alles verschoben wird, sobald ich die Kamera ändere, aber warum sollte ich so etwas tun? Zurück zum Thema.
Die 3D Balken sind Modelle; Veränderungen von scale_z, abhängig von ihren Werten, machst sie größer oder kleiner. Die Modelle werden 270 quants vor dem Spieler platziert; Ihre Position auf der y-Achse wird je nach Anzahl der Aufnahmen geändert (data + value) so wie auf diesem Bild:
Man sieht, dass die Balken unabhängig der Anzahl der Aufnahmen (von 1 bis 5) richtig dargestellt werden. Die Zeile die hierfür zuständig ist lautet:
temp.y = 100 - (5 - i) * 25;
Erkennst
du sie wieder aus der Funktion read_data? Falls wir 5 Aufnahmen in data.txt
haben, ist i = 5 und temp.y = 100; für i = 4, temp.y = 75 etc. Die
3D Balken werden an der Position die von temp gegeben wird erstellt; Wir
haben es geschafft sie an der y-Achse auszurichten, aber wir können
wir sie an der z-Achse ausrichten? Unser Balkenmodell hat seinen Ursprung
in seinem Zentrum, deswegen würden wir so etwas erhalten, wenn wir
mehrere Balken skalieren würden ohne gewisse Berichtigungen:
Also
es ist klar, dass der Ursprung eines Objekts auf der selben Höhe
bleibt; wir müssen die Balken je nach Wert aus der data.txt hoch oder
runterschieben.
j = 0;
while (j < i)
{
temp.z = -100 + data_value[j];
Wir werden einen neuen Zähler namens j verwenden, da I die Anzahl der Aufnahmen beinhaltet und wir wollen diese Werte nicht verlieren. Das Balkenmodell hat eine Höhe von 2 quants. Falls der Wert eines bestimmten Balkens 100 beträgt, wird dieser Balken allen Platz auf der z-Achse ausfüllen(200 quants); Für kleinere Werte wird der Balken nach unten bewegt entsprechend dem Wert von data_value; So werden alle Balken an den Boden ausgerichtet.
ent_create (bar_mdl, temp, size_bar);
temp.y -= 50;
j += 1;
wait (3);
}
}
Alle Balken werden auf der Position die von temp gegeben wird erstellt; Der 2te Balken wird sein y-Wert um 50 quants gesenkt haben und so weiter. Wir müssen mindesten 3 Frames warten, da wir 5 verschiedene Werte auf 5 verschiedenen Plätzen anzeigen wollen indem wir ein einziges Panel verwenden mit einem digit. Wenn du eine ältere 3d-Karte hast die double buffering verwendet, kannst du wait (2) verwenden aber es ist sicherer anzunehmen, dass die Karte trible buffering verwendet, also verwenden wir wait (3).
Jeder Balken der erstellt wird bekommt diese Funktion:
function
size_bar()
{
my.albedo = 100;
my.light = on;
my.lightrange = 0;
my.lightred = bar_color[k+0];
my.lightgreen = bar_color[k+1];
my.lightblue = bar_color[k+2];
k += 3;
my.scale_z = data_value[j];
vec_set(temp_value, my.pos);
vec_to_screen(temp_value, camera);
value_pan.pos_x = temp_value.x;
value_pan.pos_y = 80 + (100 - data_value[j]) * 4;
temp_value = data_value[j];
value_pan.visible = on;
}
Ich habe albedo auf 100 gesetzt, da die Balken auf Licht reagieren müssen; Ihre Farben werden aus einem array genommen – die Definition steht hier:
var bar_color[15] = 250, 0, 0, 0, 250, 0, 0, 0, 250, 250, 250, 0, 250, 250, 250; // red, green, blue, yellow, white
Die ersten 3 Werte bestimmen die Farben des ersten Balkens, die nächsten 3 werden für die Farben des 2ten Balkens genutzt und so weiter. Ich habe mich dazu entschlossen, rot, grün, blau, gelb und weiß z7u verwenden; Alle Farben sind dem weißen Balkenmodell zugewiesen und bewirken, dass es leuchtet, da ich my.light = on gesetzt habe.
Die Balken sind an z skaliert je nach Wert in der data_value; Wir wollen die Ziffern über den Balken anzeigen also verwenden wir vec_to_screen um die Bildschirmkoordinaten für jeden Balken zu bekommen, dann setzen wir value_pan auf die korrekte Position, je nach data_value. Schauen wir mal wie das funktioniert:
value_pan.pos_y = 80 + (100 - data_value[j]) * 4;
Wenn der Balken einen Wert von 100 hat, ist value_pan.pos_y auf 80 gesetzt; Falls der Wert unter 100 ist, wird value_pan.pos_y grösser, da die y-Koordinate am oberen Bildschirmrand 0 beträgt. Für jeden Punkt unter 100 müssen wir 4 zu value_pan.pos_y hinzuzählen, da der Balken eine Höhe von 2 quants hat und weil jeder Balken unter 100 nach unten bewegt wird, um die Ausrichtung an den Boden beizubehalten.
Temp_value wird benutzt um den Wert über dem Balken anzuzeigen, indem es ein einziges Panel mit einem digit für alle werte verwendet:
panel
value_pan // displays the values over the bars
{
pos_x = 0;
pos_y = 0;
layer = 10;
digits = 0, 0, 3, standard_font, 1, temp_value;
flags = d3d;
}
Du wirst bemerkt haben, dass ich ein array aus strings benutze – dies kann man nicht im Handbuch nachlesen, da es zu dieser Zeit noch nicht implementiert ist. Jedoch können wir einen Text mit mehreren strings verwenden um ein array von strings zu erhalten:
text
data_name // create an array of strings using a text
{
font = standard_font;
pos_x = 0;
pos_y = 0;
strings = 6;
string = "
"; // 20 characters each
string = "
";
string = "
";
string = "
";
string = "
";
string = "
";
}
Diese Textdefinition erlaubt uns ein array aus strings mit 6 Elementen zu erschaffen, aber wir können jeden Wert verwenden. Dieses Projekt kann mit bis zu 5 Aufnahmen arbeiten also ist ein array mit 6 Elementen mehr als wir brauchen.
Ich
bin ein fauler Programmierer; also habe ich ein kleines c++ Programm erstellt
um mir bei der Entwicklung zu helfen. Alles was man zu tun hat, ist filegen.exe
mit ein paar Parametern zu starten und es wird die data.txt für dich
erstellen. Hier einige Beispiele:
filegen 56 23
Dies wird die folgende data.txt Datei erstellen:
data1,
56
data2,
23
end
filegen 99 88 77 66 55
Dies wird die folgende data.txt Datei erstellen:
data1,
99
data2,
88
data2,
77
data2,
66
data2,
55
end
So musst du nicht die data.txt verändern um zu schauen wir die Grafik mit verschiedenen Werten aussieht. Ich habe den Quellcode beigefügt.
Das Projekt kann einfach modifiziert werden um csv (comma separated values, wichtig für viele Tabellenbearbeitungsprogramme, z.B. Excel). Man kann die Dateinamen unter oder über den Balken anzeigen, indem man einen simplen Text verwendet; Wenn du viele weitere Balken zu selben Zeit anzeigen willst, verändere ihre y-Skalierung je nach Anzahl der Aufnahmen oder mache sie von Anfang an dünner.
Sicherheitskameras
Dieser
kleine Artikel wird Ihnen zeigen, wie einfach es ist eine Sicherheitskamera
einzubauen. Wir werden eine Kamera benutzen die nach dem Spieler sucht,
aber bevor ich fortfahre, lassen Sie uns ein Bild von scan_entity in Aktion
anschauen. Diese präzise Anweisung wird alle Entities innerhalb eines
Sektors scannen. Wir können den Suchwinkel horizontal und vertikal
einstellen und wir können die Suchweite einstellen:
Ich
habe eine Sicherheitskamera aus einem Mikroskop-Modell erstellt! Kommen
Sie keinem Programmierer in die Quere, der nach Modellen such :)
Der
Kamera wird die Action security_camera angefügt:
action
security_camera
{
my.skill1 = my.pan;
init_alarm();
while (1)
{
while (my.pan < my.skill1 + 60)
{
my.pan += 1 * time;
if (random(1) > 0.9)
{
start_scanning();
}
wait (1);
}
while (my.pan > my.skill1 - 60)
{
my.pan -= 1 * time;
if (random(1) > 0.9)
{
start_scanning();
}
wait (1);
}
wait (1);
}
}
Wir speichern den anfänglichen Pan-Winkel der Kamera in skill1, wir rufen die Funktion init_alarm auf (mehr dazu später) und wir drehen die Kamera 60 Grad um ihren anfänglichen Pan-Winkel, nach links und nach rechts – also einen Suchwinkel von 120 Grad. Scan_entity ist eine Anweisung, die viel Geschwindigkeit verbraucht, also sollten wir sie nicht in jedem Framezyklus aufrufen. Eine mögliche Lösung wäre ein Ersetzen von wait(1) durch waitt(3) oder etwas ähnliches, aber dadurch würde die Bewegung ruckelig. Es gibt mehrere Methoden, dieses Problem zu beheben: Die einfachste ist, eine Zufallszahl zu generieren, und wenn sie größer als ein bestimmter Wert ist (0.9 in diesem Beispiel), rufen wir die Funktion auf, die nach Objekten scannt. Sie können die Drehgeschwindigkeit anpassen, in dem Sie 1*time ändern.
OK, jetzt haben wir in jedem Frame eine Zufallszahl; wenn ihr Wert über 0.9 ist (nebenbei: das passiert ein paar Mal in der Sekunde) wird die Funktion start_scanning aufgerufen:
function
start_scanning()
{
temp.pan = 45;
temp.tilt = 90;
temp.z = 700;
scan_entity(my.x, temp);
if ((result > 0) && (result < 500))
{
my.light = on;
my.lightred = 250;
my.lightgreen = 0;
my.lightblue = 0;
my.lightrange = 0;
wait (2);
my.light = off;
alarm = 1;
}
}
Wir stellen den horizontalen Suchradius auf 45 Grad, den vertikalen auf 90 und die Suchreichweite auf 700 Quants ein. Scan_entity wird result auf den Abstand zwischen der Kamera und der nahesten Entity setzen, wenn die Entity unter 500 Quants entfernt ist. Wenn die Kamera den Spieler gefunden hat, wird sie ihre Farbe für 2 Frames auf Rot ändern und – das ist wichtiger – die Variable „alarm“ auf 1 setzen.
Ich habe versprochen, später einmal über die Funktion init_alarm zu sprechen, also los:
function
init_alarm()
{
while (alarm == 0) {wait (1);}
snd_loop(alarm_wav, 100, 0);
}
Diese
Funktion wurde bei Spielstart aufgerufen und hat darauf gewartet, dass
“alarm” auf 1 gesetzt wird. Sobald das passiert, ein Alarmton wird fortwährend
gespielt. An dieser Stelle sollten Sie die Gegner alarmieren, die Türen
schließen, den Motor ausschalten, usw... Eben genau das, was beim
Ertönen des Alarms passieren soll!