Godot 4 教程《勇者传说》依赖注入 学习笔记(0):环境配置

前言

我之前解决了C# 的IOC的配置,现在来认真学习一个完整的Godot 项目。我看B站上面这个教程非常的好,所以打算用C# 去复刻一下,使用IOC依赖注入的想法。

相关地址

十分钟制作横版动作游戏|Godot 4 教程《勇者传说》#0

人物素材

环境素材

Gclove2000/GodotNet_LegendOfPaladin

在这里插入图片描述

环境配置

  • Windows 10
  • .net core 8.0
  • Visual Studio 2022
  • godot.net 4.2.1

初始化环境配置

Godot.NET C# 工程化开发(1):通用Nuget 导入+ 模板文件导出,包含随机数生成,日志管理,数据库连接等功能

在这里插入图片描述

文件夹结构

  • Godot:Godot项目+主要游戏逻辑代码
  • GodotProgram:帮助类

代码结构

  • GodotNet_LegndOfPaladin:Godot主要逻辑
    • SceneModels:场景IOC对象
    • SceneScirpts:场景对应脚本
    • Util: Godot API帮助类
      • PackedSceneHelper:打包场景加载
    • Program:IOC容器
  • GodotProgram:C# 主要逻辑
    • Assets:资产文件
    • DB:数据库对象
    • Interfaces:接口
    • Service:服务
    • Utils:帮助类

代码运行

在这里插入图片描述
在这里插入图片描述

资源文件导入

人物素材

环境素材

在这里插入图片描述

在这里插入图片描述

像素风格窗口环境设置

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

背景设置,Tileap使用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

自动TileMap

Godot 官方2D C#重构(3):TileMap使用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
大致实现效果

在这里插入图片描述
绘制TimeMap地形需要比较强的熟练度。多多联系即可

在这里插入图片描述
在这里插入图片描述

人物场景

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
长按左键选择站立动画

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

动画节点添加

站立节点添加

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
点击6次,添加6个关键帧
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

移动动画添加

和上面的一样

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

通过依赖注入获取Godot的全局属性

Godot的全局属性是通过字符串的方式获取的,这非常容易出问题。而且我们也希望这种配置信息能在项目启动的时候就获取

在这里插入图片描述

Godot ProjectSettings 字符串对应数据

项目声明

    public class GodotProjectSettingHelper
    {
        private NlogHelper nlogHelper;

        public readonly float Gravity = 0;


        public GodotProjectSettingHelper(NlogHelper nlogHelper)
        {
            this.nlogHelper = nlogHelper;
            Gravity = (float)ProjectSettings.GetSetting("physics/2d/default_gravity");
        }
    }

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

当前项目逻辑讲解

在这里插入图片描述
在这里插入图片描述
所以我们新建一个场景的逻辑是

  • 新增XXX.tscn
  • 挂载XXXScene.sc脚本
  • IOC注入XXXSceneModel.cs 类
  • PackedSceneHelper添加对应的PackedScene

详情请看我的Github源码

Gclove2000/GodotNet_LegendOfPaladin

角色下降

在这里插入图片描述

在这里插入图片描述

添加代码

public class PlayerSceneModel : ISceneModel
{
    private NlogHelper nlogHelper;

    private GodotProjectSettingHelper godotProjectSettingHelper;
    public PlayerSceneModel(NlogHelper nlogHelper,GodotProjectSettingHelper godotProjectSettingHelper) {
        this.nlogHelper = nlogHelper;
        this.godotProjectSettingHelper = godotProjectSettingHelper;
    }

    private CharacterBody2D characterBody2D;


    public override void Process(double delta)
    {
        //给角色一个速度,因为重力是加速度,所以角色的速度会不断的增加。
        characterBody2D.Velocity += new Vector2(0, godotProjectSettingHelper.Gravity * (float)delta);

        //让物体以这个速度进行移动
        characterBody2D.MoveAndSlide();
        nlogHelper.Debug($"x:{characterBody2D.Velocity.X},y:{characterBody2D.Velocity.Y}");
    }

    public override void Ready()
    {

        nlogHelper.Debug($"当前重力值为:{godotProjectSettingHelper.Gravity}");

        characterBody2D = this.Sence.GetNode<CharacterBody2D>("CharacterBody2D");
    }
}

在这里插入图片描述

位置问题的思考

我们知道CharacterBody2D就是为了获取CollisionShape2D的位置。因为他的位置取决于重力,物理碰撞,加速度等多方面因素。相当于他的位置是自动变化的

在Node2D上面挂载Lable节点

在这里插入图片描述
在这里插入图片描述

在CharacterBody2D下面挂载

