Teil 4: Neue Hovermethode
Hallo, jetzt folgt eine kleine Fortsetzung. Zwar nicht so forgeschritten wie geplannt, aber etwas weiter. Der oben angesprochene Bug wird anscheinend bearbeitet. Ich kann jedenfalls keine Kommentare mehr hinzufügen, also ist er in Berbeitung bei LL. Kann deshalb sein, dass die Höhenanpassung auch in einer Skybox oder auf Platformen funktionieren wird.
Aber JointVenture hat vorgeschlagen, das Landen der Biene per Animation durchzuführen, das heißt indem die Prims des Bienenkörpers gegenüber dem Rootprim, welches den Char bildet, verschoben wird. Das macht zwar etwas mehr Arbeit, besonders wenn der Körper aus mehreren Prims besteht, aber ist derzeit die einzige überall funktionierende Lösung. Außerdem ermöglicht sie, dass die Blume bzw. der Bienenstock 10m über dem Boden hängen kann, alte Methode könnte nur 5m erreichen, weil der Char maximal 10m lang sein kann.
In diesem Teil wird diese Lösung implemntiert und das Char so wie der Pendelskript angepasst.
1. Markierungsskript
Der Markierungsskript bleibt wie in
#6, Abschnitt. 2, das heißt man kann problemlos die Koni vom letzten Teil übernehmen. Zur Erinerung, ihre Spitzen representieren die Blumen, also Punkte zum Landen. Der Markierungsskript meldet an den Charskript die Koordinate auf dem Navmesh und die Höhe des Landepunktes darüber, indem das Char diese Höhe einnimmt, landet er visuel.
2. Charskript
Dieser ist neu. Im Grunde ist der Skript dem letzten Pendler ännlich. Die wichtigste Änderung ist, die neue Funktion
hoverHeight(float height), welche die Höhe anpasst und rausgeschmissene
llUpdateCharacter() - Aufrufe (eines ist durch
hoverHeight() ersetzt.) Außerdem wird die Charhöhe gleich relativ klein festgelegt und bleibt auch so.
Ferner wird die vom Markerungsskript gemeldete Höhenangabe etwas anders gespeichert, und die Konstante
VERBOSE schaltet das Labbern ein oder aus.
Code:
integer PFWPC = 1606231603;
float HALFLEN = 0.2;
integer VERBOSE = TRUE;
list lTargets = []; // [(key object)*]
list lCoords = []; // [(vector pos)*]
list lHeights = []; // [(float height)*]
integer gTargNum = -1;
key kTarget = NULL_KEY;
vector vTarget;
float fHeight;
// --- ----------------------------------------------------
goToTarget(integer targNum) {
gTargNum = targNum;
if (gTargNum >= llGetListLength(lTargets)) gTargNum = 0;
kTarget = llList2Key(lTargets, gTargNum);
vTarget = llList2Vector(lCoords, gTargNum);
fHeight = llList2Float(lHeights, gTargNum);
if (VERBOSE) {
llOwnerSay("Visit "+llKey2Name(kTarget)
+" at "+(string)vTarget);
}
llNavigateTo(vTarget, []);
}
hoverHeight(float height) {
height = height - HALFLEN;
llSetLinkPrimitiveParams(2,
[PRIM_POS_LOCAL, <0.0, 0.0, height>]);
}
// --- ----------------------------------------------------
default {
state_entry() {
llSay(0, "Hello World");
llDeleteCharacter();
llCreateCharacter([
CHARACTER_MAX_SPEED, 3.0,
CHARACTER_DESIRED_SPEED, 2.0,
CHARACTER_RADIUS, 0.125,
CHARACTER_LENGTH, HALFLEN*2.0,
CHARACTER_AVOIDANCE_MODE, AVOID_CHARACTERS,
CHARACTER_DESIRED_TURN_SPEED, 3.0,
CHARACTER_MAX_TURN_RADIUS, 0.5
]);
llListen(PFWPC, "", NULL_KEY, "");
llShout(PFWPC, "pf.waypoints?");
}
on_rez(integer start_param) {
llResetScript();
}
// message = "pf.waypoint:<x, y, z>|h"
listen(integer channel, string name, key id, string message) {
if (llGetSubString(message, 0, 11) == "pf.waypoint:") {
message = llGetSubString(message, 12, -1);
list tmp = llParseString2List(message, ["|"], []);
vector target = (vector)llList2String(tmp, 0) - llGetRegionCorner();
float height = (float)llList2String(tmp, 1);
if (height < 0.0) height = 0.0;
else if (height > 10.0) height = 10.0;
// Korrigiere die Zielkoordinate auf die exakte
// Position des char-Prims (0.5m über dem Boden)
target.z = target.z + HALFLEN;
channel = llListFindList(lTargets, [id]);
if (channel < 0) {
lTargets += [id];
lCoords += [target];
lHeights += [height];
}
else {
lCoords = llListReplaceList(lCoords, [target], channel, channel);
lHeights = llListReplaceList(lHeights, [height], channel, channel);
}
if (id == kTarget) {
vTarget = target;
fHeight = height;
llNavigateTo(vTarget, []);
}
channel = (integer)llGetListLength(lTargets);
llSetText((string)channel+" points", <1.0, 1.0, 1.0>, 1.0);
}
}
touch_start(integer total_number) {
if (llDetectedKey(0) == llGetOwner() && lTargets != []) {
llSetTimerEvent(0.0);
if (gTargNum < 0) goToTarget(0);
else {
llExecCharacterCmd(CHARACTER_CMD_SMOOTH_STOP, []);
gTargNum = -1;
kTarget = NULL_KEY;
}
}
}
path_update(integer update, list reserved) {
// We are near target.
if (update == PU_SLOWDOWN_DISTANCE_REACHED) {
if (gTargNum > -1) llSetTimerEvent(10.0);
}
// We are at target.
if (update == PU_GOAL_REACHED) {
llExecCharacterCmd(CHARACTER_CMD_SMOOTH_STOP, []);
if (gTargNum > -1) {
llSetRegionPos(vTarget);
hoverHeight(fHeight);
llSetTimerEvent(10.0);
}
}
// Navigation failed. Try direct
else if (update == PU_FAILURE_INVALID_START) {
llNavigateTo(vTarget, [FORCE_DIRECT_PATH, TRUE]);
}
// Otherwise, the bee is lost
else {
llExecCharacterCmd(CHARACTER_CMD_SMOOTH_STOP, []);
}
}
timer() {
llSetTimerEvent(0.0);
goToTarget(gTargNum+1);
}
}
3. Versuchsanordnung
Ich habe desen Charskript mit der Rampe getestet, der funktioniert, da sind die Koni aber gleich hoch, die Höhe wird also nicht angepasst. Das werde ich hier deshalb nicht mehr wiederholen. Stattessen wird eine etwas andere Anordng aufgebaut. Der Sinn ist dabei, die neue Höhenanpasung zu prüfen, deshalb werden vier Koni gerezzt und unterschiedlich hoch skalliert. Den Alpha habe ich auf 10m Höhe gestellt, also die zunächst maximale angestrebte Höhe. Dazu noch ein kleines Hindernis, damit die Route nicht so langweilig wird:
Die Koni haben verschiedene Farben bekommen, das weiße Alpha ist 10m hoch. Den Rahmen sollte man per Floater auf
Static Obstacle setzen, oder
Exclusion Volume (sollte das eine begehbare Hecke sein, die von der Biene herumzufliegen ist), tut man das nicht, ist der Rahmen dem Navmesh nicht bekannt und das Char bleibt in der Ecke hängen.
4. Charobjekt
So, neben der inneren Koni wird das Char aufgebaut. Er besteht aus einem (später unsichtbaren) Rootprim, das eigentlich der Char ist, und dem Childprim, das den sichbaren Bienenkörper repreäsentiert. Der Skript geht zunächst davon aus, dass es nur diese zwei Prims sind. Der Rootprim wird später unsichtbar, aber jetzt habe ich ihn wie Schatten da gelasen. Nachdem beide verlinkt wurden, geht da der Skript rein:
Der sollte sich gleich initialisieren, alle Markierungspositionen empfangen haben und etwa auf die Höhe von 20cm über dem Boden schweben (die Konstante
HALFLEN gibt die konstante Schwebehöhe des eigentlichen Chars an.)
5. Bienenflug
So, jetzt das Baumenu schließen und den Char anklcken. Er fliegt zunächst zu Alpha (diesem 10m hohen Konus, die Route habe ich ausgelassen) und dann um dien Zaun herum zu Beta (roter Konus.) Die hohe Flughöhe behällt sie bei. Erst wenn angekommn, stürzt die Kugel auf den Konus:
Fragt mich nicht, warum da so weiter Umweg genomen wurde, anscheinend hatte die Navmesh der Sim was an der Stelle, ich blieb aber an der Position mit der Anordung.
Beim roten Konus angekommen, spring die Kugel zunächst auf den blauen, dann gelben, und dann setzt sich in den Flug richtung Alpha. Wieder über die komische weite Route:
Danach schließt sich der Kreislauf.
Wie man sieht, fliegt die Biene den Zaun um, obwohl sie optisch daüber fliegen könnte. Man könnte das vielleicht dadurch erreichen, dass man den Zaun als
Material Volume setzt. Je nach der Umgebung, das könnte auch eine Hecke sein. Dann kann man selbst zwar dadurch laufen, die Biene könnte man aber sogar abbrremsen, wenn man die Hecke richtig parametrisiert.
LG und danke für die Geduld mit dem Tutorial lesen
