Visible twitch when swapping player vehicles

Place to get help with not working mods / modding interface.
Post Reply
MostlyNumbers
Inserter
Inserter
Posts: 26
Joined: Fri Apr 13, 2018 10:07 pm
Contact:

Visible twitch when swapping player vehicles

Post by MostlyNumbers »

Hi all, trying to solve an annoying visual glitch in my Hovercraft mod.

Background:
Basically, the vehicle needs to collide with all the usual things over land (ie. collision_mask=player_layer), but not be prevented from skimming over water.
Simply removing the mask from water tiles is no good because the bare character shouldn't be able to walk over it, and turning up the friction causes the player to get stuck in water (doesn't behave like a wall as it does with a collision mask). To my understanding, you can't alter the entity collision mask in runtime.

So, to resolve this there are two vehicles, one for land with collision mask, one for water without. control.lua swaps the vehicles as you drive into/away from water.

Issue:
There is a perceptible twitch as this swap happens.
I believe it's because the game is placing the character next to the first vehicle for a split second when it's destroyed, before inserting into the second.

Any thoughts on how to resolve this?

Rough vehicle swapping code here:

Code: Select all

local function swapVehicle(oldCar,newCarType)
	local newCar = oldCar.surface.create_entity{name=newCarType,position=oldCar.position,force=oldCar.force}
	newCar.orientation = oldCar.orientation
	newCar.speed = oldCar.speed
	newCar.health = oldCar.health
	newCar.burner.currently_burning = oldCar.burner.currently_burning
	newCar.burner.remaining_burning_fuel = oldCar.burner.remaining_burning_fuel
	local driver = oldCar.get_driver()
	local passenger = oldCar.get_passenger()
	for k,v in pairs({carFuel,carTrunk}) do
		for n,c in pairs(oldCar.get_inventory(v).get_contents()) do
			newCar.get_inventory(v).insert({name = n, count = c})
		end
	end
	oldCar.destroy()
	newCar.set_driver(driver)
	newCar.set_passenger(passenger)
end

User avatar
eradicator
Smart Inserter
Smart Inserter
Posts: 5206
Joined: Tue Jul 12, 2016 9:03 am
Contact:

Re: Visible twitch when swapping player vehicles

Post by eradicator »

I don't follow your reasoning on requiring two vehicle types, why does the water "car" need to be different? Just remove the water collision layer from the "car".

Code: Select all

collision_mask = { "object-layer", "player-layer"}

MostlyNumbers
Inserter
Inserter
Posts: 26
Joined: Fri Apr 13, 2018 10:07 pm
Contact:

Re: Visible twitch when swapping player vehicles

Post by MostlyNumbers »

water tiles have the default collision masks:

Code: Select all

collision_mask = {
        "water-tile",
        "item-layer",
        "resource-layer",
        "player-layer",
        "doodad-layer"
      }
so the vehicle would still collide with water tiles

User avatar
eradicator
Smart Inserter
Smart Inserter
Posts: 5206
Joined: Tue Jul 12, 2016 9:03 am
Contact:

Re: Visible twitch when swapping player vehicles

Post by eradicator »

Well. I guess i know less about the default collision masks than i should. I assumed the player would collide with water, and not water with the player. I.e. i thought the player prototype collision mask would contain "water-tile", but the water tile prototype not "player-layer". I wonder if there's any real reason excelt "legacy code" for this.

Back to the original question...as by your own reasoning, why do you destroy the old car before moving the player to the new one if you think that causes the glitch? Looks like you can just move the oldCar.destroy() to the end of the function. And if that doesn't work you could detach the character from the player alltogether while moving it to the new car.

Code: Select all

local c = player.character
player.character = nil
move_driver(c,car1,car2)
player.character = c

MostlyNumbers
Inserter
Inserter
Posts: 26
Joined: Fri Apr 13, 2018 10:07 pm
Contact:

Re: Visible twitch when swapping player vehicles

Post by MostlyNumbers »

I don't think the character collision mask is exposed in data.raw, but I believe it's just "player-layer", i.e. the character collides with anything else having the mask. I tried adding one of the unused masks to the player and water tile but not vehicle, but it doesn't seem to let you add new collision masks to the player.

Tried just moving oldCar.destroy() to the end, but it ejects the player, since the old car still being on the map collides with the player being in the new car "under" the old one.

Will try removing the character.. main question is if you can assign a player to a vehicle without a character? Since you can't drive vehicles in 'god' mode

User avatar
eradicator
Smart Inserter
Smart Inserter
Posts: 5206
Joined: Tue Jul 12, 2016 9:03 am
Contact:

Re: Visible twitch when swapping player vehicles

Post by eradicator »