在这里插入图片描述
在这里插入图片描述

解决方案

在这里插入图片描述

我们只需要CharacterBody2D给我们的位置更改即可,而在Godot中,Position都是相对父节点的位置。所以每次Character移动的时候,我们将CharacterBody2D的位置获取,然后我们将Character的相对位置 设置为0即可

修改代码
public override void Process(double delta)
{
    //给角色一个速度,因为重力是加速度,所以角色的速度会不断的增加。
    characterBody2D.Velocity += new Vector2(0, godotProjectSettingHelper.Gravity * (float)delta);
    
    //让物体以这个速度进行移动
    characterBody2D.MoveAndSlide();

    var postion = characterBody2D.Position;
    characterBody2D.Position = new Vector2(0, 0);
    this.Sence.Position += postion;

}
动画节点的问题,需要重新绑定

主要,如果修改动画节点的位置,会导致绑定出现问题

在这里插入图片描述

为什么我要这么写

因为我们不一定会写横版战斗游戏,横版战斗是有重力的,但是俯视角战斗又没有重力了,或者说不是垂直向下的重力,而是俯视角的效果。比如【以撒的结合】

在这里插入图片描述

动画效果

在Godot中,AnimationPlayer通过【Play】这个函数来播放动画。但是Godot中,Play是通过字符串的形式调用的。为了保证字符串的正确性,我们添加一个Enum枚举类型来对其进行限制

在这里插入图片描述

初始化AnimationPlayer

在这里插入图片描述

//枚举类型,防止拼写错误
public enum AnimationFlame { REST, idel,running }


......

public override void Ready()
{

    nlogHelper.Debug($"当前重力值为:{godotProjectSettingHelper.Gravity}");
    //初始化子节点
    characterBody2D = this.Sence.GetNode<CharacterBody2D>("CharacterBody2D");
    animationPlayer = this.Sence.GetNode<AnimationPlayer>("AnimationPlayer");
    //播放动画
    animationPlayer.Play(AnimationFlame.idel.ToString());
}

在这里插入图片描述

输入映射

我们输入上下左右,一般都是wasd,但是因为我们可能要做手柄,可能也要做移动端。所以最好设置一个输入映射好一些。

在这里插入图片描述
我的输入是,wsad是上下左右,【j】/【空格】是跳跃

在这里插入图片描述

在这里插入图片描述

获取输入

Godot 输入处理

我们在任意一个节点下面去获取按钮事件


public override void Process(double delta)
{
	//获取move_left对应按下事件
    if (Input.IsActionPressed("move_left"))
    {
        nlogHelper.Debug("move_left 按下");
    }
    
}

在这里插入图片描述

简单移动

在这里插入图片描述

public const float RUN_SPEED = 200;
.......

public override void Process(double delta)
{

    var velocity = new Vector2();
    var direction = Input.GetAxis(InputMapEnum.move_left.ToString(), InputMapEnum.move_right.ToString());
    var y = godotProjectSettingHelper.Gravity * (float)delta;
    var x = direction * RUN_SPEED;

    //在C# 中,
    velocity = characterBody2D.Velocity;
    //X是最终速度,所以不需要相加
    velocity.X = x;
    //给角色一个速度,因为重力是加速度,所以角色的速度会不断的增加。
    velocity.Y += y;
    characterBody2D.Velocity = velocity;
    //让物体以这个速度进行移动
    characterBody2D.MoveAndSlide();
    //同步场景根节点位置
    var postion = characterBody2D.Position;
    characterBody2D.Position = new Vector2(0, 0);
    this.Sence.Position += postion;
}

在这里插入图片描述

完善输入和添加动画

using Godot;
using GodotNet_LegendOfPaladin.Utils;
using GodotProgram.Interfaces;
using GodotProgram.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static GodotNet_LegendOfPaladin.Utils.GodotProjectSettingHelper;

namespace GodotNet_LegendOfPaladin.SceneModels
{
    public class PlayerSceneModel : ISceneModel
    {

        

        public const float RUN_SPEED = 200;
        public const float JUMP_VELOCITY = -300;

        //枚举类型,防止拼写错误
        public enum AnimationFlame {  idel, running,jump }




        #region IOC注入

        private NlogHelper nlogHelper;
        private GodotProjectSettingHelper godotProjectSettingHelper;
        public PlayerSceneModel(NlogHelper nlogHelper, GodotProjectSettingHelper godotProjectSettingHelper)
        {
            this.nlogHelper = nlogHelper;
            this.godotProjectSettingHelper = godotProjectSettingHelper;
        }
        #endregion


        #region 子节点获取

        private CharacterBody2D characterBody2D;

        private AnimationPlayer animationPlayer;

