Arma 3 – Hisser un drapeau (Part 2)

Dans l’article précédent, nous avons vu comment faire un beau drapeau. Il était possible de changer la texture et c’était déjà bien !

Mais on peut aller beaucoup plus loin, sécuriser un peu pour que le script fonctionne en multijoueur. Gérer une animation pour que ce soit un peu plus sympathique ?

Sécuriser client/serveur

Déjà essayons de comprendre pourquoi ?
Pourtant, la documentation montre bien que les conséquences sont GLOBAL
https://community.bistudio.com/wiki/setFlagTexture

Dans presque tous les cas, quand vous avez ce EG, ça signifie que les effets seront transmis à tous les autres clients et serveur.
Sauf que c’est une vieille méthode et qu’il y a un warning dans la description

NOTE: In MP this command has to be executed where Flag Pole is local. If you add Flag Pole in the editor, it will be local to the server, so executing setFlagTexture on the server will change flag texture on all clients. The command is also persistent and is synchronised for JIP clients.

https://community.bistudio.com/wiki/setFlagTexture

Ce qu’explique la documentation étant qu’il faut exécuter cette commande sur le serveur ou le client à qui appartient cet objet.
Si vous avez posé le drapeau via Eden, il appartiendra au serveur, qui fera tourner les objets. On verra plus tard pour une piste dans le cas contraire.

Il y a pas mal de possibilité, mais ma préférée étant le remoteExec qui permet très simplement de demander à un client, ou le serveur d’exécuter du code… autant dire des possibilités infinies

Il y aurait beaucoup à dire sur cette méthode, je vais vous proposer un format qui fait fonctionner tout ce que vous voulez, mais avec moins d’optimisation.

[ 
	[_target],
	{ 
		params ["_target"]; 
		_target setFlagTexture "images\cpc.jpg"; 
	} 
] remoteExec ["spawn", 2];

Si vous ne comprenez pas tout, ce n’est pas très grave pour le moment.
Ce qu’il faut comprendre c’est trois choses

[_target],

Il permet depuis de passer en paramètre ce dont on aura besoin.
Le script passé par réseau n’aura pas accès à nos autres variables. On aura cependant accès aux variables de celui qu’on appelle. C’est-à-dire que notre flag_0 du début, on y aura accès, puisqu’il existe autant sur notre client, que côté du serveur.

{ 
	params ["_target"]; 
	_target setFlagTexture "images\cpc.jpg"; 
} 

Le script en lui-même qu’on demande d’exécuter, avec notre _target, qui a été passé en paramètre, mais qu’il faut de nouveau extraire du contexte (_this).

] remoteExec ["spawn", 2];

Les deux précédents, étaient les paramètres de la méthode, mais nous arrivons à la méthode en elle-même.
Laisser tomber pour le moment le SPAWN, retenez juste que ça nous permet d’envoyer n’importe quel code sans contrainte.
Le paramètre « 2 » est aussi important, même si dans notre cas, on pourra l’oublier sans grand impacte. C’est ce paramètre qui force l’exécution PAR le serveur et personne d’autre !

Pour vous montrer à quel point cette méthode peut être compliquée, on aurait le même résultat avec :

[_target, "images\cpc.jpg"] remoteExec ["setFlagTexture", 2];
[_target, "images\cpc.jpg"] remoteExec ["setFlagTexture", _target];
[ 
     _target,
     { _this setFlagTexture "images\cpc.jpg"; } 
 ] remoteExec ["spawn", 2];
[_target, "images\cpc.jpg"] remoteExec ["setFlagTexture", [0, 2] select isMultiplayer];

Il me faudrait un article complet pour expliquer, tout ceci, mais c’était seulement pour vous montrer la complexité ou la profondeur de cette méthode. (Ou alors mon esprit tordu, au choix)

Avec ces améliorations, voilà à quoi ressemble notre script :

this addAction
[ 
	"Hisser le drapeau",
	{ 
		params ["_target", "_caller", "_actionId", "_arguments"]; 
		_target setVariable ['cpc_flaged', true, true];

		[ 
			[_target],
			{ 
				params ["_target"]; 
				_target setFlagTexture "images\cpc.jpg"; 
			} 
		] remoteExec ["spawn", 2]; 
	}, 
	[], 
	1.5,
	true,
	true,
	"", 
	"!(_target getVariable ['cpc_flaged', false])", 
	3, 
	false, 
	"", 
	"" 
];