MostlyNumbers wrote:but it doesn't seem to let you add new collision masks to the player.
Oh? I expected you could just add collision_mask to the prototype. The default mask is {"player-layer","train-layer"} btw, as can be seen via the api game.player.character.prototype.collision_mask.
Will try removing the character.. main question is if you can assign a player to a vehicle without a character? Since you can't drive vehicles in 'god' mode
Ofc, just like the api doc says:
set_driver(driver)

Sets the driver of this vehicle.

Parameters
driver :: LuaEntity or LuaPlayer: The new passenger or nil to eject the current driver if any.
MostlyNumbers wrote: Tried just moving oldCar.destroy() to the end, but it ejects the player, since the old car still being on the map collides with the player being in the new car "under" the old one.
o_O

I can't reproduce the glitch your're talking about. I wrote a sample script that swaps between tank and car while riding and it "just works".

Code: Select all

/c
local my = game.player
  
function newcar(my)
  swap = {car = 'tank',tank = 'car'}
  local newcar = my.surface.create_entity{
    position=my.position,
    name=swap[my.vehicle.name],
    force=my.force}
  newcar.orientation = my.vehicle.orientation
  newcar.speed = my.vehicle.speed
  newcar.burner.currently_burning = my.vehicle.burner.currently_burning
  newcar.burner.remaining_burning_fuel = my.vehicle.burner.remaining_burning_fuel
  return newcar
  end 

if my.vehicle then
  local oldcar = my.vehicle
  newcar(my,my.vehicle.name).set_driver(my)
  oldcar.destroy()
  end

Bilka
Factorio Staff
Factorio Staff
Posts: 3156
Joined: Sat Aug 13, 2016 9:20 am
Contact:

Re: Visible twitch when swapping player vehicles

Post by Bilka »

eradicator wrote:The default mask is {"player-layer","train-layer"} btw, as can be seen via the api game.player.character.prototype.collision_mask.
I also fell for that quite a while ago.. the default is {"player-layer", "train-layer", "consider-tile-transitions"}. The consider tile transitions "mask" cannot be read through LuaEntityPrototype::collision_mask.
I'm an admin over at https://wiki.factorio.com. Feel free to contact me if there's anything wrong (or right) with it.

User avatar
eradicator
Smart Inserter
Smart Inserter
Posts: 5206
Joined: Tue Jul 12, 2016 9:03 am
Contact:

Re: Visible twitch when swapping player vehicles

Post by eradicator »

Bilka wrote:
eradicator wrote:The default mask is {"player-layer","train-layer"} btw, as can be seen via the api game.player.character.prototype.collision_mask.
I also fell for that quite a while ago.. the default is {"player-layer", "train-layer", "consider-tile-transitions"}. The consider tile transitions "mask" cannot be read through LuaEntityPrototype::collision_mask.
Which means that player collision mask can be changed contrary to what OP said. Who named that thing though, without the linked thread i couldn't have guessed what it means.

MostlyNumbers
Inserter
Inserter
Posts: 26
Joined: Fri Apr 13, 2018 10:07 pm
Contact:

Re: Visible twitch when swapping player vehicles

Post by MostlyNumbers »

Which means that player collision mask can be changed contrary to what OP said
Yeah, seems I was just doing it wrong.

With that in mind, final fix is below.
It avoids the original stated problem by assigning an extra collision mask ("layer-12") to the character, any vehicles other than the hovercraft, and units. That mask is used to replace the "player-layer" mask on water tiles.

In data-updates.lua:

Code: Select all

--player
data.raw.player.player.collision_mask = {"player-layer","train-layer","consider-tile-transitions","layer-12"}

-- Remove collision mask from water tiles
for k,waterTiles in pairs({"water","water-green","deepwater","deepwater-green"}) do
	local mask = data.raw.tile[waterTiles].collision_mask
	for i=#mask,1,-1 do
		if mask[i] == "player-layer" then	  -- only change if not already altered by another mod
			mask[i] = "layer-12"
		end
	end
end


-- Add collision mask to vehicles
local vehicles = data.raw.car
for k,v in pairs(vehicles) do
	if k ~= "hovercraft-entity" then
		local mask = data.raw.car[k].collision_mask
		if mask == nil then			-- if not defined, set new default
			data.raw.car[k].collision_mask = {"player-layer","train-layer","layer-12"}
		elseif #mask > 0 then	  	-- ignore vehicles with no collision_mask (ie airplanes)
			mask[#mask+1] = "layer-12"
		end
	end
end

-- Add collision mask to units
local units = data.raw.unit
for k,v in pairs(units) do
	local mask = data.raw.unit[k].collision_mask
	if mask == nil then			-- if not defined, set new default
		data.raw.unit[k].collision_mask = {"player-layer","train-layer","layer-12"}
	elseif #mask > 0 then	  	-- ignore units with explicitly no collision_mask
		mask[#mask+1] = "layer-12"
	end
end

Post Reply

Return to “Modding help”