Berry Frenzy (mini SFML game)

What do you know... SFML can be fun!

I've been playing around with it for a while and I made this:

http://www.4shared.com/file/IHtDCwbF/berry_frenzy.html

Any suggestions for design or gameplay improvement are welcome.

Some notes:

When implementing the notify-for-delete functionality for the TimedBerry class, at first I tried to do something sophisticated using the observer pattern, but I had too many objects pointing to each other and I was getting segfaults out of nowhere, so I ended up doing it with that dead_list/about_to_die container.

Initially, I had three different classes for the concrete berries (Red/Blue/Pink) and it felt horrible to see the same piece of code three times... Then, I remembered that tag class trick. Now, adding a new concrete timed berry is as simple as creating a tag, setting its properties and typedefing the result. I know this might look like an overkill (instead of having three classes I could have one timed berry class with different member variable values for different berry types) but I don't think it is. It looked better to have a separate class for each berry type, because this way I can also make these berry types vary (slightly) in behavior, not just in properties.

The game map as it is now is a refinement of several earlier implementations. The first time I tried something like this, I used a vector of object pointers and a 2D array of object pointers. Finding the position of a vector object in the array was easy, as the coordinates were stored in the object, but the opposite was O(n), as I had to use std::find on the vector. The second time, I realized I didn't need random access, so the vector could be changed to a list. Then, I also noticed that I could store list iterators in the 2D array, which made access easy in both directions (list <-> 2D array), but at the cost of an extra level of indirection. The third time (which is this one), I noticed that a set would be a better choice.

Last edited on
About gameplay, it could be a bit more colorful, like poisonous berries or berries of different size. You could also punish the player a bit more. Something like reducing time for every uncollected berry or for every missed click (the penalties could start off as 0 and slowly grow like the one on your timer does). Another nice thing would be if berries somehow notified that you're holding the mouse on them or at least that you've clicked on them. The square picking box feels weird. It is sometimes hard to tell whether you clicked the berry or the time ran out. Also you could prevent berries from being created behind the timer. Lastly, you should make your game full screen. Many times I've clicked out of the window, it's quite irritating..
Oh, and nice menu, by the way.

About design, it seems a bit overcomplicated. Is there anything wrong with Berry map[width][height] with struct Berry{ BerryProperties* type; int timer; }; ? You don't even need a set, as the map is so tiny (but you can still have one).

edit: By the way, is this your original game or a copy of something?
Last edited on
hamsterman wrote:
About gameplay, it could be a bit more colorful, like poisonous berries or berries of different size.

Yes, I plan on adding more berry types with special properties and abilities (e.g. freeze berries that will stop the time for a while), but first, I want to create a groundwork that will allow me to do this easily.

hamsterman wrote:
Another nice thing would be if berries somehow notified that you're holding the mouse on them or at least that you've clicked on them. The square picking box feels weird. It is sometimes hard to tell whether you clicked the berry or the time ran out.

Yes, I know... I think playing a sound whenever a berry is clicked would be enough, but maybe I'll add some special effects too (e.g. little dancing stars).

hamsterman wrote:
Lastly, you should make your game full screen. Many times I've clicked out of the window, it's quite irritating..

Haha, yeah, the only reason I disabled resizing was that I couldn't align the score string properly xD When I decrease the window width it shows up left and when I increase the window width it shows up right (actually, it doesn't show up, since it goes off screen...). I guess that's the first thing I'll try to fix.

hamsterman wrote:
Oh, and nice menu, by the way.

Lol... I guess I'll have to replace it with a graphical one eventually...

hamsterman wrote:
About design, it seems a bit overcomplicated. Is there anything wrong with Berry map[width][height] with struct Berry{ BerryProperties* type; int timer; }; ? You don't even need a set, as the map is so tiny (but you can still have one).

