Another Basic Problem Door Open/Shut

Blitz3D Forums/Blitz3D Programming/Another Basic Problem Door Open/Shut

Spot(Posted 2003) [#1]
Allright, I may seem stupid, but I have been learning blitz for all of two days, and I am still having some difficulties.

I am trying to get a door to open and close using the same key (e).

My code is:

If KeyHit(18) Then
If EntityDistance#(p\entity,motellcd) < 20
If EntityYaw# (motellcd) = 0 Then
.Dooro
If doory<91 Then
doory=doory+1
RotateEntity motellcd,0,doory,0
Goto dooro
EndIf
EndIf
If EntityYaw# (motellcd) > 89 Then
.Doorc
If doory2>0 Then
doory2=doory2-1
RotateEntity motellcd,0,doory2,0
Goto doorc
EndIf

EndIf
EndIf
EndIf


Of course what happens is the door will open but not close. Is there any way of fixing this... I have gotten the code to work using two seperate keys, but not using the same key.


semar(Posted 2003) [#2]
Some advice:
1) NEVER USE GOTO - NEVER !

2) use a status to handle the door.

For example, when your door is closed, its status is D_CLOSED. When the door is in this status, and the player is near the door and press a key, then change the status to D_OPENING.

While in the status D_OPENING, open the door and continue to do so until the door is completely opened. When this is achieved, then change again the door status with D_OPENED; and so on.
Example:
;const values for door status
const D_OPENING = 1
const D_CLOSING = 2
const D_OPENED = 3
const D_CLOSED = 4

;main loop
while not keydown(1)
select door_status

case D_OPENING
;continue to open
opening_door()

case D_CLOSING
;continue to close
closing_door()

case D_CLOSED
;attempt to open the door
open_door()

case D_OPENED
;atempt to close the door
close_door()


end select
;end of main loop
wend
end

;===============================
function opening_door()
;===============================
If doory<91 Then 
doory=doory+1 
RotateEntity motellcd,0,doory,0
else
door_status = D_OPENED
endif

end function

;===============================
function closing_door()
;===============================
If doory2>0 Then 
doory2=doory2-1 
RotateEntity motellcd,0,doory2,0
else
door_status = D_CLOSED
endif
end function

;===============================
function open_door()
;===============================
If KeyHit(18) Then 
If EntityDistance#(p\entity,motellcd) < 20 
If EntityYaw# (motellcd) = 0 Then 
door_status = D_OPENING
endif
endif
endif
end function

;===============================
function close_door()
;===============================
If KeyHit(18) Then 
If EntityDistance#(p\entity,motellcd) < 20 then
If EntityYaw# (motellcd) = 0 Then 
door_status = D_CLOSING
endif
endif
endif
end function


Another advice is to use a type structure for your door, so to handle multiple doors having their proper flags:
type t_door
field status ;the door status
field speed# ;the speed used to move the door
field orientation ;x,y,z where the door should move to
field mesh ;the door model
field x#,y#,z# ;the position of the door in 3D world
end type
Global door.t_door

.
.
for door.t_door = each t_door
select door\status
case D_OPENING
opening_door(door)
.
.
.
next

function opening_door(door.t_door)
.
.
end function


Hope this has sense for you,
Sergio.


Warren(Posted 2003) [#3]
1) NEVER USE GOTO - NEVER !

Don't subscribe to the dogma, but use goto as a last resort. It can sometimes make code clearer than trying to wrap status flags around everything.


CyBeRGoth(Posted 2003) [#4]
Yeah there are some situations where a a goto is the best choice, or even the fastest, calling a function every game loop is not always as efficent as using a goto :)


Skitchy(Posted 2003) [#5]
This isn't exactly what you wanted, but it could be adapted pretty easily.

http://www.binary-people.com/downloads/lbexamplelevel.zip

It's a 'tech-demo' example I put together with LightBulb. The source is in there and it's pretty well commented. The doors are 'automatic' but could just as easily be activated by a keypress with a bit of creative coding.

Hope that's of some help.

:)


