Force player along path (sonic in 2.5D)

Hello,

During the development of my sonic fangame, I’ve been working on adding sections of 2.5D gameplay to the 3D environment. I use invisible planes that the player - sonic - can pass through that change the camera view from 3D to a side-view perspective, and vice versa. I’ve also been using similar planes that re-orient sonic to the orientation of the plane to keep in line with the path at all points.

This system, as I’ve actually only started actually implementing yesterday, generally works, but there’s circumstances that cause failures: (1) the position on the platform before the switch to 3D can cause sonic to fall off the platform edge given unfortunate circumstances, (2) should sonic mess up a loop somehow, he falls at a new position than he had begun with, resulting in him either getting stuck in the middle of the loop or falling off entirely (and sometimes, for whatever reason, this changes his rotation on the z-axis too), and (3) his velocity causes problems with sharp turns where his direction is forced to change, causing him to slide off of the platform in the direction that he was previously traveling.

Now, I’m well aware of Blendenzo’s 3D side-scrolling method that he shared back in 2007. I figured that this might be a decent way to force sonic across the 2.5D paths, however, it seems more oriented towards games that are purely from a 2.5D perspective. I’m not sure how to have this method work properly with multiple 2.5D sections existing throughout a level, and it doesn’t open the possibility for vast branching pathways.

Of course, while I was writing this thread, I accidentally stumbled upon this, something that appears to be the work of cyborg_ar (and, as I understand, a team of his as well) in some “Project S”. The videos are from 2008, but apparently not released until very recently; the point is, he(/his team) appears to have a really decent paths system worked out, as I saw in the second video from the thread. If no one reading this thread knows what he used for the paths system, ideas or suggestions for implementing something very similar would be awesome.

Thanks for reading, I’m hoping someone can be of assistance. A response from Cyborg himself would be epic, but either way =P

Sorry to bump, but my thread escaped to the 2nd page without a reply. =\

My current system of using invisible planes to block movement and using another type of invisible ghost plane to realign movement works, but poorly in that sometimes it fails altogether with keeping sonic properly aligned with the platform (causing him to veer too far to the edge and fall off or get stuck).

Any suggestions for a potential new and better system for 2.5D paths would be greatly appreciated!

Afterthought: I’m wondering if it’s possible to get the midpoint between the two edges of an object via python… I wouldn’t know where to begin with that, especially since the possibility of some platforms not being a strictly vertical or horizontal plane (y and x -axis, respectfully) adds a kink to that idea, whereas some might be at an angle.

I’m really beginning to wonder if I should try and see how I can use IPOs. I really don’t know, I’m rather new to the idea of using IPOs, I would think using them would mess up animations somehow and wouldn’t always work. I don’t know… can anyone offer anything on the matter?

My best advice is to learn the python API (particulary functions related to position, orientation, and velocity)

Invisible plans may work in some cases, but python would allow you to restrain your character with full freedom and without the clunky geometry.

For one thing you can use an invisible reference strip that a ray sensor on the player would send a ray towards, you then use python to get the hit normal (the face normal, property name is hitNormal), then use the vector information to set the orientation.

Before you get scared of the prospect of using Matrices the Mathutils functions that Blender has can convert the character’s current orientation matrix to a Euler (which is three simple values), then use a little math to modify the values you have for the hitNormal, change the Euler values to those, convert it back into a Matrix, and set the player’s orientation to the values of that Matrix.

As to restrain position after restraining orientation you would have it so that there’s always a counter-velocity when the velocity on a certain axis is above 0 or the counter-velocity is 0, the character say, gets pushed by something that would knock him off the path otherwise, the counter force would prevent that.

Considering you may just set the Character according to maybe just one of the values according to how you have the 2D path set up (like only the Z-orientation needs changing)

The more complicated stuff is only needed if you need the character to be rotated, if it’s just on a plane and rotation isn’t needed then it can simply be done through the ‘advanced’ tab in the physics and restrain the character using the built in options.

Sorry for not replying sooner, but thanks a lot for the detailed reply.

I’m afraid most of what you’ve suggested is over my head, I have worked with orientation and position a little already - mainly for things like springs and boosters, along with the projectiles badniks fire - but I don’t have enough python experience or the problem solving abilities to figure out how to accomplish this.

While I’m not asking for anyone to write something for me, I believe what I want to do - based on your suggestions - might be do-able through some editing of the slopes script I’m already using. It’s originally written by Cyborg_ar, with a few very slight changes I made for sound effects.

import GameLogic

def cross3d(v1, v2):
    "Finds the cross product of two 3d vectors."
    vect = [0, 0, 0]
    vect[0] = v1[1] * v2[2] - v2[1] * v1[2]
    vect[1] = v1[2] * v2[0] - v2[2] * v1[0]
    vect[2] = v1[0] * v2[1] - v2[0] * v1[1]
    return vect

def dot3d(v1, v2):
    "Returns the dot product of 2 3d vectors."
    return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]

def vec2mat(vect, track):
    if dot3d(vect, track) == 0:
        track.append(track[0])
        del track[0]
    z = vect
    x = cross3d(track,z)
    y = cross3d(z, x)
    return [
            [ x[0], y[0], z[0] ],
            [ x[1], y[1], z[1] ],
            [ x[2], y[2], z[2] ]
            ]

cont = GameLogic.getCurrentController()
own = cont.getOwner()
ray = cont.getSensor("ray")
c_floor = cont.getSensor("c_floor")
SFX = cont.getActuator("Land Grass SFX")

if ray.isPositive(): 
    ori = own.getOrientation() 
    ori = [ori[0][1], ori[1][1], ori[2][1]]
    norm = ray.getHitNormal()
    #print norm
    own.setOrientation(vec2mat(norm, ori))
    own.slopcount = 0
elif own.slopcount < 11:
    own.slopcount += 1
    if own.slopcount == 10:
        ori = own.getOrientation() 
        ori = [ori[0][1], ori[1][1], ori[2][1]]
        norm = [0, 0.000001, 1]
        own.setOrientation(vec2mat(norm, ori))

if c_floor.isPositive() | ray.isPositive():
    own.stepping = 1
    if own.jumping:
        own.jumping = 0
        own.spinning = 0
        SFX.setGain(1)
        GameLogic.addActiveActuator(SFX,1)
else:
    own.stepping = 0

I wouldn’t know where to start in order to manipulate this to work for 2.5D paths, so for now, I’m just going to continue using my current system. Cyborg’s Project-S resources are being slowly released, and from what I understand, he’ll also be releasing the programming used in the game, including his methods for proper 2.5D paths. I can’t wait to dig into some of the delicious things cyborg and his team have done for the project, especially with it being built in the BGE.