Mit einer Funktion mehrere entities unabhängig voneinander steuern

mnemjc

Garg
Hi..

habe folgendes Problem.. ich möchte mittels GUI eine funktion in meinem script aufrufen das wiederum ein func_mover steuert. Da dies aber eine relativ einfache funktion ist.. und ich viele dieser func_mover in meiner map habe, möchte ich das alles vereinfachen.

Also eine funktion die ich über jeden func_mover aufrufen kann.. konkret sieht das so aus:

Ich hab einen func_mover namens smallLocker1 der über "test.gui" die funktion "testMove1" aufruft
dann hab ich einen func_mover names smallLocker2 der über "test.gui" die funktion "testMove2" aufruft

Hoffe es ist einigermaßen verständlich.

Das ist mein derzeitiges Script

Code:
void testMove(float g)
{
       entity smallLocker;

       if (g > 1 && g < 20)
       {
               smallLocker = sys.getEntity ("smallLocker" + g);
               smallLocker.rotateOnce('0 90 0');
       }
}

Woran ich hänge ist, das ich die unabhängig voneinander steuern möchte... d.h. wenn ich den mover1 an Platz A trigger, soll ichder mover2 an platz B nicht bewegen.


Bin seit mehren Stunden drüber aber ich bekomms nicht hin..bin für jede hilfe dankbar..
 
Last edited:

MacX

Light Guard
Funktionieren deine Funktionen erstmal grundsätzlich so wie du dir das vorstellst?
So wie ich dich verstehe, funktioniert alles, nur willst du es über eine Funktion lösen.

Was mir spontan einfiele, wäre folgendes:
Code:
void testMove( entity mover );

void testMover1()
{
    testMove( sys.getEntity( "smallLocker1" ) );
}

void testMover2()
{
    testMove( sys.getEntity( "smallLocker2" ) );
}

void testMoverX()
{
    testMove( sys.getEntity( "smallLockerX" ) );
}

void testMove( entity mover )
{
    mover.rotateOnce('0 90 0');
}

Wenn ich davon ausgehe, dass du ca. 20 func_mover hast, sparst du zwar ein paar Zeilen, weil du das rotateOnce nicht in jeder Funktion aufrufen musst, aber natürlich hast du immer noch für jeden func_mover eine eigene Funktion, was nicht das gewünschte Verhalten ist.

Ich gehe weiterhin davon aus, dass du im GUI sowas wie
Code:
onAction {
   runScript "gui::gui_parm1" ;
}

auführst, wobei der gui_parm-Wert bei jedem func_mover angegeben wurde, und dem Namen der Funktion entspricht, die aufgerufen werden soll.

So, und jetzt lasst uns mal überlegen, wie wir das alles auf eine Skriptfunktion reduzieren, die für beliebig viele func_mover anwendbar ist...

Ich muss mir erstmal eine Testmap zusammenbasteln.
 

mnemjc

Garg
Funktionieren deine Funktionen erstmal grundsätzlich so wie du dir das vorstellst?
So wie ich dich verstehe, funktioniert alles, nur willst du es über eine Funktion lösen.

Genau, ansich funktioniert alles..nur würde ich bei 20 mover, nochmal mindetens 20 entitys brauchen um es über den editor zu steuern.. oder 20 zeilen in meinem script, wo eigtl. alles gleich ist, bis auf den namen des jeweiligen movers.

Darum dachte ich mir, dass es sicherlich einen (einfachen) weg gibt, eine kleine variable einzubauen die alle mover seperat ansteuern kann.




Genau, da wäre es ja fast kürzer jedem eigenen mover einen eigenen thread zu schreiben ^^
Ich gehe weiterhin davon aus, dass du im GUI sowas wie
Code:
onAction {
   runScript "gui::gui_parm1" ;
}
auführst, wobei der gui_parm-Wert bei jedem func_mover angegeben wurde, und dem Namen der Funktion entspricht, die aufgerufen werden soll.

