[gnome-games/gsoc-seed-games] [lightsoff] Implement keyboard-based play (use arrow keys/enter)



commit a7f47db4d95f94edba69b5cfeface958ee0774f0
Author: Tim Horton <hortont424 gmail com>
Date:   Sat Jun 27 01:39:12 2009 -0400

    [lightsoff] Implement keyboard-based play (use arrow keys/enter)

 lightsoff/Board.js                   |   77 +++++++++++++++------------
 lightsoff/Game.js                    |   69 +++++++++++++++++++++++
 lightsoff/main.js.in                 |    2 +
 lightsoff/themes/tango/Makefile.am   |    2 +
 lightsoff/themes/tango/highlight.svg |   99 ++++++++++++++++++++++++++++++++++
 lightsoff/themes/tango/theme.js.in   |    3 +
 lightsoff/themes/up/Makefile.am      |    2 +
 lightsoff/themes/up/highlight.svg    |   99 ++++++++++++++++++++++++++++++++++
 lightsoff/themes/up/theme.js.in      |    3 +
 9 files changed, 322 insertions(+), 34 deletions(-)
---
diff --git a/lightsoff/Board.js b/lightsoff/Board.js
index a5e4f33..5363969 100644
--- a/lightsoff/Board.js
+++ b/lightsoff/Board.js
@@ -9,7 +9,7 @@ BoardView = new GType({
 	parent: Clutter.Group.type,
 	name: "BoardView",
 	signals: [{name: "game_won"}],
-	init: function()
+	init: function(self)
 	{
 		// Private
 		var self = this;
@@ -28,7 +28,8 @@ BoardView = new GType({
 				for(var y = 0; y < tiles; y++)
 				{
 					var l = new Light.LightView();
-					l.set_position((x + 0.5) * l.width, (y + 0.5) * l.height);
+					var loc = self.position_for_light(x, y);
+					l.set_position(loc.x, loc.y);
 					l.signal.button_release_event.connect(light_clicked, {"x":x, "y":y});
 					
 					lights[x][y] = l;
@@ -39,8 +40,39 @@ BoardView = new GType({
 			}
 		}
 		
+		// Check if the game was won; if so, emit the game_won signal
+		// in order to notify the Game controller.
+		
+		var check_won = function()
+		{
+			if(cleared())
+				self.signal.game_won.emit();
+		}
+		
+		// Callback for button_release_event from each light; user_data
+		// is an object containing the coordinates of the clicked light.
+		var light_clicked = function(light, event, coords)
+		{
+			self.light_toggle(coords.x, coords.y);
+			
+			return false;
+		}
+		
+		// Returns whether or not the board is entirely 'off' (i.e. game is won)
+		var cleared = function()
+		{
+			for(var x = 0; x < tiles; x++)
+				for(var y = 0; y < tiles; y++)
+					if(lights[x][y].get_state())
+						return false;
+			
+			return true;
+		}
+		
+		// Public
+		
 		// Toggle a light and those in each cardinal direction around it.
-		var light_toggle = function(x, y)
+		this.light_toggle = function(x, y)
 		{
 			if(!playable)
 				return;
@@ -68,37 +100,14 @@ BoardView = new GType({
 				timeline.start();
 		}
 		
-		// Check if the game was won; if so, emit the game_won signal
-		// in order to notify the Game controller.
-		
-		var check_won = function()
-		{
-			if(cleared())
-				self.signal.game_won.emit();
-		}
-		
-		// Callback for button_release_event from each light; user_data
-		// is an object containing the coordinates of the clicked light.
-		var light_clicked = function(light, event, coords)
-		{
-			light_toggle(coords.x, coords.y);
-			
-			return false;
-		}
-		
-		// Returns whether or not the board is entirely 'off' (i.e. game is won)
-		var cleared = function()
+		this.position_for_light = function(x, y)
 		{
-			for(var x = 0; x < tiles; x++)
-				for(var y = 0; y < tiles; y++)
-					if(lights[x][y].get_state())
-						return false;
+			var p_l = {x: (x + 0.5) * Settings.theme.light[0].width,
+			           y: (y + 0.5) * Settings.theme.light[0].height};
 			
-			return true;
+			return p_l;
 		}
 		
-		// Public
-		
 		// Pseudorandomly generates and sets the state of each light based on
 		// a level number; hopefully this is stable between machines, but that
 		// depends on GLib's PRNG stability. Also, provides some semblance of 
@@ -124,18 +133,18 @@ BoardView = new GType({
 					i = Math.round((tiles - 1) * GLib.random_double());
 					j = Math.round((tiles - 1) * GLib.random_double());
 					
-					light_toggle(i, j);
+					self.light_toggle(i, j);
 					
 					// Ensure some level of "symmetry"
 					var x_sym = Math.abs(i - (tiles - 1));
 					var y_sym = Math.abs(j - (tiles - 1));
 					
 					if(sym == 0)
-						light_toggle(x_sym, j);
+						self.light_toggle(x_sym, j);
 					else if(sym == 1)
-						light_toggle(x_sym, y_sym);
+						self.light_toggle(x_sym, y_sym);
 					else
-						light_toggle(i, y_sym);
+						self.light_toggle(i, y_sym);
 				}
 			}
 			while(cleared());
diff --git a/lightsoff/Game.js b/lightsoff/Game.js
index bb3d5c8..ccf7485 100644
--- a/lightsoff/Game.js
+++ b/lightsoff/Game.js
@@ -20,8 +20,10 @@ GameView = new GType({
 		var backing_view = new Clutter.Clone({source:Settings.theme.backing});
 		var left_arrow = new Arrow.ArrowView();
 		var right_arrow = new Arrow.ArrowView();
+		var keycursor_view = new Clutter.Clone({source:Settings.theme.highlight});
 		var new_board_view = null;
 		var timeline;
+		var keycursor = {x:0, y:0, ready: false};
 		
 		// Set up a new board.
 		var create_next_board = function()
@@ -41,6 +43,7 @@ GameView = new GType({
 			self.remove_actor(board_view);
 			board_view = new_board_view;
 			board_view.set_playable(true);
+			keycursor_view.raise_top();
 			timeline = 0;
 		}
 		
@@ -171,6 +174,68 @@ GameView = new GType({
 			return false;
 		}
 		
+		// Change the currently selected tile with the keyboard
+		this.update_keyboard_selection = function (actor, event, ud)
+		{
+			// TODO: this is wrong. but, they're defines...
+			var kUp = 65362, kDown = 65364, kLeft = 65361, kRight = 65363, kEnter = 65293, kEsc = 65307;
+			
+			if(event.key.keyval == kEsc)
+			{
+				keycursor_view.animate(Clutter.AnimationMode.EASE_OUT_SINE, 250,
+				{
+					opacity: 0
+				});
+				
+				keycursor.ready = false;
+			}
+			
+			if(keycursor.ready)
+			{
+				if(event.key.keyval == kUp && keycursor.y > 0)
+					keycursor.y--;
+				else if(event.key.keyval == kDown && keycursor.y < 4)
+					keycursor.y++;
+				else if(event.key.keyval == kLeft && keycursor.x > 0)
+					keycursor.x--;
+				else if(event.key.keyval == kRight && keycursor.x < 4)
+					keycursor.x++;
+				else if(event.key.keyval == kEnter)
+					board_view.light_toggle(keycursor.x, keycursor.y);
+			}
+			
+			if(event.key.keyval != kDown &&
+				event.key.keyval != kUp &&
+				event.key.keyval != kLeft &&
+				event.key.keyval != kRight)
+				return false;
+		
+			var loc = board_view.position_for_light(keycursor.x, keycursor.y);
+			
+			if(keycursor.ready)
+			{
+				keycursor_view.animate(Clutter.AnimationMode.EASE_OUT_SINE, 250,
+				{
+					x: loc.x,
+					y: loc.y
+				});
+			}
+			else
+			{
+				keycursor_view.opacity = 0;
+				keycursor_view.set_position(loc.x, loc.y);
+				
+				keycursor_view.animate(Clutter.AnimationMode.EASE_OUT_SINE, 250,
+				{
+					opacity: 255
+				});
+			}
+			
+			keycursor.ready = true;
+	
+			return false;
+		}
+		
 		// Implementation
 				
 		score_view.set_width(5);
@@ -204,6 +269,10 @@ GameView = new GType({
 		right_arrow.signal.button_release_event.connect(swap_board, {direction: 1});
 		
 		this.set_size(board_view.width, score_view.y + score_view.height);
+		
+		keycursor_view.set_position(-100, -100);
+		keycursor_view.anchor_gravity = Clutter.Gravity.CENTER;
+		this.add_actor(keycursor_view);
 
 		Settings.Watcher.signal.theme_changed.connect(theme_changed);
 	}
diff --git a/lightsoff/main.js.in b/lightsoff/main.js.in
index 8bd2100..fff7d9d 100755
--- a/lightsoff/main.js.in
+++ b/lightsoff/main.js.in
@@ -54,6 +54,8 @@ stage.add_actor(game);
 stage.set_size(game.width, game.height);
 clutter_embed.set_size_request(stage.width, stage.height);
 
+stage.signal.key_release_event.connect(game.update_keyboard_selection);
+
 stage.show_all();
 window.show_all();
 
diff --git a/lightsoff/themes/tango/Makefile.am b/lightsoff/themes/tango/Makefile.am
index 9d2f4c1..cde0d38 100644
--- a/lightsoff/themes/tango/Makefile.am
+++ b/lightsoff/themes/tango/Makefile.am
@@ -5,6 +5,7 @@ theme_DATA = \
 	led-back.svg \
 	off.svg \
 	on.svg \
+	highlight.svg \
 	theme.js
 
 EXTRA_DIST = \
@@ -13,4 +14,5 @@ EXTRA_DIST = \
 	led-back.svg \
 	off.svg \
 	on.svg \
+	highlight.svg \
 	theme.js.in
diff --git a/lightsoff/themes/tango/highlight.svg b/lightsoff/themes/tango/highlight.svg
new file mode 100644
index 0000000..a830854
--- /dev/null
+++ b/lightsoff/themes/tango/highlight.svg
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="75"
+   height="75"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="highlight.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   version="1.0">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient3179">
+      <stop
+         style="stop-color:#35669b;stop-opacity:0.96078432;"
+         offset="0"
+         id="stop3181" />
+      <stop
+         style="stop-color:#5e92c8;stop-opacity:0.96078432;"
+         offset="1"
+         id="stop3183" />
+    </linearGradient>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 526.18109 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="744.09448 : 526.18109 : 1"
+       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+       id="perspective10" />
+    <filter
+       inkscape:collect="always"
+       id="filter3393"
+       x="-0.43563023"
+       width="1.8712605"
+       y="-0.43563023"
+       height="1.8712605">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="5.5324044"
+         id="feGaussianBlur3395" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#000000"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="1"
+     inkscape:pageshadow="2"
+     inkscape:zoom="8.76"
+     inkscape:cx="17.522831"
+     inkscape:cy="37.5"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1438"
+     inkscape:window-height="882"
+     inkscape:window-x="0"
+     inkscape:window-y="16" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-164.71428,-194.21933)">
+    <path
+       sodipodi:type="arc"
+       style="opacity:0.64102568;fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1;filter:url(#filter3393)"
+       id="path3183"
+       sodipodi:cx="22.888128"
+       sodipodi:cy="25.285389"
+       sodipodi:rx="15.239726"
+       sodipodi:ry="15.239726"
+       d="M 38.127854,25.285389 A 15.239726,15.239726 0 1 1 7.6484022,25.285389 A 15.239726,15.239726 0 1 1 38.127854,25.285389 z"
+       transform="matrix(1.247191,0,0,1.247191,173.66841,200.18362)" />
+  </g>
+</svg>
diff --git a/lightsoff/themes/tango/theme.js.in b/lightsoff/themes/tango/theme.js.in
index d6cb044..0922369 100644
--- a/lightsoff/themes/tango/theme.js.in
+++ b/lightsoff/themes/tango/theme.js.in
@@ -8,6 +8,7 @@ var light = [ load_svg("off.svg"), load_svg("on.svg") ];
 var arrow = load_svg("arrow.svg");
 var backing = load_svg("backing.svg");
 var led_back = load_svg("led-back.svg");
+var highlight = load_svg("highlight.svg");
 
 // TODO: figure out how to fix this new offscreen cloning thing. this is a hack.
 
@@ -22,6 +23,7 @@ function map_stuff(a)
 	a.add_actor(arrow);
 	a.add_actor(backing);
 	a.add_actor(led_back);
+	a.add_actor(highlight);
 	a.show_all();
 	
 	light[0].set_position(-500, -500);
@@ -29,6 +31,7 @@ function map_stuff(a)
 	arrow.set_position(-500, -500);
 	backing.set_position(-500, -500);
 	led_back.set_position(-500, -500);
+	highlight.set_position(-500, -500);
 }
 
 // helper functions should be put somewhere global
diff --git a/lightsoff/themes/up/Makefile.am b/lightsoff/themes/up/Makefile.am
index 831465f..605c997 100644
--- a/lightsoff/themes/up/Makefile.am
+++ b/lightsoff/themes/up/Makefile.am
@@ -5,6 +5,7 @@ theme_DATA = \
 	led-back.svg \
 	off.svg \
 	on.svg \
+	highlight.svg \
 	theme.js
 
 EXTRA_DIST = \
@@ -13,4 +14,5 @@ EXTRA_DIST = \
 	led-back.svg \
 	off.svg \
 	on.svg \
+	highlight.svg \
 	theme.js.in
diff --git a/lightsoff/themes/up/highlight.svg b/lightsoff/themes/up/highlight.svg
new file mode 100644
index 0000000..a830854
--- /dev/null
+++ b/lightsoff/themes/up/highlight.svg
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="75"
+   height="75"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="highlight.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   version="1.0">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient3179">
+      <stop
+         style="stop-color:#35669b;stop-opacity:0.96078432;"
+         offset="0"
+         id="stop3181" />
+      <stop
+         style="stop-color:#5e92c8;stop-opacity:0.96078432;"
+         offset="1"
+         id="stop3183" />
+    </linearGradient>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 526.18109 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="744.09448 : 526.18109 : 1"
+       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+       id="perspective10" />
+    <filter
+       inkscape:collect="always"
+       id="filter3393"
+       x="-0.43563023"
+       width="1.8712605"
+       y="-0.43563023"
+       height="1.8712605">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="5.5324044"
+         id="feGaussianBlur3395" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#000000"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="1"
+     inkscape:pageshadow="2"
+     inkscape:zoom="8.76"
+     inkscape:cx="17.522831"
+     inkscape:cy="37.5"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1438"
+     inkscape:window-height="882"
+     inkscape:window-x="0"
+     inkscape:window-y="16" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-164.71428,-194.21933)">
+    <path
+       sodipodi:type="arc"
+       style="opacity:0.64102568;fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1;filter:url(#filter3393)"
+       id="path3183"
+       sodipodi:cx="22.888128"
+       sodipodi:cy="25.285389"
+       sodipodi:rx="15.239726"
+       sodipodi:ry="15.239726"
+       d="M 38.127854,25.285389 A 15.239726,15.239726 0 1 1 7.6484022,25.285389 A 15.239726,15.239726 0 1 1 38.127854,25.285389 z"
+       transform="matrix(1.247191,0,0,1.247191,173.66841,200.18362)" />
+  </g>
+</svg>
diff --git a/lightsoff/themes/up/theme.js.in b/lightsoff/themes/up/theme.js.in
index efc097e..63ea95f 100644
--- a/lightsoff/themes/up/theme.js.in
+++ b/lightsoff/themes/up/theme.js.in
@@ -8,6 +8,7 @@ var light = [ load_svg("off.svg"), load_svg("on.svg") ];
 var arrow = load_svg("arrow.svg");
 var backing = load_svg("backing.svg");
 var led_back = load_svg("led-back.svg");
+var highlight = load_svg("highlight.svg");
 
 // TODO: figure out how to fix this new offscreen cloning thing. this is a hack.
 
@@ -22,6 +23,7 @@ function map_stuff(a)
 	a.add_actor(arrow);
 	a.add_actor(backing);
 	a.add_actor(led_back);
+	a.add_actor(highlight);
 	a.show_all();
 	
 	light[0].set_position(-500, -500);
@@ -29,6 +31,7 @@ function map_stuff(a)
 	arrow.set_position(-500, -500);
 	backing.set_position(-500, -500);
 	led_back.set_position(-500, -500);
+	highlight.set_position(-500, -500);
 }
 
 // helper functions should be put somewhere global



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]