lib: move game.nit as lib/scene2d.nit
[nit.git] / lib / scene2d.nit
diff --git a/lib/scene2d.nit b/lib/scene2d.nit
new file mode 100644 (file)
index 0000000..18a5d13
--- /dev/null
@@ -0,0 +1,163 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 2D management of game elements
+#
+# TODO: collision framework (with quad tree?)
+module scene2d
+
+# The root class of the living objects (sprites, group of sprites, etc.)
+abstract class LiveObject
+       # Compute the position, state and appearance.
+       fun update do end
+
+       # Controls whether `update' and `draw' are automatically called by `LiveGroup'
+       var exists writable = true
+
+       # Redefine this method to asks how to draw on a view
+       fun draw(view: View) is abstract
+end
+
+
+# The basic atomic living and moving object.
+#
+# A sprite has a position and a velocity
+class Sprite
+       super LiveObject
+
+       # x coordinate of the center point
+       var x: Int writable = 0
+
+       # y coordinate of the center point
+       var y: Int writable = 0
+
+       # width of the sprite
+       var width: Int writable = 100
+
+       # height of the sprite
+       var height: Int writable = 100
+
+       fun left: Int do return x - width/2
+       fun right: Int do return x + width/2
+       fun top: Int do return y - height/2
+       fun bottom: Int do return y + height/2
+
+       # x velocity (applied by `update')
+       var vx: Int writable = 0
+
+       # y velocity (applied by `update')
+       var vy: Int writable = 0
+
+       redef fun update
+       do
+               self.x += self.vx
+               self.y += self.vy
+       end
+
+       redef fun draw(view) do view.draw_sprite(self)
+
+       # Is self overlaps (or contains) an other sprite
+       # `x', `y', `width', and `height' of both sprites are considered
+       fun overlaps(other: Sprite): Bool
+       do
+               return self.right > other.left and self.left < other.right and self.bottom > other.top and self.top < other.bottom
+       end
+
+       # Return the current angle of velocity
+       # Often used to rotate the displayed image with the correct angle
+       fun velocity_angle: Float
+       do
+               return atan2(self.vx.to_f, -self.vy.to_f)
+       end
+
+       # Return the angle to target an other sprite
+       fun angle_to(target: Sprite): Float
+       do
+               return atan2((target.x-self.x).to_f, (self.y-target.y).to_f)
+       end
+
+       # Update of vx and vy toward a given angle and magnitude
+       fun set_velocity(angle: Float, maginude: Int)
+       do
+               var magf = maginude.to_f
+               self.vx = (angle.sin * magf).to_i
+               self.vy = (angle.cos * -magf).to_i
+       end
+
+end
+
+# Organizational class to manage groups of sprites and other live objects.
+class LiveGroup[E: LiveObject]
+       super LiveObject
+       super List[E]
+
+       init
+       do
+       end
+
+       # Recursively update each live objects that `exists'
+       redef fun update
+       do
+               for x in self do if x.exists then x.update
+       end
+
+       # Remove all live Objects that do not exists
+       # Call this to cleanup the live group
+       fun gc
+       do
+               var i = self.iterator
+               while i.is_ok do
+                       var e = i.item
+                       if not e.exists then
+                               i.delete
+                       else if e isa LiveGroup[LiveObject] then
+                               e.gc
+                       end
+                       i.next
+               end
+       end
+
+       # Recursively draw each live objects that `exists'
+       redef fun draw(view)
+       do
+               for x in self do if x.exists then x.draw(view)
+       end
+end
+
+# A state in the game logic
+# A scene manage a bunch of live objects
+class Scene
+       super LiveObject
+end
+
+# Abstract view do draw sprites
+#
+# Concrete views are specific for each back-end.
+# View can also be used to implements camera and other fun things.
+interface View
+       # Draw a specific sprite on the view
+       #
+       # This method must be implemented for each specific view.
+       # A traditional way of implementation is to use a double-dispatch mechanism
+       #
+       # Exemple:
+       #     class MyView
+       #         redef fun draw_sprite(s) do s.draw_on_myview(self)
+       #     end
+       #     redef class Sprite
+       #         # How to draw a sprite on my specific view
+       #         fun draw_on_myview(myview: MyView) is abstract
+       #     end
+       fun draw_sprite(s: Sprite) is abstract
+end