Genau, aber ich hab 2 parms in den GUI eingebaut.
Erster Klick = Mover fährt hoch/auf
Zweiter Klick = mover fährt zu/runter
Aber letztendlich benutze ich sowieso nur einen, da ich eh im skript eine if/else funktion einbauen will, womit sich der 2te parm erübrigt.

So, und jetzt lasst uns mal überlegen, wie wir das alles auf eine Skriptfunktion reduzieren, die für beliebig viele func_mover anwendbar ist...

Ich muss mir erstmal eine Testmap zusammenbasteln.

Wenn du willst, kann ich dir auch schnell eine testmap zusammenbasteln, sodass wir den selben Ausgangspunkt haben.. aber ich glaube du hast mein problem schon verstanden..

Irgendwo entweder wars bei q4 oder doom3.. gabs mal ein skript in der art.. bin mir sicher das die auch schon auf die idee gekommen sind, das so zu vereinfachen.. ich mal mich mal auf die Suche.
 

MacX

Light Guard
Eine Testmap habe ich schon... funktioniert bei mir so, wie ich es oben bereits beschrieben habe, aber das ist ja wie wir wissen noch nicht die Lösung. Also weiterprobieren. Wäre schade, wenn man dafür auf das SDK zurückgreifen müsste.

Edit: Ja, Quake 4 tickt da irgendwie ein wenig anders...

Edit 2: Mit Quake 4 kommt mir ein verzwicktes Konstrukt mit script object und GUI-Event Abfrage in den Sinn...aber wir sind hier ja bei Doom 3. Und weiter gehts...
 
Last edited:

MacX

Light Guard
Ich befürchte, dass das, was du vorhast, nicht ohne unnötigen Aufwand umsetzbar ist. In Quake 4 sollte das dank optionaler Entitäten-Parameter umsetzbar sein, in Doom 3 gibt es das nicht.
Vielleicht ginge es noch, wenn man die func_mover dynamisch im Spiel erzeugen würde, aber da hast du keinen Mehrwert.

Im IRC hatte ich dir ja bereits meinen alternativen Ansatz präsentiert. Dieser hat noch einen Bug drin, den ich spontan noch nicht zu beseitigen weiß, aber vielleicht nützt es ja trotzdem jemandem:

test.script
Code:
object func_mover_door {
	boolean is_open;
	
	void	init();
	void	rotateDoor();
};

void func_mover_door::init()
{
	is_open = false;
}

void func_mover_door::rotateDoor()
{
	if( !is_open ) {
		rotateOnce( '0 90 0' );
		is_open = true;
	} else {
		rotateOnce( '0 -90 0' );
		is_open = false;
	}
}

object trigger_mover {
	entity this;

	void      init();
	void      triggered();
};

void trigger_mover::init()
{
	this = sys.getEntity( getName() );

	sys.onSignal( SIG_TRIGGER, this, "trigger_mover::triggered" );

	while (1){
		sys.waitFrame();
	}
}

void trigger_mover::triggered()
{
	entity mover = this.getTarget( 0 );

	if( mover.getKey( "classname" ) == "func_mover_door" ) {
		mover.callFunction( "rotateDoor" );
	}
}  

void main()
{
}

func.def
Code:
entityDef func_mover_door {
	"inherit"                    "func_mover"
	"scriptobject"            "func_mover_door"
}

trigger.def
Code:
entityDef trigger_mover {

	"inherit"                    "trigger_multiple"
	"spawnclass"             "idTrigger_Multi"
	
	"editor_usage"           "Calls script object function 'trigger_mover::triggered' when activated"
	"scriptobject"            "trigger_mover"
}

test.map (vereinfacht)
Code:
"classname" "func_mover_door"
"name" "func_mover_door_1"
"model" "func_mover_door_1"
"origin" "-144 80 48"
"gui" "guis/testmove.gui"
"target" "trigger_mover_1"

