Wecker

Der Uhrencode erlaubt Ihnen, eine Alarmzeit festzulegen, durch Angabe einer Stunde und Minuten. Der Wecker wird seinen durchdringenden Sound für eine Minute ertönen lassen.

Das Main Panel zeigt die Uhr und die 4 Knöpfe ändern die Alarmzeit: + - Stunden und + - Minuten.

panel main_pan // main panel
{
bmap = main_pcx;
pos_x = 0;
pos_y = 0;
layer = 10;

button = 260, 260, arrowup_pcx, arrowup_pcx, arrowup_pcx, null, hours_up, null;
button = 280, 260, arrowdown_pcx, arrowdown_pcx, arrowdown_pcx, null, hours_down, null;
button = 420, 260, arrowup_pcx, arrowup_pcx, arrowup_pcx, null, minutes_up, null;
button = 440, 260, arrowdown_pcx, arrowdown_pcx, arrowdown_pcx, null, minutes_down, null;

flags = overlay, refresh, d3d, visible;
}

Clock_text zeigt die aktuelle Zeit im Format hh:mm:ss und alarm_text zeigt die Alarmzeit im Format hh:mm an. Ich muß nicht erwähnen, dass h für Stunden (hour), m für Minuten und s für Sekunden steht, oder?

text clock_text
{
layer = 20;
pos_x = 270;
pos_y = 200;
font = lcd_font;
string = clock_string;
flags = visible;
}

text alarm_text
{
layer = 20;
pos_x = 300;
pos_y = 260;
font = lcd_font;
string = alarm_string;
flags = visible;
}

Der wichtigste Teil des Codes steckt in main:

function main()
{
screen_color.red = 0;
screen_color.green = 0;
screen_color.blue = 0;
mouse_map = mouse_pcx;
mouse_mode = 2;
while (1)
{
mouse_pos.x = pointer.x;
mouse_pos.y = pointer.y;

Diese main Funktion lädt keinen Level. Wir setzen die Hintergrundfarbe auf rgb = 000, benutzen mouse_pcx für den Mauszeiger und zeigen en Cursor an. Die ersten 2 Zeilen der while Schleife stellen sicher, dass wir die Maus auf dem Panel bewegen können.

str_for_num(clock_string, sys_hours);
str_cat(clock_string, ":");
if (sys_minutes < 10)
{
str_cat(clock_string, "0");
}
str_for_num(temp_string, sys_minutes); // read sys_minutes and convert it to string
str_cat(clock_string, temp_string); // add minutes to clock_string
str_cat(clock_string, " "); // leave a blank space before adding seconds
if (sys_seconds < 10) // add a "0" if the seconds are displayed with a digit
{
str_cat(clock_string, "0");
}
str_for_num(temp_string, sys_seconds); // read sys_seconds and convert it to string
str_cat(clock_string, temp_string); // add seconds to clock_string

Wir lesen sys_hours ein, konvertieren es in einen String und schreiben den Inhalt in clock_string. Wir fügen ":" ein; bislang haben wir "hh:". Falls sys_minutes < 10, würde die Uhr so etwas wie "23: 2" anzeigen, also fügen wir in dem Fall eine "0" nach dem ":" ein, damit statt dessen so etwas wie "23:02" dort steht. Nun lesen wir sys_minutes, konvertieren es in einen String, fügen die Minuten dem clock_string bei und lassen ein Leerzeichen " " bevor die Sekunden hinzugefügt werden. Wieder kommt die "0" dazu, wenn sys_seconds < 10. Nachdem auch die Sekunden angefügt sind, wehalten wir etwas wie "23:02 45".

Dieser Code kümmert sich um den Alarm:

str_for_num(alarm_string, alarm_hours); // convert alarm_hours to string
str_cat(alarm_string, ":"); // add :
if (alarm_minutes < 10) // add a "0" if the minutes are displayed with a digit
{
str_cat(alarm_string, "0");
}
str_for_num(temp_string, alarm_minutes); // convert alarm_minutes to string
str_cat(alarm_string, temp_string); // add alarm_minutes to alarm_string

if ((alarm_hours == sys_hours) && (alarm_minutes == sys_minutes)) // sound the alarm
{
start_alarm();
}

Ich habe folgende (Default) Werte für alarm_hours and alarm_minutes gewählt: 12 und 30. Wir konvertieren alarm_hours in einen String und fügen es in den alarm_string ein, dann kommt ein ":" und eine "0", falls alarm_minutes < 10 und dann kommen die alarm_minutes, nachdem sie in einen String konvertiert wurden. Falls alarm_hours == sys_hours und alarm_minutes == sys_minuten, startet der Alarm. Er läuft automatisch 1 Minute lang, solange bis alarm_minutes != sys_minutes.

wait (1);
}
}

