I. Introduction▲
Dans cette vidéo, nous allons apprendre à faire un jeu de plates-formes 2D basique dans lequel le joueur pourra déplacer un personnage ramassant des pièces sur son chemin. L'accent est mis sur le contrôle du personnage. Celui-ci peut se déplacer de gauche à droite et sauter.
II. Vidéo▲
Session en direct : création d'un jeu de plates-formes basique en 2D
III. Résumé▲
III-A. Importation des ressources▲
Pour cette session, les ressources viennent du pack « 2D Platformer » publié par Unity Technologies et gratuitement téléchargeable à partir de l'Asset Store.
Toutefois, toutes les ressources ne sont pas utilisées. Voici la liste des éléments importés :
- les animations ;
- les contrôleurs ;
- tous les .asset du dossier des paramètres du projet (ProjectSettings) ;
- les matériaux physiques ;
- le préfabriqué du personnage « hero » ;
- tous les sprites.
Ensuite, il est nécessaire d'ajouter un sprite « CoinSprite.png » du pack « 2D Pack » aussi publié par Unity Technologies.
III-B. Configuration du personnage▲
Pour commencer la configuration du personnage, glissez puis déposez le préfabriqué « hero » dans la scène. Retirez les composants de type script qui n'ont pu être chargés, car aucun script n'a été importé ainsi que la source audio.
Le jeu est pacifique, donc enlevez le bazooka et le « gun » du héros.
Sachant que la caméra suit toujours le personnage, placez-la comme enfant du héros et réinitialisez sa position en X et Y. Définissez sa taille à 8.
III-C. Scripts▲
Le premier script (en C#) à créer est le « SimplePlatformController » permettant de déplacer le personnage suivant les actions du joueur.
Dans ce script, l'auteur utilise [HideInInspector] afin de cacher la variable de l'inspecteur (de l'éditeur) tout en définissant la variable comme publique. Celle-ci sera tout de même sérialisée.
III-C-1. Gestion du saut▲
Le joueur ne peut pas sauter uniquement s'il appuie sur le bouton de saut. Il est aussi nécessaire de vérifier si le personnage est au sol. Pour cela, un lancer de rayon (en 2D avec LineCast) est utilisé :
grounded =
Physics2D.
Linecast
(
transform.
position,
groundCheck.
position,
1
<<
LayerMask.
NameToLayer
(
"Ground"
));
if
(
Input.
GetButtonDown
(
"Jump"
) &&
grounded)
{
jump =
true
;
}
III-C-2. Retourner le personnage▲
Afin de retourner le sprite du personnage lorsqu'il va vers la gauche, vous pouvez simplement changer sa transformation en inversant sa coordonnée X :
void
Flip
(
)
{
facingRight =
!
facingRight;
Vector3 theScale =
transform.
localScale;
theScale.
x *=
-
1
;
transform.
localScale =
theScale;
}
III-C-3. Physique du personnage▲
Le code suivant permet de gérer la physique du personnage : la vitesse, la direction et le saut.
void
FixedUpdate
(
)
{
float
h =
Input.
GetAxis
(
"Horizontal"
);
anim.
SetFloat
(
"Speed"
,
Mathf.
Abs
(
h));
if
(
h *
rb2d.
velocity.
x <
maxSpeed)
rb2d.
AddForce
(
Vector2.
right *
h *
moveForce);
// Limitation de la vitesse
if
(
Mathf.
Abs (
rb2d.
velocity.
x) >
maxSpeed)
rb2d.
velocity =
new
Vector2
(
Mathf.
Sign (
rb2d.
velocity.
x) *
maxSpeed,
rb2d.
velocity.
y);
// Rotation du sprite suivant sa direction
if
(
h >
0
&&
!
facingRight)
Flip (
);
else
if
(
h <
0
&&
facingRight)
Flip (
);
if
(
jump)
{
anim.
SetTrigger
(
"Jump"
);
rb2d.
AddForce
(
new
Vector2
(
0f
,
jumpForce));
jump =
false
;
}
}
III-C-4. Créer des plates-formes▲
Une plate-forme peut être créée à partir d'un objet 3D, dont le Box Collider 3D aura été remplacé par un Box Collider 2D. Il ne faut pas oublier de placer la plate-forme sur le calque « Ground ». Afin de pouvoir créer des plates-formes à partir d'un script, il faut transformer cet objet en préfabriqué.
De plus, un nouveau composant vide « SpawnManager » est ajouté à la scène.
Finalement, un nouveau script « SpawnManager » gérera la création des plates-formes. Celui-ci ne fait qu'instancier (avec la fonction Instanciate) les plates-formes suivant des contraintes spécifiques.
III-C-5. Chute des plates-formes▲
Un nouveau script « PlatformFall » est utilisé pour provoquer la chute des plates-formes une fois qu'elles sont en contact du joueur :
void
OnCollisionEnter2D (
Collision2D other)
{
if
(
other.
gameObject.
CompareTag
(
"Player"
))
{
Invoke (
"Fall"
,
fallDelay);
}
}
void
Fall
(
)
{
rb2d.
isKinematic =
false
;
}
III-C-6. Intégration des pièces▲
Après l'ajout du sprite « CoinSprite » à la scène, ajoutez un « Circle Collider 2D », cochez la boite « Is Trigger » afin que la collision n'affecte pas la physique, puis créez un nouveau script « Coin ».
Ce script permettra de supprimer la pièce de la scène une fois que celle-ci est touchée par le joueur.
III-C-7. Créer des pièces▲
Pour faire apparaître les pièces dans le niveau, créez trois composants vides, enfants du sol et placez-les à la position à laquelle vous voulez voir apparaître les pièces. Ensuite, créez un nouveau script « SpawnCoins » qui se chargera d'instancier les pièces aléatoirement à la position des composants vides.
III-C-8. Réinitialisation après la chute▲
Finalement, lorsque le joueur tombe, le jeu doit être réinitialisé. Pour cela, ajoutez un cube d'une longueur taille de 500 sur l'axe des X et placez-le en dessus du niveau. Cochez la case « Is Trigger » et associez-lui le nouveau script « Reset ». Lorsque le joueur entre en collision avec le cube, le script recharge le niveau avec la fonction LoadLevel :
void
OnTriggerEnter2D (
Collider2D other)
{
if
(
other.
gameObject.
CompareTag
(
"Player"
))
Application.
LoadLevel
(
Application.
loadedLevel);
}
III-D. Récapitulatif▲
Voici le code de chacun des scripts :
using
UnityEngine;
using
System.
Collections;
public
class
SimplePlatformController :
MonoBehaviour {
[HideInInspector]
public
bool
facingRight =
true
;
[HideInInspector]
public
bool
jump =
false
;
public
float
moveForce =
365f
;
public
float
maxSpeed =
5f
;
public
float
jumpForce =
1000f
;
public
Transform groundCheck;
private
bool
grounded =
false
;
private
Animator anim;
private
Rigidbody2D rb2d;
// Utilisez cette fonction pour l'initialisation
void
Awake (
)
{
anim =
GetComponent<
Animator>(
);
rb2d =
GetComponent<
Rigidbody2D>(
);
}
// Update est appelee une fois par frame
void
Update (
)
{
grounded =
Physics2D.
Linecast
(
transform.
position,
groundCheck.
position,
1
<<
LayerMask.
NameToLayer
(
"Ground"
));
if
(
Input.
GetButtonDown
(
"Jump"
) &&
grounded)
{
jump =
true
;
}
}
void
FixedUpdate
(
)
{
float
h =
Input.
GetAxis
(
"Horizontal"
);
anim.
SetFloat
(
"Speed"
,
Mathf.
Abs
(
h));
if
(
h *
rb2d.
velocity.
x <
maxSpeed)
rb2d.
AddForce
(
Vector2.
right *
h *
moveForce);
if
(
Mathf.
Abs (
rb2d.
velocity.
x) >
maxSpeed)
rb2d.
velocity =
new
Vector2
(
Mathf.
Sign (
rb2d.
velocity.
x) *
maxSpeed,
rb2d.
velocity.
y);
if
(
h >
0
&&
!
facingRight)
Flip (
);
else
if
(
h <
0
&&
facingRight)
Flip (
);
if
(
jump)
{
anim.
SetTrigger
(
"Jump"
);
rb2d.
AddForce
(
new
Vector2
(
0f
,
jumpForce));
jump =
false
;
}
}
void
Flip
(
)
{
facingRight =
!
facingRight;
Vector3 theScale =
transform.
localScale;
theScale.
x *=
-
1
;
transform.
localScale =
theScale;
}
}
using
UnityEngine;
using
System.
Collections;
public
class
SpawnPlatforms :
MonoBehaviour {
public
int
maxPlatforms =
20
;
public
GameObject platform;
public
float
horizontalMin =
7
.
5f
;
public
float
horizontalMax =
14f
;
public
float
verticalMin =
-
6f
;
public
float
verticalMax =
6
;
private
Vector2 originPosition;
void
Start (
) {
originPosition =
transform.
position;
Spawn (
);
}
void
Spawn
(
)
{
for
(
int
i =
0
;
i <
maxPlatforms;
i++
)
{
Vector2 randomPosition =
originPosition +
new
Vector2 (
Random.
Range
(
horizontalMin,
horizontalMax),
Random.
Range (
verticalMin,
verticalMax));
Instantiate
(
platform,
randomPosition,
Quaternion.
identity);
originPosition =
randomPosition;
}
}
}
using
UnityEngine;
using
System.
Collections;
public
class
PlatformFall :
MonoBehaviour {
public
float
fallDelay =
1f
;
private
Rigidbody2D rb2d;
void
Awake
(
)
{
rb2d =
GetComponent<
Rigidbody2D>(
);
}
void
OnCollisionEnter2D (
Collision2D other)
{
if
(
other.
gameObject.
CompareTag
(
"Player"
))
{
Invoke (
"Fall"
,
fallDelay);
}
}
void
Fall
(
)
{
rb2d.
isKinematic =
false
;
}
}
using
UnityEngine;
using
System.
Collections;
public
class
SpawnCoins :
MonoBehaviour {
public
Transform[]
coinSpawns;
public
GameObject coin;
// Utilisez cette fonction pour l'initialisation
void
Start (
) {
Spawn
(
);
}
void
Spawn
(
)
{
for
(
int
i =
0
;
i <
coinSpawns.
Length;
i++
)
{
int
coinFlip =
Random.
Range (
0
,
2
);
if
(
coinFlip >
0
)
Instantiate
(
coin,
coinSpawns[
i].
position,
Quaternion.
identity);
}
}
}
using
UnityEngine;
using
System.
Collections;
public
class
PickupCoin :
MonoBehaviour {
// Utilisez cette fonction pour l'initialisation
void
Start (
) {
}
// Update est appelee une fois par frame
void
Update (
) {
}
void
OnTriggerEnter2D (
Collider2D other)
{
if
(
other.
gameObject.
CompareTag
(
"Player"
))
Destroy
(
gameObject);
}
}
using
UnityEngine;
using
System.
Collections;
public
class
Reset :
MonoBehaviour {
// Utilisez cette fonction pour l'initialisation
void
Start (
) {
}
// Update est appelee une fois par frame
void
Update (
) {
}
void
OnTriggerEnter2D (
Collider2D other)
{
if
(
other.
gameObject.
CompareTag
(
"Player"
))
Application.
LoadLevel
(
Application.
loadedLevel);
}
}
IV. Commenter▲
Vous pouvez commenter et donner vos avis dans la discussion associée sur le forum.