虚幻引擎C#插件现在已经开源,开发者可以使用C#语言来开发项目了。

源码地址:https://github.com/xiongfang/UnrealCS

文档地址:https://github.com/xiongfang/UnrealCS/wiki


示例项目地址:https://github.com/xiongfang/UnrealCS/wiki/Demonstration-project


这个示例是基于ThirdPerson 蓝图工程创建的,只做了一点点修改。

包含地图:

  • Engine.umap (Persistent Level)
  • UI.umap (sublevel1)
  • ThirdPersonExampleMap.umap (sublevel2)

包含组件(用C#写的)

  • Engine
  • MainUI
  • MyCharacter
  • MyPlayerController
  • LightFade

流程: 1.Engine.umap 包含Engine Actor,这个Actor包含Engine组件。Engine组件的生命周期存在于整个游戏的生命周期。 启动游戏后,在Engine.BeginPlay函数中,加载UI地图

        /// <summary>
        /// called on begin play
        /// </summary>
        void BeginPlay()
        {
            LogInfo("BeginPlay");

            //Open UI Level
            LogInfo("Open UI Level");
            FLatentActionInfo Info = new FLatentActionInfo();
            UGameplayStatics.LoadStreamLevel(this, "UI",true,false, Info);
        }

2.UI.umap 包含UI Actor,这个Actor包含MainUI组件。这个组件处理UI事件。

    /// <summary>
    /// Main Scene UI
    /// </summary>
    public class MainUI:UnrealEngine.UMonoActorComponent
    {
        public TSubclassOf<UUserWidget> MainWidget;

        APlayerController PC;
        UUserWidget widget;

        public static MainUI Instance;

        public MainUI()
        {
            Instance = this;
        }

        /// <summary>
        /// called on register 
        /// </summary>
        void OnRegister()
        {
            Instance = this;
        }

        /// <summary>
        /// called on unregister 
        /// </summary>
        void OnUnRegister()
        {
            Instance = null;
        }

        /// <summary>
        /// called on begin play
        /// </summary>
        void BeginPlay()
        {
            //Show UI
            _Open();
        }


        /// <summary>
        /// Called On End Play
        /// </summary>
        void OnDestroy()
        {
            Instance = null;
        }

        void Init()
        {
            if (widget != null)
                return;
            PC = UGameplayStatics.GetPlayerController(GetWorld(), 0);
            widget = UWidgetBlueprintLibrary.Create(this, MainWidget, PC);

            //bind start game button event
            {
                UButton BtnStart = widget.WidgetTree.FindWidget<UButton>("Button_Start");
                FMulticastScriptDelegate OnClick = BtnStart.OnClicked;
                OnClick.Add(this, "OnClickStart");
                BtnStart.OnClicked = OnClick;
            }
            //bind quit game button event
            {
                UButton BtnStart = widget.WidgetTree.FindWidget<UButton>("Button_Quit");
                FMulticastScriptDelegate OnClick = BtnStart.OnClicked;
                OnClick.Add(this, "OnClickQuit");
                BtnStart.OnClicked = OnClick;
            }
        }

        /// <summary>
        /// This Must be Public for export to blueprint
        /// </summary>
        public void OnClickStart()
        {
            LogInfo("ClickStart");
            UGameplayStatics.LoadStreamLevel(this, "ThirdPersonExampleMap", true, true, new FLatentActionInfo());
            ULevelStreaming LvStreaming = UGameplayStatics.GetStreamingLevel(this, "ThirdPersonExampleMap");
            FMulticastScriptDelegate Del = LvStreaming.OnLevelLoaded;
            Del.Add(Engine.Instance, "OnThirdPersonExampleMapShown");
            LvStreaming.OnLevelShown = Del;

            //Close UI
            _Close();
            //Unload UI Level
            UGameplayStatics.UnloadStreamLevel(this, "UI", new FLatentActionInfo());
        }

        /// <summary>
        /// This Must be Public for export to blueprint
        /// </summary>
        public void OnClickQuit()
        {
            LogInfo("OnClickQuit");
            _Close();
            UKismetSystemLibrary.QuitGame(GetWorld(), PC, EQuitPreference.Quit);
        }



        void _Close()
        {
            if (widget != null)
            {
                widget.RemoveFromParent();
            }
            PC.bShowMouseCursor = false;
            UWidgetBlueprintLibrary.SetInputMode_GameOnly(PC);
        }

        void _Open()
        {
            if (widget == null)
            {
                Init();
            }
            widget.AddToViewport();
            PC.bShowMouseCursor = true;
            UWidgetBlueprintLibrary.SetInputMode_UIOnlyEx(PC, widget);
        }
    }

3.点击开始游戏按钮,加载ThirdPersonExampleMap地图,在MyCharacter组件的BeginPlay方法中,给角色创建了武器和盾牌

    public class MyCharacter:UMonoActorComponent
    {
        public TSubclassOf<AStaticMeshActor> SwordPrefab;
        public TSubclassOf<AStaticMeshActor> ShieldPrefab;

        void BeginPlay()
        {
            //Create Shield And Sword

            ACharacter Char = Cast<ACharacter>(this.GetOwner());
            USkeletalMeshComponent skeletalMesh = Char.Mesh;
            AActor weapon = GetWorld().SpawnActor(SwordPrefab, new FVector(), new FRotator());
            weapon.K2_AttachToComponent(skeletalMesh, "hand_rSocket", EAttachmentRule.SnapToTarget, EAttachmentRule.SnapToTarget, EAttachmentRule.SnapToTarget, true);
            AActor shield = GetWorld().SpawnActor(ShieldPrefab, new FVector(), new FRotator());
            shield.K2_AttachToComponent(skeletalMesh, "lowerarm_lSocket", EAttachmentRule.SnapToTarget, EAttachmentRule.SnapToTarget, EAttachmentRule.SnapToTarget, true);
        }

        void Tick(float DeltaTime)
        {
            //UKismetSystemLibrary.DrawDebugString(this, new FVector(0, 0, 0), "wsad to move,j attack", GetOwner(),FLinearColor.Red);
        }
    }

4.在MyPlayerController组件的Tick方法中,监测玩家是否按下J键,如果按下了J键,则使用技能

技能的表现包括:

  • 禁用玩家输入
  • 播放一个刀光
  • 播放剑的残影特效
  • 播放空间扭曲特效
  • 播放相机震动效果
	/// <summary>
        /// Called Every Frame
        /// </summary>
        /// <param name="DeltaTime"></param>
        void Tick(float DeltaTime)
        {
            if (Target == null)
                return;

            if(OwnerPC.WasInputKeyJustPressed(MakeKey("J")) && !_is_skill_using)
            {
                LogInfo("Key J Down");

                // Play Animation
                _skill_time_length = Target.Mesh.GetAnimInstance().Montage_Play(Montage);

                _skill_timer = 0.0f;
                _is_skill_using = true;

                //Disable Input
                Target.DisableInput(OwnerPC);

                //Attack Light
                GetWorld().SpawnActor(AttackLight, Target.GetTransform().TransformPosition(FVector.ForwardVector * 300), Target.K2_GetActorRotation());

                //Ghost
                PS_SwordGhost= UGameplayStatics.SpawnEmitterAttached(PS_SwordGhostPreafab, Target.Mesh, "hand_rSocket", FVector.ZeroVector, FRotator.ZeroRotator, EAttachLocation.SnapToTarget);

                //PS_HeatDistort
                UGameplayStatics.SpawnEmitterAtLocation(this, PS_HeatDistort, Target.GetTransform().TransformPosition(FVector.ForwardVector * 300), Target.K2_GetActorRotation());

                //Shake
                UGameplayStatics.PlayWorldCameraShake(this, ShakePrefab, Target.K2_GetActorLocation(), shake_inner_radius, shake_outer_radius);
            }

            //Update Skill
            if(_is_skill_using)
            {
                _skill_timer += DeltaTime;
                if(_skill_timer>_skill_time_length)
                {
                    _is_skill_using = false;
                    //Destroy Particle System
                    PS_SwordGhost.K2_DestroyComponent(PS_SwordGhost);
                    //Enable Input
                    Target.EnableInput(OwnerPC);
                    return;
                }

                //Apply Force
                if(_skill_timer<_skill_time_length-0.5f)
                {
                    FHitResult Hit;
                    Target.K2_AddActorWorldOffset(Target.GetTransform().TransformVector(FVector.ForwardVector) * 300 * DeltaTime, false, out Hit, false);
                }

            }
        }

5.在刀光效果的更新组件中(LightFade),让光源产生一个闪光效果

    /// <summary>
    /// Fade Light In And Out
    /// </summary>
    public class LightFade:UnrealEngine.UMonoActorComponent
    {
        float _fadeInTime = 0.3f;
        float _fadeOutTime = 0.3f;
        float _timer;

        public float intensity = 500000;

        UPointLightComponent lightCom;

        void BeginPlay()
        {
            lightCom = GetOwner().GetComponentByClass<UPointLightComponent>();
        }

        void Tick(float DeltaTime)
        {
            _timer += DeltaTime;
            if(_timer< _fadeInTime)
            {
                lightCom.Intensity = _timer / _fadeInTime * intensity;
            }
            else if(_timer < _fadeInTime+ _fadeOutTime)
            {
                lightCom.Intensity = (_timer- _fadeInTime) / _fadeOutTime * intensity;
            }
            else
            {
                //Destroy Light
                GetOwner().Destroy();
            }
        }
    }
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