Spot(Posted 2003) [#6]
Well I got it eventually. Semars post was really helpful, although it took me a couple of hours to figure out doory had to be global :O. Oh well. Thanks for the help.


Spot(Posted 2003) [#7]
Okay.. Just a couple of more questions on this matter. I was attempting to use the type, because I want many doors in my level.

Here is my code:

Not in the main loop:

Type doorprop
Field status ; the door status
Field speed# ; the speed used to move the door
Field orientation ;x,y,z where the door should move to
Field mesh ;the door model
End Type

In the UpdateGame function (called in the main loop):

For door.doorprop = Each doorprop
Select door\status
Case D_OPENING
;continue To open
opening_door(door)

Case D_CLOSING
;continue To close
closing_door(door)

Case D_CLOSED
;attempt to open the door
open_door(door)

Case D_OPENED
;attempt to close the door
close_door(door)

End Select
Next

Below the above function:

Function opening_door(door.doorprop)
If EntityYaw# (motellcd)<90
doory=1
TurnEntity motellcd,0,doory,0
Else
door\status = D_OPENED
EndIf

End Function

Function closing_door(door.doorprop)
If EntityYaw# (motellcd)>0
doory=-1
TurnEntity motellcd,0,doory,0
Else
door\status = D_CLOSED
EndIf
End Function

Function open_door(door.doorprop)
If KeyHit(18)
If EntityDistance(dummy,motellcd)<10
door\status = D_OPENING
EndIf
EndIf
End Function

Function close_door(door.doorprop)

If KeyHit(18) Then
If EntityDistance(dummy,motellcd)<10
door\status = D_CLOSING
EndIf
EndIf
End Function



And finally in the setup:

motel=LoadAnimMesh( "motel\motellcdsep.3ds")
PositionEntity motel, 0,0,100
ScaleEntity motel, .15,.15,.15
EntityType motel, TYPE_SCENERY, 1
motellcd=FindChild( motel,"LCDDoor" )
door.doorprop = New doorprop
door\status=D_CLOSED

Now there are a couple of things.

1. With this code, nothing happens, I can go up to the door, hit E and nothing happens when it should.

2. Is there a way to have it so that it searches all of the entities within a model that have door or doors with consecutive numbers have the door open action applied to them?

Thank you in advance :).


semar(Posted 2003) [#8]
Hum...
1) Motellcd should be declared as Global
2) Did you have also declared the Consts for D_CLOSED, and such ?
3) put a stop in the related function that should be called, turn the debug on, and watch if the program stops as expected. Try with simple mesh - ex create a cube and scale it appropriately to make a door, and see if it opens and closes. When you have this working, then change the cube with the model you need, and check if it works too.

Is there a way to have it so that it searches all of the entities within a model that have door or doors with consecutive numbers have the door open action applied to them?

Well this is up to programming; I did not used yet the FindChild command, I guess you have to provide the child name$ for each door, so at every call you should create a new type, and assign an ID to it (just add an ID field in the door type, and assign a progressive value as you create new type elements).

Another method - which happens to be what I use - is to make a level without doors, then use Droplet (by Dr Av - look for it @ www.blitzcoder.com ) to place waypoints in your .B3D level.

Then, use the waypoints coordinates in the program, to position your doors - which could be, again, simple scaled cube, textured with whatever you like). Droplet comes with an useful example source code, so you can see how it works and use the functions to extract the values for each waypoints.

So each time you create a door (a cube), you create a type, and just assign the value you like to ID field:
type t_door
field x#,y#,z# ;coordinates
field the_door ;the entity
field ID ;ID number
end type
Global door.t_door
door.t_door = new t_door
door\x = ...
door\y = ...
door\z = ...
door\the_door = createcube()
scaleentity door\the_door,scalex,scaley,scalez ;the scale vaoues depend on the door orientation among the x,y,z axes
total_doors = total_doors + 1 ;a local variable that you increase at each door creation
door\id = total_door


Hope this helps,
Sergio.


