Archived

This topic is now archived and is closed to further replies.

OrigamiMan64

The Challenge Grounds

Recommended Posts

I am writing a game which will be similar to chip''s challenge in nature, and I have run into a small problem. I don''t know where to handle collisions. I have four classes: Cell, Item, Object, and Level, where level holds a 2 dimensional array of Cells, Items, and Objects. Objects are the only things capable of motion. If I make objects transparent structures that use an enumerated type to differentiate between them, and have the level handle collisions, I end up with a massive switch statement two pages in length that grows exponentially with every object I add. If I make the objects themselves handle collisions, I need to provide them with a way to test what type of objects are on any given side of them, and to do this requires function pointers. Plus I still have a massive switch. If I derive each object, I can break up the code, but it makes it even more difficult to refer to the objects around them. What is the best way to go about this? The main problem to consider is the act of a hero pushing a block... if nothing is in the way of the block, both hero and block can begin to move.

Share this post


Link to post
Share on other sites
um, well I don''t the game your trying to replicate or the rules, so I can''t real offer much in the way of help. Maybe if you explained how the game is played, you could get some more help.

if all you want is to move a block in the direction the player is pushing it then. You could do that with a simple

check the space its trying to move to
if its empty move the block
otherwise don''t
then check to see if the space the player should move to is empty
if it is move the player
otherwise don''t.

-----------------------------------------------------
Writer, Programer, Cook, I''m a Jack of all Trades
Current Design project
Chaos Factor Design Document

Share this post


Link to post
Share on other sites
The first problem is getting information about the state of the level to the object, so that the object is capable of testing the spaces around it. Also, I don't want movement to be instantaneous, but rather it should take about half a second for an object to move between squares. I want to differentiate between leaving a square and entering a new square. Here is a copy of the readme I made for the text based version, so that you can get a general idea for the rules. Some of the information here will be incorrect, as I am moving to fully graphical now instead of console based.


********************************
* The Challenge Grounds *
* *
* Created By: Jason Hise, 2003 *
* Version 2.00 *
* *
********************************

How to play:
This is a puzzle game. The only objective is to reach an 'E', the
levels exit. Following is a description of each type of floor and
item, and how they react with each other.

- the yellow smiley face is the hero. you move him around with
the arrow keys to try to reach the exit.
- any open space is open floor that can be walked on normally.
= - a cyan triple equal sign is ice. the hero and/or any block
he pushes onto the ice will slide across it until landing, or
hitting an object blocking the path.
~ - double blue wavy lines mean that this is water, and stepping
in would mean certain death. If a pushable block moves onto
this space, both block and water are eliminated, leaving open
floor.
• - filled in gray blocks are walls which no object can penetrate.
@ - these are pushable blocks. use them to get rid of water or
block your path on ice so you can reach new areas. only one
block can be pushed at a time. blocks block each others
movement.
$ - a dollar is an item that can be collected by the hero, but
blocks the path of a pushable block. Once all dollars in the
level have been collected, the hero can pass through
checkpoints.
+ - plus signs are keys, another item behaving similar to the
dollar. for every key collected, the hero can pass through
one lock.
# - a lock acts like a wall until the hero has collected at least
one key. then when the hero moves on top of it, one key is
removed and the lock becomes open floor. If the hero has a
key and tries to push a block through a lock, however, he will
fail. regardless of the number of keys held, locks block
blocks.
? - checkpoints can only be passed when all keys in the level have
been collected. as with locks, these must be removed by the
hero before blocks will be able to pass.
E - the exit floor. blocks cannot be pushed on top of it, and if
the hero reaches it, the level is beaten.

When the game loads, two windows open automatically. The DOS
console window provides the actual game playing and editing area,
while the toolbar provides the options and level editing controls.

To start, the console window is completely empty. To play the
default levels, choose one from the combo box and click 'Play'.
If you want to load a previously saved or custom level, press the
'...' button to find it on your hard drive. If you want to create
a new level, hit 'New'.

Play Mode:
In play mode, you can save your progress by hitting Ctrl-S in the
console window or clicking either 'Save' or 'Save As' on the
toolbar. Although saving mid-game like this actually saves as
a new level, this level cannot be edited, even if it was a custom
level to begin with. This is to discourage cheating. If you
desperately need to alter a saved game, due to a change in the
original level or for any other reason, open the level in notepad
and change the last of the four numbers on top to a zero. This
marks the file as a custom level, rather than a saved game.

If you trapped yourself or screwed up horribly, you may want to
restart. Ctrl-R in the console window, or the 'Restart' button on
the toolbar will reload the level.

Note: Using Alt-Enter while the console window is selected allows
you to full screen it, unless you are running a version of windows
that despises this function. Pressing Alt-Enter again returns to
windowed mode. If you choose to play levels in this mode, make
sure you know the control keys, and return to windowed mode after
dying or beating the level. This is the only way to view any
popup messages. Also, note: the number of keys you have collected
and dollars remaining are only displayed in the toolbar. In full
screen mode, you wont be able to tell if you have enough keys to
pass through a door.

Note: If you need to exit the program as fast as possible, hit
'Esc' while in the console window. However, this is not
recommended, as you may lose unsaved work.

Edit Mode:
The edit tool can only be used with levels that you have created.
Default levels and saved games are protected. In edit mode, a
whole new set of controls pop up for your use. You can change the
number of keys that you start the game with, and select the floor
and object type you want to draw with. Objects can only be placed
on open floor and ice, however. It would make little sense to have
a key on top of water, where it blocks a pushable block, and
collecting it would mean certain death.