Die Funktion start_alarm ist einfach:

function start_alarm()
{
exclusive_global; // don't allow multiple instance of this function to run
while (snd_playing(alarm_handle)) {wait (1);}
alarm_handle = snd_play (alarm_wav, 100, 0);
}

Wir erlauben keine weiteren Instanzen dieser Funktion und spielen einen Sound in einer Schleife, wobei wir warten, bis er beendet ist, bevor wir erneut beginnen.

Der Rest des Codes ist zum Ändern der Alarmzeit, wenn auf die Knöpfe gedrückt wird:

function hours_up()
{
if (alarm_hours < 23)
{
alarm_hours += 1;
}
}

function hours_down()
{
if (alarm_hours > 0)
{
alarm_hours -= 1;
}
}

function minutes_up()
{
if (alarm_minutes < 59)
{
alarm_minutes += 1;
}
}

function minutes_down()
{
if (alarm_minutes > 0)
{
alarm_minutes -= 1;
}
}

Hier ist nichts besonderes: wenn Sie auf den "+" Knopf für Stunden drücken, wird alarm_hours erhöht, bis zum Wert 23. Die anderen Funktionen sind ähnlich.

Kopfschüsse

Falls Sie nach einer einfachen Methode suchen, wie Ihr Moel verschieden reagieren kann, je nachdem wo es getroffen wird, sind Sie an der richtigen Adresse. Es ist normal, einen gegnerischen Soldaten zu töten, wenn wir ihm einen Kopfschuß verpaßt haben, richtig? Andererseits ist es nicht normal, einen Gegner durch einen einmaligen Beinschuß umzubringen.

Ich werde meine Methode verraten - sie ist schnell und funktioniert einwandfrei. Ich nenne Sie die (Setzen Sie hier etwas ein) Methode.

Die Idee ist einfach: wir wählen einige "Schlüssel"-Punkte (Vertizes) im Model des Gegners und ermitteln ihre Höhe in einer Schleife. Wenn eine Kugel das Model trifft, vergleichen wir die Höhe der Kugel mit der Höhe jedes dieser Schlüsselpunkte. Der nächstgelegene Punkt wird die entsprechende Animation auslösen. Der Code ist so leicht, wie er klingt (ist das eine gute oder eine schlechte Nachricht?)

Ich werde mit Hilfe eines Textes einen String auf dem Bildschirm darstellen, ebenso wie zwei Panels:

text info_txt
{
layer = 20;
pos_x = 0;
pos_y = 0;
font = _a4font;
string = "head vertex:\nmiddle vertex:\nleg vertex:\nhit coord:";
flags = visible;
}

panel crosshair_pan
{
bmap = crosshair_pcx;
layer = 20;
pos_x = 0;
pos_y = 0;
flags = transparent, refresh, d3d, visible;
}

panel coords_pan
{
layer = 20;
pos_x = 80;
pos_y = 0;
digits = 0, 0, 4, _a4font, 1, vertex_coords.x;
digits = 0, 9, 4, _a4font, 1, vertex_coords.y;
digits = 0, 18, 4, _a4font, 1, vertex_coords.z;
digits = 0, 27, 4, _a4font, 1, bullet_pos.z;
flags = refresh, d3d, visible;
}

