Java课程设计(双人对战游戏)持续更新......

news2025/4/1 6:54:13

少废话,当然借助了ai,就这么个实力,后续会逐渐完善......

考虑添加以下功能:

选将,选图,技能,天赋,道具,防反,反重力,物理反弹,击落,计分,粒子效果,打击感加强,陷阱,逃杀......

package game;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;

public class GameFrame extends JFrame {
    public GameFrame() {
        setTitle("平台射击对战");
        setSize(800, 600);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        add(new GamePanel());
        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new GameFrame());
    }
}

class GamePanel extends JPanel implements KeyListener, ActionListener {
    private Player p1, p2;
    private Timer timer;
    private boolean[] keys = new boolean[256];
    private boolean gameOver = false;
    private boolean gameStarted = false;
    private JButton startButton, restartButton, exitButton;
    private List<Platform> platforms = new ArrayList<>();
    private List<Bullet> bullets = new ArrayList<>();

    public GamePanel() {
        setLayout(null);
        setFocusable(true);
        addKeyListener(this);

        // 对称平台布局
        platforms.add(new Platform(150, 350, 200, 20));  // 左平台
        platforms.add(new Platform(300, 250, 200, 20));  // 中央平台
        platforms.add(new Platform(450, 350, 200, 20));  // 右平台

        startButton = createButton("开始游戏", 300, 250);
        restartButton = createButton("重新开始", 300, 300);
        exitButton = createButton("退出游戏", 300, 350);

        restartButton.setVisible(false);
        exitButton.setVisible(false);

        add(startButton);
        add(restartButton);
        add(exitButton);

        startButton.addActionListener(e -> startGame());
        restartButton.addActionListener(e -> restartGame());
        exitButton.addActionListener(e -> System.exit(0));
    }

    private JButton createButton(String text, int x, int y) {
        JButton button = new JButton(text);
        button.setBounds(x, y, 200, 40);
        button.setFocusable(false);
        button.setFont(new Font("微软雅黑", Font.BOLD, 18));
        button.setBackground(new Color(200, 200, 200));
        return button;
    }

    private void startGame() {
        gameStarted = true;
        gameOver = false;
        bullets.clear();
        startButton.setVisible(false);
        restartButton.setVisible(false);
        exitButton.setVisible(false);

        p1 = new Player(100, 400, Color.BLUE, KeyEvent.VK_A, KeyEvent.VK_D, KeyEvent.VK_W, KeyEvent.VK_F);
        p2 = new Player(600, 400, Color.RED, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, KeyEvent.VK_UP, KeyEvent.VK_M);

        if (timer != null && timer.isRunning()) {
            timer.stop();
        }
        timer = new Timer(16, this);
        timer.start();
        requestFocusInWindow();
    }

    private void restartGame() {
        gameOver = false;
        gameStarted = false;
        startGame();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (!gameStarted) {
            g.setColor(new Color(30, 30, 30));
            g.fillRect(0, 0, getWidth(), getHeight());
            g.setColor(Color.WHITE);
            g.setFont(new Font("微软雅黑", Font.BOLD, 48));
            g.drawString("平台射击对战", 250, 150);
            return;
        }

        Graphics2D g2d = (Graphics2D) g;
        g2d.setPaint(new GradientPaint(0, 0, new Color(30, 30, 50), 0, 600, new Color(10, 10, 20)));
        g2d.fillRect(0, 0, getWidth(), getHeight());

        g.setColor(new Color(80, 50, 30));
        g.fillRect(0, 450, getWidth(), 150);
        g.setColor(new Color(110, 70, 40));
        for(int i=0; i<getWidth(); i+=30){
            g.fillRect(i, 450, 15, 10);
            g.fillRect(i+15, 460, 15, 10);
        }

        for (Platform platform : platforms) {
            platform.draw(g);
        }

        p1.draw(g);
        p2.draw(g);

        for (Bullet bullet : bullets) {
            bullet.draw(g);
        }

        drawHealthBar(g, p1, 20, 20);
        drawHealthBar(g, p2, getWidth() - 220, 20);

        if (gameOver) {
            g.setColor(new Color(255, 255, 255, 200));
            g.fillRect(0, 0, getWidth(), getHeight());
            g.setColor(Color.BLACK);
            g.setFont(new Font("微软雅黑", Font.BOLD, 48));
            String winner = p1.getHealth() <= 0 ? "红方胜利!" : "蓝方胜利!";
            g.drawString(winner, getWidth()/2 - 120, getHeight()/2);

            restartButton.setVisible(true);
            exitButton.setVisible(true);
        }
    }