Spot(Posted 2003) [#9]
Well your debug help really helped me... I got it working with the types and all...

Just one other question. How would I go about using the Type command to create many doors?


semar(Posted 2003) [#10]
Just one other question. How would I go about using the Type command to create many doors?

Do you mean the command to create a new type element ?
type t_door ;type declaration
field ... ;fields...
.
.
end type
Global door.t_door ;global pointer

;let's create 10 'doors'
for n = 1 to 10 ;loop from 1 to 10
door.t_door = New t_door ;Note the New statement. This creates a new door element
next


Being more specific, what I do is to place 'door' objects using Droplet (see above post), and then in the program, at the beginning of a level, I read each 'door' info from the .drp file generated by droplet, which contains the info related to each object placed from within droplet.

Then, simply check wich type of object should be created, and if it is a 'door', then... creates a door !!

Advice: Download droplet, is free and very useful. Have a play with it, position some object in your .B3D level, then use the object viewer - an handy function included in Droplet - and see how it works; I bet you can master it in a couple of minutes..

;-)

Hope this has sense for you,
Sergio.


Spot(Posted 2003) [#11]
Hmm... I still don't understand. I tried to create a new door by using the code

motellcd=FindChild( motel,"LCDoor" )
door.doorprop = New doorprop
door\status=D_CLOSED
door\mesh=motellcd


For one door, and

door1=FindChild( food,"door9" )
door.doorprop = New doorprop
door\status=D_CLOSED
door\mesh=door1

For the other.

Now with this code I can open the first door, but not the second, why? Also if I rem the first set of code (for the motellcd) I can open the second door (as such it isn't the code)...

What have I done wrong?

I am not too fond of using an external editor for placing my doors. They have all been placed and their origins have been worked out in my 3D program, so I should be able to seperate them...


semar(Posted 2003) [#12]
Do you loop through all the type collection, when you close/open a door ?
You have to control all the doors, not only one. If you use always the same door pointer, then you will only act on the same door.

I mean, in the section where the call to the open_door(door.t_door) function is, you should have a loop like:
For door.t_door = Each t_door
open_door(door)
.
.
next


In this way you loop through all the doors. If it works only with one door, is probably because the door pointer points always to the same type element...

More, you don't need to create a temporary mesh like you do with motellcd (and door1):
motellcd=FindChild( motel,"LCDoor" ) 
door.doorprop = New doorprop 
door\status=D_CLOSED 
door\mesh=motellcd 

You can write instead:
door.doorprop = New doorprop ;I would use t_door as type name, is more readable and mnemonic IMO.
door\mesh = FindChild( motel,"LCDoor" )
door\status = D_CLOSED 


Now open all doors !!! Then listen some song from 'The Doors' - LOL !
Sergio.


Spot(Posted 2003) [#13]
Hmm I did loop the Type collection like so

For door.doorprop = Each doorprop
Select door\status
Case D_OPENING
;continue To open
opening_door(door)

Case D_CLOSING
;continue To close
closing_door(door)

Case D_CLOSED
;attempt to open the door
open_door(door)

Case D_OPENED
;attempt to close the door
close_door(door)

End Select
Next

But that was the only type loop, does there have to be others?


semar(Posted 2003) [#14]
But that was the only type loop, does there have to be others?

No. It should work.

Check if 'door' points at different meshes each time - just inspect the value of door\mesh, you should get two values at each loop:
for..each
.
Debuglog.print door\mesh
.
next

Do you place the doors at corrected positions ?

Did you try with two simple cubes, one red and one green, and see if both can be opened/closed ?

Also, you seem to use always the same model when testing the distance with the player:
If EntityYaw# (motellcd)>0
and
If EntityDistance(dummy,motellcd)<10

You should use something like:
If EntityYaw# (door\mesh)>0 
and
If EntityDistance(dummy,door\mesh)<10 


Check this also for moving and rotation commands, and verify that you use the generic door\mesh, instead of the 'fixed' ones (motellcd for example).

Sergio.


Spot(Posted 2003) [#15]
Hmm... This is very strange.

When I write it to the Debug log thing I get two numbers written, and both doors work, but when I turn it off the doors don't work. Whats the problem?


Spot(Posted 2003) [#16]
BUMP! Any fixes?