"classname" "trigger_mover"
"name" "trigger_mover_1"
"model" "trigger_mover_1"
"origin" "-144 80 120"
"target" "func_mover_door_1"

Der func_mover_door hat ein GUI, was nach einem Klick darauf das Nachfolgende ausführt:
Code:
    onAction {
        set	"cmd" "activate" ;
    }
Bei dem Aufruf, wird der als Target eingetragene trigger_mover aufgerufen. Dabei wird automatisch die Skriptfunktion "trigger_mover::triggered" ausgeführt, darin der func_mover ermittelt und für diesen dann die "rotateMover"-Funktion ausgeführt.
Das Skriptobjekt für den func_mover merkt sich, ob dieser schon rotiert wurde, und soll bei der nächsten Ausführung wieder in die andere Richtung rotiert werden. Das Problem an der Sache ist, dass SIG_TRIGGER-Signal nur einmal ausgeführt und das obwohl es sich im Prinzip um einen trigger_multiple handelt. Vermutlich wird es nach dem erstmaligen Aufruf einfach entfernt. Den Eindruck hatte ich jedenfalls nach dem Debuggen. Wenn man den trigger_mover zur Laufzeit immer wieder erstellen und entfernen würde, könnte das eventuell funktionieren.

Das nächste Problem scheint dann aber zu sein, dass für Doom 3 die Anzahl der Signal-Threads auf 16 begrenzt wurde.

Wenn man das alles etwas dynamischer gestaltet, klappt es womöglich. Du hast dann irgendwann wirklich nur eine Rotate-Funktion für jegliche mover-Entität, aber wahrscheinlich hast du dennoch keine Skriptzeilen eingespart. Am Ende wahrscheinlich einige mehr.

Am einfachsten ist es als immer noch so, wie ich es in meinem ersten Post hier im Thread demonstriert habe. Die meisten Doom 3 Mods, deren Skripte ich überflogen habe, würden auch für die einzelnen Entitäten jeweils eine Funktion erstellen.
 
Last edited:

MacX

Light Guard
Ok, ich habe doch noch eine Lösung...werde ich gleich hier reinbringen.

Edit:

testmover.script
Code:
object func_rotating_door {
	boolean is_open;
	
	void	init();
	void	destroy();
	void	main();
	void	rotateDoor();
};

void func_rotating_door::init()
{
	is_open = false;
	
	main();
}

void func_rotating_door::destroy()
{
	clearSignal( SIG_TRIGGER );
}

void func_rotating_door::main()
{
	sys.onSignal( SIG_TRIGGER, self, "func_rotating_door::rotateDoor" );
	
	while (1){
		sys.waitFrame();
	}
}

void func_rotating_door::rotateDoor()
{
	if( !is_open ) {
		rotateOnce( '0 90 0' );
		is_open = true;
	} else {
		rotateOnce( '0 -90 0' );
		is_open = false;
	}
	
	main();
}

void main()
{
}

func_rotating_door.def
Code:
/***********************************************************************

 func_rotating_door

***********************************************************************/

entityDef func_rotating_door {
	"inherit"					"func_mover"
	"scriptobject"				"func_rotating_door"
}

Im Anhang habe ich mal eine Testmap hinzugefügt.
Das pk4-Archiv einfach in den base-Ordner legen und per "map testmover.map" über die Konsole in Doom 3 starten.

Meine Aussage zur der Begrenzung der Signal-Threads auf 16 muss ich wohl zurückziehen. Die Begrenzung bezieht sich wohl nur auf eine Entität. Mit 20 func_rotating_door-Threads im Hintergrund konnte ich keine Probleme feststellen.
Wenn du einmal auf das GUI klickst wird der Block 90° in die eine Richtung und beim 2ten Klick 90° in die andere Richtung rotiert.

View attachment testmover.pk4
 
Last edited:
Top