27 Eylül 2026 Pazar

2D árekstrargreining í MonoGame: Frá grunnrétthyrningum til núllúthlutunar Pixel-Perfect Systems




2D árekstrargreining í MonoGame: Frá grunnrétthyrningum til núllúthlutunar Pixel-Perfect kerfi

Þegar þú smíðar 2D leiki í sjónvélum eins og Unity eða Godot, líður árekstrargreiningu oft eins og röð af gátreitum eftirlitsaðila: þú skellir á BoxCollider2D eða CircleCollider2D, festir Rigidbody og vonar að innra eðlisfræðiþrepið stami ekki á farsímum.

Í MonoGame og C# hefurðu hins vegar fulla stjórn. Það er engin falin eðlisfræði yfir höfuð, engin óæskileg snúningstregðu og engir dularfullir sorpsöfnunarbroddar sem stela rammakostnaðarhámarkinu þínu.

Á Arar Games, þegar við smíðuðum Blocked: Pixel Panzer og Paint Trek, þurfti spilakassaleikjalykkjur okkar til að vinna úr hundruðum háhraða óvinakúla, sprungið múrsteinsnet, snúnings skriðdrekaturn, orrustuþotur og agnahlífar á 60 til 120 FPS tæki í bæði Windows PC og Android tæki. Almennur eðlisfræðivél kom ekki til greina - við þurftum sérsmíðaðan, stigskipt árekstraarkitektúr.

Í þessari yfirgripsmiklu, kóðadrifnu handbók munum við byrja á algerum grunnatriðum MonoGame áreksturs („Rectangle.Intersects“ með raunverulegum „Bullet“ og „Enemy“ sprites) og byggja upp í háþróaða hringathugun, blandaða klemmu, geislavörn gegn jarðgöngum, framleiðslu-gráðu PixelPer,All Spa Pixel-Zero og All Grids fínstillt fyrir farsíma GC lifun.


1. Grunnurinn: Einfalt „Sprite“ stigveldi í einleikjum

Áður en við greinum árekstra þurfum við hreina leikjaeiningar. Í MonoGame býr eining í grundvallaratriðum yfir stöðu, áferð og afmarkandi rétthyrning.

Hér er grunneiningaarkitektúrinn sem notaður er í leikjum okkar:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

public class Sprite
{
    public Vector2 Position;
    public Texture2D Texture;
    public Color Tint = Color.White;
    public bool IsActive = true;

    // The raw Axis-Aligned Bounding Box (AABB)
    public virtual Rectangle Bounds => new Rectangle(
        (int)Position.X,
        (int)Position.Y,
        Texture != null ? Texture.Width : 0,
        Texture != null ? Texture.Height : 0
    );

    public virtual void Draw(SpriteBatch spriteBatch)
    {
        if (!IsActive || Texture == null) return;
        spriteBatch.Draw(Texture, Position, Tint);
    }
}

Nú skulum við búa til „Player“, „Enemy“ og „Bullet“ flokka:

public class Bullet : Sprite
{
    public Vector2 Velocity;
    public int Damage = 25;

    public void Update(GameTime gameTime)
    {
        Position += Velocity * (float)gameTime.ElapsedGameTime.TotalSeconds;
    }
}

public class Enemy : Sprite
{
    public int Health = 100;

    public void TakeDamage(int damage)
    {
        Health -= damage;
        if (Health <= 0)
        {
            IsActive = false;
        }
    }
}

public class Player : Sprite
{
    public int Health = 100;
    public bool IsInvulnerable = false;

    public void TakeDamage(int damage)
    {
        if (IsInvulnerable) return;
        Health -= damage;
    }
}

Með þessar einingar á sínum stað skulum við kanna hvernig á að greina árekstra á milli þeirra, byrjað á einföldustu aðferðinni.


2. Stig 1: Einfaldasti áreksturinn – Rectangle.Intersects (AABB)

Grundvallaratriði tvívíddar árekstraeftirlitsins í MonoGame er Axis-Aligned Bounding Box (AABB) prófið. Hugtakið "ás-jafnað" þýðir einfaldlega að brúnir rétthyrningsins eru alveg samsíða \(X\) og \(Y\) ásum skjásins (enginn snúningur).

