lua 游戏开发 (脚本通信,差异化表达)投票系统实例

这是一个正经的说明文档

  • 两端通信
    • 1 local script & script
    • 2 Event
    • 服务器到服务器
  • 组成架构
    • 架构
      • 计数器
      • 广告牌
      • 触碰块
    • 地图
  • 映射关系
  • 功能实现
    • text change
    • image change
    • n选m且不重复算法
  • 设计文稿
    • 逻辑草图
    • 对应代码
      • script
      • local script

两端通信

1 local script & script

script :全局脚本,影响所有玩家和游戏主进程

script
服务器
客户端1
客户端2
客户端3

local script:本地脚本,只对客户端玩家产生影响,可以做区别操作

作用
作用
local script1
客户端1
local script2
客户端2

2 Event

远程事件可以提供服务器和客户端之间的单向通信。
有以下三个种类
1.客户端定向到服务器
2.服务器定向到特定客户端
3.服务器定向到所有客户端。

注:
RemoteEvent 对象本身必须位于两者均可查看的场景。
一般会在ReplicatedStorageTool下面新建RemoteEvent,比较多的话放在一个Events文件夹中

客户端到服务器
通过FireServer函数来触发
客户端:
remoteEvent:FireServer()
服务器:
remoteEvent.OnServerEvent:connect(执行的函数)

实例:服务器端投票计数器的增加

function add(player, index)
	--print("index=")
	--print(index)
	ballot[index]=ballot[index]+1
	show[index].Text = string.format(ballot[index])
	have={
     }
	script.Parent.TestMapValue.Value=whatsmap()
	print("map is",script.Parent.TestMapValue.Value)
end

function reduce(player, index)
	ballot[index]=ballot[index]-1
	show[index].Text = string.format(ballot[index])
end

function initailize()
	for i=1,3 do
		ballot[i]=0
		show[i].Text = string.format(ballot[i])
	end
end

game.ReplicatedStorage.Events.voteEvent.OnServerEvent:Connect(add)
game.ReplicatedStorage.Events.dropEvent.OnServerEvent:Connect(reduce)

服务器到客户端
两种方式:向单个客户端 / 同时向每个客户端 发送消息

向单个客户端发送消息,需要带参数:
remoteEvent:FireClient(Player)
或者
remoteEvent:FireClient(player, Players.MaxPlayers, Players.RespawnTime)

实例:客户端触碰块的反馈

votePart[index].Touched:Connect(function(hitPart)--碰到时
		local player = game.Players:GetPlayerFromCharacter(hitPart.Parent)
		
			if not partCDList[index] and player == game.Players.LocalPlayer then
			
				if currentVoteIndex ~= 0 then--不是第一次了 
					votePart[currentVoteIndex].Color = Color3.fromRGB(70, 150, 70)    --变绿
					--	votePart[currentVoteIndex].Size= Vector3.new(0.9, 9.06, 9.06)
					votePart[currentVoteIndex].Position=votePart[currentVoteIndex].Position+Vector3.new(0,0.7,0)
					game.ReplicatedStorage.Events.dropEvent:FireServer(currentVoteIndex)--减一
				end
			
			votePart[index].Color = Color3.fromRGB(255, 0, 0)--正红
			--votePart[index].Size= Vector3.new(0.5, 9.06, 9.06)
			votePart[index].Position=votePart[index].Position-Vector3.new(0,0.7,0)
			currentVoteIndex = index
			game.ReplicatedStorage.Events.voteEvent:FireServer(currentVoteIndex)
			
			partCDList[index] = true
			wait(0.5)
			partCDList[index] = false
			--不让一直判定
		end
	end)

要向所有客户端发送消息,不用传递Player物体:
RemoteEvent:FireAllClients()
要在客户端上监听消息,LocalScript 需将函数连接至 RemoteEvent 的 OnClientEvent事件:
RemoteEvent.OnClientEvent:connect(执行的函数)

实例:初始化


function initialize()
	game.ReplicatedStorage.Events.qxjgEvent:FireServer()
	if currentVoteIndex ~=0 then
	votePart[currentVoteIndex].Color = Color3.fromRGB(70, 150, 70)    --变绿
	votePart[currentVoteIndex].Position=votePart[currentVoteIndex].Position+Vector3.new(0,0.7,0)
	currentVoteIndex = 0
	end	
end
game.ReplicatedStorage.Events.InitrializeEvent.OnClientEvent:Connect(initialize)

客户端到客户端
必须通过服务器中转

客户端1 服务器 客户端2 服务器!我要让客户端2执行函数1 执行函数1 收到信号 执行函数1. 服务器!我要让所有客户端执行函数2 执行函数2 执行函数2 客户端1 服务器 客户端2

