pythonshapelycoordinate-systemscoordinate-transformationrotational-matrices

How To draw a changing trajectory with direction and angle as values in Python


What I am trying to do is collect Keyboard and mouse input data while I play a first person shooter game. I can record this data with SerpentAI and save it to a file.

I then want to draw my trajectory as I move through the map in the game. So my inputs are the 'w', 'a', 's' and 'd' keys on the keyboard with 'w' representing one movement forward, 's' representing one movement backward, 'a' one movement to the left and 'd' one movement to the right.

My Issue is that I also have mouse inputs that change the direction of what 'forward' is. For example: I press 'w' to move in a straight line in the game, then move my mouse a certain distance to make a 90 degree turn and then press the 'w' again. I am still moving forward but in a new direction. This will happen many times in my data and I do not know how to plot it.

To make things simpler I created a dummy dataset with a few inputs that should result in the drawing of a square:

Keyboard MouseTurnAngle TimeStamp
w 1657161124
w 1657161125
w 1657161126
90 1657161127
w 1657161128
w 1657161129
w 1657161130
90 1657161131
w 1657161132
w 1657161133
w 1657161134
90 1657161135
w 1657161136
w 1657161137
w 1657161138

So far I have used pandas to create coordinates for each timestamp and then matplotlib to draw a scatterplot of the coordinates but the coordinates I have been generating are incorrect and my python geometric visualization knowledge is not up to par on this task. I do not have a way to generate the correct coordinates.

I have been experimenting with the shapely library, specifically shapely.affinity.rotate to help get the correct coordinates but no luck so far.


Solution

  • Since your timestamps are equidistant and your keyboard and mouse inputs are mutually exclusive, you could simplify this task to an interpretation of a list of actions:

    import numpy as np
    from matplotlib import pyplot as plt
    
    actions = ["w", "a", "s", "d", 90, "w", "a", "a", -180, "s", "d", "w", 90, "w", "w", "a", "a", "a"]
    delta_times = [1,2,5,3,5,1,1, 2, 3, 2, 2, 1, 1, 1, 4, 2, 1, 1]
    
    # initial direction and position
    direction = np.array((0,1))  # moving in +y
    position = np.array((0,0))
    
    # change relative direction
    movement_translator = {
        "w": lambda pos, direction: pos + direction,
        "s": lambda pos, direction: pos - direction,
        "a": lambda pos, direction: pos - np.flip(direction),
        "d": lambda pos, direction: pos + np.flip(direction),
    }
    
    # change direction
    def rotatation_matrix(deg):
        theta = np.deg2rad(deg)
        return np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]])
    
    # show live movement
    def plot_movement(x_pos, y_pos, position, direction):
        plt.cla()
        plt.plot(x_pos, y_pos, '.-')
        plt.plot(x_pos[-1], y_pos[-1], 'xr')  # show current position as red x
        plt.show(block=False)
        plt.title(f"Position: {np.round(position)}, Direction: {np.round(direction)}")
        plt.pause(1)
    
    # initialize position lists
    x_pos = [position[0]]
    y_pos = [position[1]]
    
    for action, delta_time in zip(actions, delta_times):
        try:  # to apply movement, i.e. w,a,s,d
            for _ in range(delta_time):
                # keep moving in same direction
                position = movement_translator[action](position, direction)
                x_pos.append(position[0])
                y_pos.append(position[1])
                plot_movement(x_pos, y_pos, position, direction)
        except KeyError:  # it is not a movement, so apply rotation instead
            direction = np.dot(rotatation_matrix(action), direction)
            for _ in range(delta_time):
                plt.pause(1) # just wait
    
    plt.show()
    

    enter image description here