[PYTHON] Les débutants veulent créer quelque chose comme un cube rubic avec UE4 et en faire une bibliothèque pour un apprentissage amélioré # 5

Dans la continuité de la dernière fois, il s'agit d'un article dans lequel les débutants continueront à travailler à la création d'une bibliothèque Python qui implique UE4 (presque comme un mémorandum pour moi-même ...).

Premièrement: # 1 Dernière fois: # 4

Connexion du traitement de rotation d'animation avec Python

Dans l'article précédent, nous avons connecté la fonction de rotation immédiate avec Python, mais ensuite nous connecterons également celle avec animation.

Commençons par le travail du côté des plans. C'est presque le même que le BP de rotation immédiate. Presque tout ce dont vous avez besoin est prêt, il vous suffit donc de faire une boucle autour du cube et d'indiquer la rotation du cube que vous souhaitez faire pivoter.

image.png

Tourne la boucle,

image.png

Vérifiez s'il s'agit d'une cible de rotation,

image.png

Définissez un drapeau.

Préparez une fonction de plan pour la rotation dans une direction et essayez de l'appeler depuis Python avec du code provisoire.

Content\Scripts\action.py


...
class Action:

    total_delta_time = 0
    rotation_count = 0

    def tick(self, delta_time):
        """
Une fonction qui est exécutée à peu près toutes les images pendant le jeu.

        Parameters
        ----------
        delta_time : float
Secondes écoulées depuis le dernier appel de tick.
        """
        self.total_delta_time += delta_time
        if self.total_delta_time > 3 and self.rotation_count == 0:
            self.uobject.rotateXLeft1()
            self.rotation_count += 1
            return
        if self.total_delta_time > 6 and self.rotation_count == 1:
            self.uobject.rotateXLeft2()
            self.rotation_count += 1
            return
        if self.total_delta_time > 9 and self.rotation_count == 2:
            self.uobject.rotateXLeft3()
            self.rotation_count += 1
            return
        if self.total_delta_time > 12 and self.rotation_count == 3:
            self.uobject.rotateXRight1()
            self.rotation_count += 1
            return
...

20191114_1.gif

J'ai vérifié la rotation et il semble qu'il n'y ait pas de problème, je vais donc passer à la suivante. De plus, en fonction de l'objectif de rotation, l'affichage peut être cassé ou rugueux, mais cela sera-t-il corrigé par l'emballage pour la distribution? Ou y a-t-il quelque chose qui manque ...? (Anti-aliasé)

Nous allons procéder à la correspondance de spécification de données à partir de Python externe

Lors de son utilisation réelle, il est nécessaire d'enregistrer la bibliothèque avec PyPI (pip) etc., d'appeler ces bibliothèques depuis Jupyter etc. et de donner une instruction d'action du côté UE4.

Par conséquent, nous préparerons une table sur laquelle les données seront écrites du côté Python de la bibliothèque. J'ai pensé que je continuerais avec le module via PyActor, mais j'ai trouvé quelques inconvénients, donc je vais l'écrire avec un module généraliste sous commun.

Win64\common\sqlite_utils.py


from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
...
declarative_meta = declarative_base()
...

#Le statut de l'état ajouté à la cible de traitement de l'action.
ACTION_INSTRUCTION_STATUS_QUEUED = 1

#Le statut de l'état en cours (animation) de l'action.
ACTION_INSTRUCTION_STATUS_RUNNING = 2

#Le statut de l'état traité de l'action.
ACTION_INSTRUCTION_STATUS_ENDED = 3


class ActionInstruction(declarative_meta):
    """
Gère les données d'instruction d'action du côté de la bibliothèque Python
Modèle de table.

    Attributes
    ----------
    id : Column of Integer
Colonne de clé primaire.
    action : Column of Integer
L'action spécifiée. La définition est action.Selon la valeur en py.
    current_status : Column of Integer
Le statut de l'action en cours. Dans ce module
        ACTION_INSTRUCTION_STATUS_D'une constante avec un préfixe de
Suivez la définition.
    skip_animation : Column of Integer
Spécifiez s'il faut ignorer l'animation.
        0=Ne sautez pas, 1=Il est prêt à sauter.
    """

    id = Column(Integer, primary_key=True)
    action = Column(Integer)
    current_status = Column(Integer)
    skip_animation = Column(Integer)
    __tablename__ = 'action_instruction'


session = None


def create_from_python_db_session():
    """
Session de lecture de SQLite écrite à partir de la bibliothèque Python
Produire.

    Returns
    -------
    session : Session
La session SQLite générée.

    Notes
    -----
Si la session a déjà été créée, l'instance créée sera renvoyée.
    """
    global session
    if session is not None:
        return session
    session_start_time_str = file_helper.get_session_start_time_str()
    file_name = 'from_python_%s.sqlite' % session_start_time_str
    session = create_session(
        sqlite_file_name=file_name,
        declarative_meta=declarative_meta)
    return session

Pour le moment, j'ajouterai un test pour confirmer qu'une session peut être créée et une ligne d'insertion et de suppression réussit.