    private void drawHealthBar(Graphics g, Player p, int x, int y) {
        g.setColor(Color.BLACK);
        g.fillRect(x, y, 200, 25);
        g.setColor(p.getColor());
        g.fillRect(x + 2, y + 2, (int)(196 * (p.getHealth() / 100.0)), 21);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (!gameOver && gameStarted) {
            handleInput();
            updatePlayers();
            updateBullets();
            checkCollisions();
            checkGameOver();
        }
        repaint();
    }

    private void handleInput() {
        p1.setMovingLeft(keys[p1.getLeftKey()]);
        p1.setMovingRight(keys[p1.getRightKey()]);
        if (keys[p1.getJumpKey()] && p1.isOnGround()) {
            p1.jump();
        }
        if (keys[p1.getAttackKey()] && p1.canAttack()) {
            bullets.add(p1.shoot());
        }

        p2.setMovingLeft(keys[p2.getLeftKey()]);
        p2.setMovingRight(keys[p2.getRightKey()]);
        if (keys[p2.getJumpKey()] && p2.isOnGround()) {
            p2.jump();
        }
        if (keys[p2.getAttackKey()] && p2.canAttack()) {
            bullets.add(p2.shoot());
        }
    }

    private void updatePlayers() {
        p1.update(getWidth(), platforms);
        p2.update(getWidth(), platforms);
    }

    private void updateBullets() {
        List<Bullet> toRemove = new ArrayList<>();
        for (Bullet bullet : bullets) {
            bullet.update();
            if (bullet.x < -10 || bullet.x > getWidth() + 10) {
                toRemove.add(bullet);
            }
        }
        bullets.removeAll(toRemove);
    }

    private void checkCollisions() {
        List<Bullet> toRemove = new ArrayList<>();
        for (Bullet bullet : bullets) {
            for (Platform platform : platforms) {
                if (bullet.hitsPlatform(platform)) {
                    toRemove.add(bullet);
                    break;
                }
            }

            Player target = bullet.shooter == p1 ? p2 : p1;
            if (bullet.hitsPlayer(target)) {
                target.takeDamage(10);
                toRemove.add(bullet);
            }
        }
        bullets.removeAll(toRemove);
    }

