为了吃鸡苦练狙击,避免坑队友自己造一个狙击游戏!

在这里插入图片描述

引言

一文教会你造一个简易的狙击游戏。

说到狙击,相信大家都不陌生,无论是影视作品还是网络游戏,都经常能看到狙击枪的身影,最深刻的是它能够从百里之外,一枪爆头

本文将介绍如何在Cocos Creator中造一个简易的狙击游戏非常详细

本文源工程在文末获取,小伙伴们自行前往。

1.狙击游戏常见的元素有什么?

以下是狙击游戏中常见的一些元素

  1. 狙击枪: 各种类型的狙击枪。

  2. 瞄准镜: 玩家可以使用各种瞄准镜来提高精准度和观察敌人。

  3. 目标: 狙击目标。

那么实现狙击游戏需要哪些知识点?

2.实现狙击游戏的知识点

想要在Cocos Creator中造一个简易的狙击游戏,需要掌握以下知识点:

  1. 动画编辑:狙击游戏通常包含一些动画效果,例如打开瞄准镜的时候、子弹的运动轨迹等等都需要一些简易的动画效果,本文用到动画编辑器Tween动画。

  2. 瞄准镜效果:瞄准镜的效果通常使用RTT方法,全称RenderToTexture,通过把摄像机拍到的内容渲染到2DUI上。

  3. 碰撞检测:本文是简易狙击游戏,开枪即判断是否命中,采用的是屏幕射线检测,子弹的物理碰撞不做详细介绍。

  4. 圆形遮罩:圆形的瞄准镜,需要借助一下Mask遮罩。

  5. 3D游戏基础:例如模型的摆放、坐标的计算转换以及相机的调整

以上相关知识点笔者前面的文章都有介绍,可在文末100个Cocos实例专栏查阅。

话不多说,一起来看下如何在Cocos Creator中造一个简易的狙击游戏

3.一起来造一个简易的狙击游戏

我们根据以下的步骤一步一步来造一个简易的狙击游戏:

1.环境

引擎版本:Cocos Creator 3.8.1

编程语言:TypeScript

2.资源准备

首先从市场搞一把帅气带瞄准镜狙击枪模型,还送了个开火特效!(这回节目组可是下重本啊。)

下重本了

然后找一张简单的瞄准镜画面UI,准备做几个小按钮用作瞄准镜开镜、射击和重置复位。

与技术无关,没有他我能闭着眼爆头

给瞄准镜添加一个Mask组件形成圆形遮罩。

方便好用

为了营造一个非常好的打鸡效果,我们把熟悉的鸡朋友拉过来当靶子

给我摆高一点

添加2个摄像机,并且分别调整各自的摄像机的机位,包括原有的主摄像机瞄准镜摄像机子弹轨迹跟踪摄像机

没想到做个Demo都那么不容易

小技巧

瞄准镜摄像机可以和主摄像机一致,包括位置、旋转和设置,通过改变相机Fov实现放大效果

通过动画编辑器简单编辑一下开镜动画

有手就行

3.编写代码

首先定义一个Snipe组件,包含以下几个属性。

@ccclass('Snipe')
export class Snipe extends Component {
    bulletPfb: Node;         //子弹预制体
    animation: Animation;    //动画组件
    sighting: Node = null;   //瞄准UI节点
    bullet: Node;            //当前子弹
    checkerCameraNode: Node; //相机检测节点
}

然后在start方法里面初始化一下,并且监听一下开镜、射击、重置事件。

start() {
    this.animation = this.node.getComponent(Animation);
    director.getScene().on("PreShoot", this.PreShoot, this);
    director.getScene().on("Shoot", this.Shoot, this);
    director.getScene().on("Reset", this.Reset, this);
    this.bulletPfb = this.node.getChildByPath("qiang/Line16");
    this.SightingCamera();
}

开镜、射击、重置事件从UI_Joystick中的按钮发出。

const sighting = this.node.getChildByName('Sighting');
this.node.getChildByName('BtnOpen').on(NodeEventType.TOUCH_END, () => {
    this._scene.emit("PreShoot", sighting);
}, this);
this.node.getChildByName('BtnShoot').on(NodeEventType.TOUCH_END, () => {
    if (sighting.active) {
        this._scene.emit("Shoot", checkerCamera.node);
    }
}, this);
this.node.getChildByName('BtnReset').on(NodeEventType.TOUCH_END, () => {
    this._scene.emit("Reset");
}, this);