MonoGame býður upp á hraðvirka, innbyggða aðferð: Rectangle.Intersects(Rectangle value).

Hvernig Rectangle.Carsects virkar undir hettunni

Undir yfirborðinu framkvæmir MonoGame fjóra heiltölusamanburð:

public bool Intersects(Rectangle value)
{
    return value.Left < this.Right &&
           this.Left < value.Right &&
           value.Top < this.Bottom &&
           this.Top < value.Bottom;
}

Ef öll fjögur skilyrðin eru uppfyllt skarast ferhyrningarnir. Ef jafnvel eitt skilyrði bregst, skilur tómur ás þá að og enginn árekstur er mögulegur.

Raunverulegur spilunarkóði: 'Bullet' vs. 'Enemy' í 'Game1.Update'

Hér er hvernig þú athugar árekstra milli lista yfir virkar byssukúlur og lista yfir virka óvini í aðal MonoGame Update lykkjunni þinni:

public class Game1 : Game
{
    private List<Bullet> _bullets = new List<Bullet>();
    private List<Enemy> _enemies = new List<Enemy>();

    protected override void Update(GameTime gameTime)
    {
        // 1. Update bullet and enemy positions
        foreach (var bullet in _bullets) bullet.Update(gameTime);

        // 2. Collision Check: Bullets vs Enemies
        for (int b = _bullets.Count - 1; b >= 0; b--)
        {
            var bullet = _bullets[b];
            if (!bullet.IsActive) continue;

            for (int e = _enemies.Count - 1; e >= 0; e--)
            {
                var enemy = _enemies[e];
                if (!enemy.IsActive) continue;

                // The AABB check!
                if (bullet.Bounds.Intersects(enemy.Bounds))
                {
                    // Collision occurred!
                    enemy.TakeDamage(bullet.Damage);
                    bullet.IsActive = false;

                    // Remove inactive bullet immediately
                    _bullets.RemoveAt(b);
                    
                    if (!enemy.IsActive)
                    {
                        _enemies.RemoveAt(e);
                    }

                    // A bullet can only hit one enemy; break the inner loop
                    break;
                }
            }
        }

        base.Update(gameTime);
    }
}

Ábending um árangur: Taktu eftir að við endurtökum afturábak (for (int i = list.Count - 1; i >= 0; i--))! Ef þú notar foreach og reynir að kalla _bullets.Remove(bullet), sendir C# InvalidOperationException: Collection was modified. Ítrekun aftur á bak gerir kleift að fjarlægja hluti á öruggan hátt án vandamála við endurskráningu minni.

The Arcade Secret: "Fair Hitboxes" í gegnum Inflate

Í afturleikjum eins og Blocked: Pixel Panzer inniheldur sprite áferð oft gagnsæja spássíu eða loftnetsgadda. Ef tankur leikmannsins springur vegna þess að byssukúla snerti tómt gagnsætt horn af áferð hans, mun leikmaðurinn líða svikinn.

Til að láta árekstur líða móttækilega og sanngjarnan nota leikir minni Hitbox inni í spritenum með því að nota Rectangle.Inflate:

public class EnemyTank : Enemy
{
    // Shrink the bounding box by 6 pixels on all sides for fair collision
    public override Rectangle Bounds
    {
        get
        {
            Rectangle raw = base.Bounds;
            raw.Inflate(-6, -6); // Reduces width and height by 12px
            return raw;
        }
    }
}

3. Level 2: Circle-to-Circle Collision (Rotational Immunity)

Rectangles work great for static blocks and grid tiles, but they fail when sprites rotate. Þegar geimskip sem er ekki ferhyrnt snýst í Paint Trek, verður ásbundinn afmarkareitur að stækka til að umvefja hornin sem snúast, sem leiðir til pirrandi „fantómaárekstra“ í tómu lofti.

For circular asteroids, homing energy orbs, and rotating spacecraft, Bounding Circles are the ideal solution.

Fermetrarótargildran