    private void checkGameOver() {
        if (p1.getHealth() <= 0 || p2.getHealth() <= 0) {
            gameOver = true;
            timer.stop();
        }
    }

    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() < keys.length) {
            keys[e.getKeyCode()] = true;
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
        if (e.getKeyCode() < keys.length) {
            keys[e.getKeyCode()] = false;
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {}
}

class Player {
    private static final int GRAVITY = 1;
    private static final int JUMP_FORCE = -15;
    private static final int ATTACK_COOLDOWN = 30;
    private static final int SPEED = 5;
    private static final int BULLET_SPEED = 10;

    private int x, y;
    private int width = 40, height = 80;
    private int dx, dy;
    private int health = 100;
    private Color color;
    private boolean onGround = false;
    private int attackTimer = 0;
    private boolean movingLeft = false;
    private boolean movingRight = false;
    private boolean facingRight = true;
    private int leftKey, rightKey, jumpKey, attackKey;

    public Player(int x, int y, Color color, int leftKey, int rightKey, int jumpKey, int attackKey) {
        this.x = x;
        this.y = y;
        this.color = color;
        this.leftKey = leftKey;
        this.rightKey = rightKey;
        this.jumpKey = jumpKey;
        this.attackKey = attackKey;
    }

    public void update(int screenWidth, List<Platform> platforms) {
        // 处理水平移动
        dx = 0;
        if (movingLeft) {
            dx -= SPEED;
            facingRight = false;
        }
        if (movingRight) {
            dx += SPEED;
            facingRight = true;
        }

        // 保存移动前的坐标
        int xPrev = x;
        x += dx;
        x = Math.max(0, Math.min(screenWidth - width, x));

        // 水平碰撞检测
        Rectangle playerRect = getCollisionBounds();
        for (Platform platform : platforms) {
            Rectangle platformRect = platform.getBounds();
            if (playerRect.intersects(platformRect)) {
                if (dx > 0) { // 向右移动碰撞
                    x = platformRect.x - width;
                } else if (dx < 0) { // 向左移动碰撞
                    x = platformRect.x + platformRect.width;
                }
                break;
            }
        }

        // 处理垂直移动
        dy += GRAVITY;
        int yPrev = y;
        y += dy;

        // 垂直碰撞检测
        boolean isFalling = dy > 0;
        onGround = false;

        if (isFalling) {
            // 下落碰撞检测
            int playerBottomAfter = y + height;
            int playerBottomBefore = yPrev + height;

            Platform landingPlatform = null;
            int highestPlatformY = Integer.MIN_VALUE;

            for (Platform platform : platforms) {
                Rectangle platformRect = platform.getBounds();
                int platformTop = platformRect.y;
                int platformBottom = platformTop + platformRect.height;

                boolean xOverlap = (x < platformRect.x + platformRect.width) &&
                        (x + width > platformRect.x);

                if (xOverlap &&
                        playerBottomBefore <= platformTop &&
                        playerBottomAfter >= platformTop) {

                    if (platformTop > highestPlatformY) {
                        highestPlatformY = platformTop;
                        landingPlatform = platform;
                    }
                }
            }

            if (landingPlatform != null) {
                y = landingPlatform.getY() - height;
                dy = 0;
                onGround = true;
            } else {
                // 检查地面碰撞
                if (playerBottomAfter >= 450) {
                    y = 450 - height;
                    dy = 0;
                    onGround = true;
                }
            }
        } else if (dy < 0) {
            // 上升碰撞检测(头部碰撞)
            int playerTopAfter = y;
            int playerTopBefore = yPrev;

            Platform headPlatform = null;
            int lowestPlatformBottom = Integer.MAX_VALUE;

            for (Platform platform : platforms) {
                Rectangle platformRect = platform.getBounds();
                int platformBottom = platformRect.y + platformRect.height;

                boolean xOverlap = (x < platformRect.x + platformRect.width) &&
                        (x + width > platformRect.x);

                if (xOverlap &&
                        playerTopBefore >= platformBottom &&
                        playerTopAfter <= platformBottom) {

                    if (platformBottom < lowestPlatformBottom) {
                        lowestPlatformBottom = platformBottom;
                        headPlatform = platform;
                    }
                }
            }

            if (headPlatform != null) {
                y = headPlatform.getY() + headPlatform.getHeight();
                dy = 0;
            }
        }

        // 更新攻击计时器
        if (attackTimer > 0) {
            attackTimer--;
        }
    }

    public Bullet shoot() {
        attackTimer = ATTACK_COOLDOWN;
        int bulletX = facingRight ? x + width : x - 10;
        int bulletY = y + height/2 - Bullet.SIZE/2;
        return new Bullet(bulletX, bulletY, facingRight ? BULLET_SPEED : -BULLET_SPEED, this);
    }

    public void jump() {
        if (onGround) {
            dy = JUMP_FORCE;
            onGround = false;
        }
    }

    public void takeDamage(int damage) {
        health = Math.max(0, health - damage);
    }

    public void draw(Graphics g) {
        g.setColor(color);
        g.fillRect(x, y, width, height);
    }

    public Rectangle getCollisionBounds() {
        return new Rectangle(x + 5, y + 10, width - 10, height - 20);
    }

    public int getX() { return x; }
    public int getY() { return y; }
    public int getHealth() { return health; }
    public Color getColor() { return color; }
    public boolean isOnGround() { return onGround; }
    public void setMovingLeft(boolean moving) { movingLeft = moving; }
    public void setMovingRight(boolean moving) { movingRight = moving; }
    public boolean canAttack() { return attackTimer <= 0; }
    public int getLeftKey() { return leftKey; }
    public int getRightKey() { return rightKey; }
    public int getJumpKey() { return jumpKey; }
    public int getAttackKey() { return attackKey; }
}

class Bullet {
    int x, y;
    int speed;
    Player shooter;
    static final int SIZE = 10;

    public Bullet(int x, int y, int speed, Player shooter) {
        this.x = x;
        this.y = y;
        this.speed = speed;
        this.shooter = shooter;
    }

    public void update() {
        x += speed;
    }

    public void draw(Graphics g) {
        g.setColor(Color.YELLOW);
        g.fillOval(x, y, SIZE, SIZE);
    }

    public boolean hitsPlayer(Player player) {
        Rectangle bulletRect = new Rectangle(x, y, SIZE, SIZE);
        return bulletRect.intersects(player.getCollisionBounds());
    }

    public boolean hitsPlatform(Platform platform) {
        Rectangle bulletRect = new Rectangle(x, y, SIZE, SIZE);
        return bulletRect.intersects(platform.getBounds());
    }
}

class Platform {
    private int x, y, width, height;

    public Platform(int x, int y, int width, int height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }

    public void draw(Graphics g) {
        g.setColor(new Color(100, 100, 100));
        g.fillRect(x, y, width, height);
        g.setColor(new Color(120, 120, 120));
        g.fillRect(x, y, width, 3);
        g.fillRect(x, y + height - 3, width, 3);
    }

    public Rectangle getBounds() {
        return new Rectangle(x, y, width, height);
    }

    public int getY() { return y; }
    public int getHeight() { return height; }
}

 

 

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

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

相关文章

Windows 安装多用户和其它一些问题 VMware Onedrive打不开

以下以win10家庭版为例&#xff0c;win11、专业版类似。 Onedrive相关问题参看我的其他文章&#xff1a; Windows如何同时登录两个OneDrive个人版账号_onedrive登录两个账号-CSDN博客 win10 win11 设置文件权限以解决Onedrive不能同步问题_onedrive没有同步权限-CSDN博客 O…

java基础自用笔记:异常、泛型、集合框架(List、Set、Map)、Stream流

异常 异常体系 编译时异常代表程序觉得你可能会出错。 运行时异常代表已经出错 异常基本处理 异常的作用 可以在可能出现的异常的地方用返回异常来代替return&#xff0c;这样提醒程序出现异常简洁清晰 自定义异常 最好用运行时异常&#xff0c;不会像编译时异常那样烦人&a…

第六届 蓝桥杯 嵌入式 省赛

参考 第六届蓝桥杯嵌入式省赛程序设计题解析&#xff08;基于HAL库&#xff09;_蓝桥杯嵌入式第六届真题-CSDN博客 一、分析功能 RTC 定时 1&#xff09;时间初始化 2&#xff09;定时上报电压时间 ADC测量 采集电位器的输出电压信号。 串行功能 1&#xff09;传送要设置…

爱普生FC-135晶振5G手机的极端温度性能守护者

在5G时代&#xff0c;智能手机不仅需要高速率与低延迟&#xff0c;更需在严寒、酷暑、振动等复杂环境中保持稳定运行。作为 5G 手机的核心时钟源&#xff0c;爱普生32.768kHz晶振FC-135凭借其宽温适应性、高精度稳定性与微型化设计&#xff0c;成为5G手机核心时钟源的理想选择&…

如何备份你的 Postman 所有 Collection?

团队合作需要、备份&#xff0c;还是迁移到其他平台&#xff0c;我们都需要在 Postman 中将这些珍贵的集合数据导出。 如何从 Postman 中导出所有集合(Collection)教程

MinGW下编译ffmpeg源码时生成compile_commands.json

在前面的博文MinGW下编译nginx源码中&#xff0c;有介绍到使用compiledb工具在MinGW环境中生成compile_commands.json&#xff0c;以为compiledb是捕获的make时的输出&#xff0c;而nginx生成时控制台是有输出编译时的命令行信息的&#xff0c;笔者之前编译过ffmpeg的源码&…

【数据结构】树与森林

目录 树的存储方法 双亲表示法 孩子表示法 孩子兄弟表示法 树、森林与二叉树的转换 树转换成二叉树 森林转换成二叉树 二叉树转换成森林 树与森林的遍历 树的遍历 森林的遍历 树的存储方法 双亲表示法 这种存储结构采用一组连续空间来存储每个结点&#xff0c;同时…

跟着StatQuest学知识08-RNN与LSTM

一、RNN &#xff08;一&#xff09;简介 整个过程权重和偏置共享。 &#xff08;二&#xff09;梯度爆炸问题 在这个例子中w2大于1&#xff0c;会出现梯度爆炸问题。 当我们循环的次数越来越多的时候&#xff0c;这个巨大的数字会进入某些梯度&#xff0c;步长就会大幅增加&…

【SpringCloud】Eureka的使用

3. Eureka 3.1 Eureka 介绍 Eureka主要分为两个部分&#xff1a; EurekaServer: 作为注册中心Server端&#xff0c;向微服务应用程序提供服务注册&#xff0c;发现&#xff0c;健康检查等能力。 EurekaClient: 服务提供者&#xff0c;服务启动时&#xff0c;会向 EurekaS…

初识MySQL · 数据类型

目录 前言&#xff1a; 数值类型 文本、二进制数据类型 时间类型 String类型 前言&#xff1a; 对于MySQL来说&#xff0c;是一门编程语言&#xff0c;可能定义不是那么的严格&#xff0c;但是对于MySQL来说也是拥有自己的数据类型的&#xff0c;比如tinyint&#xff0c;…

QT图片轮播器(QT实操学习2)

1.项目架构 1.UI界面 2.widget.h​ #ifndef WIDGET_H #define WIDGET_H#include <QWidget>#define TIMEOUT 1 * 1000 QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent n…

深度解析衡石科技HENGSHI SENSE嵌入式分析能力:如何实现3天快速集成

嵌入式分析成为现代SaaS的核心竞争力 在当今SaaS市场竞争中&#xff0c;数据分析能力已成为产品差异化的关键因素。根据Bessemer Venture Partners的最新调研&#xff0c;拥有深度嵌入式分析功能的SaaS产品&#xff0c;其客户留存率比行业平均水平高出23%&#xff0c;ARR增长速…

杂草YOLO系列数据集4000张

一份开源数据集——杂草YOLO数据集&#xff0c;该数据集适用于农业智能化、植物识别等计算机视觉应用场景。 数据集详情 ​训练集&#xff1a;3,664张高清标注图像​测试集&#xff1a;180张多样性场景样本​验证集&#xff1a;359张严格筛选数据 下载链接 杂草YOLO数据集分…

Vue 2 探秘:visible 和 append-to-body 是谁的小秘密?

&#x1f680; Vue 2 探秘&#xff1a;visible 和 append-to-body 是谁的小秘密&#xff1f;&#x1f914; 父组件&#xff1a;identify-list.vue子组件&#xff1a;fake-clue-list.vue 嘿&#xff0c;各位前端探险家&#xff01;&#x1f44b; 今天我们要在 Vue 2 的代码丛林…

机器学习的一百个概念(1)单位归一化

前言 本文隶属于专栏《机器学习的一百个概念》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和参考文献请见[《机器学习的一百个概念》 ima 知识库 知识库广场搜索&…

SpringCould微服务架构之Docker(5)

Docker的基本操作&#xff1a; 镜像相关命令&#xff1a; 1.镜像名称一般分两部分组成&#xff1a;[repository]:[tag]。 2. 在没有指定tag时&#xff0c;默认是latest&#xff0c;代表着最新版本的镜像。 镜像命令的案例&#xff1a; 镜像操作常用的命令&#xff1a; dock…

SpringAI与JBoltAI深度对比:从工具集到企业级AI开发范式的跃迁

一、Java生态下大模型开发的困境与需求 技术公司的能力断层 多数企业缺乏将Java与大模型结合的标准开发范式&#xff0c;停留在碎片化工具使用阶段。 大模型应用需要全生命周期管理能力&#xff0c;而不仅仅是API调用。 工具集的局限性 SpringAI作为工具集的定位&#xff1…

Python中multiprocessing的使用详解

1.实现多进程 代码实现&#xff1a; from multiprocessing import Process import datetime import timedef task01(name):current_timedatetime.datetime.now()start_timecurrent_time.strftime(%Y-%m-%d %H:%M:%S). "{:03d}".format(current_time.microsecond //…

强化学习与神经网络结合(以 DQN 展开)

目录 基于 PyTorch 实现简单 DQN double DQN dueling DQN Noisy DQN&#xff1a;通过噪声层实现探索&#xff0c;替代 ε- 贪心策略 Rainbow_DQN如何计算连续型的Actions 强化学习中&#xff0c;智能体&#xff08;Agent&#xff09;通过与环境交互学习最优策略。当状态空间或动…

飞书电子表格自建应用

背景 coze官方的插件不支持更多的飞书电子表格操作&#xff0c;因为需要自建应用 飞书创建文件夹 创建应用 开发者后台 - 飞书开放平台 添加机器人 添加权限 创建群 添加刚刚创建的机器人到群里 文件夹邀请群 创建好后&#xff0c;就可以拿到id和key 参考教程&#xff1a; 创…