实现瞄准镜的核心源码

  • 创建RenderTexture
  • 设置摄像机的targetTexture为上面创建的RenderTexture
  • 创建SpriteFrame也设置它的texture为上面创建的RenderTexture
  • 最后将瞄准镜SpritespriteFrame为上面创建的SpriteFrame
SightingCamera() {
    const modelRtt = new RenderTexture();
    modelRtt.reset({
        width: 1024,
        height: 1024
    });
    const camera = find("Main Camera/SightingCamera").getComponent(Camera);
    camera.targetTexture = modelRtt;
    const spriteFrame = new SpriteFrame();
    spriteFrame.texture = modelRtt;
    find("Canvas/ui_joystick_panel/Sighting/Mask/SightingSprite").getComponent(Sprite).spriteFrame = spriteFrame;
}

PreShoot方法中实现开镜动画的播放,核心API如下。

  • 通过animation.play播放动画。
  • 通过animation.on(Animation.EventType.FINISHED监听动画播放完成。
  • 通过animation.targetOff取消监听。
PreShoot(sighting: Node, callback = null) {
    if (this.bullet) return;
    this.sighting = sighting;
    if (this.node.children[0].active) {
        this.animation.targetOff(this);
        this.animation.on(Animation.EventType.FINISHED, (event) => {
            this.sighting.active = true;
            this.node.children[0].active = false;
        }, this);
        this.animation.play("animation");
    }
    else {
        this.animation.targetOff(this);
        if (callback) {
            this.animation.on(Animation.EventType.FINISHED, (event) => {
                callback();
            }, this);
        }
        this.sighting.active = false;
        this.node.children[0].active = true;
        this.animation.play("animation2");
    }
}

Shoot方法中利用射线检测判断瞄准镜是否瞄准了目标核心API如下。

  • 通过camera.screenPointToRay 产生射线。
  • 通过PhysicsSystem.instance.raycast 进行射线碰撞检测并记录结果。
  • 通过PhysicsSystem.instance.raycastResults 获取射线检测结果,通过名字或者其他信息得到想要的物体。
Shoot(checkerCameraNode: Node) {
    this.checkerCameraNode = checkerCameraNode;
    var ray = new geometry.Ray();
    var camera = find("Main Camera").getComponent(Camera);
    var size = view.getViewportRect();
    camera.screenPointToRay(size.width / 2, size.height / 2, ray);
    if (PhysicsSystem.instance.raycast(ray)) {
        const raycastResults = PhysicsSystem.instance.raycastResults;
        for (let i = 0; i < raycastResults.length; i++) {
            const item = raycastResults[i];
            if (item.collider.node.name == "rooster_man_skin") {
                this.OnShootTarget(item.collider.node, item.hitPoint);
                return;
            }
        }
        this.OnShoot();
    } else {
        this.OnShoot();
    }
}

最后在OnShootTarget中通过Tween动画运行子弹并且击中目标。

OnShootTarget(hitNode: Node, hitPoint: Vec3) {
    this.checkerCameraNode.active = false;
    this.PreShoot(this.sighting, () => {
        this.node.children[1].active = true;
        const bullet = instantiate(this.bulletPfb);
        this.bullet = bullet;
        bullet.parent = this.bulletPfb.parent;
        bullet.children[0].active = true;
        // tween(bullet.children[1]).by(0.5, { eulerAngles: new Vec3(0, 360, 0) }).repeatForever().start();
        tween(bullet).by(3, { position: new Vec3(0, -0.5, 0) }).to(1, { worldPosition: hitPoint }).call(() => {
            bullet.getComponentInChildren(MeshRenderer).enabled = false;
            hitNode.getComponent(CharacterMovement).onJump("btn_slot_0");
            this.node.children[1].active = false;

        }).start();
        tween(bullet.children[0].getComponent(Camera)).to(3, { fov: 30 }).to(1, { fov: 80 }).start();
    })
}

4.效果演示

瞄准镜动画效果。

在这里插入图片描述

瞄准镜效果。

在这里插入图片描述

射击效果。
在这里插入图片描述

整体效果。

在这里插入图片描述

结语

本文源工程可通过阅读原文或者私信发送"Snipe"付费获取。付费不仅是知识的获取,更是对笔者的支持和认可,感谢!

我是"亿元程序员",一位有着8年游戏行业经验的主程。在游戏开发中,希望能给到您帮助, 也希望通过您能帮助到大家。

AD:笔者线上的小游戏《贪吃蛇掌机经典》《重力迷宫球》《填色之旅》大家可以自行点击搜索体验。

实不相瞒,想要个在看!请把该文章分享给你觉得有需要的其他小伙伴。谢谢!

推荐专栏:

100个Cocos实例

8年主程手把手打造Cocos独立游戏开发框架

和8年游戏主程一起学习设计模式

游戏开发的技巧、心得、资讯

从零开始开发贪吃蛇小游戏到上线系列

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于C/C++的libcurl多协议文件传输库dll二次封装开发使用

libcurl 可能是最便携、最强大和最常用的 这个星球上的网络传输库。官方提供的示例&#xff0c;需要在项目中引用到libcurl-imp.lib才能使用。 这里我改造了下工程&#xff0c;将常用的接口导出到了libcurl.dll中方便直接在后续的工程代码中应用&#xff0c;下面可以看到dll常用…

RNN和LSTM学习笔记-初学者

提示&#xff1a; 目录 前言一、RNN介绍二、LSTM介绍总结 前言 提示&#xff1a; 提示&#xff1a; 一、RNN介绍 RNN是一种短时记忆&#xff0c;而LSTM是长短时记忆网络 二、LSTM介绍 总结

用python+opencv+PySimpleGUI实现了一款视频播放器

目录 前言准备工作主要思路主界面视频读取进度条拖拽 源码 前言 本篇将用python实现一个mp4播放器&#xff0c;可以通过windows资源管理器选择需要播放的mp4视频文件或者图片&#xff0c;然后提供播放条的快进回放&#xff0c;播放和暂停功能&#xff1a; 准备工作 python所…

5G工业网关视频传输应用

随着科技的不断进步&#xff0c;5G网络技术已经成为了当前最热门的话题之一。而其中一个引人注目的领域就是5G视频传输和5G工业网关应用。在传统网络通信中&#xff0c;由于带宽和延迟的限制&#xff0c;视频传输常常受到限制&#xff0c;而工业网关应用也存在着链路不稳定、数…

http正向代理测试,nginx反向代理中转正向代理服务器

有3台服务器如下&#xff1a; 192.168.111.201&#xff08;反向代理到正向代理服务器&#xff09; 192.168.111.202&#xff08;正向代理服务器&#xff09; 192.168.111.203&#xff08;目标WEB系统&#xff09; 防火墙网络策略如图所示: 1、192.168.111.200 只能访问 192.168…

主宰无双H5:WIN学习手工服务端通用视频教程及GM授权物品后台,支持三网H5玩法介绍

标题&#xff1a;主宰无双H5&#xff08;游戏源码&#xff09;&#xff1a;WIN学习手工服务端通用视频教程及GM授权物品后台&#xff0c;支持三网H5玩法的百科 一、引言 随着互联网的快速发展&#xff0c;H5游戏逐渐成为人们休闲娱乐的重要方式。主宰无双H5游戏源码作为一款深…

深入理解LightGBM

1. LightGBM简介 GBDT (Gradient Boosting Decision Tree) 是机器学习中一个长盛不衰的模型&#xff0c;其主要思想是利用弱分类器&#xff08;决策树&#xff09;迭代训练以得到最优模型&#xff0c;该模型具有训练效果好、不易过拟合等优点。GBDT不仅在工业界应用广泛&#…

初识Redis缓存,一文掌握Redis重要知识文集。

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

QWebEngineView 透明色 设置白屏闪烁的问题 已解决

在项目开发中。由于qt5.15 升级到qt6.5 不知道因为什么&#xff0c;QWebEngineView 加载出现白屏&#xff0c; 网上大神给的方案 五花八门&#xff0c;没有一个解决问题。 代码 旧代码QWebEngineView* pWebEngineView new QWebEngineView();//pWebEngineView->page()->…

HTML+CSS高频面试题

面试题目录 前言1.讲一下盒模型&#xff0c;普通盒模型和怪异盒模型有什么区别2.CSS如何实现居中3.讲一下flex弹性盒布局4.CSS常见的选择器有哪些&#xff1f;优先级5.长度单位px 、em、rem的区别6.position属性的值有哪些7.display属性的值有哪些&#xff0c;分别有什么作用8.…

ChatGPT在指尖跳舞: open-interpreter实现本地数据采集、处理一条龙

原文&#xff1a;ChatGPT在指尖跳舞: open-interpreter实现本地数据采集、处理一条龙 - 知乎 目录 收起 Part1 前言 Part2 Open - Interpreter 简介 Part3 安装与运行 Part4 工作场景 1获取网页内容 2 pdf 文件批量转换 3 excel 文件合并 Part5总结 参考资料 往期推…

字符设备驱动模块的编译

一. 简介 本文继上一篇文章的学习&#xff0c;上一篇文章学习了字符设备驱动框架的初步编写。文章地址如下&#xff1a; 字符设备驱动框架的编写-CSDN博客 本文对上一篇编写的驱动模块初步框架进行编译。 二. 字符设备驱动模块的编译 上一篇文章&#xff0c;编写了字符设备…

多分类预测 | MATLAB实现CNN-LSTM-Attention多输入分类预测

分类预测 | MATLAB实现CNN-LSTM-Attention多输入分类预测 分类效果 需要源码和数据的私信&#xff08;微微有偿取哦&#xff09;

swing快速入门(十二)

注释很详细&#xff0c;直接上代码 上一篇 新增内容 1.Box容器和BroadLayout布局管理器的结合用法 2.textArea&#xff08;多行文本域&#xff09; 3.Choice&#xff08;下拉选择栏&#xff09; 4. CheckboxGroup&#xff08;多项单选选择框&#xff09; 5. Checkbox&…

爬虫chrome浏览器抓包说明

chrome浏览器抓包说明 目标&#xff1a;掌握chrome在爬虫中的使用 1. 新建隐身窗口&#xff08;无痕窗口&#xff09; 作用&#xff1a;在打开无痕窗口的时候&#xff0c;第一次请求某个网站是没有携带cookie的&#xff0c;和代码请求一个网站一样&#xff0c;这样就能够尽可…

网络服务IP属地发生变化的原因有哪些?

近期&#xff0c;许多用户发现自己的网络服务IP属地发生了变化。原本固定的IP地址不再是静态的&#xff0c;而是发生了变动。这一现象引起了广大用户的关注和疑惑&#xff0c;对网络服务的使用和信息安全产生了影响。为了解决用户的疑虑&#xff0c;我们对此现象进行了深入探究…

.NET 8的正式发布,对Telerik开发工具意味着什么?

微软日前正式发布了.NET 8稳定版&#xff0c;这是一个长期支持(LTS)的版本&#xff0c;它可以使Android、Windows和macOS跨平台应用的开发过程高效流畅&#xff0c;同样的目标也驱使着Telerik UI不断进步和发展&#xff01; Telerik DevCraft包含一个完整的产品栈来构建您下一个…

现代雷达车载应用——第2章 汽车雷达系统原理 2.6节 雷达设计考虑

经典著作&#xff0c;值得一读&#xff0c;英文原版下载链接【免费】ModernRadarforAutomotiveApplications资源-CSDN文库。 2.6 雷达设计考虑 上述部分给出了汽车雷达基本原理的简要概述。在雷达系统的设计中&#xff0c;有几个方面是必不可少的&#xff0c;它们决定了雷达系…

真正可行的vue3迁移到nuxt3方法(本人亲测,完全避坑)

终于到了总结经验的时候了&#xff0c;这绝对是全网唯一、完全真正可行的干货。 在我看来&#xff0c;知识就是要拿来分享的&#xff0c;分享给他人也是在提高自己。我绝对不会搞什么订阅或者vip专栏来搞钱坑害各位&#xff0c; 因为我在csdn写文章最主要的目的是为了记录和总…

接口测试 — 4.Requests库GET、Post请求

Requests库GET请求是使用HTTP协议中的GET请求方式对目标网站发起请求。 &#xff08;不带参数的GET请求请看上一篇文章的练习&#xff09; 1、Requests库待参数的GET请求 使用Get方法带参数请求时&#xff0c;是params参数字典&#xff0c;而不是data参数字典。data参数字典…