Two circles collide when the distance between their centers is less than or equal to the sum of their radii:

\(\text{Fjarlægð}(C_A, C_B) \le r_A + r_B\)

In code, calculating Euclidean distance uses Math.Sqrt (or Vector2.Distance). However, calculating square roots in a loop with 200 projectiles burns hundreds of unnecessary CPU cycles!

By comparing the squared distance against the squared radius sum, we completely eliminate the square root:

\(\text{DistanceSquared} \le (r_A + r_B)^2\)

MonoGame Implementation: Circle vs. Circle

public struct Circle
{
    public Vector2 Center;
    public float Radius;

    public Circle(Vector2 center, float radius)
    {
        Center = center;
        Radius = radius;
    }

    public bool Intersects(Circle other)
    {
        float radiusSum = this.Radius + other.Radius;
        
        // MonoGame built-in Vector2.DistanceSquared
        return Vector2.DistanceSquared(this.Center, other.Center) <= (radiusSum * radiusSum);
    }
}

Samþættu þetta núna beint í einingu:

public class PaintTrekFighter : Sprite
{
    public float CollisionRadius = 18f;
    public Vector2 Center => Position + new Vector2(Texture.Width * 0.5f, Texture.Height * 0.5f);

    public Circle BoundingCircle => new Circle(Center, CollisionRadius);

    public bool CollidesWith(PaintTrekFighter other)
    {
        return this.BoundingCircle.Intersects(other.BoundingCircle);
    }
}

Núll ferningsrætur, ónæmur fyrir snúningi sprite og eldingarhraður.


4. Stig 3: Blönduð form – Hringur vs. kassi (MathHelper.Clamp)

Hvað gerist þegar hringlaga geimskip í Paint Trek siglir í gegnum þröngt völundarhús rétthyrndra varnarhindrana, eða þegar kringlótt kúla lendir á ferningaðri blokk í Blocked: Pixel Panzer?

Við þurfum Hring vs. Rétthyrning árekstur.

Klemmualgrímið

Stefnan er að finna punktinn á rétthyrningnum sem er næst miðju hringsins og prófa síðan hvort fjarlægðin frá þeim punkti sem er næst miðjunni sé minni en radíus hringsins.

MathHelper.Clamp frá MonoGame gerir þetta léttvægt:

public static class Collision2D
{
    public static bool CircleIntersectsRectangle(Circle circle, Rectangle rect)
    {
        // Find the closest point on the rectangle to the circle center
        float closestX = MathHelper.Clamp(circle.Center.X, rect.Left, rect.Right);
        float closestY = MathHelper.Clamp(circle.Center.Y, rect.Top, rect.Bottom);

        // Vector from closest point to circle center
        float distanceX = circle.Center.X - closestX;
        float distanceY = circle.Center.Y - closestY;

        // Check squared distance against squared radius
        float distanceSquared = (distanceX * distanceX) + (distanceY * distanceY);
        return distanceSquared <= (circle.Radius * circle.Radius);
    }
}

Þú getur nú prófað skjöld leikmanna gegn rétthyrndum múrsteinum með núllúthlutun og mikilli nákvæmni!


5. Stig 4: Continuous Collision Detection (CCD) & Swept Rays

Hefur þú einhvern tíma skotið á háhraða leyniskyttulotu eða járnbyssuleysi í leiknum þínum, aðeins til að horfa á kúluna fara töfrandi beint í gegnum þunnt óvinaskip án þess að valda skaða?

Þessi galla er þekkt sem tunneling.

Vegna þess að stakir leikir uppfærast í tímaskrefum (\(\Delta t = 16,6\text{ms}\) við 60 FPS), ferðast hlutur sem hreyfist á 1.800 pixlum á sekúndu 30 pixlar í einum ramma. Ef skrokkur óvinarins er aðeins 15 dílar þykkur, var kúlan fyrir framan óvininn á Frame 1, og alveg fyrir aftan óvininn á Frame 2.

Frame 1:  [ Bullet ]  --->       | Enemy Wall |
Frame 2:                          | Enemy Wall |       --->  [ Bullet ]
                               (NO HIT DETECTED!)