        private Sprite2D sprite2D;

        public override void Ready()
        {

            nlogHelper.Debug($"当前重力值为:{godotProjectSettingHelper.Gravity}");
            //初始化子节点
            characterBody2D = this.Sence.GetNode<CharacterBody2D>("CharacterBody2D");
            animationPlayer = this.Sence.GetNode<AnimationPlayer>("AnimationPlayer");
            sprite2D = this.Sence.GetNode<Sprite2D>("Sprite2D");
            //播放动画
            animationPlayer.Play(AnimationFlame.idel.ToString());


        }
        #endregion
        public override void Process(double delta)
        {
            //初始化速度
            var velocity = new Vector2();
            //初始化动画节点
            var animation = AnimationFlame.idel;
            var direction = Input.GetAxis(InputMapEnum.move_left.ToString(), InputMapEnum.move_right.ToString());
            var y = godotProjectSettingHelper.Gravity * (float)delta;
            var x = direction * RUN_SPEED;
            var isOnFloor = characterBody2D.IsOnFloor();
            //在C# 中,
            velocity = characterBody2D.Velocity;
            //X是最终速度,所以不需要相加
            velocity.X = x;
            //给角色一个速度,因为重力是加速度,所以角色的速度会不断的增加。
            velocity.Y += y;

            //如果在地上并且按下跳跃,则直接给一个y轴的速度
            if(isOnFloor && Input.IsActionJustPressed(InputMapEnum.jump.ToString()))
            {
                velocity.Y = JUMP_VELOCITY;
            }
            if (isOnFloor)
            {
                if (Mathf.IsZeroApprox(direction))
                {
                    animation = AnimationFlame.idel;
                }
                else
                {
                    animation = AnimationFlame.running;
                }
            }
            else
            {
                animation = AnimationFlame.jump;
            }

            //方向翻转
            if (!Mathf.IsZeroApprox(direction))
            {
                sprite2D.FlipH = direction < 0;
            }

            characterBody2D.Velocity = velocity;
            //让物体以这个速度进行移动
            characterBody2D.MoveAndSlide();
            //同步场景根节点位置
            var postion = characterBody2D.Position;
            characterBody2D.Position = new Vector2(0, 0);
            this.Sence.Position += postion;

            animationPlayer.Play(animation.ToString());
        }

    }
}

在这里插入图片描述

完善跳跃手感

如果玩过超级马里奥或者别的平台跳跃游戏,都知道有一个手感的东西。就是有个跳跃的提前量。我们现在是正好落地的时候按下跳跃才能跳起来,现在我们将跳跃的按钮进行存储,给与一定的缓冲间隔。

/// <summary>
/// 最长跳跃等待时间
/// </summary>
public const int JUMP_WAIT_TIME = 3000;
/// <summary>
/// 初始化的时候让时间往后退一点,防止时间过快
/// </summary>
private DateTime jumpLastTime = DateTime.Now.AddDays(-1);


......
public override void Process(double delta)
{
	......
    if (Input.IsActionJustPressed(InputMapEnum.jump.ToString()))
    {
        jumpLastTime = DateTime.Now;
    }

    if (isOnFloor)
    {
        //如果在地上并且按下跳跃,则直接给一个y轴的速度
		//超时判断
        if (jumpLastTime.AddMilliseconds(JUMP_WAIT_TIME) > DateTime.Now)
        {
        	//如果刚好触发了跳跃,给个速度,将jumpLastTime推前
            velocity.Y = JUMP_VELOCITY;
            jumpLastTime = DateTime.Now.AddDays(-1);
        }
		......
    }
    ......
}

相关推荐

  1. .NET 依赖注入配置系统

    2024-04-01 06:08:04       17 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-01 06:08:04       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-01 06:08:04       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-01 06:08:04       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-01 06:08:04       20 阅读

热门阅读

  1. 文件系统 FTP Ubuntu 安装入门介绍

    2024-04-01 06:08:04       19 阅读
  2. SOA、分布式、微服务之间的关系?

    2024-04-01 06:08:04       16 阅读
  3. 深入探索语言模型:原理、应用与评估

    2024-04-01 06:08:04       17 阅读
  4. 设计模式(11):适配器模式

    2024-04-01 06:08:04       19 阅读
  5. 2024.2.1力扣每日一题——数字游戏

    2024-04-01 06:08:04       16 阅读
  6. Vue企业级项目开发axios

    2024-04-01 06:08:04       20 阅读
  7. 微信小程序——小程序和页面生命周期详解

    2024-04-01 06:08:04       20 阅读
  8. npm 常用命令详解

    2024-04-01 06:08:04       17 阅读