服务器到服务器

这一点单独拎出来说明
对于scrip1中 定义的 local 变量 ,script2是无法进行更改的,除非不使用local的定义方式将所有使用到的值,以numvalue.value的方式进行存储和读写,这显然增加了复杂程度。
我们原则上也可以使用事件通过客户端的中转。

event1
event2
服务器1
客户端
服务器2

但是如果选定的客户端退出游戏了,就会导致线路的中断,造成通信的失败。

为了确保通信的成功,就应该是采用,给全部客户端发的方式。但是这样又会来带资料浪费的问题。

一个较优的解法是设立一个value,通过自带的value.change功能,关联实现希望的效果的函数。
(像是一个服务区到服务器的event)
lua 游戏开发 (脚本通信,差异化表达)投票系统实例_第1张图片
实现方法为现在vote下插入一个value,通过如下代码关联

workspace.Hall.vote.ChangeValue.Changed:Connect(function()
	projection(4,3)--4选3
	for index=1,3 do
		ballot[index]=0
	    show[index].Text = string.format(ballot[index])
	    wordchange[index].Text=string.format(word[truth[index]])
	    image[index].Texture=string.format(picture[truth[index]])
	end
end)

使用时只需,对workspace.Hall.vote.ChangeValue的值进行改变,即可完成端到端通信

组成架构

架构

lua 游戏开发 (脚本通信,差异化表达)投票系统实例_第2张图片
lua 游戏开发 (脚本通信,差异化表达)投票系统实例_第3张图片
testmapvalue为输出接口

计数器

数量:3
功能:实时投票结果的显示
最终换算时所使用的计数结果

广告牌

数量:3
功能:显示参与投票的地图信息
显示方式:图片,地图名称

触碰块

数量:3
功能:触碰投票
本地:变色和凹陷凸起转化

地图

数量:n
作用:传送和ui指向
存放:workspace下
lua 游戏开发 (脚本通信,差异化表达)投票系统实例_第4张图片
用文件夹存放地图中所有元素,只要明白排列的先后顺序,便可以通过findchild函数定位到对应位置。

映射关系

随机且不重复投影
改变图文
n张地图
三个计数版
三个广告牌

功能实现

text change

local word ={
     "绮樱之城","甜点乐园","巨人厨房","上元盛日"}

workspace.vote.advertisementwo.word.SurfaceGui.TextLabel.Text=string.format(word[index])

image change

local picture ={
     "rbxassetid://5494130319","rbxassetid://5494129949","rbxassetid://5494133438","rbxassetid://5494130898"}

workspace.vote.advertisementwo.map.Texture.Texture=string.format(picture[index])

n选m且不重复算法

function derects(some)
	local des=math.random(1,9999)
	 des=des%some
	 des=des+1
	return des
end



function projection(n,m)--将n个数,随机选取与排序,投影到m个
	--地图数量较少,能接受O(N2)的时间复杂度,但是4选3的情况下,最后一个重复多次
	--可以通过交换法,把第一个放到[1]的位置,n-1选下一个,带来时间复杂度的降低和无需进行判断
	local toolman ={
     }
	local tempt = n
	for index=1,n do
		toolman[index]=index
	end
	--toolman 存放n个数的table
    for index=1,m do
		local rand=rand(tempt)
		truth[index]=toolman[rand]
		print(truth[index])
		local change =toolman[tempt]--n
		toolman[tempt]=truth[index]
		toolman[rand]=change
		tempt=tempt-1
	end
end

设计文稿

逻辑草图

lua 游戏开发 (脚本通信,差异化表达)投票系统实例_第5张图片
lua 游戏开发 (脚本通信,差异化表达)投票系统实例_第6张图片

对应代码

script

--定义变量声明
math.randomseed(os.time())
local vote = script.Parent
local show={
     vote.printone.SurfaceGui.num,vote.printtwo.SurfaceGui.num,vote.printthree.SurfaceGui.num}
local wordchange={
     vote.AdvertisementOne.word.SurfaceGui.TextLabel,vote.AdvertisementTwo.word.SurfaceGui.TextLabel,vote.AdvertisementThree.word.SurfaceGui.TextLabel}
local image={
     vote.AdvertisementOne.Map.Texture,vote.AdvertisementTwo.Map.Texture,vote.AdvertisementThree.Map.Texture}
local have={
     }
local ballot={
     0,0,0} --投票计数器
local truth ={
     1,2,3} --地图计数器 1,2,……,m 目前m=3
local picture ={
     "rbxassetid://5336067148","rbxassetid://5336101315","rbxassetid://5336089151","rbxassetid://5501472462"}
