animated_sprite.nim 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. # author: Ethosa
  2. ## It provides display animated sprites.
  3. import
  4. ../thirdparty/opengl,
  5. ../core/vector2,
  6. ../core/rect2,
  7. ../core/anchor,
  8. ../core/input,
  9. ../core/enums,
  10. ../core/image,
  11. ../core/color,
  12. ../core/animation,
  13. ../nodes/node,
  14. node2d
  15. type
  16. AnimatedSpriteObj* = object of Node2DObj
  17. reversed*, paused*: bool
  18. filter*: ColorRef
  19. animation*: string
  20. animations*: AnimationArray[GlTextureObj]
  21. AnimatedSpriteRef* = ref AnimatedSpriteObj
  22. proc AnimatedSprite*(name: string = "AnimatedSprite"): AnimatedSpriteRef =
  23. ## Creates a new AnimatedSprite.
  24. ##
  25. ## Arguments:
  26. ## - `name` is a node name.
  27. runnableExamples:
  28. var node = AnimatedSprite("AnimatedSprite")
  29. nodepattern(AnimatedSpriteRef)
  30. node2dpattern()
  31. result.filter = Color(1f, 1f, 1f)
  32. result.animations = @[Animation[GlTextureObj]("default", 2f)]
  33. result.animation = "default"
  34. result.paused = true
  35. result.reversed = false
  36. result.kind = ANIMATED_SPRITE_NODE
  37. method draw*(self: AnimatedSpriteRef, w, h: GLfloat) =
  38. ## this method uses in the `window.nim`.
  39. {.warning[LockLevel]: off.}
  40. let
  41. frame = self.animations[self.animation].frame
  42. frames_count = self.animations[self.animation].frames.len()
  43. if frame >= 0 and frame < frames_count:
  44. var texture = self.animations[self.animation].frames[frame]
  45. if texture.texture > 0:
  46. self.rect_size = texture.size
  47. # Recalculate position.
  48. self.position = self.timed_position
  49. if self.centered:
  50. self.position = self.timed_position - self.rect_size/2
  51. else:
  52. self.position = self.timed_position
  53. let
  54. x = -w/2 + self.global_position.x
  55. y = h/2 - self.global_position.y
  56. # Draw frame
  57. if frame >= 0 and frame < frames_count:
  58. var texture = self.animations[self.animation].frames[frame]
  59. if texture.texture > 0:
  60. if self.centered:
  61. glTranslatef(x + (self.rect_size.x / 2), y - (self.rect_size.y / 2), self.z_index_global)
  62. self.position = self.rect_size / 2
  63. else:
  64. glTranslatef(x, y, self.z_index_global)
  65. self.position = Vector2()
  66. glRotatef(self.rotation, 0, 0, 1)
  67. glColor4f(self.filter.r, self.filter.g, self.filter.b, self.filter.a)
  68. glEnable(GL_TEXTURE_2D)
  69. glEnable(GL_DEPTH_TEST)
  70. glBindTexture(GL_TEXTURE_2D, texture.texture)
  71. glBegin(GL_QUADS)
  72. glTexCoord2f(0, 0)
  73. glVertex3f(-self.position.x, self.position.y, self.z_index_global)
  74. glTexCoord2f(0, 1)
  75. glVertex3f(-self.position.x, self.position.y - self.rect_size.y, self.z_index_global)
  76. glTexCoord2f(1, 1)
  77. glVertex3f(-self.position.x + self.rect_size.x, self.position.y - self.rect_size.y, self.z_index_global)
  78. glTexCoord2f(1, 0)
  79. glVertex3f(-self.position.x + self.rect_size.x, self.position.y, self.z_index_global)
  80. glEnd()
  81. glDisable(GL_DEPTH_TEST)
  82. glDisable(GL_TEXTURE_2D)
  83. glRotatef(-self.rotation, 0, 0, 1)
  84. if self.centered:
  85. glTranslatef(-x - (self.rect_size.x / 2), -y + (self.rect_size.y / 2), -self.z_index_global)
  86. self.position = self.timed_position - self.rect_size/2
  87. else:
  88. glTranslatef(-x, -y, -self.z_index_global)
  89. self.position = self.timed_position
  90. else:
  91. self.rect_size = Vector2()
  92. # Change frame
  93. if not self.paused:
  94. if self.animations[self.animation].current < 60f:
  95. self.animations[self.animation].current += self.animations[self.animation].speed
  96. else:
  97. self.animations[self.animation].current = 0f
  98. if self.reversed:
  99. if frame - 1 < 0:
  100. self.animations[self.animation].frame = frames_count-1
  101. else:
  102. self.animations[self.animation].frame -= 1
  103. else:
  104. if frame + 1 > frames_count-1:
  105. self.animations[self.animation].frame = 0
  106. else:
  107. self.animations[self.animation].frame += 1
  108. method duplicate*(self: AnimatedSpriteRef): AnimatedSpriteRef {.base.} =
  109. ## Duplicates AnimatedSprite object and create a new AnimatedSprite.
  110. self.deepCopy()
  111. method getGlobalMousePosition*(self: AnimatedSpriteRef): Vector2Ref {.inline.} =
  112. ## Returns mouse position.
  113. Vector2Ref(x: last_event.x, y: last_event.y)
  114. method addAnimation*(self: AnimatedSpriteRef, name: string, speed: float = 2f) {.base.} =
  115. ## Adds a new animation to the AnimatedSprite animations.
  116. ##
  117. ## Arguments:
  118. ## - `name` is an animation name.
  119. ## - `speed` is an animation speed.
  120. var newanim = Animation[GlTextureObj](name, speed)
  121. if newanim notin self.animations:
  122. self.animations.add(newanim)
  123. method addFrame*(self: AnimatedSpriteRef, name: string, frame: GlTextureObj) {.base.} =
  124. ## Adds a new frame in the animation.
  125. ##
  126. ## Arguments:
  127. ## - `name` is an animation name.
  128. self.animations[name].addFrame(frame)
  129. method removeAnimation*(self: AnimatedSpriteRef, name: string) {.base.} =
  130. ## Deletes animation from the AnimatedSprite animations.
  131. ## If `name` is a current animation name, then animation will not delete.
  132. ##
  133. ## Arguments:
  134. ## - `name` is an animation name.
  135. if name == self.animation:
  136. return
  137. for i in 0..self.animations.high:
  138. if self.animations[i].name == name:
  139. self.animations.delete(i)
  140. break
  141. method pause*(self: AnimatedSpriteRef) {.base.} =
  142. ## Stops animation.
  143. self.paused = true
  144. method play*(self: AnimatedSpriteRef, name: string = "", backward: bool = false) {.base.} =
  145. ## Plays animation.
  146. ##
  147. ## Arguments:
  148. ## - `name` is an animation name. if it is "" than plays current animation.
  149. ## - if `backward` is true then plays animation in reverse order.
  150. if name != "":
  151. self.animation = name
  152. self.reversed = backward
  153. self.animations[self.animation].current = 0f
  154. if self.reversed:
  155. self.animations[self.animation].frame = self.animations[self.animation].frames.len()-1
  156. else:
  157. self.animations[self.animation].frame = 0
  158. self.paused = false
  159. method resume*(self: AnimatedSpriteRef) {.base.} =
  160. ## Resumes animation.
  161. self.paused = false
  162. method setSpeed*(self: AnimatedSpriteRef, name: string = "", speed: float = 2f) {.base.} =
  163. ## Changes animation speed.
  164. ## If `name` is "" then changes the speed of the current animation.
  165. ##
  166. ## Arguments:
  167. ## - `name` is an animation name.
  168. ## - `speed` is a new speed.
  169. if name == "":
  170. self.animations[self.animation].speed = speed
  171. else:
  172. self.animations[name].speed = speed