To place an object, you can either click with the mouse where you
want it, or maneuver with the arrow keys and place it with 'Enter'.
To fill a region with the object, hold control while clicking or hit
Ctrl-F. Ctrl-S works here as well for saving, or you can just use
the toolbar buttons.


[edited by - OrigamiMan64 on October 23, 2003 8:02:38 AM]

[edited by - OrigamiMan64 on October 23, 2003 8:03:38 AM]

[edited by - OrigamiMan64 on October 23, 2003 8:04:32 AM]

Share this post


Link to post
Share on other sites
One question I still have about your game - is it (effectively) a turn-based grid-based game, or can you continue to move around whilst, eg, a block you pushed onto ice earlier is still sliding?

If you have it so that your basic movement loop goes something like this:


while(!done)
{
move_direction=get_player_input();
if (next_cell_has_block(player,move_direction))
{
block=pick_block(move_direction);
try_move(block,move_direction);
}
try_move(player,move_direction);
}

try_move(object, direction)
{
if (next_cell_occupied(object,direction)) return;
move(object,direction);
while (cell_floor(object)==ice&&!next_cell_occupied(object,direction))
{
move(object,direction);
}
}


Obviously, you''d need to change names of variables, and write some functions yourself, but the basic logic should be clear. You might want two try_move functions - one for the player and one for blocks, and obviously there are more special cases for collisions to consider, but I think you should be able to get the general idea: rather than trying to collide everything with everything else, instead only look at the small number of moving objects and check what''s in the next square they want to move into.

Share this post


Link to post
Share on other sites
it is not turn based, but rather each object takes about .5 sec to slide from one space to another, and can then move again if it so chooses. The problem is not the logic of testing collisions, but of where to test them, ie what class should handle what. I could have the level handle the collisions, or I could have the level give the objects information so that they can handle their own collisions. The problem is that if I do the first, I need a large switch to handle different types of collisions, and it isnt modular. And if I do the second, it seems to make code horribly complex, requiring the level to provide callback functions so that objects can test for the objects surrounding them.

Share this post


Link to post
Share on other sites
I think most collision engines have a collision object, which is then associated with higher-level objects. So, for example, in pseudo-code:


high-level class SquareBob is
{
SquareBobData myData
PhysicsData myPhysicsData
}

engine class PhysicsEngine is
{
public internal class PhysicsData is
{
SomeRelevantData myData;
void RegisterWithPhysicsEngine();
}

VectorOfPhysicsData[] myPhysicsColliders();
void Tick(); // Performs movement & collisions

static PhysicsEngineRegistrationInterface GetPhysicsEngineForRegistering(); //Only needed if this engine is NOT a factory for PhysicsData

}

This structure is especially useful if you want to decouple the shape of your game objects from the shape of your physics areas/volumes. The problem it introduces is that your object and physical operations on it are no longer tied together. Implementation of that particular item is left as an exercise for the reader

HTH,
ld
[edit]pedantic code change * 2[/edit]

[edited by - liquiddark on October 23, 2003 10:06:20 PM]

[edited by - liquiddark on October 23, 2003 10:08:01 PM]

Share this post


Link to post
Share on other sites
Not sure, this was my first post here

anyhow, all of my objects are the same size. I don''t need a physics engine. I just need to define how different objects interact with eachother, and I don''t know where to put that code to make my game as modular as possible. I would like to be able to easily add other objects with different behavior in the future, so somehow I don''t feel having all the checks done in a single function based on an enumeration is a good idea.

Share this post


Link to post
Share on other sites
funnily enough I was posting about something like that on the AI forum jsut a day or two ago. So let me give you some pointers.

Personally I would simply create a collision handler class that would stand separately from the rest.
It would need to have access to the Level structure to test collision between objects and items (I assume), and possibly objects and objects.

Remember, just because it''s OO programming doesnt mean you HAVE TO use all the fancy tricks it provides.
In this particular case, just because the objects can collide doesnt mean that they should handle the collision themselves.

Does that make sense to you ?

Oh, and do your moving objects always move cell by cell, or are they moving freely in 2D ? Because that would make it slightly more complicated (the collision detection scheme, that is).


Sancte Isidore ora pro nobis !

Share this post


Link to post
Share on other sites
right now, its cell to cell... think RPG Maker 2000. Although I could make a collision manager class, I want to avoid having a function the size of four pages to handle all the collision. I want to be able to easily add new objects to the system.

Share this post


Link to post
Share on other sites
Ergo the reason why the physics engine handles movement/collision, and the object handles response.

Let's try another pseudo code example:


high-level class SquareBob implements IResponse is
{
SquareBobData myData
PhysicsData myPhysicsData
void Response(IResponse Collider)
{
if ((SuperCoin)Collider <> Nothing)
PickupCoin((SuperCoin)Collider); // Coin destroyed here


elseif((MoverBlock)Collider <> Nothing)
Collider.Move(myPhysicsData.myDirection);
}
}

high-level class SuperCoin implements IResponse is
{
SquareBobData myData
PhysicsData myPhysicsData
void Response(IResponse Collider);

}

engine class PhysicsEngine is
{
public internal class PhysicsData is
{
SomeRelevantData myData;
void RegisterWithPhysicsEngine();
}

VectorOfPhysicsData[] myPhysicsColliders();
void Tick(); // Performs movement & collisions

static PhysicsEngineRegistrationInterface GetPhysicsEngineForRegistering(); //Only needed if this engine is NOT a factory for PhysicsData

}


Another possibility would be to have Response return, for example, a boolean to say whether it considers itself "blocked" by the colliding object. That's a tad dirty, but it depends on how you want responsibilities distributed as to whether it would work for you.


ld

Edit: code cleanup

[edited by - liquiddark on October 25, 2003 2:12:41 AM]

Share this post


Link to post
Share on other sites