Superfrog monsters

Whatever you're working on - be it Art, Music, a Fan-Game or a program for use with existing Team17 games - we want to hear about it.

Moderator: Dream17 Staff

Post Reply
Moxy
Newbie
Posts: 36
Joined: Wed Nov 29, 2006 6:15 am
Contact:

Superfrog monsters

Post by Moxy » Tue Dec 05, 2006 10:39 am

I'm working on what could possibly be a superfrog fan clone, and am working on implementing the monster system. I'm trying to settle on an architecture for adding monsters to the map.

I'm wondering whether the monsters always move the same way:

I.e.
Does every hedgehog start at an arbitrary center point, then move left 10 tiles, then move right 10 tiles? Or do different hedgehogs move different distances?

User avatar
Squirminator2k
Dream17 Founder
Posts: 573
Joined: Mon Feb 28, 2005 2:07 pm
Location: Los Angeles, CA
Contact:

Post by Squirminator2k » Fri Dec 08, 2006 11:46 am

Personally I believe that the motion distance is predefined in a manner similar to how you describe it, although it may be that an upper and lower distance is defined separately and the monster just walks between the two points.

I would suggest contacting Spadge and asking him if anyone who worked on the Superfrog code is still at Team 17. If so, you may be able to email them.
PortsCenter - Gaming's forgotten history. A show all about unique video game ports.

Moxy
Newbie
Posts: 36
Joined: Wed Nov 29, 2006 6:15 am
Contact:

Post by Moxy » Sat Dec 09, 2006 6:56 pm

It's just a matter of implementation time. I can implement the way I suggested above (where all monsters of the same type move the same way on the same map) in about a half hour, whereas if all monsters move a custom way, that'll take a bit longer since I will have to write a custom file format for storing and loading monster data.

User avatar
bucky o'hare
Newbie
Posts: 28
Joined: Wed Aug 09, 2006 1:09 am
Location: Connecticut
Contact:

Post by bucky o'hare » Sun Dec 10, 2006 4:04 am

Is it possible for an obstruction in terrain to have an impact on the monsters' movements?
In one of the pyramid world levels I seem to recall a mummy that fell short of a hidden hole in the floor, and it was a good way to keep an eye out for it. Although it may have just been a coincidence, or could've been planned around the preset movement of the mummy...

K^2
Regular
Posts: 216
Joined: Thu May 26, 2005 4:02 am

Post by K^2 » Sun Dec 10, 2006 5:49 am

It looks like there are at least several classes of enemies. Hedgehogs and snails move a certain amount about the set center. Little blobs can either be stationary, or move between obstructions. Bees are stationary, but follow you if you get close. Some other types of enemies seem to just go across the screen. So you will definitely need some system that lets you select the type of action that the monster will perform. Perhaps, write separate functions for each, and use a look up table for function addresses, depending on the monster type.
None of my projects (Minus One converter, W3D/W4 Map Viewer, and WMapEditor) are endorsed, supported or otherwise affiliated with Dream17. I just find Dream17 forums to be a nice place to share and discuss my work with others.

Moxy
Newbie
Posts: 36
Joined: Wed Nov 29, 2006 6:15 am
Contact:

Post by Moxy » Thu Dec 21, 2006 4:12 am

Cool, thanks for the feedback.

I decided to set it up with code for each type of monster - i.e. those that walk left and right, the plane which flies left then resets, the bees who will follow you up to a certain radius from their start positions. Specific attributes are set in an XML file for each individual monster in the map, such as the length of the radius, the maximum left distance, etc. :)

K^2
Regular
Posts: 216
Joined: Thu May 26, 2005 4:02 am

Post by K^2 » Sat Dec 23, 2006 8:46 am

Just, please, tell me that you are not planning to use a case switch to select functions.
None of my projects (Minus One converter, W3D/W4 Map Viewer, and WMapEditor) are endorsed, supported or otherwise affiliated with Dream17. I just find Dream17 forums to be a nice place to share and discuss my work with others.

Moxy
Newbie
Posts: 36
Joined: Wed Nov 29, 2006 6:15 am
Contact:

Post by Moxy » Sat Dec 23, 2006 11:27 pm

lol kinda, but not in the way you're probably thinking.

There are obviously different kinds of monsters, which follow different types of movements.

I have a generic Monster class. Rendering, bounding box collision, etc is the same for all mosters. Monster classs has OnFrameMove as pure virtual.

There are 3 types of monsters in forest world
LeftRightWalker - snails, some of the blue blobs, etc
LeftResetWalker - for the airship (Move left full dist, reset to start position)
RadiusFollower - for the bees

For example, in the Forest1-1.xml file there is the section:

<Monsters>
<Airship X="400" Y="580" maxLeft="500"/>
<Blob X="112" Y="671" maxLeft="64"/>
<Hedgehog X="400" Y="668" maxLeft="80"/>
</Monsters>

