coderdojo-3djs

3D javascript opdrachten voor CoderDojo Leiden

View project on GitHub

Opdracht 4 - De avatar animeren

Volgende opdracht - Vorige opdracht - Uitleg

De avatar beweegt nu op commando, maar hij ziet er nog wel een beetje als een houten Klaas uit, vind je niet? Daar ga je in deze opdracht iets aan doen.

Acrobatiek uit de animate functie halen

Je gaat in deze opdracht de armen en benen van de avatar heen en weer bewegen als de avatar loopt. Maar om dat te doen moet je de animate functie aanpassen. Omdat daar nu al de code in staat voor de acrobatiek (salto’s en flips) zou die functie een beetje onoverzichtelijk worden. Daarom ga je eerst die acrobatiek eruit halen en in zijn eigen functie zetten.

Pas de animate functie aan:

function animate() {
  requestAnimationFrame(animate);
  acrobatics();
  renderer.render(scene, camera);
}
animate();

En voeg de volgende code toe, direct onder de regel animate();:

var is_cartwheeling = false;
var is_flipping = false;
function acrobatics() {
  if (is_cartwheeling) {
    avatar.rotation.z = avatar.rotation.z + 0.05;
  }
  if (is_flipping) {
    avatar.rotation.x = avatar.rotation.x + 0.05;
  }
}

Dit doet exact hetzelfde als wat je al had, maar nu kunnen we de loop-animatie toevoegen zonder dat het een rotzooi wordt.

Animatie voor de rechterhand toevoegen

Om te beginnen ga je alleen de rechterhand animeren.

Voeg eerst de volgende regel toe, direct boven de animate functie:

var clock = new THREE.Clock(true);

Dit voegt een klok toe, zodat je animaties op basis van de verstreken tijd kunt maken, zoals je in opdracht 1 ook al hebt gedaan.

Voeg nu de volgende code toe, direct onder de regel animate();:

function walk() {
  var position = Math.sin(clock.getElapsedTime() * 5) * 50;
  right_hand.position.z = position;
}

Met de functie Math.sin kun je een slingerbeweging simuleren. Als je een steeds groter getal in deze functie stopt (wat je doet omdat getElapsedTime steeds groter wordt, er is namelijk steeds meer tijd verstreken) dan zal Math.sin eerst steeds groter worden, daarna weer steeds kleiner, enzovoort. Als je het resultaat van deze functie dus gebruikt om de positie van de rechterhand te bepalen, dan krijg je dus het idee dat deze heen en weer beweegt tijdens het lopen.

Nu moet je de walk functie alleen nog aanroepen om de animatie te zien.

Pas de animate functie aan:

function animate() {
  requestAnimationFrame(animate);
  walk();
  acrobatics();
  renderer.render(scene, camera);
}
animate();

Probeer het zelf: Probeer je spel nu uit om de animatie van de hand te zien. Experimenteer met de waarden 5 en 50 om een idee te krijgen wat ze doen. Kies vervolgens waarden die jij mooi vindt.

Animatie voor de rest toevoegen

Als je tevreden bent over de animatie van de hand, dan kan je de rest van de ledematen animeren. Lukt je dit zelf zonder hieronder te spieken? Tip: Als de rechterhand naar voren gaat, dan moet de linkerhand naar achteren gaan. En meestal bewegen de armen en benen kruislings, dus rechterhand naar voren samen met het linkerbeen.

Pas (als je dat nog niet gelukt is) de walk functie aan:

function walk() {
  var position = Math.sin(clock.getElapsedTime() * 5) * 50;
  right_hand.position.z = position;
  left_hand.position.z = -position;
  right_foot.position.z = -position;
  left_foot.position.z = position;
}

Loop-animatie alleen uitvoeren tijdens het lopen

Je hebt nu een mooie loop-animatie gemaakt, maar op dit moment staat deze animatie altijd aan. Het is uiteraard de bedoeling dat de animatie alleen aan staat als je avatar ook werkelijk beweegt.

Pas daarvoor eerst de walk functie aan:

function walk() {
  if (!isWalking()) return;
  var position = Math.sin(clock.getElapsedTime() * 5) * 50;
  right_hand.position.z = position;
  left_hand.position.z = -position;
  right_foot.position.z = -position;
  left_foot.position.z = position;
}

Als de isWalking functie (die je nog moet maken) niet true teruggeeft, dan wordt de regel return; uitgevoerd. Dit betekent dat de walk functie meteen op houd en dus niet langer de positie van de handen en voeten aanpast.

Voeg nu deze isWalking functie toe, direct na de acrobatics functie:

var is_moving_right, is_moving_left, is_moving_forward, is_moving_back;
function isWalking() {
  if (is_moving_right) return true;
  if (is_moving_left) return true;
  if (is_moving_forward) return true;
  if (is_moving_back) return true;
  return false;
}

Als één van de variabelen is_moving_right, is_moving_left, is_moving_forward of is_moving_back de waarde true heeft, dan zal de isWalking functie ook true teruggeven. Anders geeft de functie false terug.

Nu moet je alleen nog zorgen dat de 4 is_moving_ variabelen de juiste waarde krijgen.

Pas daarvoor de addEventListener code aan:

document.addEventListener('keydown', function(event) {
  var code = event.keyCode;
  var speed = 15;

  if (code == 37) { // pijltje naar links
    marker.position.x = marker.position.x - speed;
    is_moving_left = true;
  }
  if (code == 38) { // pijltje omhoog
    marker.position.z = marker.position.z - speed;
    is_moving_forward = true;
  }
  if (code == 39) { // pijltje naar rechts
    marker.position.x = marker.position.x + speed;
    is_moving_right = true;
  }
  if (code == 40) { // pijltje omlaag
    marker.position.z = marker.position.z + speed;
    is_moving_back = true;
  }

  if (code == 67) is_cartwheeling = !is_cartwheeling; // C
  if (code == 70) is_flipping = !is_flipping; // F
});

Nu wordt de juiste is_moving_ variabele ingesteld als je op een pijltjestoets drukt. Helaas is dit nog niet genoeg, want als je eenmaal op een pijltjestoets hebt gedrukt wordt de is_moving_ variabele nooit meer op false gezet. Na het eerst pijltje dat je indrukt zal de avatar dus weer constant in de loop-animatie blijven.

Om dit op te lossen moet je nog een tweede addEventListener toevoegen, maar nu voor het keyup event (dus het loslaten van een toets).

Voeg de volgende code toe, helemaal onderaan index.js:

document.addEventListener('keyup', function(event) {
  var code = event.keyCode;
  
  if (code == 37) is_moving_left = false;
  if (code == 38) is_moving_forward = false;
  if (code == 39) is_moving_right = false;
  if (code == 40) is_moving_back = false;
});

Nu werkt de loop-animatie alleen maar zolang je een van de pijltjestoetsen indrukt. Maar de avatar blijft nog wel steeds in dezelfde richting staan, welk pijltje je ook indrukt. Dat probleem ga je in de volgende opdracht oplossen.

Volgende opdracht - Vorige opdracht - Uitleg