当前位置: 首页 > article >正文

从零开发游戏需要学习的c#模块,第二十一章(精灵动画 —— 让角色走起来)

今天我们要学习的内容是理解精灵图集的原理加载精灵图集并切帧实现四方向行走动画静止时显示待机帧第一步准备精灵图集精灵图集就是一张大图里包含多个小图帧播放时依次显示每一帧形成动画效果。一个简单的 4 帧行走图横向排列 [帧1][帧2][帧3][帧4]推荐资源网站免费itch.io 搜 top-down character sprite 或 rpg character sprite sheet下载任意一个角色精灵图集放到Content文件夹设为“如果较新则复制”。第二步创建动画管理器右键项目 →添加→类文件名Animation.csusing Microsoft.Xna.Framework;using Microsoft.Xna.Framework.Graphics;namespace MY_FIRST_GAME{public class Animation{private Texture2D texture; // 精灵图集private int frameCount; // 总帧数private int currentFrame; // 当前帧private float frameWidth; // 每帧宽度private float frameTime; // 每帧显示时间秒private float timer; // 计时器private bool isPlaying; // 是否播放中private bool isLooping; // 是否循环public Animation(Texture2D texture, int frameCount, float frameTime, bool looping true){this.texture texture;this.frameCount frameCount;this.frameTime frameTime;this.isLooping looping;frameWidth texture.Width / frameCount;currentFrame 0;timer 0f;isPlaying true;}public void Update(float deltaTime){if (!isPlaying) return;timer deltaTime;if (timer frameTime){timer 0f;currentFrame;if (currentFrame frameCount){if (isLooping)currentFrame 0; // 循环播放else{currentFrame frameCount - 1; // 停在最后一帧isPlaying false;}}}}// 获取当前帧的源矩形public Rectangle GetSourceRectangle(){return new Rectangle(currentFrame * (int)frameWidth,0,(int)frameWidth,texture.Height);}public void Play(){isPlaying true;}public void Stop(){isPlaying false;}public void Reset(){currentFrame 0;timer 0f;isPlaying true;}public int CurrentFrame currentFrame;public int FrameCount frameCount;public float FrameWidth frameWidth;public Texture2D Texture texture;}}第三步创建玩家类右键项目 →添加→类文件名Player.csusing Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; namespace MY_FIRST_GAME { public class Player { public Vector2 Position { get; set; } public float Speed { get; set; } 200f; public int Hp { get; set; } 100; public int MaxHp { get; set; } 100; public int Attack { get; set; } 15; private Texture2D texture; private Animation? currentAnimation; private Animation idleAnimation; private Animation walkAnimation; private bool isMoving; private Vector2 lastPosition; public Player(Texture2D spriteSheet, Vector2 startPosition) { Position startPosition; texture spriteSheet; // 假设精灵图集有4帧每帧0.15秒 // 如果你的图集帧数不同改这两个数字 idleAnimation new Animation(texture, 1, 0f, true); // 待机用第一帧 walkAnimation new Animation(texture, 4, 0.15f, true); // 行走4帧 currentAnimation idleAnimation; } public void Update(float deltaTime) { KeyboardState keyboard Keyboard.GetState(); lastPosition Position; isMoving false; if (keyboard.IsKeyDown(Keys.W) || keyboard.IsKeyDown(Keys.Up)) { Position.Y - Speed * deltaTime; isMoving true; } if (keyboard.IsKeyDown(Keys.S) || keyboard.IsKeyDown(Keys.Down)) { Position.Y Speed * deltaTime; isMoving true; } if (keyboard.IsKeyDown(Keys.A) || keyboard.IsKeyDown(Keys.Left)) { Position.X - Speed * deltaTime; isMoving true; } if (keyboard.IsKeyDown(Keys.D) || keyboard.IsKeyDown(Keys.Right)) { Position.X Speed * deltaTime; isMoving true; } // 限制边界 Position new Vector2( Math.Clamp(Position.X, 32, 768), Math.Clamp(Position.Y, 32, 568) ); // 切换动画 if (isMoving) { if (currentAnimation ! walkAnimation) { walkAnimation.Reset(); currentAnimation walkAnimation; } } else { currentAnimation idleAnimation; } currentAnimation.Update(deltaTime); } public void Draw(SpriteBatch spriteBatch) { Rectangle sourceRect currentAnimation.GetSourceRectangle(); Vector2 origin new Vector2(sourceRect.Width / 2, sourceRect.Height / 2); spriteBatch.Draw( texture, Position, sourceRect, Color.White, 0f, origin, 1f, SpriteEffects.None, 0f ); } public Rectangle GetBounds() { Rectangle sourceRect currentAnimation.GetSourceRectangle(); return new Rectangle( (int)(Position.X - sourceRect.Width / 2), (int)(Position.Y - sourceRect.Height / 2), sourceRect.Width, sourceRect.Height ); } } }第四步简化版 Game1.cs把Game1.cs完整替换为using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using System; using System.Collections.Generic; using System.IO; using FontStashSharp; namespace MY_FIRST_GAME { public enum GameState { Exploring, Battling } public class Game1 : Game { private GraphicsDeviceManager _graphics; private SpriteBatch _spriteBatch; private Player player default!; private Texture2D playerSpriteSheet; private Texture2D coinTexture; private ListVector2 coins; private Random rng; private int score; private Texture2D enemyTexture; private ListVector2 enemies; private SpriteFontBase font; private GameState state GameState.Exploring; public Game1() { _graphics new GraphicsDeviceManager(this); Content.RootDirectory Content; IsMouseVisible true; } protected override void Initialize() { _graphics.PreferredBackBufferWidth 800; _graphics.PreferredBackBufferHeight 600; _graphics.ApplyChanges(); rng new Random(); coins new ListVector2(); enemies new ListVector2(); score 0; SpawnCoins(5); SpawnEnemies(3); base.Initialize(); } protected override void LoadContent() { _spriteBatch new SpriteBatch(GraphicsDevice); // ★ 加载精灵图集 using var stream File.OpenRead(Content/player_spritesheet.png); playerSpriteSheet Texture2D.FromStream(GraphicsDevice, stream); player new Player(playerSpriteSheet, new Vector2(400, 300)); // 金币 coinTexture new Texture2D(GraphicsDevice, 24, 24); Color[] coinData new Color[24 * 24]; for (int i 0; i coinData.Length; i) coinData[i] Color.Gold; coinTexture.SetData(coinData); // 敌人 enemyTexture new Texture2D(GraphicsDevice, 40, 40); Color[] enemyData new Color[40 * 40]; for (int i 0; i enemyData.Length; i) enemyData[i] Color.Red; enemyTexture.SetData(enemyData); // 字体 var fontSystem new FontSystem(); fontSystem.AddFont(File.ReadAllBytes(Content/consola.ttf)); font fontSystem.GetFont(18); } private void SpawnCoins(int count) { for (int i 0; i count; i) coins.Add(new Vector2(rng.Next(50, 750), rng.Next(50, 550))); } private void SpawnEnemies(int count) { for (int i 0; i count; i) enemies.Add(new Vector2(rng.Next(80, 720), rng.Next(80, 520))); } protected override void Update(GameTime gameTime) { float deltaTime (float)gameTime.ElapsedGameTime.TotalSeconds; KeyboardState keyboard Keyboard.GetState(); if (state GameState.Exploring) { player.Update(deltaTime); CheckCoinCollision(); CheckEnemyCollision(); if (coins.Count 0) SpawnCoins(5); if (enemies.Count 0) SpawnEnemies(3); } if (keyboard.IsKeyDown(Keys.Escape)) Exit(); base.Update(gameTime); } private void CheckCoinCollision() { Rectangle playerRect player.GetBounds(); for (int i coins.Count - 1; i 0; i--) { Rectangle coinRect new Rectangle((int)coins[i].X, (int)coins[i].Y, 24, 24); if (playerRect.Intersects(coinRect)) { coins.RemoveAt(i); score 10; } } } private void CheckEnemyCollision() { Rectangle playerRect player.GetBounds(); for (int i enemies.Count - 1; i 0; i--) { Rectangle enemyRect new Rectangle( (int)enemies[i].X - 20, (int)enemies[i].Y - 20, 40, 40); if (playerRect.Intersects(enemyRect)) { enemies.RemoveAt(i); score 50; } } } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); _spriteBatch.Begin(); // 金币 foreach (Vector2 coinPos in coins) _spriteBatch.Draw(coinTexture, coinPos, Color.White); // 敌人 foreach (Vector2 enemyPos in enemies) _spriteBatch.Draw(enemyTexture, enemyPos, null, Color.White, 0f, new Vector2(20, 20), 1f, SpriteEffects.None, 0f); // ★ 玩家使用动画系统 player.Draw(_spriteBatch); // UI _spriteBatch.DrawString(font, $分数{score}, new Vector2(10, 10), Color.White); _spriteBatch.DrawString(font, $金币{coins.Count}, new Vector2(10, 35), Color.Gold); _spriteBatch.DrawString(font, $敌人{enemies.Count}, new Vector2(10, 60), Color.Red); _spriteBatch.DrawString(font, $HP{player.Hp}/{player.MaxHp}, new Vector2(10, 85), Color.LimeGreen); _spriteBatch.DrawString(font, WASD移动 | ESC退出, new Vector2(10, 570), Color.LightGray); _spriteBatch.End(); base.Draw(gameTime); } } }今天的学习就此结束我叫魔法阵维护师关注我下期更精彩

相关文章:

从零开发游戏需要学习的c#模块,第二十一章(精灵动画 —— 让角色走起来)

今天我们要学习的内容是 理解精灵图集的原理 加载精灵图集并切帧 实现四方向行走动画 静止时显示待机帧 第一步:准备精灵图集 精灵图集就是一张大图里包含多个小图(帧),播放时依次显示每一帧,形成动画效果。 一…...

黎曼猜想:哲学 × 数学 思维范式全链条

黎曼猜想:哲学 数学 思维范式全链条 华夏之光永存|七大数学猜想思维范式全链条 第二篇开篇 黎曼猜想被公认为数学史上最伟大的未解难题。希尔伯特曾说:“如果我沉睡百年后醒来,第一个问题就是:黎曼猜想证明了吗&…...

P vs NP:西方哲学 × 西方计算理论 —— 人类思维的终极边界

P vs NP:西方哲学 西方计算理论 —— 人类思维的终极边界 华夏之光永存|七大数学猜想思维范式全链条 第一篇开篇 P vs NP 是计算机科学第一难题,克雷数学研究所七大千禧年难题之一。 本文不宣称证明、不跳步、不民科、不超纲。 只用哲学与数…...

暗黑破坏神2存档编辑器完整指南:三步轻松修改D2/D2R角色与装备

暗黑破坏神2存档编辑器完整指南:三步轻松修改D2/D2R角色与装备 【免费下载链接】d2s-editor 项目地址: https://gitcode.com/gh_mirrors/d2/d2s-editor 你是否厌倦了在暗黑破坏神2中反复刷装备却一无所获?是否因为早期加点失误导致角色后期无法应…...

HS2-HF_Patch:Honey Select 2 终极汉化与功能增强完整指南

HS2-HF_Patch:Honey Select 2 终极汉化与功能增强完整指南 【免费下载链接】HS2-HF_Patch Automatically translate, uncensor and update HoneySelect2! 项目地址: https://gitcode.com/gh_mirrors/hs/HS2-HF_Patch HS2-HF_Patch 是专为 Honey Select 2 游戏…...

在Nodejs后端服务中集成稳定可靠的大模型能力

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 在Nodejs后端服务中集成稳定可靠的大模型能力 应用场景类,针对需要构建智能对话或内容生成功能的后端工程师&#xff0…...

CANN/pypto copysign函数API文档

# pypto.copysign 【免费下载链接】pypto PyPTO(发音: pai p-t-o):Parallel Tensor/Tile Operation编程范式。 项目地址: https://gitcode.com/cann/pypto 产品支持情况 产品是否支持Ascend 950PR/Ascend 950DT√Atlas A…...

app应用接入广告的完整流程和方法:从零搭建可持续变现体系

随着移动互联网进入存量竞争阶段,用户流量增长趋于饱和,单纯依靠用户新增实现产品增值的模式已然失效。对于绝大多数免费工具、社交、资讯、游戏类 APP 而言,合规、稳定、可持续的广告变现,已经成为补齐产品商业闭环、维持产品长期…...

2026 主流技术栈:hermes agent多环境安装配置:Windows/Mac/Linux

一、Hermes agent 大模型选择 Hermes Agent 通过统一的模型抽象层接入不同厂商的大语言模型服务。实际部署时,建议根据数据合规要求、任务类型和成本预算进行选型。 1.1 国内场景:Kimi K2.6 对于数据需境内处理或存在私有化部署需求的场景&#xff0c…...

机器学习评价指标之综合指标的关系

综合指标的关系宏平均考虑每个类别的个别表现,并对它们的评价指标(比如准确率、召回率等)进行平均。每个类别 被视为同等重要,无论类别的大小或样本数量。微平均则关注整体表现,它将所有类别的预测结果合并起来&#x…...

红黑树完全指南:从五条性质到完整插入删除实现

引言在前面的树系列中,我们学习了二叉搜索树(BST)和 AVL 树。AVL 树通过严格的平衡条件(|BF| ≤ 1)保证 O(log n) 的性能,但代价是删除操作可能触发 O(log n) 次旋转。红黑树(Red-Black Tree&am…...

10个sd-webui-regional-prompter实用技巧:从基础分割到高级2D区域配置

10个sd-webui-regional-prompter实用技巧:从基础分割到高级2D区域配置 【免费下载链接】sd-webui-regional-prompter set prompt to divided region 项目地址: https://gitcode.com/gh_mirrors/sd/sd-webui-regional-prompter sd-webui-regional-prompter是一…...

混合专家MoE拆解:GPT-4、千问、DeepSeek为什么都选这个架构

去年我写了个小模型做文本分类,全部参数只有1.5B,单卡就能跑。结果效果还行,但跟大模型比就是被吊打。 我就想,为什么那些几百B甚至上T参数的大模型,推理速度没比我的小模型慢一万倍? 答案就在MoE&#x…...

创业公司如何利用 Taotoken 统一管理多个 AI 模型服务

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 创业公司如何利用 Taotoken 统一管理多个 AI 模型服务 对于资源有限的创业团队而言,快速验证产品想法、迭代功能是生存…...

WireUI颜色选择器和日期选择器:提升用户体验的利器 [特殊字符][特殊字符]

WireUI颜色选择器和日期选择器:提升用户体验的利器 🎨📅 【免费下载链接】wireui TallStack UI components 项目地址: https://gitcode.com/gh_mirrors/wi/wireui WireUI颜色选择器和日期选择器是Laravel Livewire应用中提升用户体验的…...

为内部知识问答系统构建基于多模型聚合的智能回复引擎

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 为内部知识问答系统构建基于多模型聚合的智能回复引擎 在构建面向企业内部的智能知识问答系统时,一个核心挑战是如何在…...

互联网大厂 Java 求职面试实战:音视频场景中的技术挑战

互联网大厂 Java 求职面试实战:音视频场景中的技术挑战在这个互联网飞速发展的时代,越来越多的求职者走进了大厂的面试现场。今天,我们将跟随一位搞笑的程序员燕双非,来看看他在面试中的表现,以及他如何应对各种技术问…...

Rufus技术演进:从Windows 7告别到现代USB启动盘工具的重构之路

Rufus技术演进:从Windows 7告别到现代USB启动盘工具的重构之路 【免费下载链接】rufus The Reliable USB Formatting Utility 项目地址: https://gitcode.com/GitHub_Trending/ru/rufus 在开源工具生态中,技术栈的更新换代往往伴随着兼容性的艰难…...

【收藏干货】2026年AI Coding全面爆发!程序员终极职业升级攻略,告别被替代焦虑

2026年,AI编码技术迎来规模化落地爆发期,行业彻底告别“人工纯编码”的传统模式。对于所有程序员而言,当下最核心的生存与发展策略,早已不是埋头敲代码,而是从“被动写代码的执行者”全面升级为“主动驾驭AI的价值创造…...

MySQL高频面试题-02

这一篇的主题:日志双写机制、深分页瓶颈,以及死锁怎么查。上次和大家聊了 B 树和 MVCC,今天这篇我们直接上硬菜。在社招或者大厂面试中,面试官往往不满足于只问你“什么是索引”,他们更喜欢切入高并发、大数量、分布式的真实场景。…...

MySQL 高频面试题-01

在去面试之前,很多人天天背“八股文”,结果一到现场被面试官稍微一变形就问懵了。比如:“你天天说 B 树,那为什么不用 B 树?不用红黑树?它俩到底差在哪?”“既然索引能加速,那我把所…...

Structured3D完整指南:如何用3D结构化数据轻松构建智能室内场景

Structured3D完整指南:如何用3D结构化数据轻松构建智能室内场景 【免费下载链接】Structured3D [ECCV20] Structured3D: A Large Photo-realistic Dataset for Structured 3D Modeling 项目地址: https://gitcode.com/gh_mirrors/st/Structured3D 如果你正在…...

电子书转有声书完整指南:一键实现1158种语言的AI语音合成

电子书转有声书完整指南:一键实现1158种语言的AI语音合成 【免费下载链接】ebook2audiobook Generate audiobooks from e-books, voice cloning & 1158 languages! 项目地址: https://gitcode.com/GitHub_Trending/eb/ebook2audiobook 你是否曾希望将心爱…...

铜钟音乐:在信息洪流中找回纯粹听歌体验的现代Web应用

铜钟音乐:在信息洪流中找回纯粹听歌体验的现代Web应用 【免费下载链接】tonzhon-music 铜钟 Tonzhon (tonzhon.whamon.com): 干净纯粹的音乐平台 (铜钟已不再使用 tonzhon.com,现在的 tonzhon.com 不是正版的铜钟) 项目地址: https://gitcode.com/GitH…...

Solaar 4.0:解锁罗技设备的完整Linux管理体验

Solaar 4.0:解锁罗技设备的完整Linux管理体验 【免费下载链接】Solaar Linux device manager for Logitech devices 项目地址: https://gitcode.com/gh_mirrors/so/Solaar 你是否曾为管理多款罗技无线设备而烦恼?不同设备需要不同的配置工具&…...

哈佛教授刚警告“别让AI改写论文”,但我反手就用GPT这套技巧发了篇核心

各位同仁好,我是七哥。一个在高校里从事人工智能相关领域研究,钻研用大模型AI实操的学术人。可以和七哥交流学术写作或Gemini、GPT、Claude等大模型学术实操相关问题,多多交流,相互成就,共同进步。 多数学术同仁在撰写核心期刊论文时,常常会陷入两个极端:要么面对空白文…...

终极指南:如何用文字描述快速生成专业CAD图纸

终极指南:如何用文字描述快速生成专业CAD图纸 【免费下载链接】text-to-cad-ui A lightweight UI for interacting with the Zoo Text-to-CAD API. 项目地址: https://gitcode.com/gh_mirrors/te/text-to-cad-ui 还在为复杂的CAD软件界面感到困惑吗&#xff…...

H5P交互式视频制作终极指南:快速创建引人入胜的互动学习内容

H5P交互式视频制作终极指南:快速创建引人入胜的互动学习内容 【免费下载链接】h5p-interactive-video 项目地址: https://gitcode.com/gh_mirrors/h5/h5p-interactive-video 在数字化教育时代,如何让视频内容更具互动性和教育价值?H5…...

B站直播神器:神奇弹幕全方位操作指南

B站直播神器:神奇弹幕全方位操作指南 【免费下载链接】MagicalDanmaku 本仓库及所有相关项目已永久停止开发、维护和任何形式的分发。 项目地址: https://gitcode.com/gh_mirrors/bi/MagicalDanmaku 直播难题:为什么你需要智能弹幕助手 每个B站主…...

Wannakey:无需支付赎金,从内存中恢复WannaCry加密文件

Wannakey:无需支付赎金,从内存中恢复WannaCry加密文件 【免费下载链接】wannakey Wannacry in-memory key recovery 项目地址: https://gitcode.com/gh_mirrors/wa/wannakey Wannakey是一款专为WannaCry勒索软件受害者设计的内存密钥恢复工具&…...