c#的form实现叠叠乐游戏

news2025/7/10 23:14:16

说明:
我希望用c#的form实现叠叠乐的游戏,玩家需要堆叠方块来建造高塔。
效果图:
在这里插入图片描述

step1:游戏规则

游戏实现步骤:
a. 处理事件,玩家可以释放摆动的方块,方块会下落。
b. 更新摆动方块的位移,根据角度计算位置。
c. 当方块下落后,检测其与下方方块的碰撞,判断是否成功堆叠。
d. 成功则增加分数,失败则减少生命值并重置方块。
e. 绘制背景、所有已堆叠的方块、摆动的方块、分数和生命值。
f. 当堆叠方块超过一定数量时,移除底部的方块并调整位置,同时移动背景。
g. 检查游戏结束条件,显示胜利或失败画面,关闭窗口。

step2:游戏步骤

步骤分解:
a. 创建主窗体,设置合适的尺寸,比如950x950。
b. 添加必要的控件:Timer用于游戏循环,PictureBox或直接在窗体上绘图。
c. 处理用户输入:鼠标点击触发方块下落。
d. 摆动逻辑:使用角度和角速度,每个Timer tick更新角度,计算方块位置。
e. 方块下落:当玩家点击时,方块开始下落,可能需要另一个Timer或使用游戏循环中的状态来处理下落过程。
f. 碰撞检测:当下落的方块到达堆叠位置时,检测其与最上方方块的位置是否重叠。
g. 分数和生命值管理:成功堆叠加分,失败减生命,生命为0时游戏结束。
h. 绘制元素:包括背景、所有堆叠的方块、摆动的方块、分数和生命值显示。
i. 背景移动:当堆叠到一定高度时,背景需要上移,可能需要调整绘制的位置。
j. 开始菜单和难度选择:可以通过显示不同的面板或窗体来实现。

