How would you implement an auto-walk function?

Discuss modding questions and implementation details.
User avatar
Hazelnut
Posts: 1389
Joined: Sat Aug 26, 2017 2:46 pm
Contact:

Re: How would you implement an auto-walk function?

Post by Hazelnut » Fri Sep 21, 2018 10:28 pm

Yeah I agree. I did have some daydreams about making a travel mod myself involving carriages where you would see the journey in real time with variable time acceleration buttons but felt that was probably not going to work until roads have been modded in, and that's not a trivial task.

User avatar
Interkarma
Posts: 4721
Joined: Sun Mar 22, 2015 1:51 am

Re: How would you implement an auto-walk function?

Post by Interkarma » Fri Sep 21, 2018 10:45 pm

It seems you've resolved your issues. In any case, here's some more detail I put together for you. You can work out target location rect from anywhere without needing to wait for location to load first. May be helpful later on.

Code: Select all

// Get player's current horizontal position in exterior world
PlayerGPS playerGPS = GameManager.Instance.PlayerGPS;
int worldX = playerGPS.WorldX;
int worldZ = playerGPS.WorldZ;

// Safely get target location detail by name (can also use index overload)
DFLocation targetLocation;
if (!DaggerfallUnity.Instance.ContentReader.GetLocation("Daggerfall", "Gothway Garden", out targetLocation))
    return;

// Get the longitude/latitude of location
int longitude = targetLocation.MapTableData.Longitude;
int latitude = targetLocation.MapTableData.Latitude;

// Convert longitude/latitude into map pixel position
DFPosition mapPixel = MapsFile.LongitudeLatitudeToMapPixel(longitude, latitude);

// Convert map pixel into world coordinates (SW corner of map pixel in world space)
DFPosition worldCoord = MapsFile.MapPixelToWorldCoord(mapPixel.X, mapPixel.Y);

// Following is a helper to get actual location rect in world space directly from DFLocation data
// I've added this to the code now as DaggerfallLocation.GetLocationRect()

/// <summary>
/// Helper to get location rect in world coordinates.
/// </summary>
/// <param name="location">Target location.</param>
/// <returns>Location rect in world space. xMin,yMin is SW corner. xMax,yMax is NE corner.</returns>
public static Rect GetLocationRect(DFLocation location)
{
    // This finds the absolute SW origin of map pixel in world coords
    DFPosition mapPixel = MapsFile.LongitudeLatitudeToMapPixel(location.MapTableData.Longitude, location.MapTableData.Latitude);
    DFPosition worldOrigin = MapsFile.MapPixelToWorldCoord(mapPixel.X, mapPixel.Y);

    // Find tile offset point using same logic as terrain helper
    DFPosition tileOrigin = TerrainHelper.GetLocationTerrainTileOrigin(location);

    // Adjust world origin by tileorigin*2 in world units
    worldOrigin.X += (tileOrigin.X * 2) * MapsFile.WorldMapTileDim;
    worldOrigin.Y += (tileOrigin.Y * 2) * MapsFile.WorldMapTileDim;

    // Get width and height of location in world units
    int width = location.Exterior.ExteriorData.Width * MapsFile.WorldMapRMBDim;
    int height = location.Exterior.ExteriorData.Height * MapsFile.WorldMapRMBDim;

    // Create location rect in world coordinates
    Rect locationRect = new Rect() {
        xMin = worldOrigin.X,
        xMax = worldOrigin.X + width,
        yMin = worldOrigin.Y,
        yMax = worldOrigin.Y + height,
    };

    return locationRect;
}
jedidia wrote:
Fri Sep 21, 2018 10:02 pm
That's exactly what I expected, but it turns out that those coordinates only refer to the Map Pixel. I.e. it's always the same for both the map pixel and the location inside that map pixel.
WorldX and WorldZ coordinates are the player's absolute position in world space. With the above code, you can compare player's absolute coordinates vs. the absolute coordinates of any location in the world. I use this extensively in the quest system to determine if player is in correct city, within a location area, etc.

In any case, happy to hear you're making progress. I'll bow out of this one now. :)

jedidia
Posts: 129
Joined: Sat Sep 15, 2018 9:49 am

Re: How would you implement an auto-walk function?

Post by jedidia » Sat Sep 22, 2018 10:54 am

Great, thanks a lot everybody, especially Interkarma! :)
felt that was probably not going to work until roads have been modded in, and that's not a trivial task.
Yeah, I'm not going to bother with roads... Just point as the crow flies. Might have some weird results in mountainous regions, but I'm not going for perfection here. The main point will be to see how long it actually *takes*.

User avatar
Jay_H
Posts: 2538
Joined: Tue Aug 25, 2015 1:54 am

