独立游戏的诞生

记录游戏制作的点点滴滴。

彩色尾巴诞生记

清楚的记得彩色尾巴这个游戏的第一次代码提交是2015年的1月1日,到今天写这篇文章已经11个月了。

这期间游戏从无到有,一点一点的由雏形到最终的成品,整个过程也是值得记录一下。

游戏的想法源自一个随机的想法,就是俄罗斯方块贪吃蛇消除的一个大混杂。

所以游戏的第一版是随机的色块,玩家控制角色的上下左右移动方向。

完成了角色的方向控制,接下来要解决的就是如何搭配消除的规则,实现的手段就是吃到一个方块就把这个方块接在头部,当吃到三个连续色块时,相同的色块就消除了。

当采用滑动操作来控制四个移动方向时,觉得还是有点不太适宜触屏,所以经过思考,决定把移动方向缩减到两维,通过点击操作来在两种方向上切换。同时为了简化游戏操作,在屏幕边界做了自动转向的设定。游戏的视角也从俯视,变成了后方45度。

考虑到主角的头应该是玩家注意力集中的地方,所以把吃到的方块接到尾巴上是一个更好的选择,方块从吃到接到尾巴,采用了先放大吃到的方块,等到它到达尾巴的位置才开始移动的方式。此时的消除也是吃到三个相同即产生消除。角色的移动也从离散式变为了连续式。

由于消除只发生在一维,所以并不能产生连消的效果,二连消恰恰又是消除游戏的一个核心玩法,最后决定的方法是可以接到更长的相同的颜色,消除发生在接到一个不同的方块时。同时游戏内增加了动画表现。

贪吃蛇+消除+俄罗斯方块

最近在构思一个新的游戏,采用纯色快的风格,游戏规则是贪吃蛇与消除的结合,立方体的造型又有俄罗斯方块的感觉。

想突出的特色是,颜色和动作。

目前采用的配色是参照苹果图标的配色, 在demo中看起来颜色还是非常的和谐。

接下来会在相机移动,消除规则,还有动作之间做一些设计。

技术上希望能够运用shader实现动作,目前想要的效果是弹弹的感觉。

这会是一只清新的蛇。

一撸到底

一撸到底是一款精致打造的击破地心引力的生存游戏。高度落体中需要你躲避突入的岩石,绕开致命的炮弹。无害又可爱的乌鸦以及金币是你坠落过程的好朋友。

无论你喜欢左手,还是右手,在#一撸到底#都能满足你畅爽的体验。 随着故事的深入,需要你的手指以更快的节奏配合大脑更加沉着的判断,才能冲破重重阻碍到达最后的巅峰。

也许每个人能够游戏的时间各不相同,但是少年,努力,就一定能活的更久。

游戏特色:

超快和紧张的玩法

瞬间敏感的模拟控制

复古的音效

爆棚的成就感

模型动画查看器

美术制作的3D模型动画文件,没有很好的预览手段,往往需要手动创建Animator,然后再拖对应的动画文件到State中,在模型动画数量增多的时候,手动处理这些问题往往是耗时低效的。所以就有了制作模型动画查看器的需求。

基本的思路为读取模型文件,创建Animation Controller, 将动画文件添加到Animation Controller的Layer,并建立不同状态间的Transition. 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
using UnityEngine;
using System.Collections;
using UnityEditor;
using UnityEditorInternal;
using System.IO;
using System.Collections.Generic;

public class AnimationViewer : Editor
{
  private static string ModelPath = Application.dataPath + "/Model";
  private static string animationControllerPath = "Assets/AnimationController";
  private static string PrefabPath = "Assets/Resources/Prefabs";
  private static string FileName = "ModelNames";
  private static StreamWriter writer;
  
  static void DoCreateAnimationAssets ()
  {
      //获得模型动画所在文件夹
      DirectoryInfo raw = new DirectoryInfo (ModelPath);      
      string appendString = "";

      //遍历模型动画文件夹
      foreach (DirectoryInfo dictory in raw.GetDirectories())
      {
          appendString += ":" + dictory.Name;
          State lastState = null;

          //生成AnimationController
          AnimatorController animatorController = AnimatorController.CreateAnimatorControllerAtPath (animationControllerPath + "/" + dictory.Name + ".controller");
          //得到AnimationController的Layer, 默认layer为base
          AnimatorControllerLayer layer = animatorController.GetLayer (0);
          List<State> stateList = new List<State>();
          foreach (FileInfo file in dictory.GetFiles()) {
              //动画名称遵循"模型名@动画名"的规则,并除去.meta文件
              if (file.Name.Contains ("@") && !file.Name.Contains (".meta")) {
                  //把动画文件保存在我们创建的AnimationController中,并与上一个动画状态做Transition.
                  string fbxPath = "Assets/Model/" + dictory.Name + "/" + file.Name;
                  lastState = AddStateTransition (fbxPath, layer, lastState);
                  stateList.Add(lastState);
              }
          }

          UnityEditorInternal.StateMachine sm = layer.stateMachine;
          //首位详解,形成一个循环播放的效果
          sm.AddTransition(stateList[stateList.Count -1], stateList[0]);

          //保存为Prefab
          BuildPrefab (dictory, animatorController);
      }

      AppendString (appendString);
  }

  static void AppendString (string appendString)
  {
      //记录所有的模型名称
      File.WriteAllText (Application.dataPath + "/Resources/" + FileName + ".txt", appendString);
  }

  private static State AddStateTransition (string path, AnimatorControllerLayer layer, State lastState)
  {
      UnityEditorInternal.StateMachine sm = layer.stateMachine;
      //根据动画文件读取它的AnimationClip对象
      AnimationClip newClip = AssetDatabase.LoadAssetAtPath (path, typeof(AnimationClip)) as AnimationClip;
      AnimationUtility.SetAnimationType (newClip, ModelImporterAnimationType.Generic);
      //取出动画名子 添加到state里面
      State state = sm.AddState (newClip.name);
      state.SetAnimationClip (newClip, layer);
      //把state添加在layer里面
      if (lastState = null)
      {
          sm.AddTransition (lastState, state);
      }

      return state;
  }

  private static void BuildPrefab (DirectoryInfo dictory, AnimatorController animatorCountorller)
  {
      string modelPath = "Assets/Model/" + dictory.Name + "/" + dictory.Name + ".FBX";

      GameObject go = AssetDatabase.LoadAssetAtPath (modelPath, typeof(GameObject)) as GameObject;
      go.name = dictory.Name;

      Animator animator = go.GetComponent<Animator> ();
      animator.runtimeAnimatorController = animatorCountorller;

      PrefabUtility.CreatePrefab (PrefabPath + "/" + go.name + ".prefab", go);
  }
}

BasketBallCourt_Fight

BasketBallCourtFight