]> gitweb.factorcode.org Git - factor.git/commitdiff
game.worlds overhaul: add optional support for integrating audio.engine and make...
authorJoe Groff <arcata@gmail.com>
Tue, 19 Jan 2010 23:02:47 +0000 (15:02 -0800)
committerJoe Groff <arcata@gmail.com>
Wed, 20 Jan 2010 00:07:47 +0000 (16:07 -0800)
basis/ui/gadgets/worlds/worlds.factor
extra/game/worlds/worlds-docs.factor
extra/game/worlds/worlds.factor
extra/gpu/demos/bunny/bunny.factor
extra/gpu/demos/raytrace/raytrace.factor
extra/gpu/util/wasd/wasd.factor
extra/terrain/terrain.factor

index 1809c13dd81f3fbd8f44eac2093266c5a3a5722f..7e54b823e8ebc3e814018d1d20df31788f02b582 100644 (file)
@@ -126,7 +126,7 @@ M: world request-focus-on ( child gadget -- )
     [ T{ rgba f 1.0 1.0 1.0 1.0 } ] if ;
 
 GENERIC# apply-world-attributes 1 ( world attributes -- world )
-M: world apply-world-attributes ( world attributes -- world )
+M: world apply-world-attributes
     {
         [ title>> >>title ]
         [ status>> >>status ]
index faa21a18dc061b6d05f163de093ddcc9f0a4515f..51eb7213697c8edbd073c2d46a2e0fc558800ec8 100644 (file)
@@ -1,21 +1,28 @@
 ! (c)2009 Joe Groff bsd license
-USING: game.loop help.markup help.syntax kernel math method-chains
+USING: audio.engine game.loop help.markup help.syntax kernel math method-chains
 ui ui.gadgets.worlds words ;
 IN: game.worlds
 
-HELP: GAME:
-{ $syntax """GAME: word { attributes }
-    attribute-code ;""" }
-{ $description "Similar to " { $link POSTPONE: MAIN-WINDOW: } ", defines a main entry point " { $snippet "word" } " for the current vocabulary that opens a UI window with the provided " { $snippet "attributes" } ". In addition to the standard " { $link world-attributes } ", additional " { $link game-attributes } " can be specified to specify game-specific attributes. Unlike " { $link POSTPONE: MAIN-WINDOW: } ", the " { $snippet "attributes" } " for " { $snippet "GAME:" } " must provide values for the " { $snippet "world-class" } " and " { $snippet "tick-interval-micros" } " slots." } ;
-
 HELP: game-attributes
 { $class-description "Extends the " { $link world-attributes } " tuple class with extra attributes for " { $link game-world } "s:" }
 { $list
-{ { $snippet "tick-interval-micros" } " specifies the number of microseconds between consecutive calls to the world's " { $link tick* } " method by the game loop." }
+{ { $snippet "tick-interval-micros" } " specifies the number of microseconds between consecutive calls to the world's " { $link tick-game-world } " method by the game loop. An integer greater than zero must be provided." }
+{ { $snippet "use-game-input?" } " specifies whether the game world should initialize the " { $vocab-link "game.input" } " library for use by the game. False by default." }
+{ { $snippet "use-audio-engine?" } " specifies whether the game world should manage an " { $link audio-engine } " instance. False by default." }
+{ { $snippet "audio-engine-device" } " specifies the string name of the OpenAL device the audio engine, if any, should try to open. The default value of " { $link POSTPONE: f } " attempts to open the default OpenAL device." }
+{ { $snippet "audio-engine-voice-count" } " determines the number of independent voices the audio engine will make available. This determines how many individual audio clips can play simultaneously. This cannot exceed the OpenAL implementation's limit on supported voices." }
+{ { $snippet "audio-engine-buffer-size" } " determines the size in bytes of the audio buffers the audio engine will stream to the sound card." }
+{ { $snippet "audio-engine-buffer-count" } " determines the number of buffers the audio engine will allocate per audio clip played." }
 } ;
 
 HELP: game-world
-{ $class-description "A subclass of " { $link world } " that automatically sets up and manages connections to the " { $vocab-link "game.loop" } " and " { $vocab-link "game.input" } " libraries. It does this by providing methods on " { $link begin-world } ", " { $link end-world } ", and " { $link draw* } ". Subclasses can provide their own world setup and teardown code by adding methods to the " { $link begin-game-world } " and " { $link end-game-world } " generic words." } ;
+{ $class-description "A subclass of " { $link world } " that automatically sets up and manages connections to the " { $vocab-link "game.loop" } ", " { $vocab-link "game.input" } ", and " { $vocab-link "audio.engine" } " libraries. It does this by providing methods on " { $link begin-world } ", " { $link end-world } ", and " { $link draw* } ". Subclasses can provide their own world setup and teardown code by adding methods to the " { $link begin-game-world } " and " { $link end-game-world } " generic words."
+$nl
+"The game-world tuple has the following publicly accessible slots:"
+{ $list
+{ { $snippet "game-loop" } " contains the " { $link game-loop } " instance managed by the game world. If the world is inactive, this slot will contain " { $link POSTPONE: f } "." }
+{ { $snippet "audio-engine" } " contains the " { $link audio-engine } " instance managed by the game world. If the world is inactive, or the " { $snippet "use-audio-engine?" } " slot of the " { $link game-attributes } " object used to initialize the world was false, this slot will contain " { $link POSTPONE: f } "." }
+} } ;
 
 HELP: begin-game-world
 { $values { "world" game-world } }
@@ -25,26 +32,23 @@ HELP: end-game-world
 { $values { "world" game-world } }
 { $description "This generic word is called by the " { $link end-world } " method for " { $link game-world } " subclasses immediately after the game world stops the game loop." } ;
 
-{ game-world begin-game-world end-game-world } related-words
+HELP: tick-game-world
+{ $values { "world" game-world } }
+{ $description "This generic word is called by the " { $link tick* } " method for " { $link game-world } " subclasses every time the game loop's tick interval occurs." } ;
 
-HELP: tick-interval-micros
-{ $values
-    { "world" game-world }
-    { "micros" integer }
-}
-{ $description "Subclasses of " { $link game-world } " can override this class to specify the number of microseconds between consecutive calls to the game world's " { $link tick* } " method by the game loop. Using the " { $link POSTPONE: GAME: } " syntax will define this method for you." } ;
+{ game-world begin-game-world end-game-world tick-game-world } related-words
 
 ARTICLE: "game.worlds" "Game worlds"
-"The " { $vocab-link "game.worlds" } " vocabulary provides a " { $link world } " subclass that integrates with " { $vocab-link "game.loop" } " and " { $vocab-link "game.input" } " to quickly provide game infrastructure." 
+"The " { $vocab-link "game.worlds" } " vocabulary provides a " { $link world } " subclass that integrates with " { $vocab-link "game.loop" } " and optionally " { $vocab-link "game.input" } " and " { $vocab-link "audio.engine" } " to quickly provide game infrastructure." 
 { $subsections
     game-world
     game-attributes
-    POSTPONE: GAME:
 }
-"Subclasses of " { $link game-world } " can provide their own setup and teardown code by providing methods for these generic words:"
+"Subclasses of " { $link game-world } " can provide their own setup, teardown, and update code by providing methods for these generic words:"
 { $subsections
     begin-game-world
     end-game-world
+    tick-game-world
 } ;
 
 ABOUT: "game.worlds"
index d624a1b41e80f44837885ee0aae137507dbc1a75..cf75d37b39c0c696605ed8482e0fc749a854e509 100644 (file)
@@ -1,71 +1,86 @@
 ! (c)2009 Joe Groff bsd license
 USING: accessors combinators fry game.input game.loop generic kernel math
 parser sequences ui ui.gadgets ui.gadgets.worlds ui.gestures threads
-words ;
+words audio.engine destructors ;
 IN: game.worlds
 
 TUPLE: game-world < world
     game-loop
+    audio-engine
+    { tick-interval-micros fixnum }
+    { use-game-input? boolean }
+    { use-audio-engine? boolean }
+    { audio-engine-device initial: f }
+    { audio-engine-voice-count initial: 16 }
+    { audio-engine-buffer-size initial: 8192 }
+    { audio-engine-buffer-count initial: 2 }
     { tick-slice float initial: 0.0 } ;
 
-GENERIC: tick-interval-micros ( world -- micros )
-
 GENERIC: begin-game-world ( world -- )
 M: object begin-game-world drop ;
 
 GENERIC: end-game-world ( world -- )
 M: object end-game-world drop ;
 
+GENERIC: tick-game-world ( world -- )
+M: object tick-game-world drop ;
+
+M: game-world tick*
+    [ tick-game-world ]
+    [ audio-engine>> [ update-audio ] when* ] bi ;
+
 M: game-world draw*
     swap >>tick-slice relayout-1 yield ;
 
+<PRIVATE
+
+: open-game-audio-engine ( game-world -- audio-engine )
+    {
+        [ audio-engine-device>> ]
+        [ audio-engine-voice-count>> ]
+        [ audio-engine-buffer-size>> ]
+        [ audio-engine-buffer-count>> ]
+    } cleave <audio-engine>
+    [ start-audio* ] keep ; inline
+
+PRIVATE>
+
 M: game-world begin-world
-    open-game-input 
+    dup use-game-input?>> [ open-game-input ] when
+    dup use-audio-engine?>> [ dup open-game-audio-engine >>audio-engine ] when
     dup begin-game-world
-    dup [ tick-interval-micros ] [ ] bi <game-loop> [ >>game-loop ] keep start-loop
+    dup [ tick-interval-micros>> ] [ ] bi <game-loop> [ >>game-loop ] keep start-loop
     drop ;
 
 M: game-world end-world
     [ [ stop-loop ] when* f ] change-game-loop
-    end-game-world
-    close-game-input ;
+    [ end-game-world ]
+    [ audio-engine>> [ dispose ] when* ]
+    [ use-game-input?>> [ close-game-input ] when ] tri ;
 
 TUPLE: game-attributes < world-attributes
-    { tick-interval-micros fixnum read-only } ;
+    { tick-interval-micros fixnum }
+    { use-game-input? boolean initial: f }
+    { use-audio-engine? boolean initial: f }
+    { audio-engine-device initial: f }
+    { audio-engine-voice-count initial: 16 }
+    { audio-engine-buffer-size initial: 8192 }
+    { audio-engine-buffer-count initial: 2 } ;
 
-<PRIVATE
-
-: verify-game-attributes ( attributes -- )
+M: game-world apply-world-attributes
     {
-        [
-            world-class>> { f world } member?
-            [ "GAME: must be given a custom world-class" throw ] when
-        ]
-        [
-            tick-interval-micros>> 0 <=
-            [ "GAME: must be given a nonzero tick-interval-micros" throw ] when
-        ]
+        [ tick-interval-micros>> >>tick-interval-micros ]
+        [ use-game-input?>> >>use-game-input? ]
+        [ use-audio-engine?>> >>use-audio-engine? ]
+        [ audio-engine-device>> >>audio-engine-device ]
+        [ audio-engine-voice-count>> >>audio-engine-voice-count ]
+        [ audio-engine-buffer-size>> >>audio-engine-buffer-size ]
+        [ audio-engine-buffer-count>> >>audio-engine-buffer-count ]
+        [ call-next-method ]
     } cleave ;
 
-: define-game-tick-interval-micros ( attributes -- )
-    [ world-class>> \ tick-interval-micros create-method ]
-    [ tick-interval-micros>> '[ drop _ ] ] bi
-    define ;
-
-: define-game-methods ( attributes -- )
-    {
-        [ verify-game-attributes ]
-        [ define-game-tick-interval-micros ]
-    } cleave ;
-
-: define-game ( word attributes quot -- )
-    [ define-main-window ]
-    [ drop nip define-game-methods ] 3bi ;
-
-PRIVATE>
-
 SYNTAX: GAME:
     CREATE
     game-attributes parse-main-window-attributes
     parse-definition
-    define-game ;
+    define-main-window ;
index f56be88c78ca2659647c8d15c0381707f9d29830..b2f619c3d1cd287d877475d5a2b93b188d4c61b3 100644 (file)
@@ -306,6 +306,7 @@ GAME: bunny-game {
             T{ depth-bits { value 24 } }
         } }
         { grab-input? t }
+        { use-game-input? t }
         { pref-dim { 1024 768 } }
         { tick-interval-micros $[ 60 fps ] }
     } ;
