Unity小游戏制作 - 暗影随行
用Unity制作小游戏 - 暗影惊吓
最近玩了一个小游戏,叫做暗影惊吓,虽然是一个十分简单的小游戏,但是感觉还是十分有趣的。这里就用Unity来实现一个类似的游戏。
项目源码:DarkFollow
主要工作分析
- 主角的控制(重点):左右移动、跳跃、动画播放等
- 场景的设计:地板、空中平台、背景等
- 影子跟随(重点):跟随着主角的有害影子
- 奖励:可以加分,部分奖励会导致产生影子
- 震动:主角根据降落高度,碰到地面会使界面有一个震动效果
主角控制
左右移动
根据键盘输入,来为刚体设置速度即可,同时设置Speed变量来控制动画中Idel和Run的切换//CharacterControl.cs _HorizontalInput = Input.GetAxis("Horizontal"); ... //CharacterData.cs _Move = horizontalInput*MoveSpeed; _Rigid.velocity = new Vector2(_Move, _Rigid.velocity.y); _Animator.SetFloat("Speed", Mathf.Abs(_Move));同时,我们还需要决定玩家的面向,不能一直都朝向右边:
//CharacterData.cs _Move = horizontalInput*MoveSpeed; //决定面向 if(_Move != 0) { Vector3 oldScale = transform.localScale; float scaleX = _Move > 0 ? 1 : -1; transform.localScale = new Vector3(scaleX, oldScale.y, oldScale.z); }跳跃
首先我们要确定玩家是否站在地板上,因此我们需要首先给角色底下添加"Foot":

然后以Foot为圆心,查看是否与地板相交://CharacterData.cs Collider2D[] colliders = Physics2D.OverlapCircleAll(Foot.transform.position, Radius); _IsGrounded = false; if (colliders != null) { for(int i=0; i < colliders.Length; i++) { if(colliders[i].gameObject.layer == LayerMask.NameToLayer("Ground")) { _IsGrounded = true; } } }接着,我们就需要判断玩家是否按下了跳跃键:
//CharacterControl.cs if(!_IsJump && Input.GetKeyDown(KeyCode.UpArrow)) { _IsJump = true; }然后,就是进行跳跃判断了:
//CharacterData.cs if(jump && _IsGrounded) { _Rigid.AddForce (new Vector2(0, JumpForce)); _Animator.SetBool("Jump", true); }- 动画播放
动画状态机设计如下:

边界穿越
玩家可以走到左边界,然后从右边界出来。我们可以如下添加给左右边界均添加碰撞框:

