PDA

View Full Version : better walls?



flyingmonkey456
July 19th, 2009, 11:48 PM
i know, i know, i know, this is the most overasked question on these forums. i know how to make walls work, i just want to know if there's a better way than to move the player in the opposite direction at the same speed it is walking. that way just seems like a workaround to me. and when i have a wall that can be hit from multiple directions, i either have to have a complex series of if statements finding what side of the wall the player is on, or several invisble movie clips on the edges of the wall. it just seems like there should be a better way.

TOdorus
July 20th, 2009, 12:35 AM
calculate t the time of collision. Since walls usually are veritical or horizontal (or any linear based line) this shouldn't be too hard. This works best when tilebased.

from my line class:


public var Start:Pos3//A pos3 is just an object with an x, y and z value. So a 3D coordinate.
public var End:Pos3
//
public function Line(START:Pos3, END:Pos3)
{
Start = START
End = END
}
public function getTforX(X:Number):Number {
var t:Number
if(End.x !== Start.x){
t = (X - Start.x) / (End.x - Start.x)
} else {
t = 0
}
return(t)
}
public function getTforY(Y:Number):Number {
var t:Number
if(End.y !== Start.y){
t = (Y - Start.y) / (End.y - Start.y)
} else {
t = 0
}
return(t)
}


Start should be the current position of the object. End should be the next position of an object, if time would've moved one frame. So the distance it would move from start to end is t = 1 (one frame). In other words: the current frame is t = 0 (start position). The next frame is t = 1 (end position). Just calculate the t for surrounding tiles/walls and if it is between 0 and 1 there is a collision between those frames. That way you can move it only as far as the time the collision detection gives you.

Say that it collides at t = .6. Then you multiply your speed.x and speed.y with .6 to get the position at the next frame.

flyingmonkey456
July 20th, 2009, 01:10 AM
i just got another idea kind of based on your idea. i could check all of the surrounding tiles and if one of them is a wall, disable movement in that direction. that would give a more realistic effect. thanks :)
i could even go a step further and do it by pixel. if the point one step way from you in a given direction pointtests true with a wall, movement in that direction is disabled.
for tiles, i could simply find the numbers of tiles bordering you and check a property of those to see if they're a wall. for points i could just make all of the walls one solid object and pointest the whole thing at once. would both of those be efficient?

Caravaggio
July 20th, 2009, 01:11 AM
Depending on how you have it set up you might use a hittestpoint. I've try them with parameters that vary on which way you're heading.

I press right, "heading right" bool is true, while true it fires a function that does a hittestpoint. The object is the movieclip that contains all my non-passable pieces and the actual hit test point is the player location + 10 or 20 points, whatever his width. If true, don't even move him that way. That way he doesn't even do the walking animation which looks silly when you can't move in that direction.

edt: heh, you posted pretty much that while I was typing.

How do you think you'd check a "passable" property of a wall tile? I've been thinking about that and haven't had luck thinking of a good way.

flyingmonkey456
July 20th, 2009, 01:16 AM
How do you think you'd check a "passable" property of a wall tile? I've been thinking about that and haven't had luck thinking of a good way.

if using movie clips, have a variable in each tile that's set to either 1 or 0. 1 for passable, 0 for unpassable. don't use booleans, they're inefficient. for bitmaps, have an array of passable tiles, and an array of unpassable tiles. :)

@todorus
man, you're up 20 posts on me. you were like 10 behind me before the weekend :)

TOdorus
July 20th, 2009, 07:46 AM
i just got another idea kind of based on your idea. i could check all of the surrounding tiles and if one of them is a wall, disable movement in that direction. that would give a more realistic effect. thanks :)
i could even go a step further and do it by pixel. if the point one step way from you in a given direction pointtests true with a wall, movement in that direction is disabled.
for tiles, i could simply find the numbers of tiles bordering you and check a property of those to see if they're a wall. for points i could just make all of the walls one solid object and pointest the whole thing at once. would both of those be efficient?

The first solution is the same as "to move the player in the opposite direction at the same speed it is walking", like you've put it. Either you move them back that distance, or don't move them the distance in the first place, the effect is the same. This would only work better if the movement itself is also tilebased.

The second solution is recursive, you probably need to check several times before you reach a wall, if you do at all. That would make it an expensive way to get precision. Also this precision isn't that precise, as you could easily go smaller than pixels when using math.

Clearly I'm no fan of both of them. I always try to find the time of collision with an equation, as it's as precise as the language can give it to you and you're not using recursion.

wallX = currentX + t * velocityX


if using movie clips, have a variable in each tile that's set to either 1 or 0. 1 for passable, 0 for unpassable. don't use booleans, they're inefficient. for bitmaps, have an array of passable tiles, and an array of unpassable tiles.

Actually that can also be done with movieClips as it's independent of view. Is checking a movieClip faster then checking an array?

