自定义地图制作教程


自定义地图制作教程

地图生成器提供了利用自己写的lua脚本 和生成器提供的api, 从头生成生成一张地图的能力
所使用的lua版本为5.3,

更新日志详见 这里, 如果想用更新的测试版本,欢迎加q群 1013586495

快速入门

建议动手开编辑器(任何一个能输入文字的编辑器,推荐vscode)跟随教程一起

你的第一张lua地图

生成器提供了map这一全局变量,map提供了生成地图所需要的一系列接口函数(能力),例如初始化地图大小和人数,设置水域,设置某个位置的高度,保存地图等

首先,让我们来创建一张纯水域地图吧

-- 初始化地图大小、人数
mapWidth = 600
mapHeight = 600

-- 创建地图必须先调用下面这个函数
map:setup(mapWidth, mapHeight,6)

-- 初始化地图使用到的所有贴图
map:initTextures("Dirt_Yucatan01", "Grass_Hawaii02", "Grass_Hawaii03", "Grass_Hawaii04", "Grass_Heidelberg05")

-- 设置地图高度和贴图
for i = 0, mapWidth-1 do
    for j = 0, mapHeight-1 do
        -- 设置高度
        map:setHeight(i,j, 120)
        -- 设置地表贴图
        map.setTexture(i,j,"Dirt_Yucatan01")
    end
end

map:setWaterHeight(200)

-- 设置玩家位置,第一个参数位玩家编号,范围1到6,后面两个参数为横纵坐标
map.setPlayerPos(1, 240, 200)
map.setPlayerPos(2, 400, 300)

-- 保存地图
map:save()

保存为MyMap.lua(文件名即地图名) ,然后打开地图生成器,选择MyMap.lua文件,点击右边的生成

恭喜,你已经成功生成了一张自己的地图

添加地表贴图

所有贴图完整列表

为了添加地表贴图,需要先初始化地图所使用的的所有贴图列表

map:initTextures("Dirt_Yucatan01", "Grass_Hawaii02", "Grass_Hawaii03", "Grass_Hawaii04", "Grass_Heidelberg05")

然后再给某个位置设置贴图,注意这里所使用的贴图必须是上面那个函数参数里的其中一个

map.setTexture(i,j,"Dirt_Yucatan01")

添加矿脉

添加矿脉使用如下函数

-- 前两个参数为位置,最后一个位角度(角度制)
map.addOreNode(440, 280, 45)

添加斜坡

添加斜坡使用如下函数

目前这个函数有点问题,后面会修复

-- 参数位,起始点横纵坐标,终点横纵坐标,斜坡宽度
map:ramp(300, 90, 300, 110, 12)

让我们利用已有的知识,创建一个圆岛地图

-- 初始化地图大小、人数、名字
mapWidth = 600
mapHeight = 600

map:setup(mapWidth, mapHeight,6)
-- 初始化贴图数据
map:initTextures("Dirt_Yucatan01", "Grass_Hawaii02", "Grass_Hawaii03", "Grass_Hawaii04", "Grass_Heidelberg05")

-- 设置地图基本高度(水底高度)
for i = 0, mapWidth-1 do
    for j = 0, mapHeight-1 do
        map:setHeight(i,j, 120)
        map.setTexture(i,j,"Dirt_Yucatan01")
    end
end

-- 创建一个圆形的高度为210的陆地,圆心在地图中心
for i = 0, mapWidth-1 do
    for j = 0, mapHeight-1 do
        if (math.sqrt( (i - mapWidth /2 ) * (i - mapWidth /2 ) + (j - mapHeight /2 ) * (j - mapHeight /2 )) < 200 ) then
            map:setHeight(i,j, 210)
            map.setTexture(i,j,"Grass_Hawaii02")
        end 
    end
end

map:setWaterHeight(200)

-- 添加3个玩家
map.setPlayerPos(1, 240, 200)
map.setPlayerPos(2, 400, 300)
map.setPlayerPos(3, 300, 300)

-- 初始化随机数
math.randomseed(os.time())
math.random(); math.random(); math.random() -- 让随机数稍微启动一下

-- 利用随机数添加矿脉
for i = 1,3 do
    map.addOreNode(math.random(20, 580), math.random(20, 580), 45)
end

-- 添加斜坡
map:ramp(300, 90, 300, 110, 12)

-- 设置最大坡度(弧度制)
-- 如果地图中相邻两个位置的坡度超过这个角度,那么updatePassabilityAuto函数会把这里标记为不可通过
map:seUnPassableAngle(math.pi / 3)

-- 根据地图高度和自动更新地图可通过信息
-- 可通过信息(bool)决定了能否通过这个地方
map:updatePassabilityAuto()
-- 自动混合地表贴图(让贴图连接处更加自然)
map:mixTextures()

