PDA

View Full Version : Another question YAY! (Sprite Engines Collision).



Chesso
03-01-2007, 10:55 AM
As per my last question about collisions, I'm using a simple method of tracking the X, Y of my main sprite before movement, so that if a collision occurs, I can put the main sprite back.

Basically the setup (or the view of it), would resemble something like a basic rpg or bomberman game (actually, for testing I'm using a gameboy bomberman sprite).

When he walks into my 16x16 blocks, I would like the top half of his body to be able to walk through them, from either direction (and of course have that top half of his body drawn over a block when he runs up into one).

Anyone know how I might go about that?, Right now I'm basically thinking of checking the position of both sprites when they collide and if it happens to be one of those, just let him pass, otherwise let the collision go through like normal.

I was however hoping there might be a less intensive method lol.

Oh and also, just quickly, do I use a sprites Z value to determine whether it's drawn overtop, level with or underneath something (and what determines over and under).

Any help is greatly appreciated :).

FNX
03-01-2007, 01:43 PM
hello Chesso,
the best way to do what you want is to code your own tile engine. That
gives you more flexibility on "special effects".

Anyway, in two words you have to do 2 steps of drawing, or even only
one, it depends on level of detail you need...

First draw terrain to fill your tiled map (grass, water...) then, from top
to bottom draw the wall-items-obstacles things. You just have to check
where the player tile position is, and when drawing that tile, draw the
player sprite too. That is valid also for enemies and so on so, just check
for every tile if there's an active sprite over it and then draw it.
If you want to add a nicer fx to that, when drawing walls in front of the
player, draw that tile with alpha and it becomes transparent :)

I did a thing like that some time before but i had problems with delphix,
because of slow down, maybe undelphix solves the problem.

Another solution is to look at tilestudio that does the job for you, even
export the tiles, the map and the delphix classes to use in your game!
Here's the link: http://tilestudio.sourceforge.net/


I hope it's clear enough, i'm not happy with my english lately... :?

chronozphere
03-01-2007, 01:57 PM
Hi 8)

I've googled for some bomberman screenies to understand exactly what you mean.

So you don't want a top-down view... you want the camera to look at a 45 degree angle to the playground.

You'll have to modify the bounding box for each moving sprite. The bounding box should be the bottom half of each moving sprite (the feet of each sprite).

You can modify the bounding box by overriding the GedBoundsRect method for a TSprite descendant. :)

An example:

type

TMyPlayerSprite = class(TSprite)
private
....
protected
function GetBoundsRect: TRect; override;
public
....
end;

{implementation}

function TMyPlayerSprite.GetBoundsRect: TRect;
begin
Result := Bounds(Trunc(WorldX), Trunc(WorldY)-(Height div 2), Width, Height div 2);
end;


You should always draw the background and the walls first before drawing the active charactes.
Just use the TSprite.Z variabele. :)

Hope this helps...

Good luck ;)

Chesso
03-01-2007, 02:08 PM
Could you explain the GetBoundsRect function? Like what is going on with it, WorldX and WorldY what do they represent (it's late here I'm half asleep lol).

Oh yeah and does using the Z mean that a Z value of 2 will draw over a Z value of 1? or vice versa.

Iv'e come across (although I can't remember) things that have used either one of those.

EDIT:

Oh and another thing (don't think I asked about this before), is there any function for method of doing transparent text?

Iv'e seen the exampels that use DXPowerDraw with there own font sort of thing, which I might end up doing at a later stage for the sake of having my own fancy little font (if anyone knows where there is more info on using that component i'd appreciate that too, like is there specific dimensions or ordering of where everything goes).

chronozphere
03-01-2007, 06:46 PM
Okay.. let me explain :) :

A TSprite object has its own X and Y variabeles.
It also has a list of sub-sprites. This allows you to make a sprite-hierarchy. if you add a sub-sprite to a sprite, the subsprite's position (X,Y) is relative to the parent-sprite's position.
So if you move the parent-sprite, all it's childeren are also moved. The World X and Y are the actual world-coordinates of the sprite.
So if you use subsprites, the WorldX can be computed by adding the subsprite's X and the parent's X.
If you use a 'deeper' hierarchy with childeren who have childeren and grandchilderen etc the WorldX is the sum of the Sprite's X and it's parent's X, grandparent's X, etc.