btw how inefficient?


man, you're up 20 posts on me. you were like 10 behind me before the weekend :)

Now I'm more important than you :P

flyingmonkey456
July 20th, 2009, 12:19 PM
i'll try it both ways and see which works better for me :)

i would think that checking a 2d array would be slower than checking an integer in a movie clip. with a 2d array, you have to go through two "parents" (sort of), the 2d array and all of the arrays inside of it. for an integer in a mc you only have the mc as a parent. a normal array would probably be about the same speed. don't quote me on that, though.

and booleans aren's really THAT inefficient, someone said that in a loop with 16000000 iterations or something like that, it would take several more milliseconds to use booleans than integers. if you have a tilebased game and you have to check every tile in every frame, there could potentially be that many tiles, depending on the size of the tiles and the size of the map. if the map is 4000x4000 or more, you're at the 16000000. there could be even more than that if you're using tiles that are only a few px. the maps in classic rpg games like final fantasy and chrono trigger easily had that many, possibly more. that small bit of inefficiency can add up to a lot in certain situations.

therobot
July 20th, 2009, 01:29 PM
i'll try it both ways and see which works better for me :)

i would think that checking a 2d array would be slower than checking an integer in a movie clip. with a 2d array, you have to go through two "parents" (sort of), the 2d array and all of the arrays inside of it. for an integer in a mc you only have the mc as a parent. a normal array would probably be about the same speed. don't quote me on that, though.

and booleans aren's really THAT inefficient, someone said that in a loop with 16000000 iterations or something like that, it would take several more milliseconds to use booleans than integers. if you have a tilebased game and you have to check every tile in every frame, there could potentially be that many tiles, depending on the size of the tiles and the size of the map. if the map is 4000x4000 or more, you're at the 16000000. there could be even more than that if you're using tiles that are only a few px. the maps in classic rpg games like final fantasy and chrono trigger easily had that many, possibly more. that small bit of inefficiency can add up to a lot in certain situations.

Don't ints take up more memory than bools?

flyingmonkey456
July 20th, 2009, 02:05 PM
Don't ints take up more memory than bools?

i'm quoting someone else, don't ask me

therobot
July 20th, 2009, 02:10 PM
i'm quoting someone else, don't ask me

Who are you quoting, then?

Don't dole out advice if you're not sure what you're talking about.

flyingmonkey456
July 20th, 2009, 02:31 PM
Who are you quoting, then?

Don't dole out advice if you're not sure what you're talking about.

i don't remember who it was, it was a few weeks ago. i could probably search through my posts, but that would take forever. i should probably look up the numbers, but logically a boolean would use more memory than a number since it has more characters.

therobot
July 20th, 2009, 02:45 PM
[QUOTE=flyingmonkey456;2485955]i don't remember who it was, it was a few weeks ago. i could probably search%

flyingmonkey456
July 20th, 2009, 02:59 PM
uh.... you didn't say anything

bluemagica
July 20th, 2009, 03:06 PM
bools eat less memory! it is just one byte, int is 32!

As for collision walls, just check direction+speed for a collision, means if you are moving right by 4, check if this.x+4 hits a wall! if it hits then use a recursion or a for loop to check the least collision-free point, and snap there! That is what I always do!


Oh and arrays are faster when dealing with lots of movieclips, instead of direct naming all of them! Believe it or not, the display list, which you are working with in as3, is also an array!

flyingmonkey456
July 20th, 2009, 03:18 PM
bools eat less memory! it is just one byte, int is 32!

As for collision walls, just check direction+speed for a collision, means if you are moving right by 4, check if this.x+4 hits a wall! if it hits then use a recursion or a for loop to check the least collision-free point, and snap there! That is what I always do!


Oh and arrays are faster when dealing with lots of movieclips, instead of direct naming all of them! Believe it or not, the display list, which you are working with in as3, is also an array!

seriously? most languages compile a boolean as a 1 or 0 integer, how does flash do it?

as for walls, you said the same thing me and Caravaggio already said. thanks anyway. :pope:

therobot
July 20th, 2009, 03:39 PM
seriously? most languages compile a boolean as a 1 or 0 integer, how does flash do it?

as for walls, you said the same thing me and Caravaggio already said. thanks anyway. :pope:

dunno what happened to my post. it basically said the same thing bluemagica said:

bools SHOULD be cheaper than ints memory-wise, since a bool can be represented in 1 bit, whereas an int should require 32 bits. The fact that you have to type 'true'/'false' in flash should be irrelevant, as i believe that notation probably gets thrown out the window when the program is compiled.

I also added in my original post, that I have no idea whether any of this is true or not, since both ints and bools inherit from the object class.

flyingmonkey456
July 20th, 2009, 04:48 PM
an integer of 0 or 1 should also only use 1 bit since machine language is just a series of 0s and 1s. i couldn't find anything about memory usage for booleans, a link would be nice if you know one :)