Lausnin: Sópaður hluti vs. kassi (helluaðferð)

Í stað þess að prófa einn punkt, prófum við allan línuhlutann sem tengir stöðu skotsins á ramma 1 (fyrri staða) við ramma 2 (núverandi staðsetning).

Hér er framleiðslu geislavarpshelluskurðaraðferðin úr félagatitli okkar SpiralWar:

public static class ContinuousCollision
{
    public static bool IntersectsSweptRay(Vector2 rayStart, Vector2 rayEnd, Rectangle box, out Vector2 hitPoint)
    {
        hitPoint = Vector2.Zero;

        Vector2 direction = rayEnd - rayStart;
        float tMin = 0f;
        float tMax = 1f;

        // Clip against X slabs
        if (MathF.Abs(direction.X) > 1e-6f)
        {
            float invX = 1f / direction.X;
            float t1 = (box.Left - rayStart.X) * invX;
            float t2 = (box.Right - rayStart.X) * invX;
            if (t1 > t2) (t1, t2) = (t2, t1);

            tMin = MathF.Max(tMin, t1);
            tMax = MathF.Min(tMax, t2);
            if (tMin > tMax) return false;
        }
        else if (rayStart.X < box.Left || rayStart.X > box.Right)
        {
            return false;
        }

        // Clip against Y slabs
        if (MathF.Abs(direction.Y) > 1e-6f)
        {
            float invY = 1f / direction.Y;
            float t1 = (box.Top - rayStart.Y) * invY;
            float t2 = (box.Bottom - rayStart.Y) * invY;
            if (t1 > t2) (t1, t2) = (t2, t1);

            tMin = MathF.Max(tMin, t1);
            tMax = MathF.Min(tMax, t2);
            if (tMin > tMax) return false;
        }
        else if (rayStart.Y < box.Top || rayStart.Y > box.Bottom)
        {
            return false;
        }

        hitPoint = rayStart + direction * tMin;
        return true;
    }
}

Í Blocked: Pixel Panzer notar stöðug Laser Beam kunnátta þessa nákvæma geislavarps til að sneiða í gegnum raðir af lækkandi blokkum án þess að missa af einum árekstri.


6. Stig 5: Framleiðslueinkunn Pixel-Perfect Collision Detection

Nú náum við fullkomnu stigi tvívíddar nákvæmni: Pixel-Perfect Collision.

Í retro skriðdrekaskotleik eða hundabardaga í geimskipum eru óregluleg form (tanktunnur, vængir, stjórnklefa) umkringd gagnsæjum pixlum í sprite áferðinni. Þegar óvinaflugskeyti lendir á því gagnsæja rými taka leikmenn strax eftir því.

Pixel-fullkominn árekstur skoðar raunverulegar alfa (gagnsæi) rásir áferðanna sem skarast. Ef tveir ógegnsæir punktar skarast á sama heimshnitinu hefur raunverulegt líkamlegt högg átt sér stað.

The Fatal Mistake: GetData inni í Update()

Mörg námskeið leiðbeina byrjendum að gera þetta:

// DO NOT DO THIS!
Color[] dataA = new Color[textureA.Width * textureA.Height];
textureA.GetData(dataA); // STALLS GPU, CREATES MASSIVE GC LAG!

Að kalla Texture2D.GetData() á keyrslutíma neyðir örgjörvann til að bíða eftir að GPU leiðslan skolist og dregur áferðaminni aftur yfir rútuna. Með því að gera þetta fyrir heilmikið af sprites, hver rammi mun fylla leikinn þinn frá 60 FPS til 5 FPS og kveikja strax á Android ANR!

Bardagaprófaða lausnin frá Blocked: Pixel Panzer