当玩家碰到碰撞框时,会把位置设为另外一边://CharacterControl.cs void OnCollisionEnter2D(Collision2D coll) { Vector2 oldPos = transform.position; string name = coll.gameObject.name; //让玩家能够从左边界直接到右边界(或者相反) if(name == "LeftBorder") { transform.position = new Vector2(_RightBorderX, oldPos.y); } else if(name == "RightBorder") { transform.position = new Vector2(_LeftBorderX, oldPos.y); } }
影子跟随
记录影子数据
为了生成一个影子,我们需要玩家的历史数据,其中需要位置、面向、动画状态机的切换变量,因此可得如下数据结构:public class ShadowData { public Vector3 Pos; //位置 public Vector3 Scale; //缩放(用于决定面向) //以下都是动画状态机中的变量 public float Speed; public float VerticalSpeed; public bool IsJump; public ShadowData(Vector3 pos, Vector3 scale, float speed, float verticalSpeed, bool isJump) { Pos = pos; Scale = scale; Speed = speed; VerticalSpeed = verticalSpeed; IsJump = isJump; } }然后玩家每帧都需要记录ShadowData数据:
//CharacterData.cs void Update() { AddShadowData(); } //记录阴影数据 public void AddShadowData() { Vector3 pos = transform.position; Vector3 scale = transform.localScale; float speed = _Animator.GetFloat("Speed"); float verticalSpeed = _Animator.GetFloat("VerticalSpeed"); bool isJump = _Animator.GetBool("Jump"); ShadowData data = new ShadowData(pos, scale, speed, verticalSpeed, isJump); ShadowDatas.Add(data); }- 黑色影子
首先我们需要一个黑色的影子,因此可创建如下的Material:

然后把他赋值给SpriteRenderer:

然后就能得到一个对应的黑色影子了:

会跟随的影子
我们只要把玩家的历史数据赋值给影子就行,但是要注意,因为玩家的历史数据使用List存储的,因此越后面的数据越新。因为新生成的影子是在旧的影子后面,因此我们应该要从后面开始读数据,让旧的影子读更新的数据从而离玩家更近。而且影子和玩家要有一定距离,因此该距离之类的新数据都是暂时不能读的。如下图所示:

可见,每个影子都应该有自己对应的Index去读。代码如下:public const int GAP_TO_PLAYER = 80; //第一个影子距离玩家的距离(即这数字之后的数据才能被读) public void Refresh (CharacterData player) { int minSize = Index + GAP_TO_PLAYER; if(player.ShadowDatas.Count > minSize) { this.gameObject.SetActive(true); int index = player.ShadowDatas.Count - 1 - GAP_TO_PLAYER - Index; //读倒数的数据 ShadowData data = player.ShadowDatas[index]; RefreshStateBy(data); } else { this.gameObject.SetActive(false); //防止没数据时,影子傻乎乎地站在初始位置 } } void RefreshStateBy(ShadowData data) { transform.position = data.Pos; transform.localScale = data.Scale; _Animator.SetBool("Jump", data.IsJump); _Animator.SetFloat("Speed", data.Speed); _Animator.SetFloat("VerticalSpeed", data.VerticalSpeed); }管理影子
一个游戏中可能生成多个影子,因此我们需要进行管理。我们需要保证每个影子之间能有一定的距离。代码如下:
void Update () {
for (int i = 0; i < Shadows.Count; i++)
{
Shadows[i].Refresh(Player);
}
if (Player.ShadowDatas.Count > (Shadows.Count*GAP + Shadow.GAP_TO_PLAYER) && Shadows.Count > 0)
Player.ShadowDatas.RemoveAt(0);
}
public void CreateShadow()
{
GameObject shadowGo = (GameObject)Resources.Load("Shadow");
shadowGo = Instantiate(shadowGo);
shadowGo.transform.parent = this.transform;
Shadow shadow = shadowGo.GetComponent<Shadow>();
shadow.Index = Shadows.Count * GAP; //保证每个阴影之间有一定距离
Shadows.Add(shadow);
}
其他
其他工作就比较简单了。
奖励
我们只需要设置所有奖励的生成点:

然后随机生成即可:public void RandomCreateBonus() { int index = Random.Range(0, Bonuses.Count); while(index == _PreviousIndex) //保证不生成同一位置 { index = Random.Range(0, Bonuses.Count); } _PreviousIndex = index; Bonuses[index].CreateBonus(IsNormal()); }当然,我们还需要根据设置来生成不同类型的奖励。
摄像机抖动
根据玩家的跳跃高度来决定抖动幅度,而这里抖动是直接用协程来实现:IEnumerator ShakeCoroutine(float jumpDistance) { float t = Mathf.Clamp(jumpDistance / HEIGHT, 0, 1); float delta = Mathf.Lerp(MIN_DELTA, MAX_DELTA, t); MainCamera.transform.position = new Vector3(_OldPos.x, _OldPos.y + delta, _OldPos.z); yield return new WaitForSeconds(0.1f); MainCamera.transform.position = new Vector3(_OldPos.x, _OldPos.y - delta, _OldPos.z); yield return new WaitForSeconds(0.1f); MainCamera.transform.position = new Vector3(_OldPos.x, _OldPos.y, _OldPos.z); }剩下
剩下的直接查看项目源码吧。
Unity小游戏制作 - 暗影随行的更多相关文章
- 自制Unity小游戏TankHero-2D(2)制作敌方坦克
自制Unity小游戏TankHero-2D(2)制作敌方坦克 我在做这样一个坦克游戏,是仿照(http://game.kid.qq.com/a/20140221/028931.htm)这个游戏制作的. ...
- 自制Unity小游戏TankHero-2D(1)制作主角坦克
自制Unity小游戏TankHero-2D(1)制作主角坦克 我在做这样一个坦克游戏,是仿照(http://game.kid.qq.com/a/20140221/028931.htm)这个游戏制作的. ...
- 自制Unity小游戏TankHero-2D(5)声音+爆炸+场景切换+武器弹药
自制Unity小游戏TankHero-2D(5)声音+爆炸+场景切换+武器弹药 我在做这样一个坦克游戏,是仿照(http://game.kid.qq.com/a/20140221/028931.htm ...
- 自制Unity小游戏TankHero-2D(4)关卡+小地图图标+碰撞条件分析
自制Unity小游戏TankHero-2D(4)关卡+小地图图标+碰撞条件分析 我在做这样一个坦克游戏,是仿照(http://game.kid.qq.com/a/20140221/028931.htm ...
- 自制Unity小游戏TankHero-2D(3)开始玩起来
自制Unity小游戏TankHero-2D(3)开始玩起来 我在做这样一个坦克游戏,是仿照(http://game.kid.qq.com/a/20140221/028931.htm)这个游戏制作的.仅 ...
- 半期考html5小游戏制作
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 手把手教学h5小游戏 - 贪吃蛇
简单的小游戏制作,代码量只有两三百行.游戏可自行扩展延申. 源码已发布至github,喜欢的点个小星星,源码入口:game-snake 游戏已发布,游戏入口:http://snake.game.yan ...
- Unity引擎入门——制作第一个2D游戏(1)
Unity作为当今最流行的游戏引擎之一,受到各大厂商的喜爱. 像是炉石传说,以及最近的逃离塔克夫,都是由unity引擎开发制作. 作为初学者的我们,虽然无法直接做出完成度那么高的作品,但每一个伟大的目 ...
- Kinect+unity 实现体感格斗闯关小游戏
文章目录 项目地址 1 项目概况 1.1 项目简介 1.2 项目目的 1.3 主要技术 2 设计 2.1 基本概念 2.2 框架 2.3 算法 2.4 模型 2.5 调查问卷 3 实现 3.1 技术难 ...
随机推荐
- mac显示任何来源
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 16.0px "Microsoft YaHei"; color: #333333; ba ...
- 用Ghost进行备份还原
今天给大伙介绍一下怎么用Ghost给自己的系统进行备份和还原,在这里我用的是U盘启动盘(电脑店)里面的手动Ghost. 首先给大家介绍一下Ghost界面的一些相关选项的含义:(虽然难看但希望大伙们 ...
- APP里如何添加本地文本
首先考虑到用webview加载,那么久需要把文本转化成html的形势啊:如下,先把文字放到一个文本里,然后 文本转换H5: 1.在word中将文件格式布局 2.word中文本标题设为宋体标题,设字号, ...
- Java多线程与静态方法
Java无基础开发Android应用,发现对静态方法理解不够,有如下问题: 在多线程中使用静态方法会发生什么事?也就是说多线程访问同一个类的static静态方法会发生什么事?是否会发生线程安全问题? ...
- 查看openssl的版本
[root@ha01 tengine]# openssl version -a OpenSSL Feb built on: Thu Jul :: UTC platform: linux-x86_64 ...
- MongoDB 优化器MongoDB Database Profiler(12)
优化器profile 在MySQL 中,慢查询日志是经常作为我们优化数据库的依据,那在MongoDB 中是否有类似的功能呢?答案是肯定的,那就是MongoDB Database Profiler. 1 ...
- 解决文件上传插件Uploadify在火狐浏览器下,Session丢失的问题
因为在火狐浏览器下Flash发送的请求不会带有cookie,所以导致后台的session失效. 解决的方法就是手动传递SessionID到后台. $("#fileresultfiles&qu ...
- 【DWR系列02】-DWR逆向Ajax即服务器推送
.literal { background-color: #f2f2f2; border: 1px solid #cccccc; padding: 1px 3px 0; white-space: no ...
- Win10 UI入门RelativePanel(2)
自适应 1) Gif: 添加动画 2)
- [译]:Xamarin.Android平台功能——位置服务
返回索引目录 原文链接:Location Services. 译文链接:Xamarin.Android平台功能--位置服务 本部分介绍位置服务以及与如何使用位置提供商服务 Location Servi ...