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

vue+form实现flappybird

说明:
vue+form实现flappybird
效果图:
在这里插入图片描述

form实现:
step1:C:\Users\wangrusheng\RiderProjects\WinFormsApp3\WinFormsApp3\Form1.cs

namespace WinFormsApp3;

public partial class Form1 : Form
{
    private const int GRAVITY = 1;
    private const int JUMP_FORCE = -15;
    private const int PIPE_SPEED = 5;
    private const int PIPE_SPACING = 200;
    private const int PIPE_WIDTH = 50;

    private readonly Random random = new Random();
    private readonly Font gameFont = new Font("Arial", 24);
    private readonly StringFormat centerFormat = new StringFormat() 
        { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };

    private int score;
    private int birdY;
    private int velocity;
    private bool isGameOver;
    private List<Rectangle> pipes = new List<Rectangle>();
    private int frameCounter;
    private System.Windows.Forms.Timer gameTimer; // 添加这一行
    
    public Form1()
    {
        InitializeComponent();
    
        DoubleBuffered = true;
        ClientSize = new Size(800, 600);
        
        gameTimer = new System.Windows.Forms.Timer(); // 初始化 Timer
        gameTimer.Interval = 16; // ~60 FPS
        gameTimer.Tick += GameLoop;
        KeyDown += OnKeyPress;
        
        InitializeGame();
    }
    
     private void InitializeGame()
    {
        score = 0;
        birdY = ClientSize.Height / 2;
        velocity = 0;
        pipes.Clear();
        isGameOver = false;
        frameCounter = 0;
        
        gameTimer.Start();
        Invalidate();
    }

    private void GameLoop(object sender, EventArgs e)
    {
        if (!isGameOver)
        {
            UpdateBird();
            UpdatePipes();
            CheckCollisions();
            frameCounter++;
        }
        Invalidate();
    }

    private void UpdateBird()
    {
        velocity += GRAVITY;
        birdY += velocity;
        birdY = Math.Clamp(birdY, 0, ClientSize.Height - 50);
    }

    private void UpdatePipes()
    {
        // 生成新管道
        if (frameCounter % 100 == 0)
        {
            int gapPosition = random.Next(150, ClientSize.Height - 150);
            pipes.Add(new Rectangle(ClientSize.Width, 0, PIPE_WIDTH, gapPosition - PIPE_SPACING/2));
            pipes.Add(new Rectangle(ClientSize.Width, gapPosition + PIPE_SPACING/2, 
                PIPE_WIDTH, ClientSize.Height - gapPosition - PIPE_SPACING/2));
        }

        // 移动管道
        for (int i = pipes.Count - 1; i >= 0; i--)
        {
            pipes[i] = new Rectangle(pipes[i].X - PIPE_SPEED, pipes[i].Y, pipes[i].Width, pipes[i].Height);
            if (pipes[i].Right < 0) pipes.RemoveAt(i);
        }
    }

    private void CheckCollisions()
    {
        Rectangle birdRect = new Rectangle(100, birdY, 50, 50);
        
        foreach (var pipe in pipes)
        {
            if (pipe.IntersectsWith(birdRect))
            {
                isGameOver = true;
                return;
            }

            // 计分逻辑:当管道通过小鸟时加分
            if (pipe.X + pipe.Width == 100 && !isGameOver) score++;
        }
    }

    private void OnKeyPress(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Space)
        {
            if (isGameOver) InitializeGame();
            else velocity = JUMP_FORCE;
        }
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        var g = e.Graphics;
        g.Clear(Color.SkyBlue);

        // 绘制小鸟
        g.DrawString("🐦", gameFont, Brushes.Yellow, new Rectangle(100, birdY, 50, 50), centerFormat);

    
        // 绘制管道
        foreach (var pipe in pipes)
        {
            g.FillRectangle(Brushes.Green, pipe); // 修正 Brush.Green 为 Brushes.Green
            g.DrawString(pipe.Height > 200 ? "🌿" : "🪵", gameFont, Brushes.Green, pipe, centerFormat);
        }

        // 绘制分数
        g.DrawString($"Score: {score}", gameFont, Brushes.White, 10, 10);

        // 游戏结束提示
        if (isGameOver)
        {
            g.DrawString("游戏结束!\n按空格键重玩", gameFont, Brushes.Red, 
                ClientRectangle, centerFormat);
        }
    }
}

end

///我是分割线

vue实现:
step1:C:\Users\wangrusheng\PycharmProjects\untitled3\src\views\Bird.vue

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { useGame } from './use.game';

const canvasEl = ref<HTMLCanvasElement | null>(null);
const game = useGame();

onMounted(() => {
  const canvas = canvasEl.value;
  if (!canvas) return;
  const ctx = canvas.getContext('2d');
  if (!ctx) return;

  let animationFrameId: number;
  const gameLoop = () => {
    game.update();
    draw(ctx);
    animationFrameId = requestAnimationFrame(gameLoop);
  };
  gameLoop();

  const handleKeyPress = (event: KeyboardEvent) => {
    if (event.code === 'Space') {
      game.jump();
    }
  };
  window.addEventListener('keydown', handleKeyPress);

  onUnmounted(() => {
    cancelAnimationFrame(animationFrameId);
    window.removeEventListener('keydown', handleKeyPress);
  });
});

function draw(ctx: CanvasRenderingContext2D) {
  ctx.clearRect(0, 0, 800, 600);

  // 绘制小鸟
  ctx.fillStyle = 'yellow';
  ctx.font = '50px Arial';
  ctx.fillText('🐦', 100, game.getBirdY());

  // 绘制管道
  ctx.fillStyle = 'green';
  game.getPipes().forEach(pipe => {
    ctx.fillRect(pipe.x, pipe.y, pipe.width, pipe.height);
    ctx.fillText(
      pipe.height > 200 ? '🌿' : '🪵',
      pipe.x + pipe.width / 2,
      pipe.y + pipe.height / 2
    );
  });
}
</script>