-- 保存地图
map:save()

利用精准制作地图的能力

精准制作地图的教程参考这里
在lua里可以用通过调用函数运用此能力,函数如下

-- 下面三个函数的参数都为文件路径
-- 导入RGB图
map:loadImageTerrain("c:\\map\\myMap.png")
-- 导入物体描述文件
map:loadObjectList("objects.txt")
-- 导入贴图颜色文件
map:loadTextureColorMap("textureColor.txt")

特效

为地图添加画面特效,函数如下

-- 设置曝光特效,参数范围0.0 ~ 5.0
map:setBloom(0.5)
-- 设置lookup特效,第一个参数为特效名字,第二个参数为特效值,范围0.0~ 5.0
-- 特效名字有以下几种 LUSaturateColors_Vol , LUShiftBlue_Vol , 
-- LUSaturateColors_Vol
-- LUShiftBlue_Vol
-- BleachByPass_vol
-- LUGrayscale_Vol
map:setLookupTable("LUSaturateColors_Vol", 0.47f)

脚本

地图生成器提供了完整的脚本生成能力,涉及到的脚本主要有3个

-- beginScript表明开始一个脚本
-- conditionAnd添加一个脚本条件
-- execute添加一个脚本动作(满足脚本条件则触发)
-- endScript表明结束当前脚本编辑
-- 下面这个脚本的作用是 设置玩家1的金钱50000
map:beginScript()
    :conditionAnd(3, "CONDITION_TRUE")
    :execute(128, "PLAYER_SET_MONEY", 
        map:pair(arg_PlayerName, "Player_1"), 
        map:pair(arg_Integer, 50000))
    :endScript()

conditionAnd的第一个参数为条件类型,第二个参数为条件名字(条件类型和条件名字是一一对应的)
execute的第一个参数为动作类型,第二个参数为动作名字(动作类型和动作名字是一一对应的)。之后的参数是可变长度的参数(这些参数必须用map:pair包裹起来)
map:pair的第一个参数为脚本参数类型(都以arg_开头),第二个为脚本参数值

你可能要问,条件类型和参数类型有哪些,幸运的是,这个可以在地图编辑器中直接找到,如下图所示

每个脚本项最后的那个数字就是动作(条件)类型

参数类型则有以下这些

arg_Integer 
arg_RealNumber 
arg_ScriptName 
arg_TeamName 
arg_CounterName 
arg_FlagName 
arg_Comparison 
arg_WaypointName 
arg_Boolean 
arg_TriggerAreaName 
arg_Text
arg_PlayerName
arg_SoundName
arg_SubroutineName
arg_UnitName
arg_ObjectName
arg_PositionCoordinate
arg_Angle
arg_TeamState
arg_Relation
arg_AiMood
arg_SpeechName
arg_MusicName
arg_MovieName
arg_WaypointPathName
arg_LocalizedStringName
arg_BridgeName
arg_UnitOrStructureKind
arg_AttackPrioritySetName
arg_RadarEventType
arg_SpecialPowerName
arg_ScienceName
arg_UpgradeName
arg_UnitAbilityName
arg_BoundaryName
arg_Buildability
arg_SurfaceType
arg_CameraShakeIntensity
arg_CommandButtonName
arg_FontName
arg_ObjectStatus
arg_TeamAbilityName
arg_SkirmishApproachPath
arg_Color
arg_EmoticonName
arg_ObjectPanelFlag
arg_FactionName
arg_ObjectTypeListName
arg_MapRevealName
arg_ScienceAvailabilityName
arg_EvacuateContainerSide
arg_Percentage
arg_Percentage2
arg_UnitReference
arg_TeamReference
arg_NearOrFar
arg_MathOperator
arg_ModelCondition
arg_AudioName
arg_ReverbRoomType
arg_ObjectType
arg_Hero
arg_Emotion

至于条件名字和动作名字,目前正在寻找,会逐步给出

注意,生成脚本都是链式调用,以调用beginScript开头,以调用endScript结束

你可能会好奇,怎么没有看到设置脚本名字,这是因为生成器会自动为这个脚本赋予名字(每条脚本的名字都必须唯一),当然,你也可以自己设置名字
(方便其他地方引用),如下所示

map:beginScript()
    :name("myFirstScript1")
    :conditionAnd(3, "CONDITION_TRUE")
    :execute(128, "PLAYER_SET_MONEY", 
        map:pair(arg_PlayerName, "Player_1"), 
        map:pair(arg_Integer, 50000))
    :endScript()

再来看看几个常用脚本

-- 设置玩家1电力为60000
map:beginScript()
    :conditionAnd(3, "CONDITION_TRUE")
    :execute(487, "PLAYER_SET_BASE_POWER", 
        map:pair(arg_PlayerName, "Player_1"), 
        map:pair(arg_Integer, 60000))
    :endScript()
    