Win64\common\tests\test_sqlite_utils.py


def test_create_from_python_db_session():
    session = sqlite_utils.create_from_python_db_session()
    action_instruction = sqlite_utils.ActionInstruction()
    action_instruction.action = 1
    action_instruction.current_status = \
        sqlite_utils.ACTION_INSTRUCTION_STATUS_QUEUED
    action_instruction.skip_animation = 0
    session.add(instance=action_instruction)
    session.commit()

    action_instruction = session.query(
        sqlite_utils.ActionInstruction
    ).filter_by(
        action=1,
        current_status=sqlite_utils.ACTION_INSTRUCTION_STATUS_QUEUED,
        skip_animation=0).one()
    session.delete(action_instruction)
    session.commit()

Ensuite, du côté action.py, écrivez un processus pour vérifier périodiquement les valeurs de la table préparée. Avant cela, si vous traitez avec tick, le processus sera exécuté assez fréquemment et il sera inutile (l'accès à la base de données, etc. sera exécuté fréquemment), donc réduisez la fréquence d'exécution. Essayez de le régler une fois toutes les 0,2 secondes environ (ajustez-le en observant la situation).

Il semble que cela puisse être géré en ouvrant BP_Action et en ajustant l'intervalle de ticks (secs). La valeur par défaut est 0, et si elle est 0, la fréquence d'exécution sera basée sur la fréquence d'images.

image.png

Essayez de spécifier la sortie de la console côté Python et vérifiez-la pour le moment.

Content\Scripts\action.py


class Action:

...

    def tick(self, delta_time):
        """
Une fonction qui est exécutée à intervalles réguliers pendant le jeu.

        Parameters
        ----------
        delta_time : float
Secondes écoulées depuis le dernier appel de tick.
        """
        ue.log(delta_time)

image.png

Il s'exécute toutes les 0,2 secondes. Ça me va.

Ajoutez un processus pour examiner les données SQLite à intervalles réguliers et récupérer une donnée d'action si elle existe. Assurez-vous que None est renvoyé lorsqu'une autre action tourne ou qu'il n'y a pas de données pour l'action spécifiée.

Content\Scripts\action.py


class Action:

    def begin_play(self):
        """Une fonction qui est exécutée au début du jeu.
        """
        self.from_python_db_session = \
            sqlite_utils.create_from_python_db_session()

        python_test_runner.run_pyactor_instance_tests(
            pyactor_class_instance=self)

    def tick(self, delta_time):
        """
Une fonction qui est exécutée à intervalles réguliers pendant le jeu.

        Parameters
        ----------
        delta_time : float
Secondes écoulées depuis le dernier appel de tick.
        """
        action, skip_animation = self._get_action_instruction_data()
        if action is None:
            return
        pass

    def _get_action_instruction_data(self):
        """
Acquiert les informations d'action définies. L'état dans lequel l'action suivante peut être exécutée
(L'animation de rotation est terminée, etc.) et l'action suivante est spécifiée
S'il existe, la valeur de la première action non traitée est renvoyée.

        Returns
        ----------
        action : int or None
La valeur de type de l'action récupérée. ACTION dans ce module_
Une valeur avec le préfixe de est définie. Lorsque la cible n'existe pas
Aucun n'est défini si l'action suivante ne peut pas être exécutée.
        skip_animation : bool or None
Définir s'il faut ignorer l'animation. La cible n'existe pas
Aucun est défini si la condition est telle que l'action suivante ne peut pas être exécutée.
        """
        if self.is_any_cube_rotating():
            return None, None
        query_result = self.from_python_db_session.query(
            ActionInstruction
        ).filter_by(
            current_status=sqlite_utils.ACTION_INSTRUCTION_STATUS_QUEUED
        ).order_by(
            ActionInstruction.id.asc()
        ).limit(1)
        for action_instruction in query_result:
            action = int(action_instruction.action)
            skip_animation = int(action_instruction.skip_animation)
            if skip_animation == 0:
                skip_animation = False
            else:
                skip_animation = True
            return action, skip_animation
        return None, None

    def is_any_cube_rotating(self):
        """
Obtient la valeur booléenne indiquant si un cube est en train de tourner.

        Returns
        ----------
        is_rotating : bool
True est défini si un cube tourne.
        """
        is_rotating = self.uobject.isAnyCubeRotating()[0]
        return is_rotating

    def test__get_action_instruction_data(self):

        #L'action spécifiée existe et l'animation
        #Vérifiez le comportement lorsque le non-saut est spécifié.
        action_instruction = sqlite_utils.ActionInstruction()
        action_instruction.action = ACTION_ROTATE_X_LEFT_2
        action_instruction.current_status = \
            sqlite_utils.ACTION_INSTRUCTION_STATUS_QUEUED
        action_instruction.skip_animation = 0
        self.from_python_db_session.add(instance=action_instruction)
        self.from_python_db_session.commit()
        action, skip_animation = self._get_action_instruction_data()
        assert_equal(
            action,
            ACTION_ROTATE_X_LEFT_2)
        assert_false(skip_animation)
        self.from_python_db_session.delete(action_instruction)
        self.from_python_db_session.commit()

        #Vérifiez le comportement lorsque l'animation est ignorée.
        action_instruction = sqlite_utils.ActionInstruction()
        action_instruction.action = ACTION_ROTATE_X_LEFT_2
        action_instruction.current_status = \
            sqlite_utils.ACTION_INSTRUCTION_STATUS_QUEUED
        action_instruction.skip_animation = 1
        self.from_python_db_session.add(instance=action_instruction)
        self.from_python_db_session.commit()
        _, skip_animation = self._get_action_instruction_data()
        assert_true(skip_animation)
        self.from_python_db_session.delete(action_instruction)
        self.from_python_db_session.commit()

        #Vérifiez le comportement lorsque les données spécifiées n'existent pas.
        action, skip_animation = self._get_action_instruction_data()
        assert_equal(action, None)
        assert_equal(skip_animation, None)

    def test_is_any_cube_rotating(self):
        assert_false(
            self.is_any_cube_rotating())

Pour exécuter le test de la classe spécifiée par PyActor, ajoutez une fonction pour exécuter la méthode de test de la classe cible séparément au module polyvalent, et exécutez-la au moment de begin_play (en fait, c'est généralement normal). Ce serait bien si la fonction à tester s'écoule automatiquement comme pytest dans pytest, mais c'est parce que la classe est instanciée depuis UE4). Comme il est difficile d'écrire tous les modèles de test car il est connecté à UE4, j'écrirai des tests dans la mesure où je peux écrire rapidement.

Win64\common\python_test_runner.py


...
def run_pyactor_instance_tests(pyactor_class_instance):
    """
Défini sur l'instance de la classe Python spécifiée par PyActor
Exécutez un ensemble de fonctions de test.

    Parameters
    ----------
    pyactor_class_instance : *
Une instance de la classe Python spécifiée par le PyActor cible.
    """
    print('%Commencer à tester s...' % type(pyactor_class_instance))
    is_packaged_for_distribution = \
        file_helper.get_packaged_for_distribution_bool()
    if is_packaged_for_distribution:
        return
    members = inspect.getmembers(pyactor_class_instance)
    for member_name, member_val in members:
        if not inspect.ismethod(member_val):
            continue
        if not member_name.startswith('test_'):
            continue
        print('%Fonction cible: %s' % (datetime.now(), member_name))
        pre_dt = datetime.now()
        member_val()
        timedelta = datetime.now() - pre_dt
        print('%s ok. %s secondes' % (datetime.now(), timedelta.total_seconds()))

Maintenant que vous pouvez spécifier l'action, j'écrirai l'endroit pour appeler la fonction côté blueprint lié à la valeur de l'action acquise.

Content\Scripts\action.py


...
ACTION_KEY_FUNC_NAME_DICT = {
    ACTION_ROTATE_X_LEFT_1: 'rotateXLeft1',
    ACTION_ROTATE_X_LEFT_2: 'rotateXLeft2',
    ACTION_ROTATE_X_LEFT_3: 'rotateXLeft3',
    ACTION_ROTATE_X_RIGHT_1: 'rotateXRight1',
    ACTION_ROTATE_X_RIGHT_2: 'rotateXRight2',
    ACTION_ROTATE_X_RIGHT_3: 'rotateXRight3',
    ACTION_ROTATE_Y_UP_1: 'rotateYUp1',
    ACTION_ROTATE_Y_UP_2: 'rotateYUp2',
    ACTION_ROTATE_Y_UP_3: 'rotateYUp3',
    ACTION_ROTATE_Y_DOWN_1: 'rotateYDown1',
    ACTION_ROTATE_Y_DOWN_2: 'rotateYDown2',
    ACTION_ROTATE_Y_DOWN_3: 'rotateYDown3',
    ACTION_ROTATE_Z_UP_1: 'rotateZUp1',
    ACTION_ROTATE_Z_UP_2: 'rotateZUp2',
    ACTION_ROTATE_Z_UP_3: 'rotateZUp3',
    ACTION_ROTATE_Z_DOWN_1: 'rotateZDown1',
    ACTION_ROTATE_Z_DOWN_2: 'rotateZDown2',
    ACTION_ROTATE_Z_DOWN_3: 'rotateZDown3',
}
...
class Action:

...

    def tick(self, delta_time):
        """
Une fonction qui est exécutée à intervalles réguliers pendant le jeu.

        Parameters
        ----------
        delta_time : float
Secondes écoulées depuis le dernier appel de tick.
        """
        action, skip_animation = self._get_action_instruction_data()
        if action is None:
            return
        action_func_name: str = self._get_action_func_name(
            action=action,
            skip_animation=skip_animation,
        )
        action_func = getattr(self.uobject, action_func_name)
        action_func()

    def _get_action_func_name(self, action, skip_animation):
        """
À partir de la valeur de type de l'action spécifiée, etc., du plan directeur cible
Obtenez le nom de la fonction.

        Parameters
        ----------
        action : int
La valeur de type de l'action cible.
        skip_animation : bool
S'il faut ignorer l'animation.

        Returns
        ----------
        func_name : str
Le nom de la fonction calculée.
        """
        func_name: str = ACTION_KEY_FUNC_NAME_DICT[action]
        if skip_animation:
            last_char = func_name[-1]
            func_name = func_name[0:-1]
            func_name += 'Immediately%s' % last_char
        return func_name
...
    def test__get_action_func_name(self):
        func_name = self._get_action_func_name(
            action=ACTION_ROTATE_X_LEFT_2,
            skip_animation=False)
        assert_equal(func_name, 'rotateXLeft2')

        func_name = self._get_action_func_name(
            action=ACTION_ROTATE_X_LEFT_2,
            skip_animation=True)
        assert_equal(func_name, 'rotateXLeftImmediately2')

Nous avons préparé un dictionnaire avec le nom de la fonction en fonction de la valeur du type d'action, et obtenu le nom de la fonction en s'y référant. S'il est paramétré pour ignorer l'animation, il correspond en ajoutant le suffixe du nom de la fonction pour une rotation immédiate.

Si cela vous convient, vous devriez pouvoir effectuer une rotation du côté UE4 en écrivant des données dans la table SQLite. Essayez d'ajouter manuellement des enregistrements à SQLite.

image.png

20191116_1.gif

Il semble qu'il tourne comme spécifié par SQLite comme prévu. J'ai également défini les valeurs de type d'autres actions et vérifié la rotation, mais cela ne semble pas poser de problème.

Ajustez le nom du fichier SQLite, etc.

Je me demandais si je devais séparer les fichiers selon le sens d'écriture entre Python en UE4 et Python dans la bibliothèque, mais j'ai commencé à sentir que c'était inutile car il devenait nécessaire de s'écrire entre eux. Essayez de combiner les fichiers en un seul et ajustez le nom du fichier et le nom de la variable (les détails sont omis).

Assurez-vous de mettre à jour l'état de l'état de rotation

Actuellement, la valeur de current_status de SQLite n'est pas mise à jour, donc la rotation est répétée, donc ajustez cette zone.

Ajoutez principalement le traitement des trois fonctions suivantes.

Content\Scripts\action.py


...
    def tick(self, delta_time):
        """
Une fonction qui est exécutée à intervalles réguliers pendant le jeu.

        Parameters
        ----------
        delta_time : float
Secondes écoulées depuis le dernier appel de tick.
        """
        self._set_ended_status_to_animation_ended_action()
        action_instruction_id, action, skip_animation = \
            self._get_action_instruction_data()
        if action_instruction_id is None:
            return
        action_func_name: str = self._get_action_func_name(
            action=action,
            skip_animation=skip_animation,
        )
        action_func = getattr(self.uobject, action_func_name)
        action_func()
        self._set_running_status(
            action_instruction_id=action_instruction_id,
            skip_animation=skip_animation)
        self._set_ended_status_if_animation_skipped(
            action_instruction_id=action_instruction_id,
            skip_animation=skip_animation)

    def _set_ended_status_to_animation_ended_action(self):
        """
Si l'animation est terminée, pendant l'animation
Terminé au statut de réglage de l'action définie
        (ACTION_INSTRUCTION_STATUS_ENDED) est défini.

        Returns
        ----------
        updated : bool
Si le processus de mise à jour a été exécuté.
        """
        if self.is_any_cube_rotating():
            return False
        target_data_exists = False
        action_instructions = self.action_data_db_session.query(
            sqlite_utils.ActionInstruction
        ).filter_by(
            current_status=sqlite_utils.ACTION_INSTRUCTION_STATUS_RUNNING,
        )
        action_instruction: sqlite_utils.ActionInstruction
        for action_instruction in action_instructions:
            target_data_exists = True
            action_instruction.current_status = \
                sqlite_utils.ACTION_INSTRUCTION_STATUS_ENDED
        if target_data_exists:
            self.action_data_db_session.commit()
            return True
        return False

    def _set_ended_status_if_animation_skipped(
            self, action_instruction_id, skip_animation):
        """
Réglage de l'action cible en cas de réglage pour sauter l'animation
Terminé au statut de (ACTION_INSTRUCTION_STATUS_FIN)
Ensemble.

        Parameters
        ----------
        action_instruction_id : int
ID de la clé primaire du paramètre d'action cible.
        skip_animation : bool
S'il faut ignorer l'animation.

        Returns
        ----------
        updated : bool
Si le processus de mise à jour a été exécuté.
        """
        if not skip_animation:
            return False
        action_instruction: sqlite_utils.ActionInstruction
        action_instruction = self.action_data_db_session.query(
            sqlite_utils.ActionInstruction
        ).filter_by(
            id=action_instruction_id
        ).one()
        action_instruction.current_status = \
            sqlite_utils.ACTION_INSTRUCTION_STATUS_ENDED
        self.action_data_db_session.commit()
        return True

    def _set_running_status(self, action_instruction_id, skip_animation):
        """
Si le paramètre de rotation est animé, le paramètre d'action cible
En cours d'exécution vers l'état (ACTION)_INSTRUCTION_STATUS_FONCTIONNEMENT)
Ensemble.

        Parameters
        ----------
        action_instruction_id : int
ID de la clé primaire du paramètre d'action cible.
        skip_animation : bool
S'il faut ignorer l'animation.

        Returns
        ----------
        updated : bool
Si le processus de mise à jour a été exécuté.
        """
        if skip_animation:
            return False
        action_instruction: sqlite_utils.ActionInstruction
        action_instruction = self.action_data_db_session.query(
            sqlite_utils.ActionInstruction
        ).filter_by(
            id=action_instruction_id).one()
        action_instruction.current_status = \
            sqlite_utils.ACTION_INSTRUCTION_STATUS_RUNNING
        self.action_data_db_session.commit()
        return True

En fait, j'ai mis les valeurs dans la table SQLite et confirmé qu'elle ne tourne qu'une seule fois. Vérifiez également que la valeur de l'état est 2 (pendant l'animation) pendant l'animation et 3 (fin) une fois terminé, et pour le traitement de rotation immédiat.

image.png

Maintenant, l'animation ne s'arrête pas ...

Sauvegardez la valeur de l'observation

Créez les valeurs dans la section «Observation» de Introduction à l'apprentissage amélioré # 1: Termes de base et introduction à Gym, PyTorch. C'est une valeur d'observation pour l'apprentissage.

Quant à quoi faire

--Ajouter une nouvelle table SQLite pour l'observation --Enregistrer la valeur d'observation à la fin de l'action

Nous ajouterons des traitements tels que.

Tout d'abord, ajoutez un modèle.

Win64\common\sqlite_utils.py


class Observation(declarative_meta):
    """
Un modèle de table qui gère les données de valeur observée des résultats d'action.
La valeur est enregistrée à chaque fois que l'action se termine (l'animation se termine).

    Attributes
    ----------
    id : Column of Integer
Colonne de clé primaire.
    action_instruction_id : int
ID de la clé primaire des informations sur l'action cible (action terminée).
    position_num : int
Numéro de position du cube. Il est réglé dans l'ordre pour chaque surface.
    color_type : int
La valeur du type de couleur de la position cible.
    """
    id = Column(Integer, primary_key=True)
    action_instruction_id = Column(Integer, index=True)
    position_num = Column(Integer)
    color_type = Column(Integer)
    __tablename__ = 'observation'

Ensuite, nous ajouterons la valeur du type de position et la définition du type de couleur. Le devant est orange, et il est attribué comme décrit et pressé plus tard dans l'état du réglage de disposition des couleurs standard du monde. Le jeu de couleurs est le même que le jeu de couleurs standard mondial sur Wikipedia.

image.png

[Rubik Cube-Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%AB%E3%83%BC%E3%83%93%E3%83%83%E3%82%AF% Image citée de E3% 82% AD% E3% 83% A5% E3% 83% BC% E3% 83% 96).

Définir la valeur du type de position

Côté orange (avant)

Attribuez de 1 à 9 comme indiqué ci-dessous. Nous utiliserons le mot «FRONT» dans le nom de la constante.

temp1119_1.png

Côté blanc (côté gauche)

Allouez de 10 à 18 comme indiqué ci-dessous. Nous utiliserons le mot "LEFT" dans le nom de la constante.

temp1119_2.png

Côté jaune (côté droit)

Allouez de 19 à 27 comme indiqué ci-dessous. Nous utiliserons le mot "DROITE" dans le nom de la constante.

temp1119_3.png

Surface verte (surface supérieure)

Allouez entre 28 et 36 comme indiqué ci-dessous. Nous utiliserons le mot «TOP» dans le nom de la constante.

temp1119_4.png

Blush (arrière)

Allouez entre 37 et 45 comme indiqué ci-dessous. Nous utiliserons le mot «RETOUR» dans les noms constants.

temp1120_1.png

Face bleue (en bas)

Allouez entre 46 et 54 comme indiqué ci-dessous. Nous utiliserons le mot "BOTTOM" dans le nom de la constante.

temp1120_2.png

Ajouter des constantes de position

Définissez-le en Python. Le numéro du nom de la constante est défini par le numéro de ligne et de colonne.

Win64\common\sqlite_utils.py


POSITION_NUM_FRONT_1_1 = 1
POSITION_NUM_FRONT_2_1 = 2
POSITION_NUM_FRONT_3_1 = 3
POSITION_NUM_FRONT_1_2 = 4
POSITION_NUM_FRONT_2_2 = 5
POSITION_NUM_FRONT_3_2 = 6
POSITION_NUM_FRONT_1_3 = 7
POSITION_NUM_FRONT_2_3 = 8
POSITION_NUM_FRONT_3_3 = 9

POSITION_NUM_FRONT_LIST = [
    POSITION_NUM_FRONT_1_1,
    POSITION_NUM_FRONT_2_1,
    POSITION_NUM_FRONT_3_1,
    POSITION_NUM_FRONT_1_2,
    POSITION_NUM_FRONT_2_2,
    POSITION_NUM_FRONT_3_2,
    POSITION_NUM_FRONT_1_3,
    POSITION_NUM_FRONT_2_3,
    POSITION_NUM_FRONT_3_3,
]

POSITION_NUM_LEFT_1_1 = 10
POSITION_NUM_LEFT_2_1 = 11
POSITION_NUM_LEFT_3_1 = 12
...
POSITION_NUM_LIST = [
    POSITION_NUM_FRONT_1_1,
    POSITION_NUM_FRONT_2_1,
    POSITION_NUM_FRONT_3_1,
    POSITION_NUM_FRONT_1_2,
    POSITION_NUM_FRONT_2_2,
    POSITION_NUM_FRONT_3_2,
    POSITION_NUM_FRONT_1_3,
    POSITION_NUM_FRONT_2_3,
    POSITION_NUM_FRONT_3_3,
    POSITION_NUM_LEFT_1_1,
    POSITION_NUM_LEFT_2_1,
    POSITION_NUM_LEFT_3_1,
    POSITION_NUM_LEFT_1_2,
    ...
    POSITION_NUM_BOTTOM_1_3,
    POSITION_NUM_BOTTOM_2_3,
    POSITION_NUM_BOTTOM_3_3,
]

Définir la valeur du type de couleur

Ceci est simplement défini en 6 couleurs.

Win64\common\sqlite_utils.py


COLOR_TYPE_ORANGE = 1
COLOR_TYPE_WHITE = 2
COLOR_TYPE_YELLOW = 3
COLOR_TYPE_GREEN = 4
COLORR_TYPE_BLUE = 5
COLOR_TYPE_RED = 6

COLOR_TYPE_LIST = [
    COLOR_TYPE_ORANGE,
    COLOR_TYPE_WHITE,
    COLOR_TYPE_YELLOW,
    COLOR_TYPE_GREEN,
    COLORR_TYPE_BLUE,
    COLOR_TYPE_RED,
]

Connectez le traitement de réinitialisation au côté Python

Il n'y a pas si longtemps, le processus de réinitialisation était exécuté directement sur le plan de niveau, mais nous allons le connecter avec Python. Comme les autres fonctions précédentes, nous avons défini chaque fonction dans le plan de niveau, nous allons donc ajouter une bibliothèque de fonctions et la déplacer afin qu'elle puisse être référencée à partir du niveau et BP_Action. (À partir de maintenant, traitons-le correctement dès le début avec la bibliothèque de fonctions ... (auto-conseillé))

image.png

En ce qui concerne le traitement, les contenus qui étaient dans le plan de presque le niveau sont conservés tels quels, et seule une partie telle que le processus d'acquisition du cube est ajustée (remplacement par le nœud Obtenir tous les acteurs de la classe, etc., seule la partie qui n'est pas apportée car elle est ajustée).

Essayez de l'exécuter une fois et assurez-vous qu'il est mélangé (à ce stade, vous exécutez les fonctions de la bibliothèque de fonctions à partir du niveau BP).

image.png

Il ne semble y avoir aucun endroit où le processus d'affirmation sur chaque BP et le test sur Python sont bloqués, donc cela semble aller.

Ajoutez une interface à BP_Action pour appeler depuis Python.

image.png

C'est une fonction simple qui appelle simplement une fonction dans la bibliothèque de fonctions. Nous ajusterons également Python. Ajoutez une définition d'action.

Content\Scripts\action.py


...
ACTION_ROTATE_Z_DOWN_2 = 17
ACTION_ROTATE_Z_DOWN_3 = 18
ACTION_RESET = 19
...
ACTION_LIST = [
    ...
    ACTION_ROTATE_Z_DOWN_2,
    ACTION_ROTATE_Z_DOWN_3,
    ACTION_RESET,
]
...
ACTION_KEY_FUNC_NAME_DICT = {
    ...
    ACTION_ROTATE_Z_DOWN_2: 'rotateZDown2',
    ACTION_ROTATE_Z_DOWN_3: 'rotateZDown3',
    ACTION_RESET: 'reset',
}

Essayez de mettre les données de 19 actions directement dans SQLite et vérifiez l'opération.

image.png

image.png

Le cube a été mélangé correctement. Même si je mets à jour l'affichage des données côté SQLite et que je le vérifie, l'action est à l'état terminé.

image.png

Je suis allé ici rapidement. Nous continuerons d'avancer.

Réfléchissez à la façon de prendre la valeur de couleur de chaque côté de chaque cube

Vous pouvez dire où chaque cube est situé par l'implémentation jusqu'à présent, mais il est nécessaire de réfléchir à quel côté vous pouvez voir car la rotation, etc. est impliquée (cette valeur est nécessaire pour l'observation) Sera).

Je pensais qu'il serait calculé à partir de la quantité de rotation, mais comme il est tourné en fonction du standard mondial et tourné encore et encore, il y a de nombreux cas où cela ne devient pas une belle valeur.

image.png

Cela semble simple, mais il y a pas mal de signes que le calcul semble gênant ... Que dois-je faire ... J'y réfléchis depuis un moment, mais je pense que je peux le calculer en obtenant la position mondiale des acteurs (plans de chaque couleur) dans le plan de la classe de base du cube, donc je vais l'essayer.

Recherchez le dictionnaire de plans

Je voulais obtenir les coordonnées de référence mondiale XYZ du plan en fonction de la valeur de type de chaque position, mais je n'ai pas encore utilisé un tel dictionnaire ou un nœud de tableau associatif. Je vais essayer de savoir à quoi ça ressemble.

Il semble que l'histoire soit un peu différente entre C ++ et Blueprint, mais il semble que Map devrait être utilisé sur Blueprint. Il semble que tous les types ne peuvent pas être lancés, mais il semble qu'ils prennent probablement en charge des types tels que les nombres de base et les chaînes.

As far as I know, not every type of variable can be defined as a Map or Set in Blueprints... Maybe there's no such limitation in c++, but I'm not sure. Dictionary?

Le tableau associatif multidimensionnel ... Comme le tableau multidimensionnel, ne semble-t-il pas que vous le cherchiez? n'est-ce pas···.

Dans cet esprit, il semble simple de définir ces dictionnaires multidimensionnels du côté Python, d'obtenir uniquement les valeurs de coordonnées du plan de UE4 et de calculer du côté Python.

Vérifiez les coordonnées du plan de référence mondial à chaque position

Fondamentalement, si la coordonnée centrale est 0 et le plan de la partie arête (surface de couleur visible) est 151 (la taille du cube est 100, 50 par rayon à partir de la référence centrale, la partie couleur du plan est légèrement plus petite que le cube Puisque 1 est ajouté pour que la couleur soit visible à l'extérieur, une valeur telle que 151) devrait sortir. Nous allons afficher la console et le vérifier dans l'événement BeginPlay de la classe de base du cube.

image.png

Ce qui précède est un exemple de plan orange, mais le nom du cube et les coordonnées de référence mondiale (GetWorldLocation) sont affichés (supprimés après confirmation). Ci-dessous, je vais faire une note au format <numéro de ligne> - <numéro de colonne>: <coordonnées de sortie> (je pensais que c'était correct car je l'ai fait en fonction des coordonnées 0, mais je l'ai fait pivoter à l'avance. Il a été confirmé que la valeur cible ne change pas après cela).

Position du plan avant

Position de l'avion sur le côté gauche

Position de l'avion sur le côté droit

Position plane de la surface supérieure

Position de l'avion à l'arrière

Position plane du fond

Ajoutez un processus pour obtenir une liste des coordonnées du plan actuel pour chaque couleur du côté du plan

Pour faciliter la détermination de la position des couleurs du côté Python, nous ajouterons un processus pour acquérir le tableau de coordonnées de référence mondiale du plan pour chaque couleur dans Blueprint. Je me connecterai avec Python plus tard.

Afin d'unifier au maximum les parties superposées des fonctions, nous normaliserons sauf pour la spécification du plan cible. Je me demandais comment obtenir les acteurs dans une classe BP spécifique, mais il y a un signe que je peux l'obtenir avec un nœud appelé Get All Actors with Tag.

image.png

Lorsque j'ai cherché où définir la balise, il semble qu'elle puisse être définie normalement dans la fenêtre Détails.

image.png

J'essaierai de faire ce que j'attendais en utilisant ces derniers. ...., mais quand je l'ai essayé, il semble que je ne puisse pas trouver un acteur plat avec ça (je ne comprends pas bien et je m'inquiète environ 10 minutes ...). Le tableau du nombre de valeurs renvoyées sera toujours 0. Apparemment, le nœud Obtenir les composants par balise convient mieux. Je suis un peu confus, mais est-ce parce que la cible d'acquisition est un composant plutôt qu'un acteur? Cela signifie t-il?

La définition d'un acteur est-elle quelque chose comme une classe de plan directeur ou quelque chose qui est placé à un niveau, et un composant qui est stocké dans ces acteurs? Si vous ne le cherchez pas plus tard, il n'aura pas l'air soigné ...

image.png

Pour le moment, s'il s'agit d'un nœud Get Components by Tag, il semble que l'avion a été pris normalement, donc je vais reprendre mon esprit et continuer.

Nous répondons en ajoutant un fichier de bibliothèque de fonctions de plan directeur appelé LIB_CubeColor.

image.png

Le nom de balise du plan à acquérir est spécifié par l'argument. La balise semble utiliser le type Nom violet. En quoi est-ce différent de String?

Une vérification est placée pour voir si le nom de balise attendu au début de la fonction a un argument afin que vous puissiez immédiatement remarquer si vous avez fait une erreur en spécifiant le nom de la balise.

image.png

Si ce n'est pas la valeur du tableau ci-dessus, un message d'erreur sera affiché.

image.png

image.png

Ensuite, nous faisons une boucle pour chaque cube du monde. Étant donné que le nœud Obtenir les composants par étiquette pour l'acquisition de plan ne peut pas être appelé sans passer par l'acteur de cube, l'acteur de cube est acquis en premier. Après tout, l'acteur est-il plus apte à reconnaître que le parent / composant est l'enfant ...

image.png

Obtenez le plan de l'acteur de cube avec le nœud Obtenir les composants par étiquette. Pour la classe des composants, j'ai choisi le composant de maillage statique (car c'était l'affichage du plan sur le BP).

image.png

Le nœud Est visible vérifie si le plan est visible. La classe de base du cube a un plan d'une couleur dans l'arrangement lui-même, et comme l'affichage / non-affichage est défini dans le BP de la sous-classe de chaque cube, les masqués sont exclus. Je vais.

image.png

Après cela, GetWorldLocation prend les coordonnées mondiales du plan et les ajoute au tableau de valeurs de retour. S'il s'agit d'un flottant, la valeur s'écartera légèrement et, à des fins de comparaison, elle est convertie en un entier avec un nœud Round entre les deux.

Nous créerons le traitement une fois la boucle terminée. Pour le moment, je vais mettre un processus pour vérifier si le nombre de données de résultat est de 9 correctement.

image.png

image.png

Enfin, il renvoie 3 tableaux et se termine.

image.png

Je vais essayer. Pour le moment, sortons les coordonnées du plan orange avant l'animation.

La combinaison correspond à la liste des coordonnées du cube avant que j'ai recherché il y a quelque temps. Ça me va.

Cela s'allonge, alors j'aimerais terminer cet article ici. La prochaine fois, nous procéderons à diverses implémentations autour de l'observation.

Résumé de la page de référence

Recommended Posts

Les débutants veulent créer quelque chose comme un cube rubic avec UE4 et en faire une bibliothèque pour un apprentissage amélioré # 4
Les débutants veulent créer quelque chose comme un cube rubic avec UE4 et en faire une bibliothèque pour un apprentissage amélioré # 5
Les débutants veulent créer quelque chose comme un cube rubic avec UE4 et en faire une bibliothèque pour un apprentissage amélioré # 6
Je veux escalader une montagne avec l'apprentissage par renforcement
[Introduction] Je veux créer un robot Mastodon avec Python! 【Débutants】
Apprentissage amélioré 35 python Développement local, attachez un lien vers myModule et importez-le.
Je veux faire un jeu avec Python
Je veux écrire un élément dans un fichier avec numpy et le vérifier.
Un débutant en apprentissage automatique a essayé de créer un modèle de prédiction de courses de chevaux avec python
J'ai essayé de faire quelque chose comme un chatbot avec le modèle Seq2Seq de TensorFlow
J'ai essayé de créer un environnement d'apprentissage amélioré pour Othello avec Open AI gym
Les débutants en apprentissage automatique essaient de créer un arbre de décision
Comment dessiner de manière interactive un pipeline d'apprentissage automatique avec scikit-learn et l'enregistrer au format HTML
Je veux faire un changeur de voix en utilisant Python et SPTK en référence à un site célèbre
Associez Python Enum à une fonction pour la rendre appelable
Je veux créer un éditeur de blog avec l'administrateur de django
Expérimentez pour créer un PDF indépendant pour Kindle avec Python
Je veux faire une macro de clic avec pyautogui (désir)
Pour ceux qui souhaitent démarrer l'apprentissage automatique avec TensorFlow2
Je veux faire une macro de clic avec pyautogui (Outlook)
Bibliothèque pour spécifier un serveur de noms en python et dig
Procédure d'inscription PyPI pour ceux qui veulent faire leurs débuts PyPI
J'ai essayé de faire un processus d'exécution périodique avec Selenium et Python
Je veux créer un fichier pip et le refléter dans le menu fixe
Jetez quelque chose dans Kinesis avec python et assurez-vous qu'il est dans
Essayez de faire une stratégie de blackjack en renforçant l'apprentissage ((1) Implémentation du blackjack)
J'ai essayé de faire une étrange citation pour Jojo avec LSTM
[Concept] Stratégie pour analyser les données avec python et viser une baisse après les avantages pour les actionnaires
Est-il possible de se lancer dans une entreprise de pré-cotation et de faire fortune avec des stock-options?
[Salut Py (Partie 1)] Je veux faire quelque chose pour le moment, alors commencez par fixer un objectif.
TF2RL: bibliothèque d'apprentissage améliorée pour TensorFlow2.x
<Pour les débutants> bibliothèque python <Pour l'apprentissage automatique>
2.Faites un arbre de décision à partir de 0 avec Python et comprenez-le (2. Bases du programme Python)
Les débutants en Python ont décidé de créer un bot LINE avec Flask (commentaire approximatif de Flask)
Une collection de conseils pour accélérer l'apprentissage et le raisonnement avec PyTorch
Signifie mémo lorsque vous essayez de faire de l'apprentissage automatique avec 50 images
Créez un arbre de décision à partir de 0 avec Python et comprenez-le (4. Structure des données)
Je souhaite créer une application Web en utilisant React et Python flask
Je pensais que je pouvais créer un bon éditeur gitignore, alors j'ai essayé de faire quelque chose comme MVP pour le moment