手游开发杂谈


Life is short. You need Python.

人生苦短,我用Python

总之,python的优点就是两句话,简单灵活,要啥有啥

参考资源:

Case 1: Batch modify excel files

案例1: 批量修改Excel文件

主要用到的python库:

gooey

Turn (almost) any Python command line program into a full GUI application with one line.

from gooey import Gooey

@Gooey(program_name='GUI工具')
def main():
    parse = ArgumentParser(description='GUI工具')
    parse.add_argument('--verbose', action='store_true', help='...')

参考资源:

logging

A simple, powerful python logging library.

logger = logging.getLogger('Logger Tag')
logger.setLevel(logging.DEBUG)
# file handler
fh = logging.FileHandler('/path/to/logFile')
fh.setLevel(logging.WARNING)
fh.setFormatter(logging.Formatter(
    '%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
logger.addHandler(fh)
# console handler
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
ch.setFormatter(logging.Formatter('%(message)s'))
logger.addHandler(ch)
# then use:
logger.info('info..') # logger.debug('...') balabala

xlutils

基于xlrd和xlwt的一系列excel操作工具。

关键代码:

# formatting_info=True 用于加载格式信息
workBook = xlrd.open_workbook(filePath, formatting_info=True)
# 获取工作表数组
sheet = workBook.sheets()[i]
sheet.name # 工作表名称
sheet.ncols # 列数
sheet.nrows # 行数
cell = sheet.cell(row, col) # 获取一个单元格
cell.ctype # 单元格值类型
cell.value # 单元格值
cell.xf_index # 单元格样式索引
# 改变单元格的值
sheet.put_cell(row, col, ctype, value, xf_index)
# 保存修改后的表格,xlrd只负责读,所以需要通过xlutils来保存
xlutils.save(workBook, filePath)

参考资源:

手游优化简述

手游优化其实是一个找最佳平衡点的问题。要平衡:开发维护工作量、优化深度、性能、画面表现等之间的关系。

主要评估几个方面:

主流优化方法:

Case 2: Batch optimize png files

案例2: 批量优化压缩PNG文件

PNG索引简介

PNG:便携式网络图形(Portable Network Graphics,PNG)是一种无损压缩的位图图形格式,支持索引、灰度、RGB三种颜色方案以及Alpha通道等特性。
WikiPedia,说的非常详细。

通过PhotoShop的导出Web图片功能可以非常清晰的理解索引格式的原理。

索引压缩主要涉及的技术:

批量工具主要技术:

def getIHDRInfo(data):
    ''' 
    get information of png file which is contained in the IHDR chunk
    data: IHDR chunk Chunk Data
    return value: information
    '''
    result = struct.unpack('!iiBBBBB', data)
    # struct
    # {
    #   int32 width;
    #   int32 height;
    #   uint8 bit_depth;
    #   uint8 color_type;
    #   uint8 compression_method;
    #   uint8 filter_method;
    #   uint8 interlace_method;
    # }
    info = {}
    prop = ['width', 'height', 'bitDepth', 'colorType',
            'compressionMethod', 'filterMethod', 'interlaceMethod']

    for idx, item in enumerate(prop):
        info[item] = result[idx]

    return info


def getPNGInfo(filePath):
    f = open(filePath, 'rb')
    f.seek(8)
    f.seek(4 + 4, 1)
    data = f.read(13)
    f.close()
    return getIHDRInfo(data)


def isPNGIndexMode(filePath):
    colorTypeList = []

    colorTypeList.append('灰度')
    colorTypeList.append(' ')
    colorTypeList.append('真彩')
    colorTypeList.append('索引')
    colorTypeList.append('α灰度')
    colorTypeList.append(' ')
    colorTypeList.append('α真彩')

    info = getPNGInfo(filePath)

    return colorTypeList[info['colorType']] == '索引'
def runShellCommand(command):
    p = subprocess.Popen(command, shell=True,
                         stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    output, error = p.communicate()
    return (p.returncode, output, error)
if sys.platform == 'darwin':
    (ramDiskStatus, output, error) = runShellCommand(
        'diskutil erasevolume HFS+ TempRAMDisk `hdiutil attach -nomount ram://' + str(2 * 1024 * 64) + '`')  # 64M
else:
    (ramDiskStatus, output, error) = (-1, '', '')

优点:占用空间小,能达到20%~30%的高压缩比。
不足:主要是颜色数量不足导致的,如渐变及半透明的过渡问题(比如光效等)

常用优化工具:

动态合图

想法的来源嘛,主要为了解决换肤类型的问题。

动态合图能解决的问题:

  1. GL_CALL过多问题
  2. 加载合图纹理时的内存峰值问题
  3. 合图纹理使用索引压缩后质量下降问题
  4. 为很多使用场景提供方便的合图策略(换主题,换地貌等)

主要技术点:

二维装箱问题目前仍没有最优解解决方案,而且对最优解的趋近和速度成反比。目前MaxRects应该是最好的算法了。

UnityWiki上面有Unity官方的代码。

关于MaxRects算法,TexturePacker的官方说明是:

* Best-known algorithm for packing textures
* Is fast and has a high packing ratio
* Enable rotation and trimming for best results (depending on your target framework)
GUI/CMD value Description
Best Tests all available placements and uses the result with the least used space
ShortSideFit Short Side Fit
LongSideFit Long Side Fit
AreaFit Area Fit
BottomLeft Bottom Left
ContactPoint Contact Point
Texture2D::updateWithData(const void *data,int offsetX,int offsetY,int width,int height)

但有一点麻烦的地方,此方法使用的glTexSubImage2D要求图像宽度必须是2的倍数。

static SpriteFrame* createWithTexture(Texture2D* pobTexture, const Rect& rect, 
                                      bool rotated, const Vec2& offset, const Size& originalSize);
SpriteFrameCache::getInstance()->removeSpriteFrameByName(imageName);
SpriteFrameCache::getInstance()->addSpriteFrame(spriteFrame, imageName);

字体精简

需求来源:曾经有个项目,画风独特,使用了漂亮的字体,还需要支持14国语言。经过漫长的选择最终确定用Google思源字体作为游戏基本字库(字符全并且无版权问题)。但字体体积非常大,超过10M。游戏里面集成一个这样的字体就够大了,更何况还想多集成几个好看的字体。于是想到对字体进行精简,去掉游戏里面没有用到的字符。由于这个游戏所用到的字符相对固定(也就是说没有用户可以随便输入文字的地方),所以精简下来的字体文件应该非常小。

网上找到的工具和解决方案:

参考阅读:

SSHFS

通过SSH连接,通过SFTP传输文件,不需要额外的配置,简单实用,效率高。安全性能很好。速度快,比samba强,无需配置,映射任何目录

文件系统基于FUSE,mac需要先安装osxfuse

FUSE:用户空间文件系统(Filesystem in Userspace,簡稱FUSE)是一个面向类Unix计算机操作系统的软件接口,它使无特权的用户能够无需编辑内核代码而创建自己的文件系统。目前Linux通过内核模块对此进行支持。

sshfs [user@]host:[dir] mountpoint [options]

然后就可以像操作本地文件一样操作远程目录啦!

参考阅读:

SSH打洞

利用SSH反向隧道穿透NAT,实现内网穿透。核心技术是端口转发,它能够将其他TCP端口的网络数据通过SSH链接来转发,并且自动提供了相应的加密及解密服务。这一过程有时也被叫做“隧道”(tunneling)。总的来说SSH端口转发能够提供两大功能:

  1. 加密SSH Client端至SSH Server端之间的通讯数据。(保护隐私数据不被监听窃取)
  2. 突破防火墙的限制完成一些之前无法建立的TCP连接。(将内网服务暴露到外网)
机器代号 机器位置 地址 账户 ssh/sshd 端口 是否需要运行sshd
A 位于公网 xx.xx.xx.xx usera 22
B 位于NAT之后 127.0.0.1 userb 22
C 位于NAT之后 127.0.0.1 userc 22

目标:在C上通过SSH连接B

在B机器上执行:

ssh -p <B ssh port> -qngfNTR <A port for B>:127.0.0.1:<B ssh port> <A user>@<A IP>

连接自己的SSH端口,转发到远程端口并绑定。

在A机器上执行:

ssh -p <A port for B> <B user>@127.0.0.1

如果要用C机器连接B,需要先在A机器上将/etc/ssh/sshd_config文件中的GatewayPorts设置为yes,然后到C机器执行:

ssh -p <A port for B> <B user>@<A IP>

参考阅读:


工业和信息化部备案管理系统网站 京ICP备18043426号