index 0b44ac2e23e83ac023a3b21e078f90a9fb1a828e..fd8ae6b157911d5b30257073e782d535dbc5a770 100644 (file)
@@ -81,7 +81,7 @@ CONSTANT: fov 0.7
 AFTER: raytrace-world resize-world
     dup dim>> dup first2 min >float v/n fov v*n >>fov drop ;
 
-AFTER: raytrace-world tick*
+AFTER: raytrace-world tick-game-world
     spheres>> [ tick-sphere ] each ;
 
 M: raytrace-world draw-world*
@@ -102,6 +102,7 @@ GAME: raytrace-game {
             double-buffered
         } }
         { grab-input? t }
+        { use-game-input? t }
         { pref-dim { 1024 768 } }
         { tick-interval-micros $[ 60 fps ] }
     } ;
index b5ed28cc3d8947152a2cf7bb0a779eaf5fe52f66..7935ffce6d4c2f2a3769f6a8877ea3cdf770090b 100644 (file)
@@ -121,7 +121,7 @@ CONSTANT: fov 0.7
 : wasd-mouse-input ( world -- )
     read-mouse rotate-with-mouse ;
 
-M: wasd-world tick*
+M: wasd-world tick-game-world
     dup focused?>> [
         [ wasd-keyboard-input ] [ wasd-mouse-input ] bi
         reset-mouse
index f28e685c6680199f16cbf61c06b98544a8879996..27bd7df403550bf3c98d0519d223bf4fbcc587ac 100644 (file)
@@ -217,7 +217,7 @@ terrain-world H{
     [ tick-player-reverse ]
     [ tick-player-forward ] if ;
 
-M: terrain-world tick*
+M: terrain-world tick-game-world
     [ dup focused?>> [ handle-input ] [ drop ] if ]
     [ dup player>> tick-player ] bi ;
 
@@ -295,6 +295,7 @@ GAME: terrain-game {
             double-buffered
             T{ depth-bits { value 24 } }
         } }
+        { use-game-input? t }
         { grab-input? t }
         { pref-dim { 1024 768 } }
         { tick-interval-micros $[ 60 fps ] }