slickr 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +6 -14
  2. data/.rspec +0 -1
  3. data/.travis.yml +4 -0
  4. data/Gemfile +0 -2
  5. data/README.md +58 -52
  6. data/Rakefile +4 -0
  7. data/lib/slickr.rb +18 -1
  8. data/lib/slickr/actions/generate.rb +51 -0
  9. data/lib/slickr/behavior.rb +68 -0
  10. data/lib/slickr/cli.rb +12 -3
  11. data/lib/slickr/entity.rb +64 -0
  12. data/lib/slickr/entity_manager.rb +105 -0
  13. data/lib/slickr/generators/base.rb +95 -0
  14. data/lib/slickr/generators/behavior.rb +9 -0
  15. data/lib/slickr/generators/entity.rb +10 -0
  16. data/{files → lib/slickr/generators/files}/Rakefile +0 -0
  17. data/{files → lib/slickr/generators/files}/jinput.jar +0 -0
  18. data/{files → lib/slickr/generators/files}/libjinput-osx.jnilib +0 -0
  19. data/{files → lib/slickr/generators/files}/liblwjgl.jnilib +0 -0
  20. data/{files → lib/slickr/generators/files}/lwjgl.jar +0 -0
  21. data/{files → lib/slickr/generators/files}/openal.dylib +0 -0
  22. data/{files → lib/slickr/generators/files}/slick.jar +0 -0
  23. data/lib/slickr/generators/project.rb +36 -0
  24. data/lib/slickr/generators/reactor.rb +9 -0
  25. data/lib/slickr/generators/renderer.rb +9 -0
  26. data/lib/slickr/generators/templates/behavior.erb +3 -0
  27. data/lib/slickr/generators/templates/behaviors.erb +1 -0
  28. data/{templates → lib/slickr/generators/templates}/engine.erb +13 -9
  29. data/lib/slickr/generators/templates/entities.erb +1 -0
  30. data/lib/slickr/generators/templates/entity.erb +2 -0
  31. data/lib/slickr/generators/templates/reactor.erb +4 -0
  32. data/lib/slickr/generators/templates/reactors.erb +1 -0
  33. data/lib/slickr/generators/templates/renderer.erb +4 -0
  34. data/lib/slickr/generators/templates/renderers.erb +1 -0
  35. data/lib/slickr/reactor.rb +86 -0
  36. data/lib/slickr/renderer.rb +37 -0
  37. data/lib/slickr/tasks.rb +1 -3
  38. data/lib/slickr/version.rb +1 -1
  39. data/slickr.gemspec +0 -2
  40. data/spec/build/.gitkeep +0 -0
  41. data/spec/slickr/actions/generate_spec.rb +38 -0
  42. data/spec/slickr/entity_manager_spec.rb +31 -0
  43. data/spec/slickr/entity_spec.rb +21 -0
  44. data/spec/slickr/generators/behavior_spec.rb +17 -0
  45. data/spec/slickr/generators/entity_spec.rb +21 -0
  46. data/spec/slickr/generators/project_spec.rb +120 -0
  47. data/spec/slickr/generators/reactor_spec.rb +17 -0
  48. data/spec/slickr/generators/renderer_spec.rb +17 -0
  49. data/spec/slickr/reactor_spec.rb +25 -0
  50. data/spec/spec_helper.rb +17 -4
  51. metadata +64 -57
  52. data/lib/slickr/actions/create.rb +0 -79
  53. data/spec/slickj/actions/create_spec.rb +0 -174
  54. data/templates/components.erb +0 -5
  55. data/templates/entities.erb +0 -5
  56. data/templates/renderers.erb +0 -5
  57. data/templates/systems.erb +0 -5
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- ODRmY2E3NWEwZjg0YTc1Y2QwZDlkYTExZGNmMWZlMmQxMDEyMjJkNg==
5
- data.tar.gz: !binary |-
6
- ZjVmZWI5MTU5ZWNhOGRmZTNmM2NlYjNlNWE4MjViNjkyMDNiZTZhYQ==
7
- !binary "U0hBNTEy":
8
- metadata.gz: !binary |-
9
- ZGRkMzg4NGE3MTE1OTkyNzk1MDkxMDk5MjViNTdiYzU5ODliMDUyYTZhMDk4
10
- YTVmMWNkNTgxZjlhOWQ3NDAyYzIwYWJkMjJmYWI0ODlmMzM2ZmU4NmJiYTI5
11
- YjZjYjQ5NWNjM2RmZWM4ZTZiMjY0ZjY1MTllNGFiZTI1MjRlNTI=
12
- data.tar.gz: !binary |-
13
- YzQ4MWI3YTE3YzZkZmJjMzMwOTY4NzFkMzUyMzk5Zjg4NmVkNDQ1MDRlNzg2
14
- OTc2OWE4NWVjODg1MWZkOTJmMmE2MDg0NmFhMzRhMWYwZTkzZDdkNzM2MWNk
15
- NWFmMGY0YzFiYmY5Y2ZhYjU4M2UxZmViY2YzMDY4OTIzZTUyODM=
2
+ SHA1:
3
+ metadata.gz: 7593e388d74d18775d44ce56aac159b23a9e93ad
4
+ data.tar.gz: 05a5b28e4c555ec670421a490e6dda4c54413eb5
5
+ SHA512:
6
+ metadata.gz: 870175e5c09cea5de268086d2cc3e643f64193b947c26dd2d5c378e7660ecd20ffc42dc4fb0ea7493ca60c4a211ad88a4cf3b81cce853288502ce903e342ff1a
7
+ data.tar.gz: e0e2781159242322ad0be3ce13a439f8e32df97a6739a5aa7ee7d4f5a655a92386603013a5b933cf4e16782b261365a024a8b9c33a11c757d024eafffb51a472
data/.rspec CHANGED
@@ -1,3 +1,2 @@
1
1
  --color
