Skip to content
Vrekt edited this page Apr 12, 2024 · 5 revisions

Worlds are what provides alot of multiplayer functionality in Lunar. Worlds handle keeping track of players, entities and more.

LunarWorld

LunarWorld is an interface providing most functions a world will need. Players and entities alike will have a reference to the current world they are in.

The default implementation of LunarWorld is AbstractGameWorld. This is a typed world and you may extend this class and reference your own entity types.

Create your own world

To create a new world you could either

  • (a) Implement the interface LunarWorld and all of its methods
  • (b) Extend AbstractGameWorld and override the implementation as needed
  • (c) Extend WorldAdapter for instances in where concrete game mechanics is not implemented yet.

If you choose option (a) be aware of the class TypedGameWorld. TypedGameWorld is just a parameterized class that provides the types for your players and entities. AbstractGameWorld implements TypedGameWorld by default.

The two types included in these are just generics that extend LunarEntityNetworkPlayer and LunarEntity. With those you can specify your own player and entity types (for example MyNetworkPlayer, MyEntity) for convience sake instead of casting everytime you need your own implemented function.

Now, lets create our own custom world that extends AbstractGameWorld and implements our custom entity types.

public final class ExampleWorld extends AbstractGameWorld<MyNetworkPlayer, MyNetworkEntity> {}

With that all players will be the type MyNetworkPlayer and all entities will be the type MyNetworkEntity.

if you wish to use the default types you can simply just extend WorldAdapter instead.

Now, lets setup the constructor for our world.

    private final MyPlayer player;
    public MultiplayerGameWorld(PlayerSupplier playerSupplier, MyPlayer player, World world, WorldConfiguration configuration, Engine engine) {
        super(playerSupplier, world, configuration, engine);
        this.player = player;
    }

The class PlayerSupplier is a simple Supplier that will provide the internals with your local player. It is recommended to also have your local player defined in your class simply because you won't have to rely on the PlayerSupplier which is typed with LunarEntityPlayer and not whatever your custom player type is.

World is the box2d world to use and Engine is, of course, your entity engine.

World configuration

You can define a new world configuration by:

this.configuration = new WorldConfiguration();
Option Description
handlePhysics If the world will handle updating the physics simulation for you
updatePlayer If the world will handle updating your local player
updateNetworkPlayers If the world will handle updating all network players
updateEntities If the world will handle updating all entities
updateEngine If the world will handle updating the entity engine
velocityIterations if handlePhysics is true, will pass this value into the simulation
positionIterations if handlePhysics is true, will pass this value into the simulation
stepTime Default step time for the physics simulation (if enabled)
maxFrameTime Max frame time allowed for each step of physics simulation (if enabled)

Updating your world

Worlds need to be updated every frame of your game:

world.update(delta);

If handlePhysics is enabled this will also step the simulation, and, if also enabled, players, entities, etc.

There is a default implementation of the physics step implemented already, if you wish to use it yourself somewhere else instead of relying on the handlePhysics option

world.stepPhysicsSimulation(delta);

Entities and players

Players and entities are managed with a ConcurrentMap and use ints as their IDs. Here are a few convenient methods for retrieving players and entities alike.

if (world.hasPlayer(1)) doSomething();
if (world.hasEntity(2)) doSomethingButAgain();
world.getPlayer(1).doSomething();
world.getEntity(2).doSomethingElse();

Spawning entities and adding network players

This process is similar for players and entities alike, below is an example for players, though entities would follow the same steps.

Before spawning players into the world you want to ensure their basic properties are set.

// invoked when a player joins the world, for example
public void aPlayerJoinedTheServer() {
    final NetworkPlayer player = new NetworkPlayer();
    // lets add their default texture
    player.addRegion("texture", new TextureRegion(myAsset));
    // ignore other players collision
    player.disablePlayerCollision(true);
    // these would be provided by a network packet for example
    player.setProperties(username, entityId);
    player.setSize(16, 16, (1 / 16.0f));
    // finally, spawn this player
    player.spawnInWorld(myWorld);
}

Once spawnInWorld is invoked it will define the entities shape and add them to the world, see: Entity Body Definition.

With that, the method isInWorld would return true and the method getWorld would return the world currently in.

Removing players and entities

world.removePlayerFromWorld(id);
myNetworkPlayer.removeFromWorld();
world.removeEntityFromWorld(id);
myEntity.removeFromWorld();