Après c’est bien, on a un truc qui marche bien, sécurisé en multijoueur.
Mais il manque quand même un peu d’animation non ?
Changer le drapeau c’est bien, mais le descendre, pour hisser le bon… hey mais c’était censé être le titre « hisser un drapeau » ? 😉

Animation saccadée, mais animation

Pour comprendre un peu le principe, je vous propose une version très moche, mais qui va montrer le fonctionnement de l’animation.

La mise à jour en question, si vous voulez expérimenter.

this addAction
[ 
	"Hisser le drapeau",
	{ 
		params ["_target", "_caller", "_actionId", "_arguments"]; 
		_target setVariable ['cpc_flaged', true, true];

		[ 
			[_target],
			{ 
				params ["_target"]; 

				_target setflagAnimationPhase 0.5; 
				sleep 1.5; 
				_target setflagAnimationPhase 0; 
				sleep 1.5; 
				_target setFlagTexture "images\cpc.jpg"; 
				sleep 1.5; 
				_target setflagAnimationPhase 0.5; 
				sleep 1.5; 
				_target setflagAnimationPhase 1; 
			} 
		] remoteExec ["spawn", 2]; 
	}, 
	[], 
	1.5,
	true,
	true,
	"", 
	"!(_target getVariable ['cpc_flaged', false])", 
	3, 
	false, 
	"", 
	"" 
];

La nouvelle partie étant :

_target setflagAnimationPhase 0.5; 
sleep 1.5; 
_target setflagAnimationPhase 0; 
sleep 1.5; 
_target setFlagTexture "images\cpc.jpg"; 
sleep 1.5; 
_target setflagAnimationPhase 0.5; 
sleep 1.5; 
_target setflagAnimationPhase 1;

Le drapeau a une animation dédiée et des commandes pour la manipuler.
Ici on vient forcer l’animation se mettre à 50%… soit milieu du poteau, puis 0 soit tout en bas du poteau.
Les sleep 1.5 demandant simplement d’attendre 1,5sec à chaque fois. Pour avoir le temps de voir le changement.
Ensuite on vient changer la texture, donc le drapeau en lui-même.
Il ne reste plus qu’à rejouer avec l’animation, mais au lieu de diminuer la valeur, on l’augmente pour se diriger vers le haut du poteau

Tada, une animation saccadée et horrible !

On pourrait faire une boucle qui viendrait décrémenter petit à petit notre animation phase, … mais ce serait horrible niveau synchronisation réseau… aussi vous allez voir la version suivante est un poil plus compliqué.

Animation et event handler

C’était une première approche, on va devoir parler d’un gros morceau… les Event Handlers. Vous avez une documentation par ici mais si je vous dis qu’elle ne nous servira à rien, parce que notre cas n’est pas listé ? 😀

Pour faire simple, lorsqu’il se passe quelque chose, par exemple lorsque vous utilisez une arme en tirant. Le jeu aura une liste de scripts liées à votre arme pour cet événement qu’est le tir en appelant tous ces scripts un par un.
Il existe une bonne liste d’évènement, comme vous pouvez le voir dans la documentation.

Mais notre action est une action spécifique, qui s’appelle avec une autre fonction.

Pourquoi ? Quand on va lancer une animation, on ne sait pas quand elle va se terminer, même si on connait la durée de l’animation, elle pourrait changer ou être arrêté en plein milieu via une autre action.

Bref le plus propre étant d’utiliser ces évènements. Forcément c’est une nouvelle méthode

[
	object,
	"Event Name",
	{ code }
] call BIS_fnc_addScriptedEventHandler;

La deuxième commande que nous allons utiliser étant BIS_fnc_animateFlag

[object, phaseToReach, Instant] call BIS_fnc_animateFlag;

Pour tester et comprendre je vous propose ce script et la vidéo du résultat
( J’ai un peu réduit la taille des scripts de addAction, puisqu’on cherche à tester et non à avoir un script sécurisé)

[this, "FlagAnimationDone", {
	params ["_flag", "_anim"];
	systemChat "Animation terminée !";
}] call BIS_fnc_addScriptedEventHandler;


