20tab / UnrealEnginePython

Embed Python in Unreal Engine 4
MIT License
2.77k stars 753 forks source link

Overriding an existing actor's input controls in Python #121

Open daeilkim opened 7 years ago

daeilkim commented 7 years ago

Using the example of the advanced vehicle template in Unreal, I'd love some pointers on how one would override the movement controls using this plugin. So in other words, I would like another part of the python program to override the controls of the driver and directly give it input for its acceleration, steering, etc. Let's say I already have a PyActor component attached to this driver so that the get_owner() retrieves the driver object. Here's the general template and psuedocode i'm thinking of which doesn't really work, but thought I'd put something up here as a start...

import unreal_engine as ue
import sys

class Brain:

    # this is called on game start
    def begin_play(self):
        ue.log('Begin Play on Brain class')
        self.pawn = self.uobject.get_owner()
        self.pawn.bind_axis('MoveForward', self.move_forward)

    def move_forward(self, amount):
        ue.print_string('axis value:' + str(amount))
        rot = self.pawn.get_control_rotation()
        fwd = ue.get_forward_vector(0, 0, rot[2])
        # do some magical thing to determine how much to move it forward
        self.pawn.add_movement_input(fwd, self.magic.generate_value)

Any pointers would be very helpful!

unbit commented 7 years ago

If your "advanced vehicle" is the standard one, its input axis nodes should have the "consume input" property selected. It means that axis events are consumed by the blueprint pawn. You can disable consume input on the nodes or you can refactor the code to have the vehicle input managed by both the input axis and another virtual axis managed by your python component.

daeilkim commented 7 years ago

Thanks for that tip. I'm running into a different error right now, where it keeps saying that there is no input manager for this uobject. Here's the error:

self.pawn.bind_input_axis('MoveForwardAI') LogPython:Error: Exception: no input manager for this uobject

My process is to add a Python component to the blueprint for the driver and then doe the get_owner() object to reference the actual driver pawn. Here's the component list for the blueprint. Is this not the right way?

image

I'm using the C++ template for the advanced driver vehicle for this example.

rdeioris commented 7 years ago

Add self.pawn.enable_input() before registering event axis. This will create the transient InputComponent

daeilkim commented 7 years ago

It's still a no go unfortunately. Not sure what I'm doing wrong here, but here is the code that I'm using which is similar to the non-evented approach. I'm not doing anything special with the project other than trying to get this working on the c++ advanced vehicle template:

import unreal_engine as ue
import random

class Brain:
    # this is called on game start
    def begin_play(self):
        ue.log('Begin Play on Brain class')
        self.pawn = self.uobject.get_owner()
        self.pawn.enable_input()
        self.pawn.bind_input_axis('MoveForward')
        self.pawn.bind_input_axis('MoveRight')

    def tick(self, delta_time):
        rot = self.pawn.get_control_rotation()
        fwd = ue.get_forward_vector(random.random(), random.random(), rot[2])
        right = ue.get_right_vector(random.random(), random.random(), rot.yaw)
        self.pawn.add_movement_input(fwd, self.pawn.get_input_axis('MoveForward'))
        self.pawn.add_movement_input(right, self.pawn.get_input_axis('MoveRight'))

and here's the error now:

LogPython:Error: Exception: no input manager for this uobject LogPawn:Error: EnableInput can only be specified on a Pawn for its Controller LogPython:Error: no input manager for this uobject LogPython:Error: Traceback (most recent call last):

The only difference here is that I'm using random.random() to generate various values for the add_movement_input function. In other words, I just want something that Python can generate to move this vehicle rather than the user input. Thanks again for all your help and sorry if this isn't clear.

rdeioris commented 7 years ago

I'll check it tomorrow, thanks for reporting

rdeioris commented 7 years ago

I have tried adding a simple python component, and the events are correctly bound. Is it possible you are assuming the second argument of add_movement_input is not normalized ?

rdeioris commented 7 years ago

Oh sorry, i understand now, basically anything you pass to add_movement_input get swallowed. This is an interesting problem as you have two components fighting for add_movement_input(). I will think about it a little bit more

rdeioris commented 7 years ago

What about this:

import unreal_engine as ue
from unreal_engine.classes import WheeledVehicleMovementComponent

class VehicleAI:

    def begin_play(self):
        ue.log('Begin Play on Brain class')
        self.pawn = self.uobject.get_owner()
        self.pawn.bind_axis('MoveForward', self.move_forward)

    def move_forward(self, amount):
        ue.log(amount)
        self.pawn.get_component_by_type(WheeledVehicleMovementComponent).SetThrottleInput(-1)

i think the error was not using the vehicle movements :)

daeilkim commented 7 years ago

Hm.. it still doesn't seem to work for me. I'm wondering if there is anything different when I'm using a BP derived driver pawn. Maybe my setup was different?

Here are the steps I took using the advanced vehicle c++ starter template. 1) Go to the DriverPawn class in my c++ folder and derive a blueprint from it. 2) Attach a Python class to the blueprint as a component. 3) Configure Python for the module ('python_driver') and class ('VehicleAI'). 4) Use code as quoted above.

Still nothing happens. Let me know if you think I might be missing something here and thanks very much for helping with this.

rdeioris commented 7 years ago

Ok, i'll try subclassing the vehicle, i have only added the python component to the default one

rdeioris commented 7 years ago

This is how i did it:

If all goes well your vehicle will go only backward

Pulecz commented 7 years ago

I am kind of new to UE4 and I was quite confused especially when the third example in current readme.md starts accessing inputs and I hit the wall.

This guide helped me understand a bit how to "switch" inputs https://docs.unrealengine.com/latest/INT/Gameplay/Input/

So in other words rdeioris's procedure:

This worked for me.

However I have no idea how to edit this this simple script further I tried MoveRight and setting it to +1 (setting +1 instead of -1 in def move_forwards works for moving Forwards of course) but car does not turn right, it might be obvious that the .SetThrottleInput(+1) will not make the car go left or right, I guess I need to run dir() on that pawn.

I found this issue based on the readme, I am writing this https://github.com/Pulecz/edu/blob/master/ue4_101.md to understand the readme I got so far.

I hope by (hopefully) understanding this example I can add another example to that md file.

Thanks for this a lot, it helps greatly to understand (for m confusing) C++ code by some simple KISS methods. But however is UE4 with BluePrint KISS simple, python code makes it even simpler. Child dream come true.