[gnome-robots] Add declarative animation DSL
- From: Andrey Kutejko <akutejko src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-robots] Add declarative animation DSL
- Date: Tue, 6 Oct 2020 19:31:41 +0000 (UTC)
commit 435be43678bba7240bd1f843f983da14f9613e5e
Author: Andrey Kutejko <andy128k gmail com>
Date: Sat Sep 12 21:29:01 2020 +0200
Add declarative animation DSL
src/animation.vala | 188 +++++++++++++++++++++++++++++++++++++++++++++++++++++
src/game-area.vala | 78 ++++++++++++++++++++++
src/game.vala | 11 +---
src/graphics.vala | 122 ----------------------------------
src/meson.build | 1 +
src/theme.vala | 7 +-
6 files changed, 273 insertions(+), 134 deletions(-)
---
diff --git a/src/animation.vala b/src/animation.vala
new file mode 100644
index 0000000..651e3b8
--- /dev/null
+++ b/src/animation.vala
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2020 Andrey Kutejko <andy128k gmail com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * For more details see the file COPYING.
+ */
+
+abstract class Animated {
+ protected abstract int do_tick ();
+ public abstract void reset ();
+
+ public int frame { get; private set; }
+
+ public int tick () {
+ frame = do_tick ();
+ return frame;
+ }
+
+ public static Animated sequence (int start, int step = 1) {
+ return new Sequence (start, step);
+ }
+
+ public Animated limit (int count) {
+ return new Limit (this, count);
+ }
+
+ public static Animated bounce (int start, int limit) {
+ return sequence (start).limit (limit)
+ .then (sequence (start + limit - 1, -1).limit (limit));
+ }
+
+ public Animated then (Animated another) {
+ return new Then (this, another);
+ }
+
+ public Animated repeat (int count) {
+ return new Repeat (this, count);
+ }
+
+ public Animated forever () {
+ return new Forever (this);
+ }
+}
+
+class Sequence : Animated {
+ private int start;
+ private int step;
+ private int current;
+
+ public Sequence (int start, int step = 1) {
+ this.start = start;
+ this.step = step;
+ this.current = start;
+ }
+
+ protected override int do_tick () {
+ var result = current;
+ current += step;
+ return result;
+ }
+
+ public override void reset () {
+ current = start;
+ }
+}
+
+class Then : Animated {
+ private Animated first;
+ private Animated second;
+ private bool is_second;
+
+ public Then (Animated first, Animated second) {
+ this.first = first;
+ this.second = second;
+ this.is_second = false;
+ }
+
+ protected override int do_tick () {
+ if (is_second) {
+ return second.tick();
+ } else {
+ var result = first.tick();
+ if (result >= 0) {
+ return result;
+ } else {
+ is_second = true;
+ return second.tick();
+ }
+ }
+ }
+
+ public override void reset () {
+ this.first.reset ();
+ this.second.reset ();
+ this.is_second = false;
+ }
+}
+
+class Repeat : Animated {
+ private Animated inner;
+ private int count;
+ private int current;
+
+ public Repeat (Animated inner, int count) {
+ this.inner = inner;
+ this.count = count;
+ this.current = 0;
+ }
+
+ protected override int do_tick () {
+ if (current >= count) {
+ return -1;
+ }
+ var result = inner.tick();
+ if (result >= 0) {
+ return result;
+ } else {
+ inner.reset ();
+ ++current;
+ return inner.tick();
+ }
+ }
+
+ public override void reset () {
+ this.inner.reset ();
+ this.current = 0;
+ }
+}
+
+class Forever : Animated {
+ private Animated inner;
+
+ public Forever (Animated inner) {
+ this.inner = inner;
+ }
+
+ protected override int do_tick () {
+ var result = inner.tick();
+ if (result >= 0) {
+ return result;
+ } else {
+ inner.reset ();
+ return inner.tick();
+ }
+ }
+
+ public override void reset () {
+ this.inner.reset ();
+ }
+}
+
+class Limit : Animated {
+ private Animated inner;
+ private int _limit;
+ private int count;
+
+ public Limit (Animated inner, int limit) {
+ this.inner = inner;
+ this._limit = limit;
+ this.count = 0;
+ }
+
+ protected override int do_tick () {
+ if (count >= _limit) {
+ return -1;
+ }
+ ++count;
+ return inner.tick();
+ }
+
+ public override void reset () {
+ inner.reset ();
+ count = 0;
+ }
+}
+
diff --git a/src/game-area.vala b/src/game-area.vala
index 3863be2..8bfef4c 100644
--- a/src/game-area.vala
+++ b/src/game-area.vala
@@ -18,6 +18,7 @@
*/
using Gtk;
+using Gdk;
using Cairo;
public class GameArea : DrawingArea {
@@ -29,6 +30,11 @@ public class GameArea : DrawingArea {
private EventControllerMotion motion_controller;
private Game game;
+ private Animated player_animation;
+ private Animated player_dead_animation;
+ private Animated robot1_animation;
+ private Animated robot2_animation;
+
public GameArea (Game game) {
this.game = game;
@@ -44,6 +50,30 @@ public class GameArea : DrawingArea {
set_size_request (MINIMUM_TILE_WIDTH * game.arena.width,
MINIMUM_TILE_HEIGHT * game.arena.height);
+
+ player_animation = Animated
+ .sequence (Theme.Frames.PLAYER_START, 0)
+ .limit (20)
+ .then (
+ Animated
+ .bounce (Theme.Frames.PLAYER_START, Theme.Frames.NUM_PLAYER_ANIMATIONS)
+ .repeat (2)
+ )
+ .forever ();
+
+ player_dead_animation = Animated
+ .bounce (Theme.Frames.PLAYER_DEAD, Theme.Frames.NUM_PLAYER_DEAD_ANIMATIONS)
+ .forever ();
+
+ robot1_animation = Animated
+ .sequence (Theme.Frames.ROBOT1_START)
+ .limit (Theme.Frames.NUM_ROBOT1_ANIMATIONS)
+ .forever ();
+
+ robot2_animation = Animated
+ .sequence (Theme.Frames.ROBOT2_START)
+ .limit (Theme.Frames.NUM_ROBOT2_ANIMATIONS)
+ .forever ();
}
private bool resize_cb (Gdk.EventConfigure e) {
@@ -70,6 +100,54 @@ public class GameArea : DrawingArea {
return true;
}
+ private void draw_object (int x, int y, ObjectType type, Context cr) {
+ if ((x + y) % 2 != 0) {
+ cairo_set_source_rgba (cr, dark_background);
+ } else {
+ cairo_set_source_rgba (cr, light_background);
+ }
+
+ x *= tile_width;
+ y *= tile_height;
+
+ cr.rectangle (x, y, tile_width, tile_height);
+ cr.fill ();
+
+ int animation = 0;
+ switch (type) {
+ case ObjectType.PLAYER:
+ if (game.get_state () != Game.State.DEAD) {
+ animation = player_animation.frame;
+ } else {
+ animation = player_dead_animation.frame;
+ }
+ break;
+ case ObjectType.ROBOT1:
+ animation = robot1_animation.frame;
+ break;
+ case ObjectType.ROBOT2:
+ animation = robot2_animation.frame;
+ break;
+ case ObjectType.HEAP:
+ animation = 0;
+ break;
+ case ObjectType.NONE:
+ break;
+ }
+
+ cr.save ();
+ cr.translate (x, y);
+ theme.draw_object (type, animation, cr, tile_width, tile_height);
+ cr.restore ();
+ }
+
+ public void tick () {
+ player_animation.tick ();
+ player_dead_animation.tick ();
+ robot1_animation.tick ();
+ robot2_animation.tick ();
+ }
+
private void mouse_cb (int n_press, double x, double y) {
if (game.get_state () != Game.State.PLAYING) {
return;
diff --git a/src/game.vala b/src/game.vala
index fc50cbf..709f70d 100644
--- a/src/game.vala
+++ b/src/game.vala
@@ -124,7 +124,6 @@ public class Game {
arena[player_xpos, player_ypos] = ObjectType.PLAYER;
endlev_counter = 0;
add_aieee_bubble (player_xpos, player_ypos);
- player_animation_dead ();
set_move_action_sensitivity (false);
}
@@ -341,7 +340,6 @@ public class Game {
play_sound (Sound.YAHOO);
endlev_counter = 0;
add_yahoo_bubble (player_xpos, player_ypos);
- reset_player_animation ();
set_move_action_sensitivity (false);
}
}
@@ -358,7 +356,7 @@ public class Game {
* Game timer callback function
**/
bool timeout_cb () {
- animate_game_graphics ();
+ game_area.tick ();
clear_game_area ();
@@ -378,7 +376,6 @@ public class Game {
if (endlev_counter >= CHANGE_DELAY) {
++current_level;
remove_bubble ();
- reset_player_animation ();
clear_game_area ();
generate_level ();
state = State.PLAYING;
@@ -450,7 +447,6 @@ public class Game {
safe_teleports = config.initial_safe_teleports;
remove_bubble ();
- reset_player_animation ();
generate_level ();
clear_game_area ();
@@ -869,8 +865,6 @@ public class Game {
temp_arena.@set (player_xpos, player_ypos, ObjectType.PLAYER);
}
- reset_player_animation ();
-
remove_splat_bubble ();
update_arena ();
@@ -904,7 +898,6 @@ public class Game {
player_ypos = yp;
temp_arena.@set (player_xpos, player_ypos, ObjectType.PLAYER);
- reset_player_animation ();
update_arena ();
remove_splat_bubble ();
play_sound (Sound.TELEPORT);
@@ -952,8 +945,6 @@ public class Game {
player_ypos = yp;
temp_arena.@set (player_xpos, player_ypos, ObjectType.PLAYER);
- reset_player_animation ();
-
safe_teleports -= 1;
update_game_status (score, current_level, safe_teleports);
diff --git a/src/graphics.vala b/src/graphics.vala
index bca4f9a..2aff851 100644
--- a/src/graphics.vala
+++ b/src/graphics.vala
@@ -39,9 +39,6 @@ public const int BUBBLE_HEIGHT = 34;
public const int BUBBLE_XOFFSET = 8;
public const int BUBBLE_YOFFSET = 4;
-public const int PLAYER_WAVE_WAIT = 20;
-public const int PLAYER_NUM_WAVES = 2;
-
public int tile_width = 0;
public int tile_height = 0;
@@ -54,12 +51,6 @@ Pixbuf aieee_pixbuf = null;
Pixbuf yahoo_pixbuf = null;
Pixbuf splat_pixbuf = null;
-int robot_animation = 0;
-int player_animation = 0;
-int player_num_waves = 0;
-int player_wave_wait = 0;
-int player_wave_dir = 1;
-
int bubble_xpos = 0;
int bubble_ypos = 0;
int bubble_xo = 0;
@@ -132,57 +123,6 @@ public void set_background_color_from_name (string name) {
set_background_color (color);
}
-/**
- * draw_object
- * @x: x position
- * @y: y position
- * @type: object type
- * @cr: context to draw on
- *
- * Description:
- * Draws graphics for an object at specified location
- **/
-public void draw_object (int x, int y, ObjectType type, Context cr) {
- if (game_area == null)
- return;
-
- if ((x + y) % 2 != 0) {
- cairo_set_source_rgba (cr, dark_background);
- } else {
- cairo_set_source_rgba (cr, light_background);
- }
-
- x *= tile_width;
- y *= tile_height;
-
- cr.rectangle (x, y, tile_width, tile_height);
- cr.fill ();
-
- int animation = 0;
- switch (type) {
- case ObjectType.PLAYER:
- animation = player_animation;
- break;
- case ObjectType.ROBOT1:
- animation = robot_animation;
- break;
- case ObjectType.ROBOT2:
- animation = robot_animation;
- break;
- case ObjectType.HEAP:
- animation = 0;
- break;
- case ObjectType.NONE:
- break;
- }
-
- cr.save ();
- cr.translate (x, y);
- theme.draw_object (type, animation, cr, tile_width, tile_height);
- cr.restore ();
-}
-
-
/**
* clears the whole of the game area
**/
@@ -193,68 +133,6 @@ public void clear_game_area () {
game_area.queue_draw ();
}
-
-/**
- * reset_player_animation
- *
- * Description:
- * resets player animation to standing position
- **/
-public void reset_player_animation () {
- player_wave_wait = 0;
- player_num_waves = 0;
- player_wave_dir = 1;
- player_animation = 0;
-}
-
-
-/**
- * player_animation_dead
- *
- * Description:
- * sets player animation to be dead
- **/
-public void player_animation_dead () {
- player_wave_wait = 0;
- player_num_waves = 0;
- player_wave_dir = 1;
- player_animation = Theme.Frames.NUM_PLAYER_ANIMATIONS;
-}
-
-
-/**
- * animate_game_graphics
- *
- * Description:
- * updates animation for object graphics
- **/
-public void animate_game_graphics () {
- ++robot_animation;
- if (robot_animation >= Theme.Frames.NUM_ROBOT1_ANIMATIONS) {
- robot_animation = 0;
- }
-
- if (player_animation == Theme.Frames.NUM_PLAYER_ANIMATIONS) {
- /* do nothing */
- } else if (player_wave_wait < PLAYER_WAVE_WAIT) {
- ++player_wave_wait;
- player_animation = 0;
- } else {
- player_animation += player_wave_dir;
- if (player_animation >= Theme.Frames.NUM_PLAYER_ANIMATIONS) {
- player_wave_dir = -1;
- player_animation -= 2;
- } else if (player_animation < 0) {
- player_wave_dir = 1;
- player_animation = 1;
- ++player_num_waves;
- if (player_num_waves >= PLAYER_NUM_WAVES) {
- reset_player_animation ();
- }
- }
- }
-}
-
/**
* Draws a bubble if there is one
**/
diff --git a/src/meson.build b/src/meson.build
index 75e660f..3cf36ee 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -15,6 +15,7 @@ sources = files(
'themes.vala',
'theme.vala',
'preimage.vala',
+ 'animation.vala',
'controls.vala',
'game-config.vala',
'sound.vala',
diff --git a/src/theme.vala b/src/theme.vala
index 7a18891..ba4ceed 100644
--- a/src/theme.vala
+++ b/src/theme.vala
@@ -24,12 +24,15 @@ public class Theme {
public enum Frames {
PLAYER_START = 0,
+ PLAYER_DEAD = 4,
ROBOT1_START = 5,
ROBOT2_START = 9,
HEAP_START = 13,
COUNT = 14,
- NUM_PLAYER_ANIMATIONS = ROBOT1_START - PLAYER_START,
+ NUM_PLAYER_ANIMATIONS = PLAYER_DEAD - PLAYER_START,
+ NUM_PLAYER_DEAD_ANIMATIONS = ROBOT1_START - PLAYER_DEAD,
+ NUM_PLAYER_TILES = ROBOT1_START - PLAYER_START,
NUM_ROBOT1_ANIMATIONS = ROBOT2_START - ROBOT1_START,
NUM_ROBOT2_ANIMATIONS = HEAP_START - ROBOT2_START,
NUM_HEAP_ANIMATIONS = COUNT - HEAP_START,
@@ -54,7 +57,7 @@ public class Theme {
int tile_no = -1;
switch (type) {
case ObjectType.PLAYER:
- tile_no = Frames.PLAYER_START + frame_no % Frames.NUM_PLAYER_ANIMATIONS;
+ tile_no = Frames.PLAYER_START + frame_no % Frames.NUM_PLAYER_TILES;
break;
case ObjectType.ROBOT1:
tile_no = Frames.ROBOT1_START + frame_no % Frames.NUM_ROBOT1_ANIMATIONS;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]