【Unity造轮子】制作一个简单的2d抓勾效果(类似蜘蛛侠的技能)
前言
欢迎阅读本文,本文将向您介绍如何使用Unity游戏引擎来实现一个简单而有趣的2D抓勾效果,类似于蜘蛛侠的独特能力。抓勾效果是许多动作游戏和平台游戏中的常见元素,给玩家带来了无限的想象和挑战。




不需要担心,即使您是一位新手,也可以轻松跟随本文学习。我们将从头开始,从创建一个新的Unity项目开始,一直到最终的完成效果。
借助本文提供的步骤和技巧,您将能够为您的游戏增添一个的特色。希望您能享受这个过程,并从中获得灵感,探索更多关于游戏开发的乐趣。
照例,我们先来看看本文实现的最终效果,以决定你是否继续往下看


源码我放在文章末尾了
开始
1. 实现简单的抓勾效果
新建一个2d项目,添加一个2对象作为我们的角色物体,并挂载rigidbody 2d、碰撞器、Distance Joint 2d、Line Renderer(记得配置好材质和线宽)

书写脚本代码,代码已经加了详细的解释了,这里就不得过多介绍了
using System.Collections;
using System.Collections.Generic;
using UnityEngine;// Grappler类,用于处理角色的抓取动作
public class Grappler : MonoBehaviour
{// 主摄像机public Camera mainCamera;// 线渲染器,用于渲染抓取线public LineRenderer _lineRenderer;// 距离关节,用于处理抓取物体的物理效果public DistanceJoint2D _distanceJoint;void Start(){// 初始化时,禁用距离关节_distanceJoint.enabled = false;}void Update(){// 检测鼠标左键是否按下if (Input.GetKeyDown(KeyCode.Mouse0)){// 获取鼠标在世界坐标中的位置Vector2 mousePos = (Vector2)mainCamera.ScreenToWorldPoint(Input.mousePosition);// 设置线渲染器的起始和结束位置_lineRenderer.SetPosition(0, mousePos);_lineRenderer.SetPosition(1, transform.position);// 设置距离关节的连接点_distanceJoint.connectedAnchor = mousePos;// 启用距离关节和线渲染器_distanceJoint.enabled = true;_lineRenderer.enabled = true;}// 检测鼠标左键是否松开else if (Input.GetKeyUp(KeyCode.Mouse0)){// 禁用距离关节和线渲染器_distanceJoint.enabled = false;_lineRenderer.enabled = false;}// 如果距离关节启用if (_distanceJoint.enabled){// 更新线渲染器的结束位置_lineRenderer.SetPosition(1, transform.position);}}
}
挂载脚本和绑定对象

简单配置一下环境

运行效果

可以看到,如果连线时碰撞会出现问题,如果你先实现好的碰撞效果,可以勾选Distance Joint 2d的Enable Collision及开启碰撞

效果

2. 高阶钩爪效果
在场景中创建GameObject如下(由父对象到子对象一一进行讲解):