2
2
  --format progress
3
- -d
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ rvm:
2
+ - "1.9.2"
3
+ - "1.9.3"
4
+ - jruby-19mode
data/Gemfile CHANGED
@@ -1,4 +1,2 @@
1
1
  source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in slickj.gemspec
4
2
  gemspec
data/README.md CHANGED
@@ -1,18 +1,49 @@
1
- # slickr
1
+ # Welcome to Slickr
2
+ [![Build Status](https://travis-ci.org/mnoble/slickr.png?branch=master)](https://travis-ci.org/mnoble/slickr)
3
+ [![Code Climate](https://codeclimate.com/github/mnoble/slickr.png)](https://codeclimate.com/github/mnoble/slickr)
2
4
 
3
- JRuby Slick2D project generators.
5
+ Slickr is a JRuby, Slick2D, project framework.
4
6
 
5
- ## Overview
7
+ Slickr tries to merge concepts from Entity-Component and good old
8
+ fashion Object Oriented Design. Ruby gives you a lot of power to
9
+ write great code and Slickr tries to help you do that, while developing
10
+ games.
6
11
 
7
- The project Slickr sets up is an attempt to merge concepts from
8
- Entity-Component and just plain old OOP best practices. Ruby gives you
9
- a lot of power to write great code and Slickr tries to set you up to do
10
- that well.
12
+ "Slick2D is an easy to use set of tools and utilities wrapped around
13
+ LWJGL OpenGL bindings to make 2D Java game development easier." —
14
+ [http://www.slick2d.org/wiki/index.php/Main_Page](http://www.slick2d.org/wiki/index.php/Main_Page)
11
15
 
12
- Keep things simple. Components should have no knowledge of the Entities
13
- that will implement them; Systems should not care about what type of
14
- Entity they're acting on. Basically, watch or read anything Sandi Metz
15
- says and follow it.
16
+ ## Getting Started
17
+
18
+ 1\. Install Slickr
19
+
20
+ ```
21
+ $ gem install slickr
22
+ ```
23
+
24
+ 2\. Create a new Slickr game
25
+
26
+ ```
27
+ $ slickr new my_game
28
+ ```
29
+
30
+ where "my_game" is the name of the game.
31
+
32
+ 3\. Change directory to `my_game` and play it
33
+
34
+ ```
35
+ $ cd my_game
36
+ $ rake play
37
+ ```
38
+
39
+ You should see a Window with nothing but a white background and some FPS
40
+ information.
41
+
42
+ ## Generating New Code
43
+
44
+ ```
45
+ $ slickr generate [component|entity|renderer|system] NAME
46
+ ```
16
47
 
17
48
  ## Project Structure
18
49
 
@@ -22,62 +53,37 @@ says and follow it.
22
53
  │   ├── jinput.jar
23
54
  │   ├── lwjgl.jar
24
55
  │   └── slick.jar
25
- ├── lib
26
- │   ├── components
27
- │   ├── components.rb
56
+ ├── lib/
57
+ │   ├── behaviors/
58
+ │   ├── behaviors.rb
28
59
  │   ├── engine.rb
29
- │   ├── entities
60
+ │   ├── entities/
30
61
  │   ├── entities.rb
31
- │   ├── renderers
62
+ │   ├── renderers/
32
63
  │   ├── renderers.rb
33
- │   ├── systems
34
- │   └── systems.rb
64
+ │   ├── reactors/
65
+ │   └── reactors.rb
35
66
  ├── libjinput-osx.jnilib
36
67
  ├── liblwjgl.jnilib
37
68
  └── openal.dylib
38
69
 
39
- ### assets
40
-
70
+ **assets/**<br/>
41
71
  Images, sounds, videos, etc.
42
72
 
43
- ### java
44
-
73
+ **java/**<br/>
45
74
  Slick2D framework jars.
46
75
 
47
- ### lib
48
-
49
- Your game code.
50
-
51
- ### lib/components
52
-
53
- Behaviors that entities will include. These are modules that implement
54
- whatever behavior the entity should have. A common example will be a
55
- `Spatial` component that implements `x` and `y` position and movement.
56
-
57
- ### lib/entities
58
-
59
- The actual objects that live your game's world. Entities will implement
60
- Components and Systems conduct Entities. These will be your Heros,
61
- Enemies, Bosses, etc.
76
+ **lib/behaviors/**<br/>
77
+ Behaviors that entities will include.
62
78
 
63
- ### lib/renderers
79
+ **lib/entities/**<br/>
80
+ The actual objects that live your game's world.
64
81
 
82
+ **lib/renderers/**<br/>
65
83
  Draws the current state of entities to the screen.
66
84
 
67
- ### lib/systems
68
-
69
- Systems react to changes in the world and update entitites accordingly.
70
- View these as controllers of sorts. A good example of this is an `Input`
71
- system. It would react to keyboard events and tell the appropriate
72
- entities where to move.
73
-
74
- ## Installation
75
-
76
- $ gem install slickr
77
-
78
- ## Usage
79
-
80
- $ slickr new PROJECT_NAME
85
+ **lib/reactors/**<br/>
86
+ Reactors take changes in the world and updates entitites accordingly.
81
87
 
82
88
  ## Contributing
83
89
 
data/Rakefile CHANGED
@@ -1 +1,5 @@
1
1
  require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+ task :default => :spec
data/lib/slickr.rb CHANGED
@@ -2,6 +2,23 @@ require "fileutils"
2
2
  require "pathname"
3
3
  require "thor"
4
4
  require "active_support/all"
5
+
5
6
  require "slickr/version"
7
+ require "slickr/actions/generate"
8
+ require "slickr/generators/base"
9
+ require "slickr/generators/project"
10
+ require "slickr/generators/behavior"
11
+ require "slickr/generators/entity"
12
+ require "slickr/generators/renderer"
13
+ require "slickr/generators/reactor"
14
+ require "slickr/entity_manager"
15
+ require "slickr/entity"
16
+ require "slickr/behavior"
17
+ require "slickr/reactor"
18
+ require "slickr/renderer"
6
19
  require "slickr/cli"
7
- require "slickr/actions/create"
20
+
21
+ module Slickr
22
+ class SlickrError < StandardError; end
23
+ class NotImplementedError < SlickrError; end
24
+ end
@@ -0,0 +1,51 @@
1
+ module Slickr
2
+ module Actions
3
+ # Adapter for calling the different types of Generators.
4
+ #
5
+ # This class takes the name of the generator, in any form, and
6
+ # the name the user wants to give to the new piece of code. It
7
+ # will normalize both to follow Slickr conventions.
8
+ #
9
+ # == Naming Conventions
10
+ #
11
+ # Slickr follows the same sort of conventions as Rails. Classes
12
+ # are appended with their type. Eg. a "spatiality" behavior will
13
+ # become +SpatialityBehavior+, a "hero" renderer will become
14
+ # +HeroRenderer+, etc.
15
+ #
16
+ # @example Generating a new behavior
17
+ # Slickr::Actions::Generate.new("behavior", "spatiality").start
18
+ # # => lib/behaviors/spatiality_behavior.rb
19
+ #
20
+ # @example Generating a new behavior by specifying the full name
21
+ # Slickr::Actions::Generate.new("behavior", "spatiality_behavior").start
22
+ # # => lib/behaviors/spatiality_behavior.rb
23
+ #
24
+ # @example Generating a new behavior by specifying the name in class form
25
+ # Slickr::Actions::Generate.new("behavior", "SpatialityBehavior").start
26
+ # # => lib/behaviors/spatiality_behavior.rb
27
+ #
28
+ class Generate
29
+ def initialize(type, name)
30
+ @type = type
31
+ @name = name
32
+ end
33
+
34
+ def start
35
+ generator_class.new(name).start
36
+ end
37
+
38
+ def generator_class
39
+ Slickr::Generators.const_get(:"#{@type.capitalize}")
40
+ end
41
+
42
+ def name
43
+ "#{basename}_#{@type}".squeeze("_")
44
+ end
45
+
46
+ def basename
47
+ @name.gsub(/#{@type}/i, "").downcase
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,68 @@
1
+ module Slickr
2
+ # Behaviors give entities the ability to do things. They should
3
+ # implement the logic to move around the world, detect collision,
4
+ # etc.
5
+ #
6
+ # A behavior should not care about what entities use it. It should
7
+ # specify all the attribute and methods relevant to what it does.
8
+ #
9
+ # module Spatiality
10
+ # include Slickr::Behavior
11
+ #
12
+ # attr_access :x, :y, :speed
13
+ #
14
+ # def prepare(options={})
15
+ # @x = options.fetch(:x, 0)
16
+ # @y = options.fetch(:y, 0)
17
+ # @speed = options.fetch(:speed, 0)
18
+ # end
19
+ #
20
+ # def up(delta)
21
+ # self.y -= speed * delta
22
+ # end
23
+ #
24
+ # def down(delta)
25
+ # self.y += speed * delta
26
+ # end
27
+ #
28
+ # def left(delta)
29
+ # self.x -= speed * delta
30
+ # end
31
+ #
32
+ # def right(delta)
33
+ # self.x += speed * delta
34
+ # end
35
+ # end
36
+ #
37
+ # == Preparing
38
+ #
39
+ # since behaviors are modules that get mixed into entities, we can't
40
+ # use the normal +initialize+ to set defaults. Instead, Slickr uses
41
+ # a convention of the +prepare+ method.
42
+ #
43
+ # When you specify an entity should implement some behavior, it's
44
+ # pushed into the entity's behavior stack. When that entity is
45
+ # instantiated, it will run through all of its behaviors and
46
+ # +prepare+ each one with the options specified in the entity.
47
+ #
48
+ # class Hero < Slickr::Entity
49
+ # use Spatiality, x: 10, y: 10, speed: 0.2
50
+ # end
51
+ #
52
+ # hero = Hero.new
53
+ # hero.x #=> 10
54
+ # hero.y #=> 10
55
+ # hero.speed #=> 0.2
56
+ #
57
+ # == Don't Clobber Behavior Attributes
58
+ #
59
+ # Use good OO common-sense here. Don't create multiple behaviors that
60
+ # all depend on attributes of the same name. Behaviors should be
61
+ # independent of one another.
62
+ #
63
+ module Behavior
64
+ def prepare(*args)
65
+ raise NotImplementedError
66
+ end
67
+ end
68
+ end
data/lib/slickr/cli.rb CHANGED
@@ -1,9 +1,18 @@
1
1
  module Slickr
2
2
  class CLI < Thor
3
- desc "new NAME", "Create a new jruby slick2d project"
4
- method_options :name => :string
3
+ desc "generate GENERATOR NAME", "Generate new code"
4
+ def generate(generator, name)
5
+ Actions::Generate.new(generator, name).start
6
+ end
7
+
8
+ desc "g GENERATOR NAME", "Shortcut for generate", hide: true
9
+ def g(*args)
10
+ generate(*args)
11
+ end
12
+
13
+ desc "new NAME [options]", "Create a new jruby slick2d project"
5
14
  def new(name)
6
- Actions::Create.new(name).start
15
+ Generators::Project.new(name).start
7
16
  end
8
17
  end
9
18
  end
@@ -0,0 +1,64 @@
1
+ module Slickr
2
+ class Entity
3
+ class << self
4
+ attr_writer :behaviors
5
+ end
6
+
7
+ # Specify that an Entity should behave a certain way.
8
+ #
9
+ # @param behavior [Slickr::Behavior] The behavior to use.
10
+ # @param options [Hash] Default behavior values.
11
+ #
12
+ # @example A Hero can move about the world.
13
+ #
14
+ # class Hero < Slickr::Entity
15
+ # use Spatiality
16
+ # end
17
+ #
18
+ # Different Behaviors will allow you to specify different
19
+ # default values. For example, a Spatiality behavior that
20
+ # allows an Entity to move about the world, may take a
21
+ # default +x+ and +y+ value. The Entity will be placed at
22
+ # that location when the scene is first loaded.
23
+ #
24
+ # @example A Hero starting at a specific location.
25
+ #
26
+ # class Hero < Slickr::Entity
27
+ # use Spatiality, x: 100, y: 100
28
+ # end
29
+ #
30
+ def self.use(behavior, options={})
31
+ behaviors << [behavior, options]
32
+ end
33
+
34
+ def self.behaviors
35
+ @behaviors ||= []
36
+ end
37
+
38
+ def self.reset
39
+ @behaviors = []
40
+ end
41
+
42
+ def initialize
43
+ behaviors.each { |behavior, options| behave_like(behavior, options) }
44
+ end
45
+
46
+ def behaviors
47
+ self.class.behaviors
48
+ end
49
+
50
+ private
51
+
52
+ # Mixin a behavior and configure it with the appropriate options.
53
+ #
54
+ # Each behavior must implement a +prepare+ method that initializes
55
+ # the Entity with any default values. The +prepare+ method will
56
+ # always be that of the last Behavior mixed in.
57
+ #
58
+ def behave_like(behavior, options={})
59
+ extend behavior
60
+ prepare(options)
61
+ EntityManager.register(self, behavior)
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,105 @@
1
+ module Slickr
2
+ # Provides a central repository for storing and querying for Entities
3
+ # that exhibit some behavior.
4
+ #
5
+ # Each scene of your game will probably have many entities. When you
6
+ # instantiate one of those Entities, it's automatically registered
7
+ # to the +EntityManager+, with the behaviors it implements.
8
+ #
9
+ # @example
10
+ #
11
+ # class Boss < Slickr::Entity
12
+ # use Spatial, x: 0, y: 0
13
+ # end
14
+ #
15
+ # boss = Boss.new
16
+ # # => #<Boss components=[:spatial]>
17
+ #
18
+ # EntityManager.entities
19
+ # # => [#<Boss components=[:spatial]>]
20
+ #
21
+ # Systems and Renderers are the two things that will likely need to
22
+ # alter or manipulate entities. Systems change the data associated
23
+ # with an entity and Renderers draw that to the screen. These objects
24
+ # can ask the +EntityManager+ for any entities that care about the
25
+ # behaviors they affect.
26
+ #
27
+ # @example
28
+ #
29
+ # class Systems::Input
30
+ # def call(delta)
31
+ # entities.each { |e| e.up(delta) } if up_key?
32
+ # end
33
+ #
34
+ # def entities
35
+ # EntityManager.entities_with(:controllable, :spatial)
36
+ # end
37
+ # end
38
+ #
39
+ # The +Input+ system cares about entities that can be moved by keyboard
40
+ # or mouse input and have spatial awareness; that is, things that can
41
+ # move. The above +System+ tells an entity to move up if the up key is
42
+ # pressed. What "moving up" means is determined by the component. The
43
+ # System doesn't care; it just reacts to events in the world and tells
44
+ # entities to do stuff based on that.
45
+ #
46
+ # It's important to view +:controllable+ and +:spatial+ as behaviors.
47
+ # Systems and Renderers expect these objects to conform to some standard
48
+ # API. We don't care where the object came from, what type it is or
49
+ # what it does outside of what we expect. We're going for good object
50
+ # oriented design through duck typing here.
51
+ #
52
+ module EntityManager
53
+ extend self
54
+
55
+ # @!attribute entities
56
+ # Hash of entities and their registered components
57
+ #
58
+ def entities
59
+ @entities ||= reset!
60
+ end
61
+
62
+ # Register an +Entity+ as conforming to a specific +Component+
63
+ # behavior.
64
+ #
65
+ # @param entity [Entity] The +Entity+ that includes the behavior
66
+ # @param type [Module] A +Component+ module.
67
+ #
68
+ def register(entity, type)
69
+ entities[entity] << symbolize(type)
70
+ end
71
+
72
+ # Retrieve all registered entities that include all of the
73
+ # components passed.
74
+ #
75
+ # @param components [Array<Component>] List of components
76
+ #
77
+ # @example
78
+ # EntityManager.entities
79
+ # => { #<Entity components=[:spatial, :size]>, #<Entity components=[:spatial]> }
80
+ #
81
+ # EntityManager.entities_with(:spatial, :size)
82
+ # => #<Entity components=[:spatial, :size]>
83
+ #
84
+ def entities_with(*components)
85
+ entities.select { |entity, types| includes_all?(types, Set[*components]) }.keys
86
+ end
87
+
88
+ # Remove all entities.
89
+ #
90
+ def reset!
91
+ @entities = Hash.new { |h,k| h[k] = Set.new }
92
+ end
93
+
94
+ private
95
+
96
+ def includes_all?(types, items)
97
+ items.subset?(types)
98
+ end
99
+
100
+ def symbolize(type)
101
+ type.name.demodulize.underscore.gsub("_behavior", "").to_sym
102
+ end
103
+ end
104
+ end
105
+