Í Blocked: Pixel Panzer innleiðir Sprite.cs okkar ofurbjartaða IntersectsPixel rútínu sem byggir á 5 mikilvægum reglum:

  1. Static Color Array Cache: GetData er kallað nákvæmlega einu sinni þegar áferðin hleðst, og geymd í Dictionary<Texture2D, Color[]>.
  2. AABB Early Exit Guard: Ef Bounds.Intersects(other.Bounds) er rangt, björgum við strax. 99% athugana er eytt áður en einn pixla er skoðaður.
  3. Texture Atlas & SourceRectangle Stuðningur: Meðhöndlar sprites sem er pakkað inn í texture atlases með því að nota uppruna rétthyrningastöðu.
  4. Reiknuð skörunargluggi: Við lykkjum aðeins yfir nákvæman skurðarhorn rétthyrningsins á milli beggja sprites (Math.Max(a.Top, b.Top) osfrv.).
  5. Alfa skammhlaup: Ef pixla Sprite A er gegnsær (A <= 20), er Sprite B alveg sleppt.
  6. Hífing eigna: Aðgangur að sýndareiginleikum ('Bounds') í hreiðrum lykkjum skapar þúsundir structafrita. Við geymum þær í staðbundnum staflabreytum áður en farið er inn í lykkjuna.

Hér er heill, framleiðslu-tilbúinn kóða:

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

public class AdvancedSprite : Sprite
{
    private static readonly Dictionary<Texture2D, Color[]> _textureDataCache = new();

    public Rectangle? SourceRectangle { get; set; }

    public static Color[] GetCachedTextureData(Texture2D texture)
    {
        if (!_textureDataCache.TryGetValue(texture, out var data))
        {
            data = new Color[texture.Width * texture.Height];
            texture.GetData(data);
            _textureDataCache[texture] = data;
        }
        return data;
    }

    public bool IntersectsPixel(AdvancedSprite other)
    {
        // 1. Hoist bounds into local stack variables
        Rectangle a = this.Bounds;
        Rectangle b = other.Bounds;

        // 2. Fast AABB Broad-Phase check
        if (!a.Intersects(b)) return false;

        // Fallback to rectangle check if textures are missing
        if (this.Texture == null || other.Texture == null) return true;

        // 3. Retrieve pre-cached color arrays (Zero GPU latency)
        Color[] dataA = GetCachedTextureData(this.Texture);
        Color[] dataB = GetCachedTextureData(other.Texture);

        int aTexW = this.Texture.Width;
        int bTexW = other.Texture.Width;

        // Atlas / SourceRectangle offset mapping
        bool aHasSrc = this.SourceRectangle.HasValue;
        Rectangle aSrc = aHasSrc ? this.SourceRectangle.Value : Rectangle.Empty;
        int aOriginX = aHasSrc ? aSrc.X : 0;
        int aOriginY = aHasSrc ? aSrc.Y : 0;
        int aSpanX   = aHasSrc ? aSrc.Width  : this.Texture.Width;
        int aSpanY   = aHasSrc ? aSrc.Height : this.Texture.Height;

        bool bHasSrc = other.SourceRectangle.HasValue;
        Rectangle bSrc = bHasSrc ? other.SourceRectangle.Value : Rectangle.Empty;
        int bOriginX = bHasSrc ? bSrc.X : 0;
        int bOriginY = bHasSrc ? bSrc.Y : 0;
        int bSpanX   = bHasSrc ? bSrc.Width  : other.Texture.Width;
        int bSpanY   = bHasSrc ? bSrc.Height : other.Texture.Height;

        // 4. Calculate the overlapping sub-rectangle
        int top    = Math.Max(a.Top, b.Top);
        int bottom = Math.Min(a.Bottom, b.Bottom);
        int left   = Math.Max(a.Left, b.Left);
        int right  = Math.Min(a.Right, b.Right);

        // 5. Scan only overlapping pixels
        for (int y = top; y < bottom; y++)
        {
            // Row offsets hoisted outside the inner X loop!
            int colorA_Y = aOriginY + (int)((y - a.Y) / (float)a.Height * aSpanY);
            int colorB_Y = bOriginY + (int)((y - b.Y) / (float)b.Height * bSpanY);
            int rowA = colorA_Y * aTexW;
            int rowB = colorB_Y * bTexW;

            for (int x = left; x < right; x++)
            {
                int colorA_X = aOriginX + (int)((x - a.X) / (float)a.Width * aSpanX);

                // Early Bailout: If Pixel A is transparent, skip B entirely!
                if (dataA[colorA_X + rowA].A <= 20) continue;

                int colorB_X = bOriginX + (int)((x - b.X) / (float)b.Width * bSpanX);

                // If Pixel B is also opaque, we have confirmed contact!
                if (dataB[colorB_X + rowB].A > 20)
                {
                    return true;
                }
            }
        }

        return false;
    }
}