step3:
C:\Users\wangrusheng\RiderProjects\WinFormsApp31\WinFormsApp31\Form1.cs

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace WinFormsApp31
{
    public partial class Form1 : Form
    {
        private System.Windows.Forms.Timer gameTimer;
        private float angle = 0;
        private float angularVelocity = 0.05f;
        private float maxAngle = (float)(Math.PI / 4);
        private List<RectangleF> stackedBlocks = new List<RectangleF>();
        private RectangleF swingingBlock;
        private bool isFalling = false;
        private int score = 0;
        private int lives = 3;
        private const int BlockSize = 70;
        private PointF pivot;
        private float backgroundOffset = 0;
        private Random random = new Random();
        private Color currentColor;

        public Form1()
        {
            InitializeComponent();
            // 设置默认窗体客户区大小为 800x600
            this.ClientSize = new System.Drawing.Size(600, 800);
            InitializeGame();
            SetupTimer();
            this.DoubleBuffered = true;
            this.Paint += MainForm_Paint;
            this.MouseClick += MainForm_MouseClick;
        }

        private void InitializeGame()
        {
            currentColor = GenerateRandomColor();
            pivot = new PointF(ClientSize.Width / 2, 50);
            swingingBlock = new RectangleF(
                pivot.X - BlockSize / 2,
                pivot.Y + 100,
                BlockSize,
                BlockSize);
        }

        private void SetupTimer()
        {
            gameTimer = new System.Windows.Forms.Timer();
            gameTimer.Interval = 16; // ~60 FPS
            gameTimer.Tick += GameTimer_Tick;
            gameTimer.Start();
        }

        private void GameTimer_Tick(object sender, EventArgs e)
        {
            if (!isFalling)
            {
                // Update swinging motion
                angle += angularVelocity;
                if (Math.Abs(angle) > maxAngle)
                {
                    angularVelocity *= -1;
                }

                float x = pivot.X + 150 * (float)Math.Sin(angle);
                float y = pivot.Y + 150 * (float)Math.Cos(angle);
                swingingBlock.Location = new PointF(x - BlockSize / 2, y - BlockSize / 2);
            }
            else
            {
                // Update falling block
                swingingBlock.Y += 15;
                CheckCollision();
            }

            Invalidate();
        }

        private void CheckCollision()
        {
            float targetY = ClientSize.Height - BlockSize * (stackedBlocks.Count + 1) - backgroundOffset;
            
            if (swingingBlock.Y >= targetY)
            {
                if (stackedBlocks.Count == 0 || CheckAlignment())
                {
                    // Successful stack
                    score++;
                    stackedBlocks.Add(new RectangleF(swingingBlock.Location, swingingBlock.Size));
                    currentColor = GenerateRandomColor();
                    isFalling = false;
                    
                    // Adjust background offset after 5 blocks
                    if (stackedBlocks.Count > 5)
                    {
                        backgroundOffset += BlockSize;
                        RemoveBottomBlock();
                    }
                }
                else
                {
                    // Failed stack
                    lives--;
                    if (lives <= 0)
                    {
                        GameOver();
                        return;
                    }
                    isFalling = false;
                }
                
                // Reset swinging block position
                swingingBlock.Location = new PointF(
                    pivot.X - BlockSize / 2,
                    pivot.Y + 100);
            }
        }

        private bool CheckAlignment()
        {
            var lastBlock = stackedBlocks[stackedBlocks.Count - 1];
            return swingingBlock.X < lastBlock.Right && 
                   swingingBlock.Right > lastBlock.Left;
        }

        private void RemoveBottomBlock()
        {
            if (stackedBlocks.Count > 0)
            {
                stackedBlocks.RemoveAt(0);
                // Adjust all blocks positions
                for (int i = 0; i < stackedBlocks.Count; i++)
                {
                    stackedBlocks[i] = new RectangleF(
                        stackedBlocks[i].X,
                        ClientSize.Height - BlockSize * (i + 1) - backgroundOffset,
                        stackedBlocks[i].Width,
                        stackedBlocks[i].Height);
                }
            }
        }

        private void GameOver()
        {
            gameTimer.Stop();
            MessageBox.Show($"Game Over! Final Score: {score}");
            InitializeGame();
            score = 0;
            lives = 3;
            backgroundOffset = 0;
            stackedBlocks.Clear();
            gameTimer.Start();
        }

        private void MainForm_MouseClick(object sender, MouseEventArgs e)
        {
            if (!isFalling)
            {
                isFalling = true;
            }
        }

        private void MainForm_Paint(object sender, PaintEventArgs e)
        {
            var g = e.Graphics;
            g.Clear(Color.LightSkyBlue);

            // Draw stacked blocks
            foreach (var block in stackedBlocks)
            {
                DrawBlock(g, block, currentColor);
            }

            // Draw swinging/falling block
            DrawBlock(g, swingingBlock, currentColor);

            // Draw pivot line
            if (!isFalling)
            {
                g.DrawLine(Pens.Black, pivot, new PointF(
                    swingingBlock.Left + swingingBlock.Width / 2,
                    swingingBlock.Top + swingingBlock.Height / 2));
            }

            // Draw UI
            DrawUI(g);
        }

        private void DrawBlock(Graphics g, RectangleF rect, Color color)
        {
            using (var brush = new SolidBrush(color))
            {
                g.FillRectangle(brush, rect);
            }
            g.DrawRectangle(Pens.Black, rect.X, rect.Y, rect.Width, rect.Height);

            // Draw windows
            float windowSize = 15;
            float spacing = 10;
            for (float y = rect.Y + spacing; y < rect.Bottom - windowSize; y += windowSize + spacing)
            {
                for (float x = rect.X + spacing; x < rect.Right - windowSize; x += windowSize + spacing)
                {
                    g.FillRectangle(Brushes.Black, x, y, windowSize, windowSize);
                }
            }
        }

        private void DrawUI(Graphics g)
        {
            string scoreText = $"Score: {score}";
            string livesText = $"Lives: {lives}";
            
            var scoreSize = g.MeasureString(scoreText, this.Font);
            var livesSize = g.MeasureString(livesText, this.Font);

            g.DrawString(scoreText, this.Font, Brushes.Black, 
                ClientSize.Width - scoreSize.Width - 10, 10);
            g.DrawString(livesText, this.Font, Brushes.Black, 10, 10);
        }

        private Color GenerateRandomColor()
        {
            return Color.FromArgb(random.Next(150, 255), 
                random.Next(150, 255), 
                random.Next(150, 255));
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            InitializeGame();
            Invalidate();
        }
    }
}