The GetBoundsRect function is a function which returns the bounding rectangle for a sprite. Each sprite has it's own bounding rectangle.
The bounding rectangle depends on the sprite's position in the world, that's why we use World X and Y to define it in the function.
When checking collision, the sprite engine checks for bounding-rectangle-overlaps (but i think you already knew that :) ).

The code i gave you will make sure that only the bottom half of the sprite is covered by the bounding rectangle. I assume that the width and the height of the sprite are equal to the width and the height of the picture associated with the sprite. You must set these values explicitly when you create the sprite, if i'm not mistakin. :)

Humm... The z-drawing-order.. :think:

You could find this out yourself.. but i took some secs to analize the DelphiX source for you. :)
I assume that DelphiX first draws the sprites with a low Z value and then those with a high Z value.
But you should give this a try... plz, tell me the results :razz:

About the font..
I always used DXDraw.Surface.canvas.TextOut.
Use the DXDraw.Surface.Canvas.Font record to manipulate it's fontface, size, color etc..
This will suffice for basic text's.

Good luck... hope this was enough info. ;)

Chesso
03-01-2007, 11:05 PM
Hello, yes everything fairly clear aside from the font.

I know how to use Canvas.Font for basic text but there doesn't seem to be any method in that to make it transparent.

I want to display some stat information on the screen in the game and the window size is a mere 350x350, so I figured if I made the text transparent to a degree, it would be easier to see what's underneath and seem less cluterly and at the same time providing usefull information (like lives, or fps etc).

EDIT:

NOTE: I tried the code for changing the bounding box of the sprite, and no matter what I do, Divide, Plus, Minus, Times anything, it always bases it off the bottom not the top.

I'm trying to ignore or cut, basically the top half of the sprite as far as collisions are concerned and nothing I do stops it from doing the opposite lol.

Does anyone have any advice on creating there own font for use with DXPowerFont?

I tried to create the invidual letters on photoshop, with all the nice effects and stuff, but that really screws up, because no matter what I use for the background or just transparent, alot of each letter ends up going based on that colour, rather than the colour chosen for the text.

So if I make up a letter in PS with a pink background to put in my font bitmap, any sort of blur or shadowing ends up a pinky/black and when it's transparent and output to the screen and it looks like there is pink all around the letter :(.

chronozphere
04-01-2007, 09:49 AM
it always bases it off the bottom not the top.

Uhh... what do you mean. :eh: can you show to me (somehow) how the bounding box is created when you use my function.

I'll probably need some code before i can solve the sprite bounding box problem. The creation and draw code would be usefull as well. ;)

plz notice that I might be unable to solve this problem, I haven't used DelphiX for a long time. :?

A workaround for the font problem...

For each text or label in the game, you could create a TDirectDrawSurface.
Fill the surface with a color (e.g black) and set this color as the surface's transparent color.
Then use TextOut to draw a text.
And draw the surface using TDirectDrawSurface.Draw on the main DXDraw.Surface.

It's slightly harder to code, but when succesfull this technique allows you to perform many operations and effects on you text. You can rotate, scale and wave the text using the various drawing functions. Be carefull though.. these DelphiX drawing functions are totally software-based and are rather slow. UnDelphiX has hardware accelerated graphics, so you better use that if you want cool FX.

Good luck ;)

Chesso
04-01-2007, 10:00 AM
What I mean, is that the bottom half of the sprite is allowed to pass through objects.

I'm looking to have the top half of the sprite to pass through objects (creating the effect of the sprites feet being literally infront of any object in any direction and the top half of him being drawn over top and not colliding).

Let's say the sprite is walking up into a block, it's meant to look as if the top half of the sprites body is towering over the block, due to the angle.

But all you really have to do is to look at any 2D RPG's or even Bomberman itself (not sure about bomberman but I would assume) looks.

