1. Los Pingheros
  2. News

Los Pingheros News

Version 1.1.1 - Bugfix

Changes

[h3]Menus/UI[/h3]
- Prevent matchmaking against players with a different (e.g. out of date) game version.
[h3]Gameplay[/h3]
- More items induce knockdowns when sliding into them head first.
[h3]Other[/h3]
- Improved overall CPU performance.
Fixes

[h3]Menus/UI[/h3]
- Fixed a bug that made most of the save disappear when unlocking “Spicy Steps”. This led to:
- Losing all previously unlocked content (maps, custos, gamemodes, etc.).
- Unlocking the same thing over and over each time you passed through the reward screen.
- Bugs where gamemodes requiring specific maps could end up picking Bandolon, creating a round that would never end.
- Fixed an issue where you could not connect to the game if your steam name contains a ‘\’. We just remove it from the displayed name.
- Various small fixes to the menus and character selection screen.
- Better handling of special characters in Chinese/Japanese/Korean.
[h3]Gameplay[/h3]
- Fixed an issue with the “Thief” skill, if you died before teleporting an item to you.
- Lots of small fixes bringing stability to the game.
- Fixed an issue with the “Ice Path” challenge with 4 players leading to some pingheros not respawning.
[h3]Other[/h3]
- Fixed several memory leaks that would cause the game to crash after playing for a while.

Version 1.0.3 - Hotfixes

Menus
  • Activate the possiblity to join online games with more than 1 local player.
Game
Fix inconsistent spawning position in challenges.
Challenges "Basics" & "Grab & Bomb" had their leaderboard reset because spawning at a different position was really benificial.
Fix issue with Skill Strom's "Sudden death" gamemode leading to softlocked games in case of a draw.
Fix issue where scores were not appearing at the end of the battle in team modes.
Fix an issue where pingheros could get permanently frozen by a skill combo Cardinal + Tornado was used.

Game is live!

[h3]Hola Pingheros![/h3]

The game is live! We've had a lot of fun playing this afternoon ourselves.

Unfortunately, we've had to release a build that has a known issue:
- When joining an online party with more than 1 local player, it may be impossible to continue to an actual party.

Barring a natural disaster, a fix for this will land tomorrow (along with a couple other small fixes).

10-02-2025 Edit: The online issue has been resolved, together with some other minor bugs, in last Saturday's patch 1.0.3.

This should not prevent you from enjoying the game in the meantime. May the shark be with you!


- HectiQ

DevNews #8 - New VFX, challenges and skin!

Hey Pingheros! Let's go for the DevNews #8 !!

[h2]Game[/h2]

One new challenge map is currently "work in progress" and will bring new objective. 🪙



The luchador mask will get some visual tweaks, but don’t worry—you’ll still be the number one threat (after the megalodon). 💢



The megalodon has found a whole new way to give you chills! 🦈



Love all things woolly? Dive into coziness with our new skin: Wool Pingheros🐧

DevBlog #6: Asset Actions

Introduction


Hola Pingheros! 👋

Romain here, I want to talk to you about an architectural concept that use in Los Pingheros: AssetActions. If the term looks pretty generic to you, it is because it is supposed to be, AssetActions are meant to represent a wide variety of things that can be done in our game. Let’s get into it.

In case you don’t know it already, LosPingheros is a top down snowball fighting game where a lot of crazy stuff can happen: explosions, sharks chasing you, ananas meteor sent from the penguins gods, etc.

Thus, we developed a very systemic game and as we added features, the combinatorics of associating the different incomes with the different outcomes would have quickly exploded, se we searched for a generic solution to the problem.

[h2]What is an AssetAction[/h2]

We have different kind of triggers in our game, and the goal is to unify the way we produce outcome from those triggers. We need to be able to:

  • Describe the outcome of the interaction
  • Prototype things easily
  • Give the designers the tools to leverage the systemic aspect of the game


Here is an example of what it looks like in the editor. Our coins are Interactable objects that trigger an action when the player touch them. The outcome of this interaction is given by the AssetAction associated to the Interactable component.

AssetActions are scriptable objects (more precisely AssetObject as we are using Photon Quantum, but this is not the topic) that implements the IAssetAction interface.

 internal interface IAssetAction
{
unsafe void OnAssetAction(Frame f, AssetActionRuntimeData context);
}