end

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2332033.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Qt中的元对象系统

Qt的元对象系统(Meta-Object System)提供了对象间通信的信号和槽机制、运行时类型信息和动态属性系统。 元对象系统基于以下三个方面&#xff1a; (1).QObject类&#xff1a;为可以利用元对象系统的对象提供了基类。 (2).Q_OBJECT宏&#xff1a;用于启用元对象功能&#xff0c;…

qt之opengl使用

使用qt中的openglWidget绘制一个三角形。自定义的类继承关系sunOpengl : public QOpenGLWidget,QOpenGLFunctions_3_3_Core 代码如下 /*----MainWindow.cpp----------------------------------------------*/ #include "mainwindow.h" #include "./ui_mainwin…

晋城市电子健康证上传照片尺寸要求及手机拍照制作方法

晋城市餐饮从业人员健康证电子照片上传有着明确的技术规范。根据"晋城市从业人员电子健康证明服务平台"要求&#xff0c;照片尺寸应为358像素&#xff08;宽&#xff09;441像素&#xff08;高&#xff09;&#xff0c;这一比例符合标准证件照的规格。照片底色可选择…

js实现跨域下载,展示下载进度以及自定义下载名称功能

一、 下载进度 loading弹窗结构 // loading状态DOM function setLoading() {let content document.querySelector(.loading)content.innerHTML content.innerHTML <div class"loading_content"><div class"contentBox"><div class&quo…

MCP 实战系列(Day 2)- 动手搓个文件系统 MCP 服务器

上期回顾&#xff1a;MCP 实战系列&#xff08;Day 1&#xff09;- 什么是 MCP&#xff1f; 在上期文章中&#xff0c;我们详细介绍了 Model Context Protocol&#xff08;MCP&#xff09;的基本概念和应用场景。本节将带领大家开发一个简易的 Filesystem MCP Server&#xff…

LabVIEW运动控制(三):EtherCAT运动控制器的高效加工指令自定义封装

ZMC408CE 高性能总线型运动控制器 ZMC408CE是正运动推出的一款多轴高性能EtherCAT总线运动控制器&#xff0c;具有EtherCAT、EtherNET、RS232、CAN和U盘等通讯接口&#xff0c;ZMC系列运动控制器可应用于各种需要脱机或联机运行的场合。 ZMC408CE支持PLC、Basic、HMI组态三种编…

Xilinx虚拟输入/输出(VIO)IP核详细介绍及使用示例

LogiCORE™ IP虚拟输入/输出(VIO)内核是一款可定制化的内核,能够实时监控和驱动FPGA(现场可编程门阵列)内部信号。其输入和输出端口的数量及位宽均可根据需求定制,以便与FPGA设计进行接口对接。由于VIO内核与被监控和/或驱动的设计保持同步,因此应用于您设计中的所有设计…

Vue3+Vite+TypeScript+Element Plus开发-09.登录成功跳转主页

系列文档目录 Vue3ViteTypeScript安装 Element Plus安装与配置 主页设计与router配置 静态菜单设计 Pinia引入 Header响应式菜单缩展 Mockjs引用与Axios封装 登录设计 登录成功跳转主页 多用户动态加载菜单 Pinia持久化 动态路由-配置 文章目录 目录 系列文档目…

Linux : 内核中的信号捕捉

目录 一 前言 二 信号捕捉的方法 1.sigaction()​编辑 2. sigaction() 使用 三 可重入函数 四 volatile 关键字 一 前言 如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号。在Linux: 进程信号初识-CSDN博客 这一篇中已经学习到了一种信号…

开发效率提升200%——cursor

