Ninja.as 12 KB

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