Climbing Walls

Blitz3D Forums/Blitz3D Programming/Climbing Walls

Nexinarus(Posted 2013) [#1]
hello

i have been struggling with this for a long time.

How do i get my character to cling/climb on any surface using the following [before editing] code. PS: it has jumping (no shooting yet. I am doing that last since I have figured that out within another file)



feel free to take a crack at it. I am stumped.


Kryzon(Posted 2013) [#2]
What do you mean by climbing? Is it something like this?



If so, you need to detect when you are in a condition to climb a surface. You need to detect what are the edges you can climb on to, and where you want the character to be in relation to each edge for him to be able to grab it.

This will be easier if you clean your code.
You have a lot of functionality spread out in the open that should be encapsulated in functions.
You also need to use Types so you can classify variables and objects in a more organized manner. Type Player, Type Cube etc.
If you organize your main loop into nothing but function calls, it's a great step.
Since there are no explanatory comments, if you let go of your code for a few weeks and get back to it, you'll be lost. It's better to add a good comment before each block of code, explaining what it's doing.

This isn't to appease to my eyes. This is to improve the way you deal with your code - if it's modular, it's easier to add functionality to it.


Nexinarus(Posted 2013) [#3]
I tried to clean up the code using some blitz examples. here is the new code



As for climbing, i want the character to be able to climb on all sides. Even bottom. (this is only for some characters but i need to figure it out first). I figured out jumping from the castle demo as you can see. I thought my code was somewhat organized but guess not now that i really look at it.

as for types, this is my first time using types so plz bare with me. I only used it for the cubes for now. One step at a time.

what do i mean by climbing?
like spider-man. Some characters in my game have that wall crawl ability.

By accident, i figured out how to wall jump. But that needs 2 walls close to eachother. That ability is cool too. But i got that one (in another code doc). i need actual wall-crawler climbing.

and what you said before
"If so, you need to detect when you are in a condition to climb a surface. You need to detect what are the edges you can climb on to, and where you want the character to be in relation to each edge for him to be able to grab it."

i never thought of that yet either. Good pointing out.

I am sorry that you could not understand my code tho. I thought it was straight forward. Yes with the loading stuff all out in the open it looked terrifying. The loop seemed ok. Move Jump/Up/Down/Left/Right. I tried looking at the castle demo for the organization. Since I do not fully understand the types, everything was put in the open.


Kryzon(Posted 2013) [#4]
Hi.
The code looks better, and I can understand what some of the variables are used for based on the comments. You should always aim for that and beyond (for instance, using the TAB key to align anything and everything).

The reason I suggest you use Types is because you can organize collections of variables with them.
I see a few other variables that also belong to the player but are declared in other parts, like 'plyrdir' and 'WALKSPEED'. All these could be stored in a type.

Type Character
	
	;Sprite handle for the character.
	
	Field entity
	
	;Movement information.
	
	Field walkSpeed
	Field dir#
	Field velUD
	Field tmpVUD
	Field velNS
	Field velN
	Field velS
	Field velWE
	Field velW
	Field velE

	;Skill information.
	
	Field doubleJumpSpeed#	;Speed with which the character does the ...
	Field doubleJump	;Flag that indicates if the character is ...
 
	Field grabbedWall	;Points to the handle of the mesh grabbed, or points to ZERO in case there's none grabbed. 
	Field grabbedNX#	;Components of the normal of the grabbed triangle.
	Field grabbedNY#	;"
	Field grabbedNZ#	;"
	Field helperPivot		;Handle to a Pivot used to help with the oriented movement.
	
End Type

Since you'll most likely have several characters in your game, you can do...
Global Player.Character = New Character

Global Enemy1.Character = New Character
Global Enemy2.Character = New Character

;Or even better, make functions for handling the creation of characters. 
;For example, a function that creates a Character instance, sets it up as an enemy 
;and returns the handle of this instance.
;This way you can use it like so:

Global Enemy1.Character = CreateCharacter( x, y, z, skill1, "Orc" )

Another way to consider Types is by breaking down functionality. Say the Player is a sort of character, and the enemies are also another sort of character, but the player and enemies have different settings.
Instead of having just one "Character" class for everything, you can break classes up into "building blocks" like this:
Type CharacterInfo

	;Information that each character should have.

	Field entity
	Field name$
	Field health
	Field armor

End Type

Type CharacterMovement
	
	;Movement information.
	
	Field walkSpeed
	Field dir#
	Field velUD
	Field tmpVUD
	Field velNS
	Field velN
	Field velS
	Field velWE
	Field velW
	Field velE

End Type

Type CharacterSkill
	
	;Skills information. Only used on the player and bosses.
	
	Field doubleJumpSpeed#	;Speed with which the character does the ...
	Field doubleJump	;Flag that indicates if the character is ...
 
	Field grabbedWall	;Points to the handle of the mesh grabbed, or points to ZERO in case there's none grabbed. 
	Field grabbedNX#	;Components of the normal of the grabbed triangle.
	Field grabbedNY#	;"
	Field grabbedNZ#	;"
	Field helperPivot		;Handle to a Pivot used to help with the oriented movement.

End Type

The enemies might only have movement information, but the player might have both movement and skill information:
Type Enemy
		
	Field info.CharacterInfo
	Field move.CharacterMovement

End Type

Type Player

	Field info.CharacterInfo
	Field move.CharacterMovement
	
	Field skills.CharacterSkills

End Type

Just remember to create instances of each "sub" Type along with the main instance:
Global myPlayer.Player = New Player
myPlayer.info = New CharacterInfo
myPlayer.move = New CharacterMove
myPlayer.skills = New CharacterSkills

;Or alternatively, have a single function that does all the work above of creating instances 
;and filling them with values, so creating a player becomes:

Global myPlayer.Player = CreateNewPlayer( playerSprite, "John", 100, 75 )
PositionEntity( myPlayer\info\entity, 10, 0, 30 )



Kryzon(Posted 2013) [#5]
Regarding the wall climbing, try something along these lines.
You can identify the class instance of an obstacle the player has collided with if you encode the Handle to that obstacle's instance in its entity's name.
Something like NameEntity( Wall\info\entity, Str( Handle( Wall ) ) )

;Somewhere in an update section...

col = EntityCollided( Player\info\entity, ObstacleType )

;If the player collided with an obstacle.

If col Then

	;Identify the obstacle's instance.

	Local tempName$ = EntityName( col )
	Local tempWall.Obstacle = Object.Obstacle( Int(tempName) )
	
	If tempWall\obstacle\isGrabbable Then
		
		Player\skills\grabbedWall = tempWall\info\entity 	

		;Identify the obstacle's collision contact information.
	
		For index = 1 to CountCollisions( Player\info\entity )
		
			If col = CollisionEntity( Player\info\entity, index ) Then
				Player\skills\grabbedNX = CollisionNX( Player\info\entity, index ) 	
				Player\skills\grabbedNY = CollisionNY( Player\info\entity, index )
				Player\skills\grabbedNZ = CollisionNZ( Player\info\entity, index )

				Exit
			EndIf
		
		Next
	EndIf
EndIf



;A Pivot is necessary for this. Create one, don't parent it to anything, just leave it still.

;First, divide the speeds like the original code.

Player\move\velWE = Player\move\velWE / 160.0
Player\move\velUD = Player\move\velUD / 32.0
Player\move\velNS = Player\move\velNS / 160.0

;If the player is grabbing a wall, make him climb it.

If Player\skills\grabbedWall Then

	;Align the pivot to the normal of the wall being crawled.

	AlignToVector( Player\skills\helperPivot, Player\skills\grabbedNX, Player\skills\grabbedNY, Player\skills\grabbedNZ, 2 )
	
	;Transform the player's movement speeds by this pivot.

	TFormPoint( Player\move\velWE, Player\move\velUD, Player\move\velNS, 0, Player\skills\helperPivot ) ;You may need to change the order of the speeds in this TForm command.
	Player\move\velWE = TFormedX()
	Player\move\velUD = TFormedY()
	Player\move\velNS = TFormedZ()

EndIf

;Proceed to move the player as usual.

MoveEntity( Player\info\entity, Player\move\velWE, Player\move\velUD, Player\move\velNS )
About Types in Blitz3D: http://home.cmit.net/rwolbeck/programmingtutorial/reference/types.htm

About the Object and Handle commands: http://blitzbasic.com/Community/post.php?topic=52936#591655


Nexinarus(Posted 2013) [#6]
im going to have to play around with this for a few days. All i can say is that i find arrays way simpler eheh. But ya i will give it a shot. Gimme a few days and lets see what happens


Kryzon(Posted 2013) [#7]
There are other ways to make the climbing, it depends on what you want.
That one above is more complex (but the code is incomplete nonetheless) - it's for when you have walls that may be tilted.

If the walls in your game are always straight, you can simplify the climbing by making the character only move up (any value in its Y axis).


Nexinarus(Posted 2013) [#8]
ok. Yes the walls are always vertical. But i was reading the code there is something i dont understand about it


EntityCollided( Player\info\entity, ObstacleType )

you never mentioned about a variable stating an obstacle type. do i put a countcollisions there or what?


Kryzon(Posted 2013) [#9]
ObstacleType = CLSN_OBJS.

But now that you mention it, the following is a better way to check for a climbing condition. It's the opposite way of what you're using to check for ground collisions, so it's something you're familiar with:
;This should be declared at the top.
Global climbingSomething% = 0

;The following should go inside UpdatePlayer, inserted between the "jump hit" and "move up/north" blocks.

If Not climbingSomething Then
	
	Local heCanClimb = False
	For checkAllCollisions = 1 To CountCollisions( player1 )
	
		;Identify the type of object collided by using the collision normal.
		;If the normal points horizontally, the player can only have collided
		;against a wall.
	
		If Abs( CollisionNY( player1, checkAllColisions ) ) < 0.001 Then
			
			;If the player is colliding against a wall, he can climb it if he wants to.
			heCanClimb = True	

		EndIf

	Next
	
	;If the player is colliding with at least one wall and the climbing button is pressed, begin climbing the wall.
	If heCanClimb Then climbingSomething = KeyDown( climbSkillKey )

Else
	;Update the state in case the player wants to let go of the wall.
	climbingSomething = KeyDown( climbSkillKey ) 
EndIf

;CHARACTER MOVEMENT.
;Move the character normally if he's not climbing anything, or if he is, move him up
;with the maximum walking speed.

If climbingSomething then
	If velWE Or velNS Then MoveEntity( player1, 0, (5*walkspeed)/160.0, 0 ) 
Else
	MoveEntity( player1, velwe/160.0, velud/32.0, velns/160.0 )	
EndIf
EDIT: Updated the code.


Nexinarus(Posted 2013) [#10]
i am definitely going to give this one a try. I never thought of holding a key down for climbing. I think that is brilliant. This way the player can choose to climb a wall or not. Thanx Kryzon.


Nexinarus(Posted 2013) [#11]
I did try your code Kryzon, and the character went up and up and up. maybe i added it in wrong or in the wrong places.

well this is what i came up with. It is still a work in progress. I even got the character to jump off walls.

here is the climbing code so far.



I hope i am on the right track. BTW Thanks Kryzon for all your help and ideas for this so far.

Anyone reading this post... I recommend to ask Kryzon for some helpful advice. He is definitly one of the best.


Nexinarus(Posted 2013) [#12]
I did try your code Kryzon, and the character went up and up and up. maybe i added it in wrong or in the wrong places.


well this is what i came up with. It is still a work in progress. I even got the character to jump off walls.

but here is the climbing code so far.




Nexinarus(Posted 2013) [#13]
Well i think i finished my climbing code.
change the old UpdatePlayer() with this one:

i commented the reversed velocity stuff because i do not think i will need it yet. At least to cancel it all i had to comment was the stuff at the top of the function with "Revel" the rest can remain since it wont work without the stuff from the top. I also left it there because i may do a confusion attacck which messes around with the other players movements heh. But that is later on.



so i guess i am done with this section. Thanx again Kryzon


*(Posted 2013) [#14]
One thing that I did when creating the first alphas of hunted was have climbable textures, when they player collided with something I checked what was hit and then the texture at that position. If its climbable inset climbing flag to true and they player could climb, if they moved away from it then the flash was set to false and they player fell to the floor.


fox95871(Posted 2013) [#15]
Bear in mind I am an evil, evil man. But when I've run into problems similar to this, my best solution has often been to eliminate them entirely. Like for example, I was getting a little tired of having to do about 50 frames for walking and running, so I just did some real world testing, that is, never running, and found out that works just fine for me! Even today I found out a place where I usually climb up can easily just be gone around, though I had to do a little searching. I know it's weird to answer like that, it's just I have so many stacks of modules like yours I ended up not even needing at all. Always consider how fun simple games usually are, and how disappointing complicated games tend to be. Keep your creations enjoyable for yourself, too.


Nexinarus(Posted 2013) [#16]
I do agree some complicated games are disappointing. Heck i find that some games now-a-days with great graphics tend to be way too easy. The game play is the most important thing.

And yes, if i do not enjoy my own game that i have created, i know no one else will. This is why i am testing things over and over. If i find i do not need something, i wont use it. But sometimes just figuring something out, even if i do need help a bit, or a lot does give me a sense of accomplishment. And who knows, if i don't need a specific thing for the current project, i may need it for the next. If not, i give the code to the community. If it helps someone great, if not... no big loss.

for example, for a long time, i tried to figure out jumping for 3D. With lots of questions, asking for help, and reading some blitz example code (castle demo) I figured out the jumping i wanted. Even charged jumping, which in my opinion is a bit better than double jump. When i had that completed, It actually felt good that i got to figure out something that I had trouble with, and the best way i thought to give back to the community (blitz), was to add it to the code archieves. This way if someone needs to figure out jumping in the future, there is something that might help others.

And no Fox95871, you were not being evil or mean. You were just stating your opinion. And I am only coding what i do need. And thank you for your advice. I will keep that in mind.