<template>
  <div class="container">
    <canvas ref="canvasEl" width="800" height="600"></canvas>
    <div class="score">Score: {{ game.score }}</div>
    <div v-if="game.isGameOver" class="game-over">
      游戏结束!<br>按空格键重玩
    </div>
  </div>
</template>

<style scoped>
.container {
  position: relative;
  display: block;
}

canvas {
  background: skyblue;
}

.score {
  position: absolute;
  top: 10px;
  left: 10px;
  color: white;
  font: 24px Arial;
}

.game-over {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  color: red;
  font: 24px Arial;
  text-align: center;
}
</style>

step2:C:\Users\wangrusheng\PycharmProjects\untitled3\src\views\use.game.ts

import { ref } from 'vue';

class Rectangle {
  constructor(
    public x: number,
    public y: number,
    public width: number,
    public height: number
  ) {}
}

export function useGame() {
  const score = ref(0);
  const isGameOver = ref(false);

  let birdY = 300;
  let velocity = 0;
  let pipes: Rectangle[] = [];
  let frameCounter = 0;

  // 游戏常量
  const GRAVITY = 1;
  const JUMP_FORCE = -15;
  const PIPE_SPEED = 5;
  const PIPE_SPACING = 200;
  const PIPE_WIDTH = 50;

  function update() {
    if (!isGameOver.value) {
      updateBird();
      updatePipes();
      checkCollisions();
      frameCounter++;
    }
  }

  function updateBird() {
    velocity += GRAVITY;
    birdY += velocity;
    birdY = Math.max(0, Math.min(birdY, 600 - 50));
  }

  function updatePipes() {
    // 生成新管道
    if (frameCounter % 100 === 0) {
      const gapPosition = 150 + Math.random() * 300;
      pipes.push(
        new Rectangle(800, 0, PIPE_WIDTH, gapPosition - PIPE_SPACING / 2),
        new Rectangle(
          800,
          gapPosition + PIPE_SPACING / 2,
          PIPE_WIDTH,
          600 - gapPosition - PIPE_SPACING / 2
        )
      );
    }

    // 移动并过滤管道
    pipes = pipes
      .map(pipe => new Rectangle(
        pipe.x - PIPE_SPEED,
        pipe.y,
        pipe.width,
        pipe.height
      ))
      .filter(pipe => pipe.x + pipe.width > 0);
  }

  function checkCollisions() {
    const birdRect = new Rectangle(100, birdY, 50, 50);

    for (const pipe of pipes) {
      if (checkCollision(birdRect, pipe)) {
        isGameOver.value = true;
        return;
      }

      if (pipe.x + pipe.width === 100 && !isGameOver.value) {
        score.value++;
      }
    }
  }

  function checkCollision(a: Rectangle, b: Rectangle): boolean {
    return a.x < b.x + b.width &&
           a.x + a.width > b.x &&
           a.y < b.y + b.height &&
           a.y + a.height > b.y;
  }

  function jump() {
    if (isGameOver.value) {
      resetGame();
    } else {
      velocity = JUMP_FORCE;
    }
  }

  function resetGame() {
    score.value = 0;
    birdY = 300;
    velocity = 0;
    pipes = [];
    isGameOver.value = false;
    frameCounter = 0;
  }

  return {
    score,
    isGameOver,
    update,
    jump,
    getBirdY: () => birdY,
    getPipes: () => pipes,
  };
}

end

http://www.dtcms.com/a/112401.html

相关文章:

  • 迅饶科技X2Modbus网关-GetUser信息泄露漏洞
  • Mysql 中 B 树 vs B+ 树
  • SQL Server 2022 脏读问题排查与思考
  • HTML5 vs HTML 和 CSS3 vs CSS:全面对比
  • Spring Boot 中使用 Redis:从入门到实战
  • Websoft9分享:在数字化转型中选择开源软件可能遇到的难题
  • 神经网络能不能完全拟合y=x² ???
  • WinForm真入门(7)——Button控件详解
  • 京东运维面试题及参考答案
  • k8s进阶之路:本地集群环境搭建
  • 谷歌 Gemini 2.5 Pro 免费开放
  • 24、 Python Socket编程:从协议解析到多线程实战
  • 如何完整迁移 Git 仓库 ?
  • yum list查询时部分包查找不到流程分析
  • 54.大学生心理健康管理系统(基于springboot项目)
  • 有人DTU使用MQTT协议控制Modbus协议的下位机-含数据库
  • Redis分布式锁详解
  • AWS Langfuse AI用Bedrock模型使用完全教程
  • 【万字总结】前端全方位性能优化指南(八)——Webpack 6调优、模块联邦升级、Tree Shaking突破
  • 安卓离线畅玩的多款棋类单机游戏推荐
  • 【leetcode100】动态规划Java版本
  • Debezium日常分享系列之:Debezium 3.1.0.Final发布
  • 什么是量子计算?
  • 【代码艺廊】pyside6桌面应用范例:homemade-toolset
  • 如何实现浏览器中的报表打印
  • Pytorch使用GPU、CUDA安装步骤注意事项
  • Redis 中 Set(例如标签) 和 ZSet(例如排行榜) 的详细对比,涵盖定义、特性、命令、适用场景及总结表格
  • CSS 创建与使用学习笔记
  • 室内指路机器人是否支持环境监测功能?
  • 【数据分享】2002-2023中国湖泊水位变化数据集(免费获取)