SDL - 绘制“负”圆圈(战争迷雾)

2024-03-28

我有这个 800x600square 我想绘制到屏幕上。我想在其中“切割”圆圈(其中 alpha 为 0)。基本上我是在地图上绘制整个矩形,因此在我绘制的这些“圆圈”中,您可以看到地图,否则您会看到灰色方块


所以,我假设你想在你的一款游戏中添加战争迷雾?

几周前,我为当地一所大学制作了一个小型演示,以展示 A* 寻路功能,所以我想我可以为您添加战争迷雾。结果如下:

初始地图

首先,您从完全可见的完整地图开始

Fog

然后,我添加了一个表面来覆盖整个屏幕(请注意,我的地图比屏幕小,因此对于这种情况,我只是在屏幕上添加了战争迷雾,但如果您有滚动,请确保它覆盖每个地图像素1:1)

mFogOfWar = SDL_CreateRGBSurface(SDL_HWSURFACE, in_Width, in_Height, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
SDL_Rect screenRect = {0, 0, in_Width, in_Height};
SDL_FillRect(mFogOfWar, &screenRect, 0xFF202020);

然后,你需要绘制它...我在绘制游戏对象之后和绘制 UI 之前添加了这个调用

DrawSurface(mFogOfWar, 0, 0);

Where

void RenderingManager::DrawSurface(SDL_Surface* in_Surface, int in_X, int in_Y)
{
    SDL_Rect Dest = { in_X, in_Y, 0, 0 };
    SDL_BlitSurface(in_Surface, NULL, mScreen, &Dest);
}

这应该会给你以下结果:

《冲孔面》

然后我创建了一个32位的.png看起来像这样(棋盘显示 alpha)

当渲染我的主角时,我添加了这个调用:

gRenderingManager.RemoveFogOfWar(int(mX) + SPRITE_X_OFFSET, int(mY) + SPRITE_Y_OFFSET);

偏移量只是为了使打孔与精灵居中,基本上,我要传递给的内容RemoveFogOfWar是我的精灵的中心。

消除战争迷雾

现在是战争迷雾的核心。我做了两个版本,一个版本永久删除了战争迷雾,另一个版本重置了战争迷雾。我的战争迷雾重置依赖于我punch表面具有轮廓,其中 alpha 重置为0事实上,我的角色移动的像素比每帧轮廓包含的像素少,否则我会保留Rect我的打孔器被打在哪里,我会在再次打出新的打孔器之前重新填充它。

由于我找不到与 SDL 的“乘法”混合,因此我决定编写一个简单的函数,在打孔表面上进行迭代并更新战争迷雾表面上的 alpha。最重要的部分是确保您保持在表面的范围内,因此它占用了大部分代码......可能有一些裁剪函数,但我没有费心检查:

void RenderingManager::RemoveFogOfWar(int in_X, int in_Y)
{
    const int halfWidth = mFogOfWarPunch->w / 2;
    const int halfHeight = mFogOfWarPunch->h / 2;

    SDL_Rect sourceRect = { 0, 0, mFogOfWarPunch->w, mFogOfWarPunch->h };
    SDL_Rect destRect = { in_X - halfWidth, in_Y - halfHeight, mFogOfWarPunch->w, mFogOfWarPunch->h };

    // Make sure our rects stays within bounds
    if(destRect.x < 0)
    {
        sourceRect.x -= destRect.x; // remove the pixels outside of the surface
        sourceRect.w -= sourceRect.x; // shrink to the surface, not to offset fog
        destRect.x = 0;
        destRect.w -= sourceRect.x; // shrink the width to stay within bounds
    }
    if(destRect.y < 0)
    {
        sourceRect.y -= destRect.y; // remove the pixels outside
        sourceRect.h -= sourceRect.y; // shrink to the surface, not to offset fog
        destRect.y = 0;
        destRect.h -= sourceRect.y; // shrink the height to stay within bounds
    }

    int xDistanceFromEdge = (destRect.x + destRect.w) - mFogOfWar->w;
    if(xDistanceFromEdge > 0) // we're busting
    {
        sourceRect.w -= xDistanceFromEdge;
        destRect.w -= xDistanceFromEdge;
    }
    int yDistanceFromEdge = (destRect.y + destRect.h) - mFogOfWar->h;
    if(yDistanceFromEdge > 0) // we're busting
    {
        sourceRect.h -= yDistanceFromEdge;
        destRect.h -= yDistanceFromEdge;
    }

    SDL_LockSurface(mFogOfWar);

    Uint32* destPixels = (Uint32*)mFogOfWar->pixels;
    Uint32* srcPixels = (Uint32*)mFogOfWarPunch->pixels;

    static bool keepFogRemoved = false;

    for(int x = 0; x < destRect.w; ++x)
    {
        for(int y = 0; y < destRect.h; ++y)
        {
            Uint32* destPixel = destPixels + (y + destRect.y) * mFogOfWar->w + destRect.x + x;
            Uint32* srcPixel = srcPixels + (y + sourceRect.y) * mFogOfWarPunch->w + sourceRect.x + x;

            unsigned char* destAlpha = (unsigned char*)destPixel + 3; // fetch alpha channel
            unsigned char* srcAlpha = (unsigned char*)srcPixel + 3; // fetch alpha channel
            if(keepFogRemoved == true && *srcAlpha > 0)
            {
                continue; // skip this pixel
            }

            *destAlpha = *srcAlpha;
        }
    }

    SDL_UnlockSurface(mFogOfWar);
}

然后给了我这个keepFogRemoved = false即使角色四处移动后

而这与keepFogRemoved = true

验证

重要的部分是确保您不会在像素缓冲区之外写入,因此请注意负偏移量或会使您超出宽度或高度的偏移量。为了验证我的代码,我添加了一个简单的调用RemoveFogOfWar当单击鼠标并尝试角落和边缘以确保我没有遇到“差一”问题时

case SDL_MOUSEBUTTONDOWN:
    {
        if(Event.button.button == SDL_BUTTON_LEFT)
        {
            gRenderingManager.RemoveFogOfWar(Event.button.x, Event.button.y);
        }
        break;
    }

Notes

显然,“打孔”不需要 32 位纹理,但这是我能想到的最清晰的方式来向您展示如何做到这一点。只需每像素 1 位(开/关)即可完成此操作。您还可以添加一些渐变,并更改

if(keepFogRemoved == true && *srcAlpha > 0)
{
    continue; // skip this pixel
}

对于类似的东西

if(*srcAlpha > *destAlpha)
{
    continue;
}

为了保持平滑的混合,如下所示:

3 战争迷雾状态

我想我应该添加这个...我添加了一种创建 3 状态战争迷雾的方法:visible, seen and fogged.

为此,我只需保留SDL_Rect我上次“击打”战争迷雾的地方,如果阿尔法低于某个值,我会将其限制在该值。

因此,只需添加

for(int x = 0; x < mLastFogOfWarPunchPosition.w; ++x)
{
    for(int y = 0; y < mLastFogOfWarPunchPosition.h; ++y)
    {
        Uint32* destPixel = destPixels + (y + mLastFogOfWarPunchPosition.y) * mFogOfWar->w + mLastFogOfWarPunchPosition.x + x;
        unsigned char* destAlpha = (unsigned char*)destPixel + 3;

        if(*destAlpha < 0x60)
        {
            *destAlpha = 0x60;
        }
    }
}
mLastFogOfWarPunchPosition = destRect;

就在战争迷雾被“打击”的循环之前,我得到了类似于《星际争霸》等游戏中可能出现的战争迷雾:

现在,由于“看到的”战争迷雾是半透明的,因此您需要调整渲染方法以正确剪辑雾中的“敌人”,这样您就看不到它们,但仍然可以看到地形。

希望这可以帮助!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SDL - 绘制“负”圆圈(战争迷雾) 的相关文章

  • .Net MVC4 文化设置正确,但验证仍然是英语

    我有一个非常基本的 MVC 网站 使用丹麦语 我可以在页面开头设置文化 Layout null Culture da DK 但它已经是正确的 所以我怀疑它是否重要 然后我有我的输入字段 Html EditorFor model gt mod
  • 使用参数将数据插入access数据库

    我有以下方法将数据插入到访问数据库中 该方法工作正常 但如果我尝试插入包含我学到的单引号的文本 我确实会遇到问题 WebMethod public void bookRatedAdd string title int rating stri
  • 有没有办法在 .Net 中创建“自托管”网站? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 类似于 WCF 自托管 有没有办法创建一个在控制台应用程序中 自托管 的网站或dll 提出这个问题的方
  • 将 void* 作为函数调用而不声明函数指针

    我已经搜索过 但找不到任何结果 我的术语可能有问题 所以如果以前有人问过这个问题 请原谅我 我想知道是否有一种简单的方法可以调用void 作为 C 中的函数 无需首先声明函数指针 然后为函数指针分配地址 IE 假设要调用的函数是类型void
  • 在 C# 中,为什么从列表创建 HashSet 比从 HashSet 开始更快?

    我有一个方法 它采用上限 并返回达到该限制的素数列表 public static List
  • 提升解析器中的 Spirit 段错误

    我一直在尝试将我在本科编译器中编写的一些 lex 和 yacc 代码转换为精神代码以学习精神 我发现了一个我似乎无法弄清楚的段错误 我这样写了词法分析器 namespace lex boost spirit lex enum Tokens
  • 测试 WebApi 控制器时如何生成 Asp.net 用户身份

    我正在使用 Web API 2 在 web api 控制器中我使用过GetUserId使用 Asp net Identity 生成用户 ID 的方法 我必须为该控制器编写 MS 单元测试 如何从测试项目访问用户 ID 我在下面附上了示例代码
  • MDI应用程序中父窗体的问题

    我使用按钮作为容器中的控件 父窗体 当子窗体出现时 父窗体中的控件 按钮 图片 标签 出现在子窗体上并将其覆盖 我看不到子窗体 有谁知道如何防止这种情况 我不想将这些控件设置为 Control Visible false 因为当我最小化子表
  • C# - 获取 GPU 的总使用百分比

    我正在向我的程序添加一些新功能 这些功能当前通过串行连接将 CPU 使用情况和 RAM 使用情况发送到 Arduino 请参阅this https create arduino cc projecthub thesahilsaluja cp
  • Task.WaitAll 保持循环

    我正在尝试这个异步代码只是为了测试 async 关键字 public async Task
  • Windows 消息

    我需要发送带有自定义 ID 的自定义 Windows 消息 其他应用程序将侦听该消息 Windows 是否为内部消息保留任何预定义的消息 ID 范围 如 SQL Server 那样 内部消息最多为 50 000 The 文档 https m
  • FormsAuthentication.SetAuthCookie() 是否需要重定向?

    检查用户的凭据并确认其良好后 我正在使用FormsAuthentication SetAuthCookie Username false 对用户进行身份验证 然后在母版页中我使用Page User Identity IsAuthentica
  • C 错误:格式“%s”需要“char *”类型的参数,但参数 2 的类型为“char (*)[100]”

    过去几天我正在用 c 进行练习 并且收到此警告 如标题所示 我已经尝试了很多东西 但我真的不知道如何准确地解决这个问题 我不擅长编程 所以会有错误 以下是我正在使用的结构 无法更改 因为它们就是这样给出的 typedef struct bo
  • 如何从 .NET DataGridView 控件单元格值写入文本文件?

    我有以下代码应该循环遍历我的所有行DataGridView 并将其所有单元格值写入文本文件 但是 它输出所有行 但仅输出每行的第一个单元格 而不输出其他三个单元格 string file name C test1 txt var objWr
  • 正确重载 stringbuf 以替换 MATLAB mex 文件中的 cout

    MathWorks 目前不允许您使用cout当 MATLAB 桌面打开时 从 mex 文件中读取 因为它们已重定向 stdout 他们当前的解决方法是提供一个函数 mexPrintf 他们要求你改用 http www mathworks c
  • LINQ 表达式树 Any() 位于Where() 内

    我正在尝试生成以下 LINQ 查询 Query the database for all AdAccountAlerts that haven t had notifications sent out Then get the entity
  • 如何在 if () 语句中声明变量? [复制]

    这个问题在这里已经有答案了 可能的重复 在 C 的条件或控制语句中声明和初始化变量 https stackoverflow com questions 1516919 declaring and initializing a variabl
  • MDI 窗体中的子窗口对接

    我有一个 MDI 表单和其中的一些子表单 我将子窗体停靠到 MDI 窗口的不同区域 但是当任何子窗体失去焦点时 其他停靠的窗体将重新排列 由于混乱 我准备了一组图像来展示该行为 Image1 单击任何窗口之前 Image2 点击窗口2后 问
  • 引用计数类和多线程

    我是多线程编程的新手 对此我仍然感到困惑 下面是我的引用计数类 class Rbuffer private char m pnData volatile unsigned int mRefCount public Rbuffer int n
  • 在 Blazor 中显示计时器

    我正在尝试在服务器端 Blazor 应用程序中显示倒计时器 我的代码同时使用 F 和 C 语言 该代码在某种程度上可以工作 但计时器永远不会按预期停止 并且计时器显示偶尔不会呈现所有数字 这是我第一次尝试 Blazor 服务器端应用程序 我

随机推荐

  • iOS 蓝牙应用程序仅在后台模式下“由于信号 9 而终止”

    我正在 Objective c 中开发一个 IOS 应用程序 它显示来自蓝牙 BLE 的心率以及相应的图形 如果应用程序在前台运行 则一切都可以正常分叉 没有任何问题 但是 如果应用程序进入后台模式 BLE 测量仍然会继续 我正在使用 使用
  • Lollipop Android 锁屏小部件

    棒棒糖中的锁定屏幕小部件是否有任何更改 虽然官方文件明确显示没有变化 但是 http www extremetech com computing 192112 android 5 0 lollipop all details and fea
  • 我可以使用 SocketCAN 读取 CRC 和 ACK 位吗?

    我正在寻找一种方法 通过 PiCan2 将消息从一个 Raspberry Pi 发送到另一个 并接收回来以读取 CRC 和 ACK 位 我搜索了文档但找不到这样的选项 我可能错过了什么吗 你不直接处理CRC and ACK 但当此类事件发生
  • Java 中的 HTTP 标头编码/解码

    自定义 HTTP 标头被传递到 Servlet 应用程序以进行身份 验证 标头值必须能够包含重音符号和其他非 ASCII 字符 因此必须采用某种编码 最好是 UTF 8 控制身份验证环境的开发人员向我提供了这段 Java 代码 String
  • 如何循环 QAbstractItemView 索引?

    我想开火QAbstractItemView doubleClicked以编程方式为具有特定文本的项目插入槽 我想用QAbstractItemView如果可能的话 类而不是它的实现 此任务归结为循环项目和比较字符串 但我找不到任何方法可以给我
  • 获取远程用户Mac地址

    我正在开发一个使用 mongodb express 和 nodejs 构建基于内联网的 web 应用程序的项目 该项目的目标是通过身份验证获取用户 mac 地址并运行远程 ssh 然而 我发现很难获取远程电脑的 MAC 地址 客户端和服务器
  • R Markdown 在一个项目中找不到 .bib 文件,而在另一个项目中工作正常

    Rmd 在文件 x 中引用良好 单击 knit 将引用添加到我的引用列表后 但是在文件 y 中 还有一个 rmd 文件设置如下 title Swans bibliography library bib output html documen
  • 从批处理文件运行 vbscript

    我只需要编写一个简单的批处理文件来运行 vbscript vbscript 和批处理文件位于同一文件夹中 并且位于 SysWOW64 目录中 因为 vbscript 只能在该目录中执行 目前我的批处理文件如下 echo off WINDIR
  • 如何通过 XMPP (Jabber) 消息在网络上发送图像?

    For the 用于 Stack Overflow 聊天的 XMPP 界面 https meta stackexchange com questions 57316 offer an xmpp method for chat 63420 6
  • Python 使用 urllib2 发起请求时 Tor 检查失败

    读完后other https stackoverflow com questions 1096379 tor with python 问题 https stackoverflow com questions 711351 using url
  • 如何在 Windows 7 上的 Python 2.7.1 中安装 easy_install

    我已在 Windows 7 上安装了 Python 2 7 1 但无法安装 easy install 请帮我 我通常只是跑步ez setup py http peak telecommunity com dist ez setup py I
  • 如何在Eclipse中引用不在src中的文件

    我正在尝试获取 MyBatis 的资源 该教程指出我的连接工厂中需要以下内容 String resource org mybatis example Configuration xml Reader reader Resources get
  • 如何更好地优化 iOS 上的网络?

    我在 GitHub 上创建了一个项目 以便我可以学习如何优化 iOS 应用程序的网络 我大量使用了块和 GCD 在观看 WWDC 2012 视频和过去几年的视频后 我了解到我可以使用 NSOperationQueue 做更多事情 具体来说
  • 在IIS上使用swagger发布web api

    在遵循此示例后 我正在尝试弄清楚如何使用 Swagger SwashBuckle 发布 net core 3 API 所以它可以在本地运行 当我按 F5 IIS Express 时 会在下面启动该网站http localhost 8033
  • 如何构建具有开放问题的 Dialogflow CX 代理?

    我正在尝试为 StackOverflow 之类的东西构建一个 Dialogflow 代理 它负责处理用户提出完整的问题 我想存储答案 并将其反馈给用户 例如 User I get an error CX Which error Java l
  • 扩展用户管理器

    在我的 NET Core 2 0 MVC 项目中 我添加了附加值来扩展 ApplicationUser public class ApplicationUser IdentityUser public string Name get set
  • java- libgdx build.gradle 与 AdMob 不同

    我正在为 android 构建一个应用程序并使用 libGdx 我检查了一百万个关于如何添加 Admob 的教程 每个教程都要求调整 build gradle 文件 但我的文件与他们的文件不一样 他们有依赖项和不同的东西 知道如何在我的 b
  • NSURLConnection 委托方法未执行

    我正在运行 Apple 的以下示例代码 NSString requestURL NSString alloc initWithString http google com NSURLRequest theRequest NSURLReque
  • numpy 中的数组按行排序

    我想按第一行对 numpy 中的数组进行排序 例如 import numpy as np test np array 1334 71601720318 930 9757468052002 1018 7038817663818 0 0 1 0
  • SDL - 绘制“负”圆圈(战争迷雾)

    我有这个 800x600square 我想绘制到屏幕上 我想在其中 切割 圆圈 其中 alpha 为 0 基本上我是在地图上绘制整个矩形 因此在我绘制的这些 圆圈 中 您可以看到地图 否则您会看到灰色方块 所以 我假设你想在你的一款游戏中添