Various objects cargo trolleys

BlitzMax Forums/BlitzMax Programming/Various objects cargo trolleys

Yue(Posted 2016) [#1]




I have a problem, when on stage, I have a single freight truck that pulls the tractor, everything works fine, it hooks from either of its two hooks without problem.

If I put two cars, it does not work, any suggestions?




Derron(Posted 2016) [#2]
I found something. Please don't wonder, I reformatted your code so i can see it better "in total".

' - Enganchar / Desenganchar.
	Method Enganchar()
		For local cargos:TCargo = EachIn cargos.lista
			If xEntityDistance (cargos.ganchos[0], gancho ) <= 3.0
				gancho1 = True
				
				If unionGancho:Int =  0 
					xShowEntity ( gancho ) 
				Else 
					xHideEntity ( gancho )
				End If 
				
				engancha = True
							
			ElseIf xEntityDistance (cargos.ganchos[1], gancho ) <= 3.0
			    gancho2 = True

				If unionGancho = 0 
					xShowEntity ( gancho ) 
				Else 
					xHideEntity ( gancho )
				End If 
 						
				engancha = True											
			Else 
				gancho1 = False
				gancho2 = False
			
				xHideEntity ( gancho )

				engancha = False
			End If 
		Next 
	
		If xKeyHit(xKEY_T)
			JointBisagra()
		End If
	End Method


There is this variable "engancha".
It is set to "true" if distance between two entities is smaller than 3.0
It is set to "false" if that is not the case.

Now to the problem: you set it "false" in EVERY case if a "gancho" is not unioned.

Example:
cargos 1 of the list has "cargos.ganchos[1]" in distance < 3.0, it sets "engancha" to "true".
now you go on to the next cargos:
cargos 2 of the list has no "ganchos"-distance < 3.0, sets "engancha" to "false".

So as soon as one cargos after a "connecting one" is not connecting, "engancha" will be set to "false".


What you might want, is that "engancha" stays "true" if at least one of the catgos is connecting.


Also: you doubled code which is not necessary. So what did I do in the following code? I disabled the ganchos before the loop - and if one of the ganchos is connecting, I enable it.

' - Enganchar / Desenganchar.
	Method Enganchar()
		'set to false in all cases
		engancha = False
		gancho1 = False
		gancho2 = False


		For local cargo:TCargo = EachIn cargos.lista
			If xEntityDistance (cargo.ganchos[0], gancho ) <= 3.0
				gancho1 = True
				engancha = True
							
			ElseIf xEntityDistance (cargo.ganchos[1], gancho ) <= 3.0
				gancho2 = True
				engancha = True											
			End If 
		Next 

		'display the gancho if gancho1 or gancho2 got enabled
		If unionGancho = 0 and (gancho1 or gancho2)
			xShowEntity ( gancho )
		else
			xHideEntity ( gancho )
		End If 
	
		If xKeyHit(xKEY_T:Int)
			JointBisagra()
		End If
	End Method



But this _still_ has a flaw: this allows multiple cargos to connect to the same "gancho". So the following does a "first checked, first served" approach. An alternative would be to find the "closest" one (with lowest distance) and use that as the connecting one.

Also: you do not store the information _which_ cargo is connecting. But this is needed, so I appended a param "cargo" to the second method (the one doing the joint)


' - Enganchar / Desenganchar.
	Method Enganchar()
		'set to false in all cases
		engancha = False
		gancho1 = False
		gancho2 = False

		local connectingCargo:TCargo = null

		For local cargo:TCargo = EachIn cargos.lista
			If xEntityDistance (cargo.ganchos[0], gancho ) <= 3.0
				gancho1 = True
				engancha = True

				connectingCargo = cargo

				'exit for loop, we found our gancho to use
				exit
							
			ElseIf xEntityDistance (cargo.ganchos[1], gancho ) <= 3.0
				gancho2 = True
				engancha = True

				connectingCargo = cargo

				'exit for loop, we found our gancho to use
				exit
			End If 
		Next 

		'display the gancho if gancho1 or gancho2 got enabled
		If unionGancho = 0 and (gancho1 or gancho2)
			xShowEntity ( gancho )
		else
			xHideEntity ( gancho )
		End If 
	
		If xKeyHit(xKEY_T)
			JointBisagra( connectingCargo )
		End If
	End Method





Ok, now to the method doing the "connecting":
This time you do not allow multiple cargos to connect to the same gancho. As you disconnect a previously connected one if it "unionGancho" is "false".
But there is still a flaw: you loop over all of them and connect-disconnect-connect ... because "gancho1" or "gancho2" are true ... and they keep being "true" in the whole loop.

And there is this BIG logical bug: you connect to the first cargo you find - even if this is NOT the one within <3.0 distance. You just do not store that information!


As we now added the cargo to join, we do not need to loop over all cargos in the list.



Here is your code reformatted (with still the flaw being in):
	' - Unión Bisagra.
	Method JointBisagra()
		Local cargos:TCargo = Null 
	
		For cargos:TCargo = EachIn cargos.lista
			If unionGancho = False
				If gancho1 = True
					unionGancho =  xCreateD6SpringJoint(chassis.malla, cargos.chassis.malla, 0, 4, -19.5, 0, 0.5, -21,      0, 0)
				ElseIf gancho2 = True
					unionGancho =  xCreateD6SpringJoint(chassis.malla, cargos.chassis.malla, 0, 4, -19.5, 0, 0.5, 21,   0, 0)
				End If 
			Else 
				xFreeJoint( unionGancho )
				
				unionGancho = 0
			End If 			
		Next 
	End Method 



Now we do the following:
- check if there is a cargo who unions, if not, remove the union
- create a union for the first cargo on gancho1 or gancho2

To enable "both unions" simultaneously, "unionGancho1" and "unionGancho2" need to get introduced instead of "unionGancho"


	' - Unión Bisagra.
	Method JointBisagra( cargo:TCargo = null )
		'having no gancho used?
		'no cargos to join means "remove current join" ?
		'-> remove the joint
		if not cargo or not(gancho1 or gancho2)
			if unionGancho
				xFreeJoint( unionGancho )
				unionGancho = 0
			endif

			'no need to do the join-code as we do not want to join something
			return
		endif

		'connect to the given cargo
		If gancho1 = True
			unionGancho =  xCreateD6SpringJoint(chassis.malla, cargo.chassis.malla, 0, 4, -19.5, 0, 0.5, -21,      0, 0)
		ElseIf gancho2 = True
			unionGancho =  xCreateD6SpringJoint(chassis.malla, cargo.chassis.malla, 0, 4, -19.5, 0, 0.5, 21,   0, 0)
		End If
	End Method



_I_ would do it a bit different. To make "JointBisagra" something you could call to freely join/disconnect a cargo, that function should check too, which "gancho" to use. This then would make a "field gancho1:int = false" (and gancho2 too) obsolete/unneeded.
Also "engancha" should not be set by the first method but should be updated in "JointBisagra" as this is defining whether it is joined or not.



So here is my complete suggestion:

' - Enganchar / Desenganchar.
	Method Enganchar()
		'=== find a cargo to connect ===	

		local connectingCargo:TCargo = null
		'store the used gancho here, so "xEntityDistance()" is not called
		'again in JointBisagra()
		local useGancho:int = 0
		For local cargo:TCargo = EachIn cargos.lista
			If xEntityDistance (cargo.ganchos[0], gancho ) <= 3.0
				connectingCargo = cargo
				useGancho = 1

				'exit for loop, we found our gancho to use
				exit
							
			ElseIf xEntityDistance (cargo.ganchos[1], gancho ) <= 3.0
				connectingCargo = cargo
				useGancho = 2

				'exit for loop, we found our gancho to use
				exit
			End If 
		Next 


		'connect/disconnect
		If xKeyHit(xKEY_T)
			JointBisagra( connectingCargo, useGancho )
		End If


		'display the gancho?
		If unionGancho = 0
			xShowEntity ( gancho )
		else
			xHideEntity ( gancho )
		End If 
	End Method
	
	
	' - Unión Bisagra.
	Method JointBisagra( cargo:TCargo = null, useGancho:int=0 )
		'having no gancho used?
		'no cargos to join means "remove current join" ?
		'-> remove the joint
		if not cargo
			if unionGancho
				xFreeJoint( unionGancho )
				unionGancho = 0
			endif

			engancha = False

			'no need to do the join-code as we do not want to join something
			return
		endif

		'find gancho to use - if not already defined as param
		if useGancho = 0
			if xEntityDistance (cargo.ganchos[0], gancho ) <= 3.0
				useGancho = 1
			elseif xEntityDistance (cargo.ganchos[1], gancho ) <= 3.0
				useGancho = 2
			else
				'here you could define a default - so you could force a connection
				'useGancho = 1 ??
			endif
		endif

		'connect to the given cargo using the given gancho
		'also mark "engancha" to be connected
		Select useGancho
			case 1
				unionGancho =  xCreateD6SpringJoint(chassis.malla, cargo.chassis.malla, 0, 4, -19.5, 0, 0.5, -21,      0, 0)
				engancha = True
			case 2
				unionGancho =  xCreateD6SpringJoint(chassis.malla, cargo.chassis.malla, 0, 4, -19.5, 0, 0.5, 21,   0, 0)
				engancha = True
			default
				'you could add a default union spot if no gancho was found
		End Select
	End Method 


Code might contain errors, as I just wrote it without syntax check.



bye
Ron


Derron(Posted 2016) [#3]
Regardless of above, I am not really satisfied with the code at all.

- you check for a pressed key within a method, better do this within your main loop (splitting "logic" and "input" apart)



'somewere in your update-loop:
'connect/disconnect
If xKeyHit(xKEY_T)
	if yourCar.connectedCargo
		yourCar.DisconnectCargo()
	else
		'THIS could be done also without "xKeyHit"
		'so it automatically connects if someone is in range
		'- only do this "if yourCar.connectedCargo = null"
		local cargoInRange:TCargo = yourCar.FindCargoInRange( 3.0 )
		if cargoInRange
			yourCar.ConnectCargo( cargoInRange )
		endif
	endif
End If



'In your type
'REMOVE "Field engancha:int"
'REMOVE method "Enganchar()"
'ADD:
	Field connectedCargo:TCargo = null


	Method FindCargoInRange:TCargo( range:Float = 3.0 )
		For local cargo:TCargo = EachIn cargos.lista
			local cargoGancho:int = FindNextCargoGancho( cargo, range )
			For local cargoGancho:int = EachIn cargo.ganchos
				if xEntityDistance (cargoGancho, gancho ) <= range
					return cargo
				endif
			Next
		Next
		return null
	End Method


	Method FindGanchoInRange:int( range:Float = 3.0 )
		For local cargo:TCargo = EachIn cargos.lista
			local cargoGancho:int = FindNextCargoGancho( cargo, range )
			'found a useful gancho
			if cargoGancho<>0 then return cargoGancho
		Next
		return 0
	End Method


	Method FindNextCargoGancho:int( cargo:TCargo, range:Float = 3.0 )
		if not cargo then return 0

		For local cargoGancho:int = EachIn cargo.ganchos
			if xEntityDistance (cargoGancho, gancho ) <= range
				return gancho
			endif
		Next
		
		return 0
	End Method
		

	Method DisconnectCargo()
		ConnectCargo( null, 0)
	End Method
	
	
	Method ConnectCargo( cargo:TCargo = null, useGancho:int=0 )
		'having no gancho used?
		'no cargos to join means "remove current join" ?
		'-> remove the joint
		if not cargo
			if unionGancho
				xFreeJoint( unionGancho )
				unionGancho = 0
			endif

			connectedCargo = null
		endif


		if cargo
			'find gancho to use - if not already defined as param
			if useGancho = 0
				if xEntityDistance (cargo.ganchos[0], gancho ) <= 3.0
					useGancho = 1
				elseif xEntityDistance (cargo.ganchos[1], gancho ) <= 3.0
					useGancho = 2
				else
					'here you could define a default - so you could force a connection
					'useGancho = 1 ??
				endif
			endif

			'connect to the given cargo using the given gancho
			'also mark "engancha" to be connected
			Select useGancho
				case 1
					unionGancho =  xCreateD6SpringJoint(chassis.malla, cargo.chassis.malla, 0, 4, -19.5, 0, 0.5, -21,      0, 0)
					connectedCargo = cargo
				case 2
					unionGancho =  xCreateD6SpringJoint(chassis.malla, cargo.chassis.malla, 0, 4, -19.5, 0, 0.5, 21,   0, 0)
					connectedCargo = cargo
				default
					'you could add a default union spot if no gancho was found
			End Select
		endif


		'display the gancho?
		If connectedCargo
			xShowEntity ( gancho )
		else
			xHideEntity ( gancho )
		End If 
	End Method 



- put that xKeyHit within your update loop
- remove the Field and the method I wrote in the comment
- if you have somewhere checks for "engacha", replace them with "if connectedCargo"


What benefit do you get from this approach:

- you can freely call "mycar.DisconnectCargo()" to ... disconnect the cargo ;-)
- you can freely call "mycar.ConnectCargo( cargo, ganchoToUse )" even when not in range
- you can call "mycar.FindCargoInRange(123.0)" which returns the first cargo within range (here as example "123.0")
- you can call "mycar.FindGanchoInRange(123.0)" which returns the first gancho (of all cargos) in range
- you can call "mycar.FindNextCargoGancho(cargo, range)" to return the nearest gancho of a cargo within range


For now you might not need all of these functions but they add a bit of convenience. So it is easier to retrieve which cargo is the nearest, which gancho is the nearest ...


bye
Ron


Yue(Posted 2016) [#4]
Hi Derron.

I'm progressing. If it was a few years ago, I would think that I would create the algorithm for each freight wagon, however, doing it once and running 100 wagons or whatever number is very rewarding.

In this case I have already managed to show the hitch indicator regardless of the wagon to which the tractor hook and the hook of the wagon approaches.

I continue to hook and unhook.



Derron(Posted 2016) [#5]
My suggested code already should handle hooking unhooking.


This is why the code is longer than yours...it added flexibility.
Please at least have a look at it...as your coxe contained logical flaws and my code shows ways to circumvent that.

Bye
Ron


Yue(Posted 2016) [#6]
The advances are thanks to your code, I am moving to the phase to correctly implement the hitch. And unhooking :)


Yue(Posted 2016) [#7]
Okay, Derron, this is already perfect. I'm uploading a video to youtube. But this is a nightmare, some video implements of 60 megs hard to climb two and a half hours. :(

The fact is that I can create a lot of wagons and when approaching the tractor can hook them by any of its two points of engagement. :)


Derron(Posted 2016) [#8]
You do not need to upload every new piece of functionality as a youtube video...save your bandwidth.


With my functions you could also auto-hook a cargo as soon as you do not have a connectedCargo in that moment and are having a CargoGancho in Range.so it becomes like "snapping".

ou could even do a little game out of it... Cargo with different colors need to get driven to places with colored grounds.
Soundsike a little fun arcade game.


If interested we could think about additional twists to the gameplay.

Bye
Ron


Yue(Posted 2016) [#9]
Ok, Vědeo finish uploading.


I'm really interested in making a game, I think I've learned enough but not everything. What worries me is that I do not know anything about shaders. And this is necessary for advanced effects like mapping protrusions and things like that.


What turns could this game have ?, good ideas would help me a lot. :)

Gretins.







Derron(Posted 2016) [#10]
- sort cargos (either colorized cargos, or cargo of different designs - with barrels, with suitcases/bags, ...)
- cargo-bowling (see showcase-thread)

You might mix your fork-lift-game-idea in
- multiple cars in one game (forklift, cargo-lifter ...)

For all cars:
- have narrow paths on which you need to drive, so it is like "do not hit the walls" games. These paths/ways of course need to get more and more difficult (curves, bridges, obstacles...). And time is running out ;-)


But: As a first step we should "brainstorm" about whether it would be better to use just one of the ideas - and then improve it (or split it into multiple "variants").

Then use these ideas to do a first "game mode" (but already prepare your code to allow for more levels). Then at a later stage you could code the next "game mode" - and once this is working, you could bring in the new code to the other game (with the first "game mode").


bye
ron