20tab / UnrealEnginePython

Embed Python in Unreal Engine 4
MIT License
2.72k stars 741 forks source link

Subclassing API #649

Open Ahleroy opened 5 years ago

Ahleroy commented 5 years ago

OS : Windows 10 64 bits Python : 3.6.4 Anaconda

I am looking for subclassing a pre-made class and it doesn't work :

from unreal_engine.classes import Character

class Hero(Character):

    def __init__(self):
        self.CapsuleComponent.CapsuleRadius = 117
        self.CapsuleComponent.CapsuleHalfHeight = 200

        # BodyInstance is a USTRUCT (they are always passed as value)
        body_instance = self.CapsuleComponent.BodyInstance
        body_instance.CollisionProfileName = 'OverlapAll'
        self.CapsuleComponent.BodyInstance = body_instance

        self.CharacterMovement.GravityScale = 0.0

    def OnActorBeginOverlap(self, other_actor):
        print('overlapping with {0}'.format(other_actor))

    def ReceiveTick(self, DeltaSeconds: float):
        print("test")

This code is called from a PyPawn Blueprint object.

In the python console I have :

Hero (<unreal_engine.UObject object at 0x0000021FB5474A20>,) {'module': 'monster', 'qualname': 'Hero', 'init': <function Hero.init at 0x0000021FC577C840>, 'OnActorBeginOverlap': <function Hero.OnActorBeginOverlap at 0x0000021FC577C7B8>, 'ReceiveTick': <function Hero.ReceiveTick at 0x0000021FC577C8C8>} Preparing for overwriting class Hero ... removing function ReceiveTick Found UProperty OnActorBeginOverlap added prop DeltaSeconds OVERRIDDEN FUNCTION ReceiveTick WITH 1 PARAMS (size 4) 4

I also have this error :

you cannot use call on actors, they have to be spawned

Nothing else happens. The console is supposed the print "test" at every tick but nothing displayed.

Any idea ?

rdeioris commented 5 years ago

How are you spawning the Hero instance ?

Ahleroy commented 5 years ago

I couldn't find information how to do it exactly. The script is called from a PyPawn Blueprint (as explained in the README of the repository). The Blueprint is simply dragged and dropped into the World. Is there a different way to do it ?

rdeioris commented 5 years ago

I think something is missing: you have defined a Hero class. Then you need to instantiate it, how you are instantiating it ?

Ahleroy commented 5 years ago

Which is why I thought that calling the class from the Blueprint would instantiate the Hero. How would you instantiate it otherwise ? :)

rdeioris commented 5 years ago

Actors cannot be instantiated in Unreal Engine, they must be 'spawned':

world.actor_spawn(Hero)

Ahleroy commented 5 years ago

From which script should I call this function ? How do I link this script to my current UE4 scene ?

rdeioris commented 5 years ago

You can call the 'Spawn Actor' blueprint node, the 'Hero' class should be listed in the classes list

Ahleroy commented 5 years ago

Thank you very much it now works. However the hot-reloading seems to fail. Update in my python script are not accepted. Is there a command to force the hot-reloading ?

dfb commented 5 years ago

Hot-reloading doesn't work for me either, but as a workaround: from the Python console in UE4 you can use the importlib.reload function.

from importlib import reload
import mymodule
... do some stuff ... externally edit your module ...
reload(mymodule)
... do more stuff

For our project we were having to do this a lot so we used UEPy to create a button that shows up in UE4 that deletes the object from the scene, reloads the module, and then spawns the object again:

image

It's not quite the same as hot-reloading, but it ends up being faster (at least for us) since it combines the cleanup, reload, and respawn work into a single button click.

KyooSikLee commented 2 years ago

OS: Windows 10 64bit python 3.5

I did what was written above but did not work.

My Code:

import unreal_engine as ue 
from unreal_engine.classes import Character

class PyProcMeshManager(Character):
    def begin_play(self):
        ue.log('Begin Play on Hero class')

    # this is called at every 'tick'    
    def tick(self, delta_time):
        location = self.uobject.get_actor_location()
        # increase Z honouring delta_time
        location.z += 0.1
        # set new location
        self.uobject.set_actor_location(location)

My blueprint UE4Editor_tLWlz3lmTm

But whenever I click on keyboard 1, this error pops up.

LogPython: Warning: PyProcMeshManager
LogPython: Warning: (<unreal_engine.UObject object at 0x00000267A9911240>,)
LogPython: Warning: {'__module__': 'py_proc_mesh_manager', 'begin_play': <function PyProcMeshManager.begin_play at 0x000002679092E488>, '__qualname__': 'PyProcMeshManager', 'tick': <function PyProcMeshManager.tick at 0x000002679092E510>}
LogPython: Warning: Preparing for overwriting class PyProcMeshManager ...
LogPython: Warning: Adding begin_play as attr
LogPython: Warning: Adding tick as attr
LogPython: Error: you cannot use __call__ on actors, they have to be spawned

Is there something I'm missing?