cursor带来的编程"革命" 高级语言编程转为"自然语言编程"借助cursor&#xff0c;直接超越初级后台开发、超越初级前端开发、超越初级测试、超越初级UI&#xff0c;产研一体linux命令只用学不用记&#xff0c;语言描述就是命令给一个表结构流程提示词&…

微软庆祝它成立整整50周年

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

SpringBoot 整合 MCP

SpringBoot 整合 MCP MCP MCP 协议主要分为&#xff1a; Client 客户端&#xff08;一般就是指 openai&#xff0c;deepseek 这些大模型&#xff09;Server 服务端&#xff08;也就是我们的业务系统&#xff09;我们要做的就是把我们存量系统配置成 MCP Server 环境 JDK17…

【详细】MySQL 8 安装解压即用 (包含MySQL 5 卸载)

卸载MySQL 1.卸载 2.安装目录删除残余文件&#xff08;当初安装的位置&#xff09; 3.删除programData下面的mysql数据文件 4.检查mysql服务是否存在&#xff0c;如果存在则删除&#xff08;先暂停mysql服务&#xff09; sc delete mysql 5.删除注册表中残留信息 安装MySQL 8&…

显示器各类异常处理方法

显示器各类异常处理方法 导航 文章目录 显示器各类异常处理方法导航画面无显示/黑屏/无HDMI信号输入显示器闪烁显示器花屏显示画面模糊或扭曲显示器颜色异常显示器出现死点或亮点 画面无显示/黑屏/无HDMI信号输入 ​ 首先应该检查的是显示器电源&#xff08;真的有人弄掉电源…

一、简单的 Django 服务

一、配置虚拟环境 1.1 创建一个文件夹在导航栏输入cmd打开 1.2 安装依赖两个库 pip install virtualenv virtualenvwrapper-win -i https://pypi.tuna.tsinghua.edu.cn/simple验证是否安装成功 virtualenv --version pip show virtualenvwrapper-win 1.3 创建虚拟环境 mkvi…

k8s黑科技:Linux+Vagrant+VirtualBox开启Kubernetes奇幻之旅

文章目录 1. 准备硬件2. 安装系统3. 安装 VNC4. 基础配置4.1 路由转发4.2 防火墙4.3 selinux4.4 安装包4.5 重启 5. 配置代理6. 安装 virtuabox7. 安装 vagrant8. 配置 kubespray8.1 安装依赖工具8.2 定制 Vagrantfile8.3 配置代理与时间同步8.4 配置私有镜像仓库 9. 安装虚拟机…

34% 关税冲击下 LabVIEW 开发的变局

2025 年 4 月 4 日&#xff0c;中国国务院关税税则委员会宣布&#xff0c;自 4 月 10 日起对原产于美国的所有进口商品加征 34% 关税。这一举措&#xff0c;给 LabVIEW 开发领域带来显著影响&#xff0c;相关使用者和用户亟需采取应对策略。 ​ 从成本层面看&#xff0c;LabVI…

Http代理服务器选型与搭建

代理服务器选型-Squid 缓存加速 缓存频繁访问的网页、图片等静态资源&#xff0c;减少对原始服务器的重复请求&#xff0c;提升响应速度支持HTTP、HTTPS、FTP等协议&#xff0c;通过本地缓存直接响应客户端请求 访问控制 基于ACL&#xff08;访问控制列表&#xff09;实现精细…

Linux主要开发工具之gcc、gdb与make

此系列还有两篇&#xff0c;大家想完整掌握可以阅读另外两篇 Linux文本编辑与shell程序设计-CSDN博客 Linux基础知识详解与命令大全&#xff08;超详细&#xff09;-CSDN博客 1.gcc编译系统 1.1 文件名后缀 文件名后缀 文 件 类 型 文件名后缀 文 件 类 型 .c C源…

C++初阶-C++入门基础

目录 ​编辑 1.C的简介 1.1C的产生和发展 1.2C的参考文档 1.3C优势和难度 1.4C学习的建议 2.C的第一个程序 2.1打印Hello world 2.2头文件 2.3namespace命名空间 2.4&#xff1a;&#xff1a;作用域限定符 2.5namespace的延伸 2.6C的输入输出 3.总结 1.C的简介 …