TOdorus
July 20th, 2009, 05:10 PM
to base this offtopic discussion on facts
http://lab.polygonal.de/articles/bitvector/

therobot
July 20th, 2009, 05:57 PM
to base this offtopic discussion on facts
http://lab.polygonal.de/articles/bitvector/

Gotcha, so if I read that correctly, flash reserves 32 bits for a boolean anyways.

Here's a test. Ints are a bit faster than Booleans across 100,000,000 iterations, but not by that much (20-60ms on my comp). I would say if you really need to be doing 100,000,000 checks every frame, flash probably isn't the right tool for the job anyways. That, or you're doing something wrong :)




import flash.utils.getTimer;

var b:Boolean = true;
var n:int = 1;
var i:int;
var iterations:int = 100000000;
var startTime:int = 0;
var endTime:int = 0;
var elapsedTime:int = 0;

startTime = getTimer();

for (i = 0; i < iterations; i++)
{
if (b){
//
}
}

endTime = getTimer();
elapsedTime = endTime - startTime;
trace( "bool test took: " + elapsedTime );

startTime = getTimer();

for (i = 0; i < iterations; i++)
{
if (n){
//
}
}

endTime = getTimer();
elapsedTime = endTime - startTime;
trace( "int test took: " + elapsedTime );


Edit: performance tests like this & such nitty gritty optimizations of your code aren't nearly as important as getting the job done. You can always optimize later, after your game is done 8)

flyingmonkey456
July 20th, 2009, 08:44 PM
@TO (that's what i'm calling you now)
thanks for the link, i was pretty sure i knew what i was talking about and that clarified a lot :)

@rob (yep, you get a nickname too)
in some games, you would have to check certain properties of each tile every frame. if your map is really big, that small difference in memory can make a big difference in performance. also, integers have the ability to act like a 3 way switch. for example, jumping, standing, and falling could be handled in a single variable instead of three booleans and you will usually have 3 or more different states. using booleans in most situations would require 3x the amount of memory of using an integer or more. i usually don't just say stuff unless i have some reason to believe it, trust me when i say that an integer is much more efficient than a boolean. :)

Gnoll
July 20th, 2009, 11:19 PM
If you really want to you can save a boolean in a bit, (ByteArray) but it is probably unnecessary and possibly slower. If you use integers to save state you will probably have to define extra int constants to define what each state is.

Gnoll

flyingmonkey456
July 21st, 2009, 02:52 AM
If you really want to you can save a boolean in a bit, (ByteArray) but it is probably unnecessary and possibly slower. If you use integers to save state you will probably have to define extra int constants to define what each state is.

Gnoll

you would need to define the conditions required for each state to exist, but you would have to do that for booleans too. with booleans, not only do you have to store one boolean for each state, you also have to turn them back off when the state being defined is no longer true. it's like having three light switches and only one can be on at a time. it's much easier to just use a three way switch.

Gnoll
July 21st, 2009, 03:07 AM
Why would you need to define a Boolean state? You can just use
isLightOn:Boolean;
isLightDim:Boolean; OR


static const LIGHT_OFF:int = 0;
static const LIGHT_ON:int = 1;
static const LIGHT_DIM_AND_ON:int = 2;
static const LIGHT_DIM_AND_OFF:int = 3;

var state:int

flyingmonkey456
July 21st, 2009, 03:55 AM
Why would you need to define a Boolean state? You can just use
isLightOn:Boolean;
isLightDim:Boolean; OR


static const LIGHT_OFF:int = 0;
static const LIGHT_ON:int = 1;
static const LIGHT_DIM_AND_ON:int = 2;
static const LIGHT_DIM_AND_OFF:int = 3;

var state:int


not the way i do it. lets use standing, jumping, and falling as our three states. here's the code i would use.


onClipEvent ( load ) {
state = 0;
} onClipEvent ( enterFrame ) {
if ( Key.isDown ( Key.SPACE ) && state == 0){
state = 1;
} if ( state == 1 ){
this._y += 10;
} if ( this._y => 100 ) {
state = 3;
} if ( state == 3 ) {
this._y -= 10;
} if ( this._y =< 0 && state !== 0 ) {
state = 0;
} if ( state == 0 ) {
this._y = 0;
}
}


and for booleans:


onClipEvent ( load ) {
standing = true;
jumping = false;
falling = false;
} onClipEvent ( enterFrame ) {
if ( Key.isDown ( Key.SPACE ) && standing == true ) {
standing = false;
jumping = true;
falling = false;
} if ( jumping == true ) {
this._y += 10;
} if ( this._y => 100 ) {
standing = false;
jumping = false;
falling = true;
} if ( falling == true ) {
this._y -= 10;
} if ( this._y =< 0 && standing == false ) {
standing = true;
jumping = false;
falling = false;
} if ( standing == true ) {
this._y == 0;
}
}