Die Main Funktion schaltet das "D"-Debug Panel ab, weil wir WASD für die Bewegung des Spielers nutzen wollen, und lädt dann das Level:

function main()
{
on_d = null;
level_load (damage_wmb);
}

Dies ist ein eigenständiges Projekt; wir brauchen eine Action für den Spieler:

action player_moves
{
my.invisible = on; // no need to see the player because we are in 1st person mode
crosshair_pan.pos_x = (screen_size.x - bmap_width(crosshair_pcx)) / 2;
crosshair_pan.pos_y = (screen_size.y - bmap_height(crosshair_pcx)) / 2;
while (1)
{
vec_set (camera.pos, my.pos);
camera.tilt += 20 * mouse_force.y * time;
camera.pan -= 20 * mouse_force.x * time;
my.pan = camera.pan;
my.tilt = camera.tilt;
player_speed.x = 15 * (key_w - key_s) * time; // move forward / backward
player_speed.y = 10 * (key_a - key_d) * time; // strafe left / right
vec_set (temp, my.x);
temp.z -= 1000;
trace_mode = ignore_me + use_box;
player_speed.z = -trace (my.x, temp);
move_mode = ignore_you + ignore_passable;
ent_move(player_speed, nullvector);
if (mouse_left == 1)
{
ent_create (bullet_mdl, player.pos, shoot_bullet);
snd_play (bullet_wav, 50, 0);
while (mouse_left == 1) {wait (1);}
}
wait (1);
}
}

Wir sind im 1st Person Modus, also müssen wir den Spieler nicht sehen; das Fadenkreuz wird in der Mitte des Bildschirms plaziert. Die Kamera wird an die Position des Spielers gesetzt und ändert ihren Pan und Tilt durch Bewegen der Maus. Der Spieler erhält seinen Pan und Tilt von der Kamera und wird mit Hilfe der WASD Tasten bewegt. Der Code beinhaltet auch Gravitation; wir führen einen trace 1000 Quants unter den Spieler aus und bewegen ihn, so daß seine Füße wieder auf den Boden kommen. Mit Hilfe der linken Maustaste wird eine Kugel erzeugt, ein Sound wird abgespielt und wir warten, bis die linke Maustaste losgelassen wird, um Autofeuer vorzubeugen.

Hier ist der Code für den Gegner:

action enemy
{
my.enable_impact = on;
my.enable_shoot = on;
my.enable_entity = on;
my.event = compute_shot_pos;
while (my.skill5 == 0)
{
ent_cycle ("idle", 0);
vec_for_vertex(temp, my, 222); // enemy's head vertex
my.head_pos = temp.z;
vertex_coords.x = my.head_pos;
vec_for_vertex(temp, my, 235); // enemy's belly vertex
my.middle_pos = temp.z;
vertex_coords.y = my.middle_pos;
vec_for_vertex(temp, my, 171); // enemy's leg vertex (one of the legs)
my.leg_pos = temp.z;
vertex_coords.z = my.leg_pos;
wait (1);
}
}

Der Gegner reagiert auf impact Events, shoot oder entity; wenn eines dieser Dinge geschieht, läuft die Funktion compute_shot_pos ab. Solange er noch nicht beschossen wurde (skill5 == 0), wird er still stehen. Ich habe einen einzelnen Frame für "idle" (Ruhezustand) verwendet, aber Sie können auch eine Animation benutzen. Ich habe 3 Schlüsselpunkte für den Kopf, Bauch und das Bein in MED gefunden, aber Die können so viele benutzen, wie Sie möchten; Ihre z-Koordinaten werden in head_pos (ein sprechender Name für skill1), middle_pos (skill2) und leg_pos (skill3) gespeichert. Wir müssen diese Werte in einer Schleife aktualisieren, weil sie sich ändern, wenn der Gegner sich bewegt (wenn er springt, kriecht, etc.)