local word ={
     "绮樱之城","甜点乐园","巨人厨房","上元盛日"}
local index =1
local jurge =true

--函数
function derects(some)
	local des=math.random(1,9999)
	 des=des%some
	 des=des+1
	return des
end



function projection(n,m)--将n个数,随机选取与排序,投影到m个
	--地图数量较少,能接受O(N2)的时间复杂度,但是4选3的情况下,最后一个重复多次
	--可以通过交换法,把第一个放到[1]的位置,n-1选下一个,带来时间复杂度的降低和无需进行判断
	local toolman ={
     }
	local tempt = n
	for index=1,n do
		toolman[index]=index
	end
	--toolman 存放n个数的table
    for index=1,m do
		local rand=rand(tempt)
		truth[index]=toolman[rand]
		print(truth[index])
		local change =toolman[tempt]--n
		toolman[tempt]=truth[index]
		toolman[rand]=change
		tempt=tempt-1
	end
end


function add(player, index)
	ballot[index]=ballot[index]+1
	show[index].Text = string.format(ballot[index])
	have={
     }
	script.Parent.TestMapValue.Value=whatsmap()
end

function reduce(player, index)
	ballot[index]=ballot[index]-1
	show[index].Text = string.format(ballot[index])
end


--main
for index = 1, #show do--初始化置0
	    show[index].Text = string.format(ballot[index])
	    wordchange[index].Text=string.format(word[truth[index]])
	    image[index].Texture=string.format(picture[truth[index]])
end


----地图返回计算算法
function whatsmap() 
local toolman=0
	local map=ballot--得到当时的投票结果,以免发生读者写者问题
	for i=1,3 do
		--print("map",i,"is",map[i])
		if map[i]>toolman then
			toolman=map[i]
			--print("ok")
		end
	end--得到数组最大值并存储在toolman中
	for i=1,3 do
		if map[i]==toolman then
			--high=high+1
		table.insert(have,i)	
		end
	end
	toolman=#have
	toolman=derects(toolman)
	--return have[toolman] --真实值还需要转化
	return truth[have[toolman]]
end

workspace.Hall.vote.ChangeValue.Changed:Connect(function()
	projection(4,3)--4选3
	for index=1,3 do
		ballot[index]=0
	    show[index].Text = string.format(ballot[index])
	    wordchange[index].Text=string.format(word[truth[index]])
	    image[index].Texture=string.format(picture[truth[index]])
	end
	
end)


--关联事件
game.ReplicatedStorage.Events.voteEvent.OnServerEvent:Connect(add)
game.ReplicatedStorage.Events.dropEvent.OnServerEvent:Connect(reduce)

local script

local votePart = {
     game.Workspace.Hall.vote.voteone, game.Workspace.Hall.vote.votetwo, game.Workspace.Hall.vote.votethree}
local partCDList = {
     false, false, false}
local currentVoteIndex = 0

for index = 1, #votePart, 1 do --1,2,3
	votePart[index].Touched:Connect(function(hitPart)--碰到时
		local player = game.Players:GetPlayerFromCharacter(hitPart.Parent)
		
			if not partCDList[index] and player == game.Players.LocalPlayer then
			
				if currentVoteIndex ~= 0 then--不是第一次了 
					votePart[currentVoteIndex].Color = Color3.fromRGB(70, 150, 70)    --变绿
					--	votePart[currentVoteIndex].Size= Vector3.new(0.9, 9.06, 9.06)
					votePart[currentVoteIndex].Position=votePart[currentVoteIndex].Position+Vector3.new(0,0.7,0)
					game.ReplicatedStorage.Events.dropEvent:FireServer(currentVoteIndex)--减一
				end
			
			votePart[index].Color = Color3.fromRGB(255, 0, 0)--正红
			--votePart[index].Size= Vector3.new(0.5, 9.06, 9.06)
			votePart[index].Position=votePart[index].Position-Vector3.new(0,0.7,0)
			currentVoteIndex = index
			game.ReplicatedStorage.Events.voteEvent:FireServer(currentVoteIndex)
			
			partCDList[index] = true
			wait(0.5)
			partCDList[index] = false
			--不让一直判定
		end
	end)
end

function initialize()
	if currentVoteIndex ~=0 then
	votePart[currentVoteIndex].Color = Color3.fromRGB(70, 150, 70)    --变绿
	votePart[currentVoteIndex].Position=votePart[currentVoteIndex].Position+Vector3.new(0,0.7,0)
	currentVoteIndex = 0
	end	
end
game.ReplicatedStorage.Events.InitrializeEvent.OnClientEvent:Connect(initialize)

你可能感兴趣的:(lua,游戏开发,游戏,脚本语言)