[Unity3D]Unity3D游戏开发《反对》说到游戏(上)——目标跟踪
朋友,大家好。我是秦培,欢迎关注我的博客。我的博客地址blog.csdn.net/qinyuanpei。
首先博主要自我反省,过了这么久才来更新博客,这段时间主要是在忙着写期末的作业,所以博主基本上没有空暇时间来研究技术。希望大家谅解啊。有时候,博主会情不自禁地想,假设当初选择了计算机专业,此时此刻。我可能会有很多其它的时间来和大家分享我在学习过程中的感悟吧,有时候博主感觉自己非常孤独,在身边找不到和自己志同道合对技术感兴趣的人。这可能是博主在大学里最大的遗憾了,一个人的成长环境非常重要。当你无法改变身边的环境的时候,你仅仅能努力地改变自己。每当博主对自己说这句话的时候。博主总是一个静静地像如今这样敲写代码,做自己喜欢的事情是幸福的事情。
好了。闲话有空再叙,我们正式開始今天的内容。
相信大多数的80后、90后一定对《魂斗罗》这款游戏感到熟悉吧,这款游戏能够说是FC时代引领射击类游戏潮流的一款经典之作,以致于其设计深刻影响到了像后来的《合金弹头》等游戏。这个世界上有非常多经典的东西。即使时过境迁永远无法被超越。博主在移动平台上看到这款游戏后。果断下载重温了这款经典游戏。
作为一名有追求的游戏设计人员。我们应该在玩游戏的过程中有所收获,积极寻找能够作为我们在技术领域研究的东西,博主的博客差点儿都是这么写下来的。除非是有针对性地学习某些东西,所以呢。就有了这篇文章。
好了,不卖关子了,大家在玩《魂斗罗》的时候一定知道游戏中有一种追踪弹吧,这样的炮弹会随着玩家位置的改变而改变。就像我们在某些军事题材的电影中常常看到的镜头一样,我方战斗机将敌机目标锁定后发射炮弹。炮弹就会对敌机紧追不舍并最终于摧毁敌机。但是不管影视作品特效怎样炫酷夺目,终于留给我们的就是华丽的特效背后蕴藏的原理。
在游戏开发领域。这样的技术称为追踪算法,它是属于AI的一个范畴。常见的追中算法主要有三种,即坐标追踪、视线追踪、拦截追踪。以下呢。我们来分别解说这三种不同的追踪算法:
一、坐标追踪
坐标追踪是最简单、最主要的一种追踪算法,如图,
其基本思路是依据追踪目标的坐标来改变追踪物体的坐标。使两者间距离缩短。举一个简单地样例,假设我们使用二维坐标mPosition来表示追踪物体的坐标,使用mTargetPos来表示追踪目标的坐标,则坐标追踪的算法能够简单表示成以下的代码:
if(mPosition.x<mTargetPos.x) mPosition.x+=Speed*Time.deltaTime;
if(mPosition.x>mTargetPos.x) mPosition.x-=Speed*Time.deltaTime;
if(mPosition.y<mTargetPos.y) mPosition.y+=Speed*Time.deltaTime;
if(mPosition.y>mTargetPos.y) mPosition.y-=Speed*Time.deltaTime;
二、视线追踪,主要是指每一时刻都追踪者会沿着被追逐者之间的直线方向运动。如图所看到的:
由图易知,该算法的关键是求解两个位置间的连线。
由向量的知识我们知道这条直线能够通过向量能够通过向量a-向量b得到。此时追踪者的速度应该满足约束条件:
水平分速度Vx/垂直分速度Vy=c向量的水平分量/c向量的垂直向量。
三、拦截追踪,拦截追踪是在前两种方法的基础上发展而来的一种方法,假设考虑的是追踪目标太远,假设两者者速度一样,或者相差不大。有可能非常难追上。
如图
此时。对于追踪物体而言,它仅仅须要知道追踪目标的位置、方向与速度,就会计算一个最佳的拦截位置,且所须要的时间最短。我们假设最佳拦截点是S2。由速度与位移的关系非常easy知道 S2=Sp+t*V。当中t是追踪者追上猎物的时间。
接下来问题变为一个简单的追击问题。求追击时间t。
首先我们建立追踪者与猎物的速度向量Va与Vp。及位置向量Sa与Sp。 设速度差向量 Vd =Vp-Va 。
称为靠拢速度。 设距离差向量 Sd =Sp-Sa 。
称为靠拢距离。
于是,靠拢时间 t=|Sd|/|Vd| 。
即路程除以速度等于时间。
套用公式S2=Sp+t*V 就得到了拦截点S2,剩下的过程就与视线追踪一样。
好了,在理解了追踪算法的基本原理以后。以下我们以一个最简单的样例来演示今天的内容。
首先我们在Unity3D中建立一个简单地场景,如图所看到的:
我们採取正交投影的方式来实现一个2D场景,场景中红色的方块为目标物体,绿色的方块为追踪物体。我们这里採取的是视线追踪的方法。我们首先来为追踪物体创建脚本Follow.cs。脚本定义例如以下:
using UnityEngine;
using System.Collections; public class Follow : MonoBehaviour { //追踪的目标物体
public Transform Target;
//两个物体间的最小距离
public float MinDistance=1F;
//两个物体间的最大距离
public float MaxDistance=5F;
//定义追踪的速度
public float Speed=0.25F;
//定义追踪物体的坐标
private Vector2 mPosition;
//定义目标物体的坐标
private Vector2 mTargetPos;
//是否在追踪
private bool isFollow=false; void Start ()
{
mPosition=new Vector2(transform.position.x,transform.position.y);
mTargetPos=new Vector2(Target.transform.position.x,Target.position.y);
} void Update ()
{
//获取目标物体的位置
mTargetPos=new Vector2(Target.transform.position.x,Target.position.y);
//假设追踪物体与目标物体之间距离大于等于最大距离。则開始追踪
if(Vector2.Distance(mPosition,mTargetPos)>=MaxDistance)
{
isFollow=true;
}
//假设追踪物体与目标物体之间距离小于等于最小距离,则停止追踪
if(Vector2.Distance(mPosition,mTargetPos)<=MinDistance)
{
isFollow=false;
}
//假设開始追踪,则执行以下的代码
if(isFollow)
{
//计算坐标值
if(mPosition.x<mTargetPos.x) mPosition.x+=Speed*Time.deltaTime*Mathf.Abs(Mathf.Cos(getAngle()));
if(mPosition.x>mTargetPos.x) mPosition.x-=Speed*Time.deltaTime*Mathf.Abs(Mathf.Cos(getAngle()));
if(mPosition.y<mTargetPos.y) mPosition.y+=Speed*Time.deltaTime*Mathf.Abs(Mathf.Sin(getAngle()));
if(mPosition.y>mTargetPos.y) mPosition.y-=Speed*Time.deltaTime*Mathf.Abs(Mathf.Sin(getAngle()));
//改变追踪物体的坐标
transform.position=new Vector3(mPosition.x,mPosition.y,0);
}
} private float getAngle()
{
float angle=0;
//获取水平方向与竖直方向的变化量
float deltaX=mTargetPos.x-mPosition.x;
float deltaY=mTargetPos.y-mPosition.y;
//计算角度
if(deltaX>0 && deltaY>0)
angle= Mathf.Atan(deltaY/deltaX);
if(deltaX<0 && deltaY>0)
angle= Mathf.PI-Mathf.Atan(deltaY/deltaX);
if(deltaX<0 && deltaY<0)
angle= Mathf.PI+Mathf.Atan(deltaY/deltaX);
if(deltaX>0 && deltaY<0)
angle= 2*Mathf.PI-Mathf.Atan(deltaY/deltaX);
if(deltaX==0)
{
angle=Mathf.PI/2;
}
if(deltaY==0)
{
angle=0;
}
return angle;
}
}
在这段脚本中。我们定义了一个getAngle()方法,该方法用于获取追踪物体与目标物体连线与X轴正方向所成的夹角。
这里主要用到三角函数知识,大家能够再温习下曾经学过的知识,不管是程序设计还是游戏开发。数学都应该是我们最应该掌握的东西。好了,通过角度计算,我们能够将速度分解到水平和垂直两个方向,从而保证视线追踪中的约束条件成立。
假设我们将getAngle()方法从脚本中去除,则这就是最简单的坐标追踪,希望大家自己去探讨和研究啊。假设博主有时间的话,会将三种算法的代码都展示出来的。希望大家继续关注我的博客啊。
呵呵。
好了,接下来,我们来为追踪目标创建一个脚本。以便玩家能够控制追踪目标躲避追踪。
脚本定义例如以下:
using UnityEngine;
using System.Collections; public class Control : MonoBehaviour { //定义移动的速度
public float Speed=0.25F;
//定义当前位置
private float mX,mY;
void Start ()
{
mX=transform.position.x;
mY=transform.position.y;
} void Update ()
{
if(Input.GetKey(KeyCode.A))
{
mX-=Speed*Time.deltaTime;
}
if(Input.GetKey(KeyCode.D))
{
mX+=Speed*Time.deltaTime;
}
if(Input.GetKey(KeyCode.W))
{
mY+=Speed*Time.deltaTime;
}
if(Input.GetKey(KeyCode.S))
{
mY-=Speed*Time.deltaTime;
}
transform.position=new Vector3(mX,mY,0);
}
}
好了,以下我们来測试一下程序执行的效果:
不知道为什么录制的GIF动画看不到追踪物体。囧啊,只是博主能够负责任地对大家说。程序没什么问题,哈哈。
好了。今天的内容就是这样了,希望大家喜欢,假设大家希望继续在《魂斗罗》游戏中寻找有趣的设计,请关注我的下一篇博客:Unity3D游戏开发之从《魂斗罗》游戏说起(下) 。
再次感谢大家关注我的博客,谢谢。
每日箴言:你专注于一个方向,终会比别人走得远些。
转载请注明出处,本文作者:秦元培。本文出处:http://blog.csdn.net/qinyuanpei/article/details/29891859
版权声明:本文博客原创文章。博客,未经同意,不得转载。转载请注明出处和作者,谢谢!
[Unity3D]Unity3D游戏开发《反对》说到游戏(上)——目标跟踪的更多相关文章
- 【读书笔记《Android游戏编程之从零开始》】10.游戏开发基础(View 游戏框架)
对于玩家来说,游戏是动态的:对于游戏开发人员来说,游戏是静态的,只是不停地播放不通的画面,让玩家看到了动态的效果. 进入Android之前,首先要熟悉三个重要的类:View(视图).Canvas(画布 ...
- C#游戏开发中快速的游戏循环
C#游戏开发中快速的游戏循环的实现.参考<精通C#游戏编程>一书. using System; using System.Collections.Generic; using System ...
- Unity 2D游戏开发教程之2D游戏的运行效果
Unity 2D游戏开发教程之2D游戏的运行效果 2D游戏的运行效果 本章前前后后使用了很多节的篇幅,到底实现了怎样的一个游戏运行效果呢?或者说,游戏中的精灵会不会如我们所想的那样运行呢?关于这些疑问 ...
- Unity 2D游戏开发教程之为游戏场景添加多个地面
Unity 2D游戏开发教程之为游戏场景添加多个地面 为游戏场景添加多个地面 显然,只有一个地面的游戏场景太小了,根本不够精灵四处活动的.那么,本节就来介绍一种简单的方法,可以为游戏场景添加多个地面. ...
- Libgdx游戏开发(2)——接水滴游戏实现
原文:Libgdx游戏开发(2)--接水滴游戏实现 - Stars-One的杂货小窝 本文使用Kotlin语言开发 通过本文的学习可以初步了解以下基础知识的使用: Basic file access ...
- 喵的Unity游戏开发之路 - 在球体上行走
很多童鞋没有系统的Unity3D游戏开发基础,也不知道从何开始学.为此我们精选了一套国外优秀的Unity3D游戏开发教程,翻译整理后放送给大家,教您从零开始一步一步掌握Unity3D游戏开发. 本文不 ...
- 【游戏开发】小白学Lua(上)
在很多游戏中,脚本语言是不可或缺的一部分,很多游戏都使用到了Lua,js,python一类的脚本,脚本语言可以在很多方面给开发进程带来帮助.脚本语言可以作为初始化文件读入变量和游戏数据的一个快速而方便 ...
- 【Cocos2d-x游戏开发】浅谈游戏中的坐标系
无论是开发2D还是开发3D游戏,首先必须弄清楚坐标系的概念.在Cocos2d-x中,需要了解的有OpenGL坐标系.世界坐标系和节点坐标系. 1.UI坐标系 IOS/Android/Windows ...
- 【读书笔记《Android游戏编程之从零开始》】11.游戏开发基础(SurfaceView 游戏框架、View 和 SurfaceView 的区别)
1. SurfaceView 游戏框架实例 实例效果:就是屏幕上的文本跟着点击的地方移动,效果图如下: 步骤: 新建项目“GameSurfaceView”,首先自定义一个类"MySurfac ...
随机推荐
- C++ Primer笔记7_STL之关联容器
关联容器 与顺序容器不同,关联容器的元素是按keyword来訪问和保存的.而顺序容器中的元素是按他们在容器中的位置来顺序保存的. 关联容器最常见的是map.set.multimap.multiset ...
- 全栈JavaScript之路(十八)HTML5 自己定义数据属性
HTML5 规范规定,用户能够为元素 自己定义非标准属性, 可是要加入 data- 前缀. 目的是为元素提供与页面渲染无关的信息.或者语义信息.这些属性名能够任意加入,仅仅要带上前缀 data- 开头 ...
- C#索引器的应用:自已写一个表格
C#中索引器,在一个类中有很多的同一类型成员的时候,比较适用索引器. 环境:我们假设有一个动物园,里边有很多动物. 用法: 1.先定义一个类,这是成员的类型.在这里就是要定义一个Animal类: pu ...
- 解决set /p yn= 接受键盘输入导致ECHO 处于关闭状态的问题
今天写了一个自动更新程序的批处理脚本,但是有个变量一直赋值有问题.弄了一个下午终于找到原因及解决方法: ----转载要说明来自:博客园--邦邦酱好 哦 有问题的代码如下: @echo off echo ...
- ALV DataChange EVENT
在CX项目中,根据需求,自定义一个表,维护供应商的银行账号信息,当输入供应商编号时,自动在供应商名称列里自动填写供应商名称,用到了ALV DataChange 事件 ,下面是源代码: *&- ...
- 仿CSDN Blog返回页面顶部功能
只修改了2个地方: 1,返回的速度-->改成了慢慢回去.(原来是一闪而返回) 2,返回顶部图标出现的时机-->改成了只要不在顶部就显示出来.(原来是向下滚动500px后才显示) 注意:JS ...
- KVC该机制
KVC该机制 KVC是cocoa的大招,用来间接获取或者改动对象属性的方式. 一.KVC的作用: KVC大招之中的一个: [self setValuesForKeysWithDictionary:di ...
- C++写一个简单的解析器(分析C语言)
该方案实现了一个分析C语言的词法分析+解析. 注意: 1.简单语法,部分秕.它可以在本文法的基础上进行扩展,此过程使用自上而下LL(1)语法. 2.自己主动能达到求First 集和 Follow 集. ...
- Python re正则表达式
参考: 博客园<Python正則表達式指南> 博客园<Python之re模块> 在此感谢博主的无私奉献,本文主要介绍python中re模块的几个简单使用方法.具体的使用方法请參 ...
- 神马是AB測试?
手机响起了短信提示音,桂芬拿起手机,滑动解锁,看到是来福的短信,心里不禁一阵小鹿乱撞. "喜欢看<冰封重生之门>吗?" 如此充满暗示意味的短信让桂芬激动 ...