Simple and effective, the scriptable object must describe what happens when it executes, adding score to the player that triggered the action.

 public unsafe partial class ScoreActionConfig : AssetObject, IAssetAction, IAssetInteraction
{
public ScoringValue ScoringValue;

public void OnAssetAction(Frame f, AssetActionRuntimeData context)
{
// Add score to the associated player
var player = f.C.pPlayerData->Get(f, context.Owner);
player->AddScore(ScoringValue);

// Send an event to the view to create FXs
ObservableEvent.Send(f,
position: context.Position,
owner: context.Owner);
}
}




We previously, created an explosive bomb (is there any other kind of bomb really ?) as you might have seen here: VFX Creation, and the use of symbols. So what happens if we just swap the AssetAction from the score one to the explosive one ?



We just gave a way for the designers to add a fake explosive coin without any extra development cost ! And this is just the beginning…

[h2]AssetActionRuntimeData[/h2]

You might have noticed in the IAssetAction description that a AssetActionRuntimeData is passed as a parameter of the function. This truly has 3 purposes:

Pass other possibly meaningful parameters to the Action:

This is pretty straightforward in the example, it gives information on the context of the interaction that triggered the AssetAction, such as the position, the frame, the player, etc.

Give the possibility to execute the action at another point in the frame:

You don’t always want to execute the action instantly, might it be for logical reasons or performances. For example, you might not want to apply scores before you gathered everything that triggered score in the frame. This allows you to handle things in batch.

This is what the IAssetInteraction interface is for in the ScoreActionConfig. This interface is completely empty, and serves as a tag to tell when the action is supposed to happen.
		switch (assetObject)
{
...
case IAssetInteraction:
AssetActionRuntimeData.CreateAssetAction(f, in assetAction);
//Executed later in the frame
break;
case IAssetAction config:
config.OnAssetAction(f, assetAction);
// Executed instantly
break;
...


The system handling AssetActions just check for the implementations of the AssetAction and execute different logic based on it. IAssetInteraction are added to an interaction queue to be handled later on, while basic IAssetActions are executed instantly.

Give the possibility to delay the action more in the future:

Sometime, you don’t event want the action to happen in the frame where it was triggered, in that case, you just store AssetActionRuntimeData somewhere and wait for it to be ready to be executed.

[h2]Different kind of AssetActions[/h2]

Here is a sample of the kind of AssetActions you can find in our game:



Name

Action



AOEConfig

Create an area of effect applying different kind impacts to objects in the area. There is different shapes, different elements, different propagation logic, all defined as variables in the scriptable object.



SharkConfig

Modify the AI of the shark to make him try to bite a certain location or a certain player.



CharacterStatModConfig

Apply a buff to a player, making him as jumpy as a rockhopper or as strong as an emperor.



ActionOverrideConfig

Apply some modifiers to basic actions of the character, making them fly instead of jumping for example.



JumpAction (CustomAction)

Make an object jump, even if it is not supposed to. There is a bunch of actions like that for things that are not really factorizable.



MeteorShowerConfig

Well… Create a meteor shower… of pineapples !



SpawnItemConfig

Spawn a prefab at a certain place



TweakExplodableConfig

Modify an explodable, increasing its range for example.



And the list goes on. This is really powerful and might even unlock a new level of creativity for your designers. Would they have thought of a bomb which increase the range of other bombs in the area when it explodes ?

We also have a way to describe aggregated actions in a single one, would you trigger several things at the same time, or randomly pick one in a table.

public partial class RandomActionListConfig : AssetObject, IAssetAction
{
[Serializable]
public struct WeightedAction
{
public AssetRef AssetAction;
public FP Weight;
}

public List WeightedActions;
public unsafe void OnAssetAction(Frame f, AssetActionRuntimeData context)
{
// Compute total weight
FP cumulatedWeight = 0;
foreach (var action in WeightedActions)
{
cumulatedWeight += action.Weight;
}

// Random value
var pGameSessionState = f.Unsafe.GetPointerSingleton();
var randFP = pGameSessionState->SystemRandoms.AssetAction.Next(0, cumulatedWeight);

// Find random action
cumulatedWeight = 0;
foreach (var action in WeightedActions)
{
cumulatedWeight += action.Weight;

if (cumulatedWeight > randFP)
{
context.AssetActionContext.AssetRef = action.AssetAction;
f.Signals.OnAssetAction(context);
break;
}
}
}
}


Conclusion


This is a simple overview of what you can achieve with externalizing some logic in scriptable objects. Making systems like this help you go further faster, decoupling coding the interaction from using them, and even helping the creativity of the design of systemic games. How powerful !

But… with great power… comes great responsibilities… Don’t let your designers go crazy.



Don’t freeze your brains up ‘til next time, see you on ice !

Romain GROSSE