animated_sprite.nim 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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'u32:
  46. self.rect_size = texture.size
  47. # Recalculate position.
  48. procCall self.Node2DRef.draw(w, h)
  49. self.calcGlobalPosition()
  50. let
  51. x = -w/2 + self.global_position.x
  52. y = h/2 - self.global_position.y
  53. # Draw frame
  54. if frame >= 0 and frame < frames_count:
  55. var texture = self.animations[self.animation].frames[frame]
  56. if texture.texture > 0'u32:
  57. glPushMatrix()
  58. if self.centered:
  59. glTranslatef(x + (self.rect_size.x / 2), y - (self.rect_size.y / 2), self.z_index_global)
  60. self.position = self.rect_size / 2
  61. else:
  62. glTranslatef(x, y, self.z_index_global)
  63. self.position = Vector2()
  64. glRotatef(self.rotation, 0, 0, 1)
  65. glColor4f(self.filter.r, self.filter.g, self.filter.b, self.filter.a)
  66. glEnable(GL_TEXTURE_2D)
  67. glEnable(GL_DEPTH_TEST)
  68. glBindTexture(GL_TEXTURE_2D, texture.texture)
  69. glBegin(GL_QUADS)
  70. glTexCoord2f(0, 0)
  71. glVertex3f(-self.position.x, self.position.y, self.z_index_global)
  72. glTexCoord2f(0, 1)
  73. glVertex3f(-self.position.x, self.position.y - self.rect_size.y, self.z_index_global)
  74. glTexCoord2f(1, 1)
  75. glVertex3f(-self.position.x + self.rect_size.x, self.position.y - self.rect_size.y, self.z_index_global)
  76. glTexCoord2f(1, 0)
  77. glVertex3f(-self.position.x + self.rect_size.x, self.position.y, self.z_index_global)
  78. glEnd()
  79. glDisable(GL_DEPTH_TEST)
  80. glDisable(GL_TEXTURE_2D)
  81. glPopMatrix()
  82. else:
  83. self.rect_size = Vector2()
  84. # Change frame
  85. if not self.paused:
  86. if self.animations[self.animation].current < 60f:
  87. self.animations[self.animation].current += self.animations[self.animation].speed
  88. else:
  89. self.animations[self.animation].current = 0f
  90. if self.reversed:
  91. if frame - 1 < 0:
  92. self.animations[self.animation].frame = frames_count-1
  93. else:
  94. self.animations[self.animation].frame -= 1
  95. else:
  96. if frame + 1 > frames_count-1:
  97. self.animations[self.animation].frame = 0
  98. else:
  99. self.animations[self.animation].frame += 1
  100. method duplicate*(self: AnimatedSpriteRef): AnimatedSpriteRef {.base.} =
  101. ## Duplicates AnimatedSprite object and create a new AnimatedSprite.
  102. self.deepCopy()
  103. method addAnimation*(self: AnimatedSpriteRef, name: string, speed: float = 2f) {.base.} =
  104. ## Adds a new animation to the AnimatedSprite animations.
  105. ##
  106. ## Arguments:
  107. ## - `name` is an animation name.
  108. ## - `speed` is an animation speed.
  109. var newanim = Animation[GlTextureObj](name, speed)
  110. if newanim notin self.animations:
  111. self.animations.add(newanim)
  112. method addFrame*(self: AnimatedSpriteRef, name: string, frame: GlTextureObj) {.base.} =
  113. ## Adds a new frame in the animation.
  114. ##
  115. ## Arguments:
  116. ## - `name` is an animation name.
  117. self.animations[name].addFrame(frame)
  118. method removeAnimation*(self: AnimatedSpriteRef, name: string) {.base.} =
  119. ## Deletes animation from the AnimatedSprite animations.
  120. ## If `name` is a current animation name, then animation will not delete.
  121. ##
  122. ## Arguments:
  123. ## - `name` is an animation name.
  124. if name == self.animation:
  125. return
  126. for i in 0..self.animations.high:
  127. if self.animations[i].name == name:
  128. self.animations.delete(i)
  129. break
  130. method pause*(self: AnimatedSpriteRef) {.base.} =
  131. ## Stops animation.
  132. self.paused = true
  133. method play*(self: AnimatedSpriteRef, name: string = "", backward: bool = false) {.base.} =
  134. ## Plays animation.
  135. ##
  136. ## Arguments:
  137. ## - `name` is an animation name. if it is "" than plays current animation.
  138. ## - if `backward` is true then plays animation in reverse order.
  139. if name != "":
  140. self.animation = name
  141. self.reversed = backward
  142. self.animations[self.animation].current = 0f
  143. if self.reversed:
  144. self.animations[self.animation].frame = self.animations[self.animation].frames.len()-1
  145. else:
  146. self.animations[self.animation].frame = 0
  147. self.paused = false
  148. method resume*(self: AnimatedSpriteRef) {.base.} =
  149. ## Resumes animation.
  150. self.paused = false
  151. method setSpeed*(self: AnimatedSpriteRef, name: string = "", speed: float = 2f) {.base.} =
  152. ## Changes animation speed.
  153. ## If `name` is "" then changes the speed of the current animation.
  154. ##
  155. ## Arguments:
  156. ## - `name` is an animation name.
  157. ## - `speed` is a new speed.
  158. if name == "":
  159. self.animations[self.animation].speed = speed
  160. else:
  161. self.animations[name].speed = speed