Þessi venja keyrir á innan við 0,1 millisekúndum á nútíma Android vélbúnaði og skjáborðskerfum.


7. Stig 6: Breiðfasa landnet og núllúthlutun farsíma GC

Ímyndaðu þér að leikurinn þinn hafi 100 kubba, 60 byssukúlur og 20 óvini. Ef þú prófar hverja einingu á móti hverri annarri einingu með því að nota hreiðra "for" lykkjur, framkvæmir þú:

\(\frac{180 \times 179}{2} = 16.110 \text{ ávísanir á ramma!}\)

Við 60 FPS eru það næstum 1.000.000 árekstrarpróf á sekúndu.

Til að stækka leikinn þinn verður þú að innleiða breiðfasa landskiptingu.

The Uniform Spatial Hash Grid

Við skiptum skjánum í 2D rist af samræmdum frumum (í Blocked: Pixel Panzer, hver reit er \(150 \x 150\) pixlar). Eining prófar aðeins árekstra gegn öðrum einingum sem eru í sömu hnitahólfum.

Mobile minni vandamálið: GC þras

Ef SpatialGrid þitt býr til new List<Point>() eða new List<Block>() í hverjum ramma, úthlutar þú megabæti af rusli á hverri mínútu á stýrðu hrúguna.

Á Mono keyrslutíma Android kallar þetta á tíðar Gen-0 sorpasöfnun, sem veldur: mono runtime: Innfæddur læsideilur (mono_class_is_subclass_)

Leikurinn stamar og Google Play flaggar leikinn þinn með ANR-viðvörunum!

Lausnin: Endurnýtanlegur rispúði

Hér er Zero-úthlutun Spatial Hash Grid frá CollisionManager.cs í Blocked: Pixel Panzer:

public class SpatialGridManager
{
    private const int CELL_SIZE = 150;
    private readonly Dictionary<Point, List<Sprite>> _grid = new();

    // Zero-GC: Reusable scratch buffers allocated ONCE at startup
    private readonly List<Point> _scratchCells = new();
    private readonly HashSet<Sprite> _scratchCheckedEntities = new();

    public void BuildGrid(List<Sprite> entities)
    {
        // Clear lists without re-allocating new List objects
        foreach (var list in _grid.Values)
        {
            list.Clear();
        }

        foreach (var entity in entities)
        {
            if (!entity.IsActive) continue;

            GetOccupiedCells(entity.Bounds, _scratchCells);
            foreach (var cell in _scratchCells)
            {
                if (!_grid.TryGetValue(cell, out var list))
                {
                    list = new List<Sprite>();
                    _grid[cell] = list;
                }
                list.Add(entity);
            }
        }
    }

    private void GetOccupiedCells(Rectangle bounds, List<Point> outCells)
    {
        outCells.Clear();

        int startX = bounds.Left / CELL_SIZE;
        int startY = bounds.Top / CELL_SIZE;
        int endX = bounds.Right / CELL_SIZE;
        int endY = bounds.Bottom / CELL_SIZE;

        for (int x = startX; x <= endX; x++)
        {
            for (int y = startY; y <= endY; y++)
            {
                outCells.Add(new Point(x, y));
            }
        }
    }

    public void CheckCollisions(Player player)
    {
        if (player.IsInvulnerable) return;

        GetOccupiedCells(player.Bounds, _scratchCells);
        _scratchCheckedEntities.Clear();

        foreach (var cell in _scratchCells)
        {
            if (_grid.TryGetValue(cell, out var entitiesInCell))
            {
                foreach (var other in entitiesInCell)
                {
                    if (other == player || _scratchCheckedEntities.Contains(other)) continue;
                    _scratchCheckedEntities.Add(other);

                    // 1. Broad-phase AABB test
                    if (player.Bounds.Intersects(other.Bounds))
                    {
                        // 2. High-precision Pixel-Perfect test
                        if (player is AdvancedSprite advPlayer && other is AdvancedSprite advOther)
                        {
                            if (advPlayer.IntersectsPixel(advOther))
                            {
                                player.TakeDamage(10);
                            }
                        }
                    }
                }
            }
        }
    }
}