Player:(示例中是一个 圆形的sprite)对其添加RigidBody2D、Circle Collider2D 、Spring Joint2D组件(跟前面一样Spring Joint2D组件开启Enable Collision碰撞)
Gunpivot:钩锁枪的锚点,其为空对象,位置设置在Player的中心即0.0位置(后续用于实现钩锁枪随着鼠标旋转的效果)
GrapplingGun:(示例中为一个长方形的sprite)钩锁枪,用于后期实现发射钩锁,仅添加Box Collider2D即可
FirePoint:钩锁的发射点,空对象,即钩锁发射的起始位置,设置在钩锁枪的边缘即可
Rope:在空对象上添加LineRenderer并适当改变宽度和材质即可。
下有两个脚本分别添加给GrapplingGun和Rope即可
脚本1:Perfecter_Grapple添加给GrapplingGun
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Perfecter_Grapple : MonoBehaviour
{[Header("脚本引用:")]public Grappling_Rope grappleRope;[Header("层设置:")][SerializeField] private bool grappleToAll = false;[SerializeField] private int grappableLayerNumber = 9;[Header("主摄像机:")]public Camera m_camera;[Header("变换引用:")]public Transform gunHolder;public Transform gunPivot;public Transform firePoint;[Header("物理引用:")]public SpringJoint2D m_springJoint2D;public Rigidbody2D m_rigidbody;[Header("旋转:")][SerializeField] private bool rotateOverTime = true;[Range(0, 60)] [SerializeField] private float rotationSpeed = 4;[Header("距离:")][SerializeField] private bool hasMaxDistance = false;[SerializeField] private float maxDistnace = 20;private enum LaunchType //发射类型{Transform_Launch,Physics_Launch}[Header("发射:")][SerializeField] private bool launchToPoint = true;[SerializeField] private LaunchType launchType = LaunchType.Physics_Launch;[SerializeField] private float launchSpeed = 1;[Header("无发射点")][SerializeField] private bool autoConfigureDistance = false;[SerializeField] private float targetDistance = 3;[SerializeField] private float targetFrequncy = 1;[HideInInspector] public Vector2 grapplePoint;[HideInInspector] public Vector2 grappleDistanceVector;private void Start() //开始{grappleRope.enabled = false;m_springJoint2D.enabled = false;}private void Update() //更新函数,控制输入{if (Input.GetKeyDown(KeyCode.Mouse0)) //通过Input的顺序设定函数的执行顺序,先进行钩爪选取点的定位{SetGrapplePoint(); }else if (Input.GetKey(KeyCode.Mouse0)) //从上一步的定位中把grapplerope启用{if (grappleRope.enabled){RotateGun(grapplePoint, false); //进行钩锁枪的旋转}else{Vector2 mousePos = m_camera.ScreenToWorldPoint(Input.mousePosition);RotateGun(mousePos, true);}if (launchToPoint && grappleRope.isGrappling) //如果选择点对点发射且正在钩中目标{if (launchType == LaunchType.Transform_Launch) //如果发射类型是使用Transform类型发射{Vector2 firePointDistnace = firePoint.position - gunHolder.localPosition;Vector2 targetPos = grapplePoint - firePointDistnace;gunHolder.position = Vector2.Lerp(gunHolder.position, targetPos, Time.deltaTime * launchSpeed); //采用插值的形式,模拟绳索命中的物理效果}}}else if (Input.GetKeyUp(KeyCode.Mouse0)) //若抬起左键,则将一切启用的相关布尔置否,恢复原状{grappleRope.enabled = false;m_springJoint2D.enabled = false;m_rigidbody.gravityScale = 1;}else //时刻获取鼠标的屏幕信息位置{Vector2 mousePos = m_camera.ScreenToWorldPoint(Input.mousePosition);RotateGun(mousePos, true);}}void RotateGun(Vector3 lookPoint, bool allowRotationOverTime) //实现绳索枪根据鼠标进行旋转功能{Vector3 distanceVector = lookPoint - gunPivot.position; //定义三维距离向量=朝向点-枪锚点位置float angle = Mathf.Atan2(distanceVector.y, distanceVector.x) * Mathf.Rad2Deg; //定义一个角度,其值等于距离向量tan所对应的弧度值*弧度值转化为角度值的常量if (rotateOverTime && allowRotationOverTime) //当采用根据时间延迟旋转时,采用四元数的插值旋转,在原本的旋转角和获得的绕轴的新角度中进行随时间{gunPivot.rotation = Quaternion.Lerp(gunPivot.rotation, Quaternion.AngleAxis(angle, Vector3.forward), Time.deltaTime * rotationSpeed);}else{gunPivot.rotation = Quaternion.AngleAxis(angle, Vector3.forward); //不采用时间插值变化时时,直接让强旋转角角度等于计算出的角度绕轴的四元数即可}}void SetGrapplePoint() //设定钩取点(主要是位置的计算和注意某些添加的限定条件){Vector2 distanceVector = m_camera.ScreenToWorldPoint(Input.mousePosition) - gunPivot.position; //设置一个二维向量distance用于记录鼠标点击的点和枪锚点之间的距离if (Physics2D.Raycast(firePoint.position, distanceVector.normalized)) //发射一条射线,起始点为开火点,方向为distance的方向向量{RaycastHit2D _hit = Physics2D.Raycast(firePoint.position, distanceVector.normalized); //保存刚才的射线为hitif (_hit.transform.gameObject.layer == grappableLayerNumber || grappleToAll) //选择是否选中任意的可抓取图层或是某一指定图层{if (Vector2.Distance(_hit.point, firePoint.position) <= maxDistnace || !hasMaxDistance) //当命中点和开火电站之间的距离小于最大距离或者不限定最大距离时{grapplePoint = _hit.point; //将命中点位置赋予抓取点位置grappleDistanceVector = grapplePoint - (Vector2)gunPivot.position; //抓钩的距离向量等于钩锁点减去钩锁枪的锚点位置grappleRope.enabled = true; //打开绳索变量}}}}public void Grapple() //钩锁执行(真正决定移动) {m_springJoint2D.autoConfigureDistance = false; //设定弹簧关节组建的自动计算距离属性为假if (!launchToPoint && !autoConfigureDistance) //当对点发射和自动计算距离均为假时,将目标距离和目标频率赋给弹簧组件的属性{m_springJoint2D.distance = targetDistance;m_springJoint2D.frequency = targetFrequncy;}if (!launchToPoint) //如果仅为不对点发射{if (autoConfigureDistance) //若自动计算距离{m_springJoint2D.autoConfigureDistance = true;m_springJoint2D.frequency = 0; //弹簧组件频率属性为0,该值越大,弹簧越硬}m_springJoint2D.connectedAnchor = grapplePoint; //不自动计算距离且不对点发射时m_springJoint2D.enabled = true;}else //对点发射时,选择发射类型,有物理类发射和Transform类发射{switch (launchType){case LaunchType.Physics_Launch:m_springJoint2D.connectedAnchor = grapplePoint; //当使用物理发射时,将钩取点赋予弹簧的连接锚点Vector2 distanceVector = firePoint.position - gunHolder.position; //长度变量等于开火点距离减去持枪距离m_springJoint2D.distance = distanceVector.magnitude; //将长度变量赋给弹簧组建的距离属性,保证钩爪拉到尽头时有一定的距离m_springJoint2D.frequency = launchSpeed; //弹簧频率(强度)等于发射速度m_springJoint2D.enabled = true; //打开弹簧组件,进行拉伸break;case LaunchType.Transform_Launch:m_rigidbody.gravityScale = 0; //当使用Transform发射时,将物体的重力设置为0m_rigidbody.velocity = Vector2.zero; //启动钩爪时,将物体速度清零break;}}}private void OnDrawGizmosSelected() //始终在场景中绘制可视的Gizmo,On方法{if (firePoint != null && hasMaxDistance){Gizmos.color = Color.green;Gizmos.DrawWireSphere(firePoint.position, maxDistnace);}}}
脚本2:Grappling_Rope 添加给Rope即可
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Grappling_Rope : MonoBehaviour
{[Header("一般引用:")]public Perfecter_Grapple grapplingGun; //抓钩枪public LineRenderer m_lineRenderer; //线渲染器[Header("一般设置:")][SerializeField] private int percision = 40; //精度[Range(0, 20)] [SerializeField] private float straightenLineSpeed = 5; //直线速度[Header("绳索动画设置:")]public AnimationCurve ropeAnimationCurve; //绳索动画曲线[Range(0.01f, 4)] [SerializeField] private float StartWaveSize = 2; //起始波动大小float waveSize = 0; //波动大小[Header("绳索进度:")]public AnimationCurve ropeProgressionCurve; //绳索进度曲线[SerializeField] [Range(1, 50)] private float ropeProgressionSpeed = 1; //绳索进度速度float moveTime = 0; //移动时间[HideInInspector] public bool isGrappling = true; //是否正在抓取bool strightLine = true; //是否为直线private void OnEnable() //启用时执行{moveTime = 0;m_lineRenderer.positionCount = percision;waveSize = StartWaveSize;strightLine = false;LinePointsToFirePoint(); //线点对准发射点m_lineRenderer.enabled = true;}private void OnDisable() //禁用时执行{m_lineRenderer.enabled = false;isGrappling = false;}private void LinePointsToFirePoint() //线点对准发射点{for (int i = 0; i < percision; i++){m_lineRenderer.SetPosition(i, grapplingGun.firePoint.position); //绘制连接抓取点和抓钩枪位置的绳子}}private void Update() //更新函数{moveTime += Time.deltaTime;DrawRope(); //绘制绳索}void DrawRope() //绘制绳索{if (!strightLine){if (m_lineRenderer.GetPosition(percision - 1).x == grapplingGun.grapplePoint.x){strightLine = true;}else{DrawRopeWaves(); //绘制绳索波动}}else{if (!isGrappling){grapplingGun.Grapple(); //抓取isGrappling = true;}if (waveSize > 0){waveSize -= Time.deltaTime * straightenLineSpeed;DrawRopeWaves(); //绘制绳索波动}else{waveSize = 0;if (m_lineRenderer.positionCount != 2) { m_lineRenderer.positionCount = 2; }DrawRopeNoWaves(); //绘制无波动的绳索}}}void DrawRopeWaves() //绘制绳索波动{for (int i = 0; i < percision; i++){float delta = (float)i / ((float)percision - 1f);Vector2 offset = Vector2.Perpendicular(grapplingGun.grappleDistanceVector).normalized * ropeAnimationCurve.Evaluate(delta) * waveSize; //计算偏移量Vector2 targetPosition = Vector2.Lerp(grapplingGun.firePoint.position, grapplingGun.grapplePoint, delta) + offset; //目标位置Vector2 currentPosition = Vector2.Lerp(grapplingGun.firePoint.position, targetPosition, ropeProgressionCurve.Evaluate(moveTime) * ropeProgressionSpeed); //当前位置m_lineRenderer.SetPosition(i, currentPosition); //设置线的位置}}void DrawRopeNoWaves() //绘制无波动的绳索{m_lineRenderer.SetPosition(0, grapplingGun.firePoint.position); //设置线的起始位置m_lineRenderer.SetPosition(1, grapplingGun.grapplePoint); //设置线的结束位置}
}
注意:脚本赋予对象后注意赋值,在Rope中的函数曲线绘制以及添加点时一定要注意不能逾越(0,0)以及(1,1)否则会出现钩锁无法发射的问题。
代码赋值部分参数可以参照:


绳索发射曲线样式参照:

最终效果

源码
https://gitcode.net/unity1/unity2d-clawhook

参考
【视频】https://www.youtube.com/watch?v=dnNCVcVS6uw
完结
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!
好了,我是向宇,https://xiangyu.blog.csdn.net
一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~

相关文章:
【Unity造轮子】制作一个简单的2d抓勾效果(类似蜘蛛侠的技能)
前言 欢迎阅读本文,本文将向您介绍如何使用Unity游戏引擎来实现一个简单而有趣的2D抓勾效果,类似于蜘蛛侠的独特能力。抓勾效果是许多动作游戏和平台游戏中的常见元素,给玩家带来了无限的想象和挑战。 不需要担心,即使您是一…...
Unity 人物连招(三段连击)
一: 连招思路 首先人物角色上有三个攻击实例对象 Damage,每一个damage定义了攻击的伤害值,攻击距离,触发器名称,伤害的发起者,攻击持续时间,攻击重置时间,伤害的碰撞框大小等字段: …...
关于WSL以及docker连接adb的坑
结论 WSL可以连接到adb,需要和主机保持一致的adb型号。主机是windows还是macOS的docker没法直接连接到adb设备,只有主机为Linux才可以。其他平台只能通过TCP网络协议。 具体过程 关于WSL连接adb设备 windows安装adb工具(安装可以去官网下…...
python安装第三方包时报错:...\lib\site-packages\pip\_vendor\urllib3\response.py...
安装redis第三方包: pip install redis报错现象: 解决方法:使用以下命令可成功安装 pip install redis -i http://pypi.douban.com/simple --trusted-host pypi.douban.com...
腾讯云从业者认证考试考点——云存储产品
文章目录 存储产品功能云存储产品概述存储产品存储网关存储服务 存储分类按存储方式分按存储频率分 云存储与传统存储的区别功能需求性能需求容量扩展数据共享 云硬盘CBS产品概述归档存储和文件存储归档存储CAS文件存储CFS 对象存储存储网关存储网关的分类 云数据迁移CDM日志服…...
猿辅导Motiff与IXDC达成战略合作,将在UI设计领域推动AI革新更多可能性
近日,“IXDC 2023国际体验设计大会”在北京国家会议中心拉开序幕,3000设计师、1000企业、200全球商业领袖,共襄为期5天的用户体验创新盛会。据了解,此次大会是以“设计领导力”为主题,分享全球设计、科技、商业的前沿趋…...
条件操作符(三目操作符)
比如之前我们想写一个条件判断表达式是这样写的: 用操作符就可以这样写: 应用,比如求两个数的最大值...
(五)Unity开发Vision Pro——FAQ
常见问题 (FAQ) 1.问:我看到在visionOS 模拟器中运行的结果与在硬件上运行的结果不同 请注意,在模拟器中运行时,某些特定于硬件的功能不可用 - 最明显的是 AR 数据。这可能意味着 VisionOS 模拟器中的模拟结果可能与 Vision Pro 耳机上的模…...
GitOps 与 DevOps:了解关键差异,为企业做出最佳选择
在软件开发领域,GitOps 和 DevOps 是加强协作和实现软件交付流程自动化的重要技术。虽然这两种模式都旨在提高软件开发生命周期的效率,但它们的核心原则和实施方式却各不相同。 本篇文章将帮助您了解 GitOps 和 DevOps 之间的差异、它们的工作流程&am…...
Java实现Word文档转PDF,PDF转Word,PDF转Excel,PDF转换工具
前言 java实现word文档转PDF,PDF转word 解决只能转换4页问题 解决每页头部存在水印问题 实现 引入依赖 <dependency><groupId>com.documents4j</groupId><artifactId>documents4j-local</artifactId><version>1.0.3</ve…...
Docker部署ES服务,全量同步的时候内存爆炸,ES自动关闭,CPU100%
问题 使用canal-adapter全量同步(参考Canal Adapter1.1.5版本API操作服务,手动同步数据(4))的时候 小批量数据可以正常运行(几千条)只要数据量一大(上万条),…...
Python——添加照片边框
原图: 添加边框后: 添加边框会读取照片的exif信息如时间、相机型号、品牌以及快门焦段等信息,将他们显示在下面的边框中。 获取当前py文件路径 import os #get path that py file located def Get_Currentpath():file_path os.path.abspa…...
《高性能MySQL》——查询性能优化(笔记)
文章目录 六、查询性能优化6.1 查询为什么会慢6.2 慢查询基础:优化数据访问6.2.1 是否向数据库请求了不需要的数据查询不需要的记录多表关联时返回全部列总是取出全部列重复查询相同的数据 6.2.2 MySQL 是否在扫描额外的记录响应时间扫描的行数与返回的行数扫描的行…...
【Linux操作系统】编译过程中遇到的问题-为什么加-c?执行文件提示无法执行二进制文件?main函数参数argc和*argv[]的作用和理解?
在使用GCC编译器进行程序开发时,我们经常会遇到一些编译过程中的问题, 比如为什么要加上"-c"选项,以及为什么生成的可执行文件无法执行等问题。 本篇博客将详细介绍这些问题,并给出相应的代码和解释,帮助读者…...
【数据结构与算法——TypeScript】图结构(Graph)
【数据结构与算法——TypeScript】 图结构(Graph) 认识图结构以及特性 什么是图? 在计算机程序设计中,图结构 也是一种非常常见的数据结构。 但是,图论其实是一个非常大的话题 认识一下关于图的一些内容 图的抽象数据类型一些算法实现。 什么是图?…...
C语言字符串拷贝函数详解及示例代码
目录 简介字符串拷贝函数 strcpy字符串拷贝函数 strcpy_s使用示例注意事项结束语 1. 简介 字符串拷贝是C语言中常用的操作之一。当需要将一个字符串复制到另一个字符串数组中时,可以使用字符串拷贝函数来实现。C语言提供了多种字符串拷贝函数,其中最常…...
IntelliJ IDEA热部署:JRebel插件的安装与使用
热部署 概述JRebel 概述 热部署,指修改代码后,无需停止应用程序,即可使修改后的代码生效,其有利于提高开发效率。 热部署方式: 手动热部署:修改代码后,重新编译项目,然后启动应用程…...
iTOP-3568开发板使用OpenCV处理图像-颜色转换
本小节代码在配套资料“iTOP-3568 开发板\03_【iTOP-RK3568 开发板】指南教程 \04_OpenCV 开发配套资料\05”目录下,如下图所示: cv2.cvtColor()函数功能: 将一幅图像从一个色彩空间转换到另一个色彩空间。 函数原型: cv2.cvt…...
Python技巧----解压序列/可迭代对象赋值给多个变量
1 、解压序列赋值给多个变量 我们这里说的不是正常情况的一一赋值比如下面 >>> data = [ ACME, 5, 9, (2012, 12, 1) ] >>> name, shares, price, date = data >>> name ACME...
16.3.2 【Linux】程序的管理
程序之间是可以互相控制的。举例来说,你可以关闭、重新启动服务器软件,服务器软件本身是个程序, 你既然可以让她关闭或启动,当然就是可以控制该程序。 使用kill-l或者是man 7 signal可以查询到有多少个signal。主要的讯号代号与名…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