jasonf
04-01-2007, 11:45 AM
Personally, I would ditch the DeplhiX collision detection completely for this type of game. Or at least for anything other than bad guys and bullets (if applicable)

As your game works on a fixed grid and there's no chance of a wall being in an odd place, I'd use a grid system using an array of booleans.
This array would be populated with the walls of the map. True for blocked.
Then work out if you're colliding with a block or if you can move into the free space next to you using a very simple calculation.

I implemented a system like this for a platformer in VB once. it worked quite well.

Just take the corner pixel co-ordinates and divide them by the number of pixels each cell takes up get the gridx and gridy for that corner and check if that grid is taken with a block, if so, don't move there. Do this before you apply your position changes in DoMove.

This type of collision detection is Uber fast. No pixel tests to do at all. and you'll be able to add whatever offsets you want to the X or Y axis so you'll appear to walk behind blocks for a little way then stop.

gridx := x / gridsizex;
gridy := y / gridsizey;

If you do this for each corner of the sprite, it'll work. If you only do this for the centre of the sprite, you'll be able to walk halfway into every object in all directions.

If I was doing a game like this, this is how I'd do it.

Chesso
04-01-2007, 12:00 PM
Well it is a fixed size that can be split up into 32x32 blocks, the main character, other animations, any enemies and the movement don't work in this fashion lol.

Speed isn't really too much of a problem as each level is considerably small and nothing too complex going on.

I'll probably have to re-consider this in later games where I'll need more flexibilty for sure.

jasonf
04-01-2007, 12:45 PM
I don't understand...


the main character, other animations, any enemies and the movement don't work in this fashion

How do they move?

Do they have free movement within the 32x32 cell? either way, the way I suggested will work.

Your array for your map, say for example it's 10x10 - the fact that your sprites are all 32x32 is not important at this stage.


-0123456789
0XXXXXXXXXX
1X X
2X X XX X X
3X XX X
4X X XX X X
5X XX X
6X X XX X X
7X X XX X X
8X X
9XXXXXXXXXX

say your sprite starts with a left-top of 32x32 a right-top of 63x32, a left-bottom of 32x63 and a right-bottom of 63x63

this would equate to all four points being in the grid cell 1x1
now if you wanted to move diagonally to the right by a couple of pixels,
34x34 65x34

34x65 65x65

the bottom-right pixels when translated to the grid are in 2x2 which is obstructed.. so he can't move that way.


Does this explain what I'm on about? or did you understand before and I don't understand the problem?

Chesso
04-01-2007, 01:04 PM
Maybe I just don't understand this whole tiling thing, Iv'e tried it before but could never get my head around it for some reason.

How would I know which square he's on and which he's moving too, to check?

He wouldn't be moving from one square to another in each move like a chess piece, that would look a bit iff.

Paizo
04-01-2007, 01:36 PM
:o

for example with any game resolution you can do:

EDIT ( :oops: i invert row with column):

X position div 10 = column
Y div 10 = row

this for a 10x10 table.

but x and y usually is related to the upper left corner of your sprite, you have to adjust this part as Jasonf wrote.

this doesn't mean you have too move like chess!

jasonf
04-01-2007, 02:01 PM
I understand your concern about the jumpy movement, but it's not like that at all, certainly nothing like Chess or Checkers.

You'll still have pixel smooth movement. And you'll still draw your tiles as sprites in the usual way. The only thing is, in the background you've got an array telling you where the obstacles are.