Ok, stellen wir uns nun vor, dass unsere Kugel den Gegner getroffen hat. Compute_shot_pos() wird dann ablaufen:

function compute_shot_pos()
{
my.skill5 = 1;
vec_set(bullet_pos, you.pos);
wait (1);
my.event = null;

Skill5 wird auf 1 gesetzt und beendet die While Schleife in der Enemy Action. Wir speichern die Koordinaten der Kugel bevor sie verlorengehen (die Kugel verschwindet), warten einen Frame lang und setzen my.event auf null.

if (abs(bullet_pos.z - my.head_pos) < abs(bullet_pos.z - my.middle_pos)) // we've got a head shot, no need to check the legs
{
my.skill5 = 0;
while (my.skill10 < 80) // skip the last frame
{
ent_cycle("head", my.skill10);
my.skill10 += 4 * time;
wait (1);
}
}

Falls die Distanz zwischen der Kugel und dem Kopf-Vertex kleiner ist als die Distanz zwischen der Kugel und dem Bauch-Vertex (middle_pos), haben wir einen Kopfschuß erzielt, spielen also die "head" Animation.

else // middle or leg shot
{
if (abs(bullet_pos.z - my.middle_pos) < abs(bullet_pos.z - my.leg_pos)) // middle shot
{
my.skill10 = 0;
while (my.skill10 < 80) // skip the last frame
{
ent_cycle("middle", my.skill10);
my.skill10 += 2 * time;
wait (1);
}
}
else // leg shot
{
my.skill10 = 0;
while (my.skill10 < 80) // skip the last frame
{
ent_cycle("leg", my.skill10);
my.skill10 += 4 * time;
wait (1);
}
}
}
}

Ist die Distanz zwischen der Kugel und dem Kopf-Vertex größer als die Distanz zwischen Kugel und Bauch-Vertex, könnte es ein Bauchschuß oder ein Beinschuß sein, also spielen wir die korrekte Animation. Ich habe das Model animiert, also sehen Sie sich vor... es könnte gruselig werden!

Die letzte Funktion erzeugt die Kugeln und entfertn sie:

function shoot_bullet()
{
my.enable_entity = on;
my.enable_block = on;
my.event = remove_bullet;
my.passable = on;
my.pan = player.pan;
my.tilt = camera.tilt;

Die Kugel reagiert auf Entities und Level Blocks. Wenn sie mit einer anderen Entity (dem Gegner) oder einem Level Block kollidiert, wird sie nach einem Frame removed, denn wir müssen vorher ihre Koordinaten sichern. Die Kugel erhält dieselbe Orientierung wie der Spieler.

my.skill20 = 0;
my.skill1 = 300;
my.skill2 = 0;
my.skill3 = 0;
my.skill1 *= time;

while (my.skill20 < 250)
{
if (my.skill20 < 1) // don't collide with the player
{
my.passable = on;
}
else
{
my.passable = off;
}
my.skill20 += 1 * time;
ent_move (my.skill1, nullvector);
wait (1);
}
remove_bullet();
}

function remove_bullet()
{
wait (1);
ent_remove(me);
}

Wir setzen skill20 auf 0 und erhöhen den Wert in einer Schleife bis zum Wert 250. Wenn die Kugel nichts getroffen hat, wenn skill20 >= 250 ist, dann wird sie entfernt, da wir keine Rechenzeit vergeuden wollen. Skill1 bis Skill3 werden als lokale Variablen für die Bewegung benutzt. Ein kleiner Trick: da die Kugel innerhalb des Spielrmodels erzeugt wird, muß sie am Anfang auf passable gesetzt werden, um nicht mit dem Spieler zu kollidieren. Wenn skill20 >= 1 ist, dürfen wir annehmen, dass die Kugel weit genug gekommen ist und wir machen setzen ihr passable Flag auf off.

Sie können mehr Schlüsselvertizes verwenden, zum Beispiel einen am anderen Bein, 2 an den Armen, etc.