this addAction [ 
	"Monter le drapeau",
	{ [(_this#0), 1, false] call BIS_fnc_animateFlag; }
];

this addAction [ 
	"Descendre le drapeau",
	{ [(_this#0), 0, false] call BIS_fnc_animateFlag; }
];

Tout du long j’utilise Instant à false, puisqu’on veut l’animation, on ne veut pas qu’elle soit instantanée !

On peut remarquer que notre event handler, ne s’active que lorsqu’on arrive soit tout en haut, soit tout en bas et pas ailleurs.

Comme on ne compte pas donner de contrôle, mais seulement activer l’action, on va pouvoir enchainer. Notre action va faire descendre le drapeau, et l’event handler le fera remonter avec le bon drapeau.

[this, "FlagAnimationDone", {
	params ["_flag", "_anim"];

	if(_anim == 0) then {
		_flag spawn {
			_this setFlagTexture "images\cpc.jpg";
			sleep 1;
			[_this, 1, false] call BIS_fnc_animateFlag;
		};
	};
}] call BIS_fnc_addScriptedEventHandler;


this addAction
[ 
	"Hisser le drapeau",
	{ 
		params ["_target", "_caller", "_actionId", "_arguments"]; 
		_target setVariable ['cpc_flaged', true, true];
		[_target, 0, false] call BIS_fnc_animateFlag;
	}, 
	[], 
	1.5,
	true,
	true,
	"", 
	"!(_target getVariable ['cpc_flaged', false])", 
	3, 
	false, 
	"", 
	"" 
];

Normalement le 2ème bloc, on devrait être bon sur les explications.
Sur le premier, j’utilise simplement la fonction, en m’inscrivant à l’évènement FlagAnimationDone… qu’on aurait du mal à inventer.
Je sors cet évènement directement de la documentation du animateFlag.

Et on ne vient interagir que si notre animation à est 0, soit que le drapeau est en bas (comme le montrait nos tests).
Dans ce cas, on lance la suite, comme on le faisait sur la version saccadée, soit on change le drapeau, et on le remonte.

J’ai seulement ajouté une attente de 1 seconde, en bas du poteau, pour ralentir et simuler légèrement le changement de drapeau.

Conclusion

Avec ça vous avez une version tout à fait fonctionnelle qui respecte le cahier des charges. Marchant en solo comme en serveur dédié, avec une animation fluide et votre drapeau personnalisé !

Je n’ai pas poussé plus que nécessaire chaque étape, mais j’espère que vous avez une vision d’ensemble de ce qui est utilisable, et vers quel élément chercher.

Allez plus loin – Machine à états

Pourquoi faire simple quand on peut faire compliqué ?
La raison est simple, j’ai besoin de complexifier un peu pour des cas comme celui de forcer à le joueur à rester à côté, sinon on stoppe l’animation (ou s’il meurt :))

Mais je ne m’attarderais pas dessus, je vous mets cette version qui fait EXACTEMENT comme la version précédente

[this, "FlagAnimationDone", {
	params ["_flag", "_anim"];

	switch (_flag getVariable ['cpc_flag_state', 0]) do {
		case 1: {
			_flag spawn {
				_this setVariable ['cpc_flag_state', 2, true];
				_this setFlagTexture "images\cpc.jpg";
				sleep 1;
				[_this, 1, false] call BIS_fnc_animateFlag;
			};
		};
		case 2: {
			_flag setVariable ['cpc_flag_state', 3, true];
		};
		default {};
	};
}] call BIS_fnc_addScriptedEventHandler;


this addAction
[ 
	"Hisser le drapeau",
	{ 
		params ["_target", "_caller", "_actionId", "_arguments"]; 
		_target setVariable ['cpc_flag_state', 1, true];
		[_target, 0, false] call BIS_fnc_animateFlag;
	}, 
	[], 
	1.5,
	true,
	true,
	"", 
	"(_target getVariable ['cpc_flag_state', 0]) == 0", 
	3, 
	false, 
	"", 
	"" 
];

Arma 3 – Hisser un drapeau (Partie 1)

Hisser un drapeau dans un jeu comme Arma vous semble simple ? Derrière cette simple opération se cache pas mal de subtilités, surtout dans le cas d’un serveur dédié.

Dans cet article, on va tenter de comprendre l’animation d’un objet, la gestion des évènements, mais aussi les appels client/serveur.
Le but n’est pas de pousser chaque partie à fond, mais déjà de comprendre la base.

Le but n’est pas de devenir expert, mais d’avoir une compréhension globale afin de savoir ce qu’il est possible de faire et vers où se tourner pour savoir comment.

Continuer la lecture

Arma 3 – Outils de debug et dossiers importants

Je commence cette série d’articles sur le scripting d’arma 3, y passant beaucoup (trop) de temps afin d’aider ou préparer des missions pour la communauté Grèce de canards.

Avant de s’attaquer à du concret, pour partir avec les mêmes outils, voyons ce que Bohemia nous propose.

Je pars du principe que ceux qui lisent cette article connaissent déjà un peu le langage sqf. S’il y a de la demande, je pourrais faire un article plus complet pour introduire ce langage.

Continuer la lecture

Unreal – Position aléatoire au sommet d’un cube

Pour un prototype, je devais générer des positions aléatoires au dessus d’un terrain plat formé uniquement d’un Cube, pour être exacte un StaticMeshActor de type cube.

Après quelques recherches, je n’ai pas trouvé de solution qui me convenait. La solution la plus propre étant de faire une « zone de spawn » mais dans mon cas où je voudrais faire spawn au dessus de multiple blocs… il ne serait pas très optimisé d’avoir autant de zone.

Je vous propose donc de comprendre comme fonctionne les StaticMeshActor et voir comment on peut générer une position aléatoire dans une zone dynamique.

Continuer la lecture

Unreal – Comment initialiser GIT

Afin de partager son code, ou simplement de le versionner, c’est à dire pouvoir revenir en arrière en cas de problème, d’erreur ou juste retrouver ce qu’on a pu mettre de supprimer, nous allons voir comment mettre en place Git dans un projet Unreal.

Prérequis

On va voir pour installer Git/Git LFS et Créer un compte sur Github

Git va nous permettre de gérer l’envoie et le versionning des fichiers. L’outil est uniquement en ligne de commande, mais je vous proposerais plus loin un client.

Pour l’installation, vous pouvez laisser tout les paramètres par défaut.

Continuer la lecture

Highscore avec Firebase

J’ai eu besoin il y a peu d’ajouter un highscore à un jeu, mais j’ai trouvé assez peu de tutos expliquant comment faire.
Cet article va donc vous montrer comment le faire gratuitement avec Firebase. À noter que cet article vous présente comment utiliser une base de données NoSql. Vous pourrez donc l’adapter pour ce que vous voulez ayant besoin de stocker des données.

 

Continuer la lecture

Comment créer un jeu multijoueur rapidement avec PUN (Photon unity Networking) ?

Photon Unity ou PUN (Photon unity Networking) est un moteur réseau qui permet, en très peu de lignes, de faire ce que vous voulez.

Avant d’écrire l’article théorique sur le multijoueur, j’ai testé plusieurs moteurs :

  • Un serveur en NodeJs discutant en socketIO les clients Unity.
  • UN ou UNet pour unity network, qui est le moteur réseau proposé directement par Unity.
  • PUN qui me semble le plus intéréssant, au moins pour commencer et comprendre comment la couche réseau fonctionne.

Continuer la lecture

Vue et déplacement TPS sous Unity

Commençant un nouveau projet, j’ai regardé rapidement s’il y avait des scripts simples pour faire une vue TPS gratuit. J’ai été assez déçu d’où cet article. Déjà TPS ou third personne shooter, est traduit par vue à la 3ème personne… c’est à dire ce que vous voyez sur l’image ci-dessus. On le traduit parfois par vue à l’épaule même si ce n’est pas toujours au niveau de l’épaule. Le but étant de voir notre avatar… après tout on c’est cassez le culs à faire un modèle 3D autant le mettre en avant !

 

Je vous propose donc un script assez simple pour gérer la caméra et le déplacement de l’avatar. Je cherche un script très simple qui permet seulement de se déplacer avant/arrière, gauche/droite, et tourner la caméra avec la souris. Après il est possible d’utiliser des assets plus complet, mais le but est déjà de comprendre les bases avant de partir dans plus complexe.

Continuer la lecture