what you could do is use an array as the definition of your maps.
Each type of tile has a number with a Zero as the ground (or anynumber, you may want different types of tiles as ground tiles. You could say if the tile type <5 then it's ground, otherwise, it's wall.

You know which tile he's on by checking the center of your sprite against the grid by dividing your X & Y positions by 32

You know which tile he's going to move to by writing a function like this.
(I'm at work and don't have access to Delphi, so I can't check if they syntax is 100% )


Procedure DoMove( blah blah )
begin

// About to move.. check each of the corners.

if ( checkNextSquareIsGround( X+moveAmountX, Y+moveAmountY) ) and
( checkNextSquareIsGround( X+width+moveAmountX, Y+moveAmountY) ) and
( checkNextSquareIsGround( X+moveAmountX, Y+moveAmountY+height) ) and
( checkNextSquareIsGround( X+width+moveAmountX, Y+moveAmountY+height) ) then
begin
X := X + moveAmountX;
Y := Y + moveAmountY;
end;

end;

function checkNextSquareIsGround( X,Y:integer ) : boolean
var
gridX,gridY : integer;
tileNumber : integer;
begin

// Get Grid location for pixel location.
gridX := x div 32; // 32 pixels per square.
gridY := y div 32;

if (gridx>=0) and (gridx<=10) and (gridy>=0) and (gridy<=10) then
begin

tileNumber := grid[gridx,gridy];

if tileNumber <5 then
begin
result := true;
end
else
begin
result := false;
end;
end
else
begin
result := false;
end;

end;

hopefully, this should give you an idea.

Then at the start of each level, when you want to create your wall sprites, go through the grid.
Place tiles at gridx*32, gridy*32 and set the image to the relevant image to the number in the grid array.

does this make sense?
[/pascal]

Chesso
04-01-2007, 02:05 PM
But using the uhh sprite engine, if I ended up using this method at some point is still allright?

Mainly because it handles the animations for me pretty well :P.

jasonf
04-01-2007, 02:22 PM
yeah, you'd still be using the sprite engine.

You would just not worry about collisions with wall sprites.. you'd let the grid code handle that.

I trust you have a few different types of sprites.

TPlayerSprite
TWallSprite
TBaddieSprite

You can tell which is which when the collision code is called. Just make sure pixel test is off on the wall sprites. Just do Nothing if you hit a wall.

Does this make sense?

Chesso
04-01-2007, 02:39 PM
True, but I don't think that stops the sprite engine from checking collisions, and then doing more additional checks (outside of the DoCollision event) would just be asking for a performance hit wouldn't :P.

If I could get my head around the code above for changing the bounding box I might be able to get the desired effect.

I modified it to what, well if I were to set the bounding box myself would work, but it doesn't seem to take it the way I would lol.

Chesso
06-01-2007, 06:31 PM
Wow this is confusing as hell.

Using chronozphere earlier method with the GetBoundsRect function, I added a call to draw either Rectangle, Flood Fill and FrameRect with input that matched what was put into Bounds();

And guess what happens......

It draws the LEFT and TOP a little away from the screens *Literal* LEFT and TOP (not the sprites) even if I use X, Y instead of WorldX and WorldY, and the RIGHT and BOTTOM drag themselves to follow a little away from the top left hand corner of the sprite.

Wth is that lol, I can't test why I'm getting it wrong if it goes whack like this lmao.

DraculaLin
06-01-2007, 08:41 PM
The fastest way is to use a 'dummy' block instead of real block. like wall,tile..etc.
The dummy block is samll,unvisible and you need adjust its position(for collision)
Your sprite is only collide with the 'dummy' block.The wall,tile... is just for 'show'.
So your sprite can walk through them(top half of his body) and have collision effect.

Chesso
07-01-2007, 12:29 AM
I think I know just what you mean, but I'd think that it does add just a little more to it then it could if I worked this bounding box problem.

I mean if I can manage (with code from earlier in this thread) to make it basically stop checking the bottom half, there must be a way to do the opposite or atleast I hope so lol.

Chesso
07-01-2007, 02:41 AM
Ok I have been playing around with the values, and come to the conclusion that this function is absolutely wack.

When using GetBoundsRect function and returning the result as Bounds(Left, Top, Width, Height).

The Left and Top are basicallly treated as his X and Y (if you set them to 0, he can't move).

Only the Width and Height, affect what part of his imagery that is collisions and it can *only* allow him to walk through stop of his bottom half, or on his right.

Doign the opposite, simply increases his bounds (so like sticking an invisible wall on opposite sides so it collisions earlier than it should).

No amount of mixing and matching can get the desired effect.

Either this function doesn't do what I think it does, or it is seriously screwed up lol.