Indeed, having a primitive data type (int or double perhaps) to hold the time is a good idea, as it will allow me to implement a 'pause' feature and my freeze berries more easily (I don't seem to be able to 'pause' the SFML Clock...).

As for the berry properties, I really like the tag class system, as it's very very flexible. For example, suppose that I want to add a BombBerry. A BombBerry will be directly derived from Berry, not TimedBerry, and it will stay on the place it appears until I click it. When I click it, it explodes and destroys the surrounding berries (and I get credit for them of course). A BombBerry doesn't need life_time, (bonus) time or (bonus) score properties. All it needs is a radius property. No problem! This can be easily represented like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
struct RedBerryTag {};
struct SmallBombBerryTag {};
struct BigBombBerryTag {};

//...

template <class BerryTag>
struct BerryProperties;

template <>
struct BerryProperties<RedBerryTag>
{
    enum {score=10,time=0,life_time=5};
};

template <>
struct BerryProperties<SmallBombBerryTag>
{
    enum {radius=1};
};

template <>
struct BerryProperties<BigBombBerryTag>
{
    enum {radius=2};
};

//... 

Finally, I like having two containers for my berries. It's kind of cool xD

hamsterman wrote:
By the way, is this your original game or a copy of something?

Well, you can't exactly say that a game where you click on things to get points is something original... I recall doing something like this a couple of years ago. That was easier though, as it was in Visual Basic. I had a big command button moving randomly on the main form. When you clicked on it you would get points and another command button would appear on the place you clicked. Both command buttons had pics on them. The first one had pics of three fellow student girls that I got from fb, and the second one had a pic of a red kiss.

Thanks for the feedback! :D
Last edited on
Indeed, having a primitive data type (int or double perhaps) to hold the time is a good idea, <...>
I didn't even notice the original timer type. My point was that you don't need all that dynamic memory allocation. It could be 100% static. You'd save a lot of code. You can still do the tag class thing for BerryProperties class, though I'm not sure why you would want to.

Another thing is about the radius. If you're going to implement that, you may have to break the tile system. Then my suggestion won't work at all and your method will only need several changes.
hamsterman wrote:
Another thing is about the radius. If you're going to implement that, you may have to break the tile system.

Not necessarily.

radius==1

XXX
XOX
XXX

radius==2

 XXX
XXXXX
XXOXX
XXXXX
 XXX

radius==3

  XXX
 XXXXX
XXXXXXX
XXXOXXX
XXXXXXX
 XXXXX
  XXX

And so on...

hamsterman wrote:
My point was that you don't need all that dynamic memory allocation. It could be 100% static.

There are two problems with that approach. A small one and a big one.
The small one is that I'd have to have an additional bool 2D array
to know wether or not there actually is a berry in a position.
The big one is that I lose polymorphism...

hamsterman wrote:
You can still do the tag class thing for BerryProperties class, though I'm not sure why you would want to.

Ok, I'll try to give a better example. Suppose I want the following:

(1) A 10% chance that red berries will explode when I click them.
(2) A 20% chance that blue berries will freeze the time for 1 second when I click them.
(3) A 15% chance that pink berries will give a bonus of 20 seconds if you click them when the timer is < 10 s.

No problem!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//...

struct Berry
{
    //...

    //I add a virtual function here.
    virtual void Click(Args * args) {}

    //...
};

struct TimedBerry : public Berry { /* This doesn't change at all! */ };

struct RedBerryTag {};
struct BlueBerryTag {};
struct PinkBerryTag {};

template <class BerryTag>
struct BerryProperties;

template <>
struct BerryProperties<RedBerryTag>
{
    enum {score=10, time=0, life_time=5, exp_chance=10, exp_radius=1};
    static const sf::Color color;
};

template <>
struct BerryProperties<BlueBerryTag>
{
    enum {score=50, time=0, life_time=2, freeze_chance=20, freeze_time=1};
    static const sf::Color color;
};

template <>
struct BerryProperties<PinkBerryTag>
{
    enum {score=0, time=10, life_time=1, bonus_chance=15, bonus_time=20};
    static const sf::Color color;
};

const sf::Color BerryProperties<RedBerryTag>::color=sf::Color::Red;
const sf::Color BerryProperties<BlueBerryTag>::color=sf::Color::Blue;
const sf::Color BerryProperties<PinkBerryTag>::color=sf::Color::Magenta;

template <class BerryTag>
struct ConcreteTimedBerry : public TimedBerry { /* This doesn't change at all! */ };

template <class BerryTag>
int ConcreteTimedBerry<BerryTag>::count=0;

template <class BerryTag>
sf::Shape ConcreteTimedBerry<BerryTag>::sprite=sf::Shape::Circle(0,0,BERRY_SIZE/2-2,
    BerryProperties<BerryTag>::color,2,sf::Color::Yellow);

typedef ConcreteTimedBerry<RedBerryTag> RedBerry;
typedef ConcreteTimedBerry<BlueBerryTag> BlueBerry;
typedef ConcreteTimedBerry<PinkBerryTag> PinkBerry;

void RedBerry::Click(Args * args)  { /* EXPLODE!!! */ }
void BlueBerry::Click(Args * args) { /* FREEZE!!!  */ }
void PinkBerry::Click(Args * args) { /* TIME++!!!  */ }

//... 

The only things I added are the ones in bold!
Plus, if I make the properties variable (static ints) instead of constant, they can be upgradable.

Now, regarding this -> Args * args, I'm thinking of making a SpecialEffectsApplier that gets special effect messages from berries and applies them to the map, because passing around the game map and other game variables (like the timer) looks really ugly...

Ok, that's all for now. I probably won't write any code for this until Friday (I constantly move from Smallville to Metropolis (Thessaloniki) and back and I only code when I'm in Smallville (Friday, Saturday, Sunday)). If I make any major updates I'll let you know.
Last edited on
XXX
XOX
XXX
That's one giant berry. I assumed larger berry would be something like 1.2 times larger, not 3. Though I guess this is fine.

I'd have to have an additional bool 2D array
No, you only need to compare 'timer' to 0 to know it berry is still there.
I lose polymorphism...
No, polymorphism is hidden in BerryProperties class.
hamsterman wrote:
That's one giant berry.

Oh, I was talking about explosion radius.
The 'O' is the berry that explodes and the 'X's are the berries affected by the explosion.

hamsterman wrote:
No, you only need to compare 'timer' to 0 to know it berry is still there.
hamsterman wrote:
No, polymorphism is hidden in BerryProperties class.

Hmmm... I guess I'll have to think about that approach too...

Last edited on
On second thought, I don't like my design, at all.

I give timed berries too much value by making them a berry subclass.
Also, it's difficult to add more than one special abilities the way I described above.

This -> struct Berry{ BerryProperties* type; int timer; }; gave me an idea...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
struct Ability
{
    //struct Berry * owner;

    virtual ~Ability() {}

    virtual void OnUpdate(UpdateArgs * args) {}
    virtual void OnDraw(DrawArgs * args) {}
    virtual void OnClick(ClickArgs * args) {}
};

struct TimedAbility : public Ability {/*...*/};
struct BonusScoreAbility : public Ability {/*...*/};
struct BonusTimeAbility : public Ability {/*...*/};
struct BombAbility : public Ability {/*...*/};
struct FreezeAbility : public Ability {/*...*/};

struct Berry
{
    int x, y;

    std::list<Ability*> abilities;

    void Update(UpdateArgs * args) {/*call OnUpdate for every ability*/}
    void Draw(DrawArgs * args) {/*call OnDraw for every ability*/}
    void Click(ClickArgs * args) {/*call OnClick for every ability*/}
};

I'll work on this and see how it turns out.
Last edited on
Topic archived. No new replies allowed.