You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor组件中创建依赖对象实现Pong游戏的初始化方案咨询

在Blazor中实现Pong游戏的依赖对象初始化与事件触发

这种按依赖顺序创建独立对象并让它们自行触发事件的方式完全可行,不需要依赖单例服务就能实现。以下是具体的实现思路和代码示例:


1. 定义带事件的实体类

先把Area、Racket、Ball封装成独立类,各自维护自身状态并定义所需事件:

// 游戏区域类
public class Area
{
    public int Width { get; }
    public int Height { get; }

    public Area(int width, int height)
    {
        Width = width;
        Height = height;
    }
}

// 球拍类
public class Racket
{
    public int Width { get; }
    public int Height { get; }
    public int YPosition { get; private set; }

    // 定义移动事件,位置变化时触发
    public event Action<int>? Moved;

    public Racket(int initialY, int areaWidth, int areaHeight)
    {
        Width = 20;
        Height = areaHeight / 5;
        YPosition = initialY;
    }

    public void Move(int deltaY)
    {
        YPosition += deltaY;
        // 触发移动事件
        Moved?.Invoke(YPosition);
    }
}

// 球类
public class Ball
{
    public int XPosition { get; private set; }
    public int YPosition { get; private set; }
    public int SpeedX { get; private set; } = 5;
    public int SpeedY { get; private set; } = 3;

    // 定义碰撞事件
    public event Action? CollidedWithRacket;

    public Ball(int racketWidth, int racketHeight, int initialY)
    {
        XPosition = racketWidth + 10; // 初始在左球拍右侧
        YPosition = initialY + racketHeight / 2;
    }

    public void UpdatePosition()
    {
        XPosition += SpeedX;
        YPosition += SpeedY;
        // 这里可添加碰撞检测逻辑,触发对应事件
        // if (碰撞条件) CollidedWithRacket?.Invoke();
    }
}

2. 在Blazor组件中按顺序初始化对象

直接在组件内部声明私有字段,在OnInitialized或OnParametersSetAsync(如果尺寸依赖父组件参数)中按依赖顺序初始化,同时订阅对象事件:

@page "/pong"
@implements IDisposable

<!-- 游戏画布 -->
<div style="position: relative; width: @_area.Widthpx; height: @_area.Heightpx; background: #000; margin: 20px auto;">
    <!-- 左球拍 -->
    <div style="position: absolute; left: 10px; top: @_r1.YPositionpx; width: @_r1.Widthpx; height: @_r1.Heightpx; background: #fff;"></div>
    <!-- 右球拍 -->
    <div style="position: absolute; right: 10px; top: @_r2.YPositionpx; width: @_r2.Widthpx; height: @_r2.Heightpx; background: #fff;"></div>
    <!-- 球 -->
    <div style="position: absolute; left: @_ball.XPositionpx; top: @_ball.YPositionpx; width: 10px; height: 10px; border-radius: 50%; background: #fff;"></div>
</div>

<button @onclick="() => _r1.Move(-10)">左拍上移</button>
<button @onclick="() => _r1.Move(10)">左拍下移</button>

@code {
    private Area? _area;
    private Racket? _r1;
    private Racket? _r2;
    private Ball? _ball;

    protected override void OnInitialized()
    {
        base.OnInitialized();
        
        // 1. 初始化游戏区域
        int areaWidth = 800;
        int areaHeight = 600;
        _area = new Area(areaWidth, areaHeight);

        // 2. 初始化左右球拍(垂直居中)
        int centerY = (_area.Height / 2) - (_area.Height / 10);
        _r1 = new Racket(centerY, _area.Width, _area.Height);
        _r2 = new Racket(centerY, _area.Width, _area.Height);

        // 3. 初始化球(依赖左球拍的位置和尺寸)
        if (_r1 != null)
        {
            _ball = new Ball(_r1.Width, _r1.Height, _r1.YPosition);
        }

        // 订阅左球拍移动事件
        _r1.Moved += OnLeftRacketMoved;
    }

    // 处理左球拍移动后的逻辑
    private void OnLeftRacketMoved(int newY)
    {
        // 如果球还未开始运动,同步球的垂直位置
        if (_ball != null && _ball.XPosition == _r1.Width + 10)
        {
            _ball.YPosition = newY + _r1.Height / 2;
            StateHasChanged(); // 通知Blazor更新UI
        }
    }

    // 组件销毁时取消事件订阅,避免内存泄漏
    public void Dispose()
    {
        if (_r1 != null)
        {
            _r1.Moved -= OnLeftRacketMoved;
        }
    }
}

3. 关键注意事项

  • 避免单例:单例适合全局共享状态,但Pong游戏是组件级的独立实例,每个组件应该拥有自己的游戏对象集合,直接在组件内初始化更合理。
  • UI更新触发:当对象内部状态变化(比如球拍移动)时,通过事件通知组件,调用StateHasChanged()强制Blazor重新渲染UI。
  • 事件订阅清理:组件销毁时必须取消事件订阅,防止内存泄漏。

内容的提问来源于stack exchange,提问作者EagleStar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 01:57:36