Monster factory knows that the Airship is a LeftResetWalker, when the airship is created, the LeftResetWalker is instantiated, added to the monster manager class, and left to fly. (Btw, dropping bombs is not setup yet, for that I'll extend LeftResetWalker into an Airship class)

And, btw, certain attributes such as the bounding box of the airship is pulled from elsewhere.

K^2
Regular
Posts: 216
Joined: Thu May 26, 2005 4:02 am

Post by K^2 » Mon Dec 25, 2006 11:56 pm

Class inheritance is not a bad way to do it. I would probably still use a function pointer even with classes. Consider this code.

Code: Select all

#include <stdio.h>

class Monster
{
	public:
		Monster(void)
		{
			x=0;
		}
		int getx(void)
		{
			return x;
		}
		int (*OnFrameMove)(void);
		int x;
};

int foo(Monster *th)
{
	th->x++;
	return 0;
}

int main(void)
{
	int i;

	Monster monster;
	monster.OnFrameMove=(int(*)())foo;
	for(i=0;i<5;i++)monster.OnFrameMove();
	printf("%d\n",monster.getx());

	return 0;
}
I use the fact that the first parameter in any member function call is always a pointer to the object, even though the function is declared as (*)(void) in the class. The typecast at assignment of address of foo to OnFrameMove resolves the difference. In the example above, monster.getx() returns 5, because monster.OnFrameMove(), equivalent to foo(monster), is called 5 times within the loop.

This kind of coding allows you not to worry about managing monsters as different monster classes. They are all the same class, but different monster objects can use differetn OnFrameMove functions. Now you can keep all your monster objects in the same array, linked list, or some other basic data structure, without needing to keep track which class each object belongs to.
None of my projects (Minus One converter, W3D/W4 Map Viewer, and WMapEditor) are endorsed, supported or otherwise affiliated with Dream17. I just find Dream17 forums to be a nice place to share and discuss my work with others.

Moxy
Newbie
Posts: 36
Joined: Wed Nov 29, 2006 6:15 am
Contact:

Post by Moxy » Tue Dec 26, 2006 2:20 am

Cool, that's a fair way to do it.
In the example you gave, your code and my code are effectively doing the exact same thing, just through different means.

With the setup I have, I don't have to care which monster is on screen. When the map is being loaded into memory, and once I've determined which monster is being added (as per the map xml file), I can go

Monster m = new Airship(...)

(Above, on the surface, that is effectively the same as setting OnFrameMove with the address of the foo function)

MonsterManager.Add(m) (basically calls _monster.Add(...) internally)

then, in MonsterManager.OnFrameMove(...), I can

foreach (Monster m in _monsters) {
m.OnFrameMove(...)
}


Simple.

The only time I need to think of the monster as an Airship is when I'm loading the map. The rest of the time, I just call the OnFrameMove and specific functionality is handled without me having to care.

OnFrameMove parameters are defined in Monster, and the body of the function is overridden in Airship.

K^2
Regular
Posts: 216
Joined: Thu May 26, 2005 4:02 am

Post by K^2 » Tue Dec 26, 2006 7:31 am

Right. It's just that I don't like messing with the inheritance in such a way. When you do something like:

Code: Select all

class Airship : public Monster {...};
Monster m = new Airship();
m.OnFrameMove();
It doesn't click in my head right away that m.OnFrameMove points to the function declared in Airship class, despite m being pointer to Monster class. Of course, internally, it works out exactly the same as the code I wrote, so it's a matter of convenience.

I'm wondering, though, if something that doesn't use classes at all could run faster. Not that it matters here, but purely in theory. Say, something like this:

Code: Select all

struct monster
{
	int x,y,speedx,speedy;
};

void MoveAirship(monster *);
void MoveBee(monster *);

...

void **m_list = new (void*[2*N_monsters]);
m_list[0]=(void*)new monster;
m_list[1]=(void*)MoveAirship;
m_list[2]=(void*)new monster;
m_list[3]=(void*)MoveBee;

...

int k;
for(k=1;k<2*N_monsters;k+=2)
	((void(*)(monster*))(m_list[k]))(m_list[k&0x8FFFFFFE]);
That should loop through the monsters pretty fast. Of course, it assumes that MoveAirship and MoveBee are very short functions and there is a crap load of monsters. In every other case, this is absolutely pointless.
None of my projects (Minus One converter, W3D/W4 Map Viewer, and WMapEditor) are endorsed, supported or otherwise affiliated with Dream17. I just find Dream17 forums to be a nice place to share and discuss my work with others.

Moxy
Newbie
Posts: 36
Joined: Wed Nov 29, 2006 6:15 am
Contact:

Post by Moxy » Tue Dec 26, 2006 10:47 am

K^2 wrote:Right. It's just that I don't like messing with the inheritance in such a way.
It's a problem that inheritance is designed to solve. Also, I declare Monster::OnFrameMove as pure virtual. Child classes HAVE to implement the method. If you read the class def, it's super clear that it's a custom function.

The technique you came up with to avoid the overhead when dynamically trying to determine which OnFrameMove to call MAY indeed improve runtime performance. On the surface, it LOOKS like it may perform better for the case of a million monsters or so, it really depends on how the code is compiled, and the compiler - performance may be exactly the same either way - especially since there are only 8 or so types of monsters in superfrog.

K^2
Regular
Posts: 216
Joined: Thu May 26, 2005 4:02 am

Post by K^2 » Tue Dec 26, 2006 12:16 pm

Yeah. I know how pure virtual functions work. I just don't like them. It's an aesthetics thing.

I wonder, though. The pure virtual function is null function pointer. Obviously, when you call new to allocate space for a class that is a child of an abstract class, virtual functions will be initialized to the addresses of child class methods. The question is, does the initialization occur in the code for the operator new or in the constructor? Both of these can be overloaded. Can overloaded code of the new/constructor treat initialization of virtual functions differently?

And you are absolutely right. The performance boost of the above code would be marginal if at all existent. I'm just used to tunning inner loops in simulations. When you have millions of particles simulated, each needing thousands of steps for every second of simulation time, cutting a few cycles here and there can mean the difference between being done by lunch and having to come back for results on Saturday morning. Sometimes I go crazy and write inner loops in Assembly. It's all absolutely irrelevant to what you are doing.
None of my projects (Minus One converter, W3D/W4 Map Viewer, and WMapEditor) are endorsed, supported or otherwise affiliated with Dream17. I just find Dream17 forums to be a nice place to share and discuss my work with others.

Post Reply