if you know a better way please let me know, because that one is a bit long :)

EDIT: the boolean one is long, the integer one was pretty short. if you can do the same thing with booleans and make it shorter than the way i did it with integers, i'd be impressed :)

Gnoll
July 21st, 2009, 04:11 AM
a) I don't use AS2
b) untyped variables? x.x
c) Well you can just use your int but you should have some constant's there to tell people what those states mean.

Gnoll

flyingmonkey456
July 21st, 2009, 04:16 AM
a) I don't use AS2
b) untyped variables? x.x
c) Well you can just use your int but you should have some constant's there to tell people what those states mean.

Gnoll

i've said this before, i'm in the process of converting to as3.
what are untyped variable and is that a good thing?
nobody will be looking at the code when they play the game, so it's not necessary to add constants.

Gnoll
July 21st, 2009, 04:27 AM
An untyped variable well... doesn't have a defined type. I don't even know if you can do types in as2 but in as3 you would do var state:int or var state:Boolean and they would be of the type int / Boolean respectively. You can just do var state but it is way slower, not neat and very bad practice :)

Gnoll

Edit. What happens when you go back to your project in a year? What does 3 mean? Or 2? etc :P I think constants are good practice.

flyingmonkey456
July 21st, 2009, 04:48 AM
An untyped variable well... doesn't have a defined type. I don't even know if you can do types in as2 but in as3 you would do var state:int or var state:Boolean and they would be of the type int / Boolean respectively. You can just do var state but it is way slower, not neat and very bad practice :)

Gnoll

Edit. What happens when you go back to your project in a year? What does 3 mean? Or 2? etc :P I think constants are good practice.

i normally do it that way, but i was trying to cut down on small things like that so it wasn't too long. to remember what numbers mean what, i would put a comment next to where i declared the variable.

something i just thought of, do comments use memory or are they taken out during compilation?

Gnoll
July 21st, 2009, 04:55 AM
Comments are removed when compiled I am quite sure,
Gnoll

therobot
July 21st, 2009, 10:45 AM
Comments are removed when compiled I am quite sure,
Gnoll

I would use the constants. When you are ready to actually release your game, it would take a few minutes to find&replace those constants if you really needed to.

TOdorus
July 25th, 2009, 11:38 PM
Comments are removed when compiled I am quite sure,
Gnoll

That made me chuckle, the Flash compiler is quite a joke. I wouldn't be surprised if it didn't do such a thing.


I would use the constants. When you are ready to actually release your game, it would take a few minutes to find&replace those constants if you really needed to.

You're inferring to the fact that the compiler doesn't replace all the constants with the actual value (and saving an lookup to find the value of the constant)? It makes defining something as a constant is pretty much useless as it's the same as just declaring it a normal variable.

therobot
July 30th, 2009, 03:03 PM
Gotcha, so if I read that correctly, flash reserves 32 bits for a boolean anyways.

Here's a test. Ints are a bit faster than Booleans across 100,000,000 iterations, but not by that much (20-60ms on my comp). I would say if you really need to be doing 100,000,000 checks every frame, flash probably isn't the right tool for the job anyways. That, or you're doing something wrong :)




import flash.utils.getTimer;

var b:Boolean = true;
var n:int = 1;
var i:int;
var iterations:int = 100000000;
var startTime:int = 0;
var endTime:int = 0;
var elapsedTime:int = 0;

startTime = getTimer();

for (i = 0; i < iterations; i++)
{
if (b){
//
}
}

endTime = getTimer();
elapsedTime = endTime - startTime;
trace( "bool test took: " + elapsedTime );

startTime = getTimer();

for (i = 0; i < iterations; i++)
{
if (n){
//
}
}

endTime = getTimer();
elapsedTime = endTime - startTime;
trace( "int test took: " + elapsedTime );


Edit: performance tests like this & such nitty gritty optimizations of your code aren't nearly as important as getting the job done. You can always optimize later, after your game is done 8)


I did another test, this time testing bools against a bit mask. bools are twice as fast.



import flash.utils.getTimer;

var b:Boolean = true;
var m:int = 0;
var bit1:int = 1;
var i:int;
var iterations:int = 100000000;
var startTime:int = 0;
var endTime:int = 0;
var elapsedTime:int = 0;

startTime = getTimer();

for (i = 0; i < iterations; i++)
{
if (b){
//
}
}

endTime = getTimer();
elapsedTime = endTime - startTime;
trace( "bool test took: " + elapsedTime );

startTime = getTimer();

for (i = 0; i < iterations; i++)
{
if (m & bit1){
//
}
}

endTime = getTimer();
elapsedTime = endTime - startTime;
trace( "int test took: " + elapsedTime );


edit: if anyone cares :)