Re: How would you implement an auto-walk function?

Post by Jay_H » Sat Sep 22, 2018 3:14 pm

Something to consider is to grant the PC no-clip status. Every once in a while there'll be a town with a building, like those in L-shape, that'll trap him or her and make the journey endless. It'll be rare, but something sufficiently important to think about, I believe.
Come join the Unofficial Daggerfall Unity Discord.
See the Daggerfall Unity Wiki on the UESP.
Progress on fixing classic quests here.

jedidia
Posts: 129
Joined: Sat Sep 15, 2018 9:49 am

Re: How would you implement an auto-walk function?

Post by jedidia » Sat Sep 22, 2018 8:58 pm

It'll be rare, but something sufficiently important to think about, I believe.
Not actually as rare as you think... happens all the time, in fact. Good forward-thinking skills there! :) I haven't taken care of it yet because it's not quite the priority at this point, so I haven't looked into how to do that yet. Do I have to get the players collider and turn it off, or is there something in the daggerfallworkshop API to facilitate this?

jedidia
Posts: 129
Joined: Sat Sep 15, 2018 9:49 am

Re: How would you implement an auto-walk function?

Post by jedidia » Sun Sep 23, 2018 8:17 pm

Hummmm, turning off that collision detection is turning out to be a problem. I fully anticipated that I'd have toe look a bit for how to set it, but I'm running out of ideas.

The PlayerController conveniently provides a property "detectCollisions". Most inconveniently, this property does not have any effect.
So I noticed the PlayerCollision script, dug that out of the component tree and disabled it. That too has no effect.
Finally I dug out the player objects very own collider and disabled that, only to realise that now the player couldn't move at all. The reason for this is pretty simple once I took a closer look: The PlayerController I tried first *is* the colider (it inherits it), so effectively I was having the same object on hand as before, and since there's no player model or anything, that collider really is the physical representation of the player in the game world. If it's disabled it can't move, hence the player can't move. That's the way it looks to me right now anyways.
It also seems to be a time-honored unity hack to turn colliders into triggers for this purpose, but if I try to do that the CharacterController explicitly slaps me with an exception.
From where I stand right now, I don't think disabling collision detection for the player is possible unless specifically supported by the API. Have I missed something here?

User avatar
Interkarma
Posts: 4721
Joined: Sun Mar 22, 2015 1:51 am

Re: How would you implement an auto-walk function?

Post by Interkarma » Sun Sep 23, 2018 11:52 pm

Yep, the CharacterController is responsible for both movement and collisions. But even if you could just switch off collisions, you probably don't want to do this anyway as player would just fall through terrain. There's at least two other ways you could approach this.

First approach is add steering behaviour to make player route around location areas. Wouldn't need true pathfinding or anything like that, just basic obstacle avoidance. If you really wanted to go nuts with it, you could route player towards nearby taverns automatically once a day, and allow player to start/stop journey as they wish. Then they could do a little RP in town before resuming their journey.

Second approach if you just want to ghost through towns in a straight line for now is disable CharacterController and move player object manually via its transform.position. You can keep them aligned above terrain using a raycast down from current position. Set controller active again when player ends cruise control. Will probably want to toggle a couple of other movement-related components as well to avoid any weird side-effects of controller being disabled.

It will be interesting to see where you go with this once the early problems are solved. :)

jedidia
Posts: 129
Joined: Sat Sep 15, 2018 9:49 am

Re: How would you implement an auto-walk function?

Post by jedidia » Mon Sep 24, 2018 7:19 pm

But even if you could just switch off collisions, you probably don't want to do this anyway as player would just fall through terrain.
Yeah, I was afraid this might be the case.

Code: Select all

First approach is add steering behaviour to make player route around location areas.
I've started thinking along those lines, shouldn't be too tough. The easyiest way would be a kind of "ray-trace" to see if the path intersects with a locations rect, but rotating location rect around the players position for a quick boundaries check would probably be a lot more efficient... I guess I'll leave it out of a first version and play with it some more once the rest is working smoothly.

Code: Select all

If you really wanted to go nuts with it, you could route player towards nearby taverns automatically once a day
Nah, that feels like way too much automation. I want to plan my journeys, otherwise I could just stick with what's there. :D
allow player to start/stop journey as they wish.
That part is working already, as is interruption by enemies. There's quite a few of the later, I wonder if I'll need to tweak spawn rates a bit. I guess I'll decide based on the feedback from a first release.

I'd also have loved to put in a bit of an RPG mechanic, with a skillcheck when entering a new tile that sets the player off-course when he fails, but alas daggerfall has absolutely no nature related skills at all... :cry:

Post Reply