Með því að endurnýta _scratchCells og _scratchCheckedEntities keyrir allt árekstrarskrefið með 0 bætum af hrúguúthlutun á hvern ramma.


8. Samanburðartafla

Tækni Stærðfræðilegur kostnaður Snúningsstuðningur Öruggt að fara í jarðgöng? Besta notkunarmálið í MonoGame
AABB (Rectangle.Skærur) Ofur-Fast (~4 heiltölu samanburður) Nei Nei Grid blokkir, bullet breiðfasa, UI
Hringur (DistanceSquared) Mjög hratt (3 múl, 0 sqrt) Já (óbreytilegt) Nei Hringskip, eldkúlur, orkuhnöttur
Circle vs Box (Clamp) Hratt (Local MathHelper.Clamp) Já Nei Hringlaga leikmaður að sigla um þrönga veggi
Swept Ray (Slab CCD) Miðlungs (Parametric Raycast) Já Já Hraðar leyniskyttukúlur, járnbrautarbyssur, leysir
Pixel-Perfect (IntersectsPixel) Sértækur (Takmarkaður undirgrein) Já Nei Óreglulegar sprite útlínur, sanngjörn hitbox
Rýmisnet (núll-GC) Breiðfasa (\(O(N^2) \to O(N)\)) N/A N/A Þéttar öldur, skothelvíti, Android 60 FPS

Framleiðslusýningar í raunheimum: Arar leikir

Þessir árekstrararkitektúrar eru ekki fræðilegar tilraunir - þeir eru raunverulegur verkfræðilegur grunnur sem knýr titla okkar sem eru gefnir út í atvinnuskyni:

  • Lokað: Pixel Panzer: Retro tank survival spilakassaleikurinn okkar á Google Play og Microsoft Store. Það býður upp á fullkomið tveggja hæða árekstrarkerfi okkar: núllúthlutun staðbundið kjötkássanet sem síar fallkubba og pixla-fullkomna snertiskoðun fyrir skriðdreka, orrustuþotur, virkisturnskeljar og ColorWheel frumefni skotfæri.
  • Paint Trek: Hraðvirka geimskotleikurinn okkar með snúningshringárekstri, samfelldri geislavörn og eldflaugavarnarkerfi með sópuðu rúmmáli.

Niðurstaða og næstu skref

MonoGame gefur þér kraft til að hanna árekstrargreiningu sem passar fullkomlega við þarfir leiksins. Með því að setja dýrar Pixel-Perfect athuganir á bak við hröð AABB próf, nota Squared Distances fyrir hringi og útrýma sorphirðu með Endurnýtanlegum Scratch Buffers, geturðu skilað sléttum 60/120 FPS afköstum á bæði borðtölvum og farsímakerfum.

Skoðaðu leiki okkar í app-verslunum til að sjá þessi árekstrakerfi í aðgerð og byrjaðu að innleiða þessi mynstur í þínum eigin MonoGame verkefnum í dag!


Verslunartenglar og tilföng


SEO leitarorð og Hashtags

Lykilorð: MonoGame 2D árekstrargreining, C# leikjaþróun, Rectangle.Skærur MonoGame, pixla fullkominn árekstur C#, staðbundið hash rist MonoGame, sópað geisla samfelldur árekstur, fínstilling á afköstum leikja, núllúthlutun leikjalykkja, Android Pixel MonoGame fínstilling, blokkuð.

#MonoGame #CSharp #GameDev #IndieDev #GamePhysics #DotNet #2DGameDev #MobileGameDev #PerformanceOptimization #CleanCode #BlockedPixelPanzer ##GameGamegrammes``##




Hiç yorum yok:

Yorum Gönder