-- 禁止玩家1建造苏联真空内爆蛋
map:beginScript()
    :conditionAnd(3, "CONDITION_TRUE")
    :execute(283, "ALLOW_DISALLOW_ONE_BUILDING", 
        map:pair(arg_PlayerName, "Player_1"), 
        map:pair(arg_ObjectName, “SovietSuperWeaponAdvanced”)
        map:pair(arg_Boolean, 0))
    :endScript()
    
map:beginScript()
    :conditionAnd(3, "CONDITION_TRUE")
    :execute(534, "PLAYER_LOCK_PLAYER_TECH", 
        map:pair(arg_PlayerName, "Player_1"), 
        map:pair(arg_ObjectName, “PlayerTech_Allied_TimeBomb_Rank1”)
        map:pair(arg_Boolean, 0))
    :endScript()

目前一些脚本支持还潜在一些错误,等待后续会逐步修正

队伍

地图生成器也支持队伍的创建,通过以下函数

-- 添加一个队伍
-- 第一个参数为玩家名字,第二个参数为队伍名字(随意设置)

-- 给队伍添加一种单位类型(每个队伍最多7种)
map:teamAdd("Player_1", "xunluo")
-- 第一个参数为玩家名字,第二个参数为队伍名字(随意设置),第三个参数为最小值,第四个参数为最大值,第五个参数为单位类型名称
map:teamAddType("Player_1", "xunluo", 4, 6, "SovietMCV")

-- 设置单位微操
map:teamSetMicroManager("Player_1", "xunluo", "FearlessMicroManager")

路径点

地图生成器也支持路径点的创建,通过以下函数

-- 前两个是横纵坐标,第三个是路径点名称(注意路径点名称必须唯一)
map:addWaypoint(100,200,"luaPoint")

区域

地图生成器也支持区域的创建,通过以下函数

-- 第一个是区域名称(注意区域名称必须唯一),后面可变长度的区域顶点坐标(3个以上)
map:addArea("myArea1", map:pair(100,200), map:pair(200,300), map:pair(400,100))

小地图颜色控制

为特定地表贴图设置对应的小地图颜色

-- 第一个参数为贴图名称,后面三个分别为R, G, B值
map:setTextureColor("Grass_Hawaii02", 255,255,0)

添加物体

所有物体名称列表
通过以下函数添加属于某个玩家的某个队伍的物体

-- 在(300, 300)这个位置添加属于玩家1的苏联MCV,并且命名叫luaMCV
map:addObject("SovietMCV", "Player_1", "teamPlayer_1", 300, 300, math.pi / 2, "luaMCV")

地图默认设定

地图中合法的玩家名称为

"Player_1",
"Player_2",
"Player_3",
"Player_4",
"Player_5",
"Player_6",
"PlyrCivilian",
"PlyrNeutral"

其中前6个才是玩家可操控的,后面2个是中立玩家(如果一个物体属于中立玩家,那么这个物体就是中立的)

每个玩家名称都有默认的队伍,如下

Player_1的默认队伍为teamPlayer_1
Player_2的默认队伍为teamPlayer_2
Player_3的默认队伍为teamPlayer_3
Player_4的默认队伍为teamPlayer_4
Player_5的默认队伍为teamPlayer_5
Player_6的默认队伍为teamPlayer_6
PlyrCivilian的默认队伍为teamPlyrCivilian
PlyrNeutral的默认队伍为teamPlyrNeutral

API

void setup(int width, int height, int playerCount)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;初始化地图

void setHeight(int x, int y, float value)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;设置某个位置的高度

public float getHeight(int x, int y)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;获取某个位置的高度

public bool getPassability(int x, int y)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;获取某个位置的通过性(返回true表示可通过,返回false表示不可通过)

save()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;保存地图

void initTextures(params string[] textures)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;设置地图使用的贴图,参数为可变长度

void setTexture(int x, int y, string name)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;设置某个位置使用的使用的贴图名字

void seUnPassableAngle(double angle)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;设置最大不可通过角度

void setPassability(int x, int y, bool passible)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;设置某个位置的通过性

bool getPassability(int x, int y)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;获得某个位置的通过性

void setPlayerPos(int playerNum, float x, float y)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;设置玩家出生点位置

void addOreNode(float x, float y, float angle)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在某位置增加矿脉

void ramp(float x1,float y1, float x2, float y2, float rampWidth)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在两点间创建指定宽度的斜坡

void mixTextures()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;自动混合地表贴图

void updatePassabilityAuto()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;自动根据seUnPassableAngle所设置的角度更新整个地图的不可通过性


  目录