Ninja.as 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. #include "Scripts/NinjaSnowWar/GameObject.as"
  2. #include "Scripts/NinjaSnowWar/AIController.as"
  3. const int LAYER_MOVE = 0;
  4. const int LAYER_ATTACK = 1;
  5. const float ninjaMoveForce = 25;
  6. const float ninjaAirMoveForce = 1;
  7. const float ninjaDampingForce = 5;
  8. const float ninjaJumpForce = 450;
  9. const Vector3 ninjaThrowVelocity(0, 4.25, 20);
  10. const Vector3 ninjaThrowPosition(0, 0.2, 1);
  11. const float ninjaThrowDelay = 0.1;
  12. const float ninjaCorpseDuration = 3;
  13. const int ninjaPoints = 250;
  14. class Ninja : GameObject
  15. {
  16. Controls controls;
  17. Controls prevControls;
  18. AIController@ controller;
  19. bool okToJump;
  20. bool smoke;
  21. float inAirTime;
  22. float onGroundTime;
  23. float throwTime;
  24. float deathTime;
  25. float deathDir;
  26. float dirChangeTime;
  27. float aimX;
  28. float aimY;
  29. Ninja()
  30. {
  31. health = maxHealth = 2;
  32. okToJump = false;
  33. smoke = false;
  34. onGround = false;
  35. isSliding = false;
  36. inAirTime = 1;
  37. onGroundTime = 0;
  38. throwTime = 0;
  39. deathTime = 0;
  40. deathDir = 0;
  41. dirChangeTime = 0;
  42. aimX = 0;
  43. aimY = 0;
  44. }
  45. void DelayedStart()
  46. {
  47. SubscribeToEvent(node, "NodeCollision", "HandleNodeCollision");
  48. // Get horizontal aim from initial rotation
  49. aimX = controls.yaw = node.rotation.yaw;
  50. // Start playing the idle animation immediately, even before the first physics update
  51. AnimationController@ animCtrl = node.children[0].GetComponent("AnimationController");
  52. animCtrl.PlayExclusive("Models/NinjaSnowWar/Ninja_Idle3.ani", LAYER_MOVE, true);
  53. }
  54. void SetControls(const Controls&in newControls)
  55. {
  56. controls = newControls;
  57. }
  58. Quaternion GetAim()
  59. {
  60. Quaternion q = Quaternion(aimX, Vector3(0, 1, 0));
  61. q = q * Quaternion(aimY, Vector3(1, 0, 0));
  62. return q;
  63. }
  64. void FixedUpdate(float timeStep)
  65. {
  66. // For multiplayer, replicate the health into the node user variables
  67. node.vars["Health"] = health;
  68. if (health <= 0)
  69. {
  70. DeathUpdate(timeStep);
  71. return;
  72. }
  73. // AI control if controller exists
  74. if (controller !is null)
  75. controller.Control(this, node, timeStep);
  76. RigidBody@ body = node.GetComponent("RigidBody");
  77. AnimationController@ animCtrl = node.children[0].GetComponent("AnimationController");
  78. // Turning / horizontal aiming
  79. if (aimX != controls.yaw)
  80. aimX = controls.yaw;
  81. // Vertical aiming
  82. if (aimY != controls.pitch)
  83. aimY = controls.pitch;
  84. // Force the physics rotation
  85. Quaternion q(aimX, Vector3(0, 1, 0));
  86. body.rotation = q;
  87. // Movement ground/air
  88. Vector3 vel = body.linearVelocity;
  89. if (onGround)
  90. {
  91. // If landed, play a particle effect at feet (use the AnimatedModel node)
  92. if (inAirTime > 0.5)
  93. SpawnParticleEffect(node.children[0].worldPosition, "Particle/SnowExplosion.xml", 1);
  94. inAirTime = 0;
  95. onGroundTime += timeStep;
  96. }
  97. else
  98. {
  99. onGroundTime = 0;
  100. inAirTime += timeStep;
  101. }
  102. if (inAirTime < 0.3f && !isSliding)
  103. {
  104. bool sideMove = false;
  105. // Movement in four directions
  106. if (controls.IsDown(CTRL_UP|CTRL_DOWN|CTRL_LEFT|CTRL_RIGHT))
  107. {
  108. float animDir = 1.0f;
  109. Vector3 force(0, 0, 0);
  110. if (controls.IsDown(CTRL_UP))
  111. force += q * Vector3(0, 0, 1);
  112. if (controls.IsDown(CTRL_DOWN))
  113. {
  114. animDir = -1.0f;
  115. force += q * Vector3(0, 0, -1);
  116. }
  117. if (controls.IsDown(CTRL_LEFT))
  118. {
  119. sideMove = true;
  120. force += q * Vector3(-1, 0, 0);
  121. }
  122. if (controls.IsDown(CTRL_RIGHT))
  123. {
  124. sideMove = true;
  125. force += q * Vector3(1, 0, 0);
  126. }
  127. // Normalize so that diagonal strafing isn't faster
  128. force.Normalize();
  129. force *= ninjaMoveForce;
  130. body.ApplyImpulse(force);
  131. // Walk or sidestep animation
  132. if (sideMove)
  133. {
  134. animCtrl.PlayExclusive("Models/NinjaSnowWar/Ninja_Stealth.ani", LAYER_MOVE, true, 0.2);
  135. animCtrl.SetSpeed("Models/NinjaSnowWar/Ninja_Stealth.ani", animDir * 2.2);
  136. }
  137. else
  138. {
  139. animCtrl.PlayExclusive("Models/NinjaSnowWar/Ninja_Walk.ani", LAYER_MOVE, true, 0.2);
  140. animCtrl.SetSpeed("Models/NinjaSnowWar/Ninja_Walk.ani", animDir * 1.6);
  141. }
  142. }
  143. else
  144. {
  145. // Idle animation
  146. animCtrl.PlayExclusive("Models/NinjaSnowWar/Ninja_Idle3.ani", LAYER_MOVE, true, 0.2);
  147. }
  148. // Overall damping to cap maximum speed
  149. body.ApplyImpulse(Vector3(-ninjaDampingForce * vel.x, 0, -ninjaDampingForce * vel.z));
  150. // Jumping
  151. if (controls.IsDown(CTRL_JUMP))
  152. {
  153. if (okToJump && inAirTime < 0.1f)
  154. {
  155. // Lift slightly off the ground for better animation
  156. body.position = body.position + Vector3(0, 0.03, 0);
  157. body.ApplyImpulse(Vector3(0, ninjaJumpForce, 0));
  158. inAirTime = 1.0f;
  159. animCtrl.PlayExclusive("Models/NinjaSnowWar/Ninja_JumpNoHeight.ani", LAYER_MOVE, false, 0.1);
  160. animCtrl.SetTime("Models/NinjaSnowWar/Ninja_JumpNoHeight.ani", 0.0); // Always play from beginning
  161. okToJump = false;
  162. }
  163. }
  164. else okToJump = true;
  165. }
  166. else
  167. {
  168. // Motion in the air
  169. // Note: when sliding a steep slope, control (or damping) isn't allowed!
  170. if (inAirTime > 0.3f && !isSliding)
  171. {
  172. if (controls.IsDown(CTRL_UP|CTRL_DOWN|CTRL_LEFT|CTRL_RIGHT))
  173. {
  174. Vector3 force(0, 0, 0);
  175. if (controls.IsDown(CTRL_UP))
  176. force += q * Vector3(0, 0, 1);
  177. if (controls.IsDown(CTRL_DOWN))
  178. force += q * Vector3(0, 0, -1);
  179. if (controls.IsDown(CTRL_LEFT))
  180. force += q * Vector3(-1, 0, 0);
  181. if (controls.IsDown(CTRL_RIGHT))
  182. force += q * Vector3(1, 0, 0);
  183. // Normalize so that diagonal strafing isn't faster
  184. force.Normalize();
  185. force *= ninjaAirMoveForce;
  186. body.ApplyImpulse(force);
  187. }
  188. }
  189. // Falling/jumping/sliding animation
  190. if (inAirTime > 0.1f)
  191. animCtrl.PlayExclusive("Models/NinjaSnowWar/Ninja_JumpNoHeight.ani", LAYER_MOVE, false, 0.1);
  192. }
  193. // Shooting
  194. if (throwTime >= 0)
  195. throwTime -= timeStep;
  196. // Start fading the attack animation after it has progressed past a certain point
  197. if (animCtrl.GetTime("Models/NinjaSnowWar/Ninja_Attack1.ani") > 0.1)
  198. animCtrl.Fade("Models/NinjaSnowWar/Ninja_Attack1.ani", 0.0, 0.5);
  199. if ((controls.IsPressed(CTRL_FIRE, prevControls)) && (throwTime <= 0))
  200. {
  201. Vector3 projectileVel = GetAim() * ninjaThrowVelocity;
  202. animCtrl.Play("Models/NinjaSnowWar/Ninja_Attack1.ani", LAYER_ATTACK, false, 0.0);
  203. animCtrl.SetTime("Models/NinjaSnowWar/Ninja_Attack1.ani", 0.0); // Always play from beginning
  204. Node@ snowball = SpawnObject(node.position + vel * timeStep + q * ninjaThrowPosition, GetAim(), "SnowBall");
  205. RigidBody@ snowballBody = snowball.GetComponent("RigidBody");
  206. snowballBody.linearVelocity = projectileVel;
  207. GameObject@ snowballObject = cast<GameObject>(snowball.scriptObject);
  208. snowballObject.side = side;
  209. snowballObject.creatorID = node.id;
  210. PlaySound("Sounds/NutThrow.wav");
  211. throwTime = ninjaThrowDelay;
  212. }
  213. prevControls = controls;
  214. ResetWorldCollision();
  215. }
  216. void DeathUpdate(float timeStep)
  217. {
  218. RigidBody@ body = node.GetComponent("RigidBody");
  219. CollisionShape@ shape = node.GetComponent("CollisionShape");
  220. Node@ modelNode = node.children[0];
  221. AnimationController@ animCtrl = modelNode.GetComponent("AnimationController");
  222. AnimatedModel@ model = modelNode.GetComponent("AnimatedModel");
  223. Vector3 vel = body.linearVelocity;
  224. // Overall damping to cap maximum speed
  225. body.ApplyImpulse(Vector3(-ninjaDampingForce * vel.x, 0, -ninjaDampingForce * vel.z));
  226. // Collide only to world geometry
  227. body.collisionMask = 2;
  228. // Pick death animation on first death update
  229. if (deathDir == 0)
  230. {
  231. if (Random(1.0) < 0.5)
  232. deathDir = -1;
  233. else
  234. deathDir = 1;
  235. PlaySound("Sounds/SmallExplosion.wav");
  236. VariantMap eventData;
  237. eventData["Points"] = ninjaPoints;
  238. eventData["Receiver"] = lastDamageCreatorID;
  239. eventData["DamageSide"] = lastDamageSide;
  240. SendEvent("Points", eventData);
  241. SendEvent("Kill", eventData);
  242. }
  243. deathTime += timeStep;
  244. // Move the model node to center the corpse mostly within the physics cylinder
  245. // (because of the animation)
  246. if (deathDir < 0)
  247. {
  248. // Backward death
  249. animCtrl.StopLayer(LAYER_ATTACK, 0.1);
  250. animCtrl.PlayExclusive("Models/NinjaSnowWar/Ninja_Death1.ani", LAYER_MOVE, false, 0.2);
  251. animCtrl.SetSpeed("Models/NinjaSnowWar/Ninja_Death1.ani", 0.5);
  252. if ((deathTime >= 0.3) && (deathTime < 0.8))
  253. modelNode.Translate(Vector3(0, 0, 4.25 * timeStep));
  254. }
  255. else if (deathDir > 0)
  256. {
  257. // Forward death
  258. animCtrl.StopLayer(LAYER_ATTACK, 0.1);
  259. animCtrl.PlayExclusive("Models/NinjaSnowWar/Ninja_Death2.ani", LAYER_MOVE, false, 0.2);
  260. animCtrl.SetSpeed("Models/NinjaSnowWar/Ninja_Death2.ani", 0.5);
  261. if ((deathTime >= 0.4) && (deathTime < 0.8))
  262. modelNode.Translate(Vector3(0, 0, -4.25 * timeStep));
  263. }
  264. // Create smokecloud just before vanishing
  265. if ((deathTime > (ninjaCorpseDuration - 1)) && (!smoke))
  266. {
  267. SpawnParticleEffect(node.position + Vector3(0, -0.4, 0), "Particle/Smoke.xml", 8);
  268. smoke = true;
  269. }
  270. if (deathTime > ninjaCorpseDuration)
  271. {
  272. SpawnObject(node.position + Vector3(0, -0.5, 0), Quaternion(), "LightFlash");
  273. SpawnSound(node.position + Vector3(0, -0.5, 0), "Sounds/BigExplosion.wav", 2);
  274. node.Remove();
  275. }
  276. }
  277. bool Heal(int amount)
  278. {
  279. if (health == maxHealth)
  280. return false;
  281. health += amount;
  282. if (health > maxHealth)
  283. health = maxHealth;
  284. // If player, play the "powerup" sound
  285. if (side == SIDE_PLAYER)
  286. PlaySound("Sounds/Powerup.wav");
  287. return true;
  288. }
  289. }