Skip to main content

Wrapping the Universe

When the ship leaves the boundary of the world, we want it to reappear at the other edge of the screen. This will be particularly interesting when we start adding more objects to the game, as it will force the player to deal with them eventually.

Defining BoundaryWrappingSystem

We are going to want many things in our game to wrap around the boundary of the world, so let's define a reusable system to do this.

Create a new file called boundary.easel and copy and paste the following code into it:

pub const BoundaryRadius = 20

pub fn this.BoundaryWrappingSystem(radius, [body]) {
on AfterPhysics {
if Pos.X.Abs > radius + BoundaryRadius && Velocity.X.Sign == Pos.X.Sign {
Pos *= @(-1, 0)
}
if Pos.Y.Abs > radius + BoundaryRadius && Velocity.Y.Sign == Pos.Y.Sign {
Pos *= @(0, -1)
}
}
}

Give the ship the BoundaryWrappingSystem

Now we can give our ship the BoundaryWrappingSystem to make it wrap around the edges of the screen.

Switch to ship.easel. Insert the highlighted code snippet, just after the PolygonCollider component in your Ship function:

pub fn unit.Ship([owner]) {
use body=unit
let radius=1

Body(pos=@(0,0))
ImageSprite(@hero.png, radius=1.5*radius, angleOffset=0.25rev, shadow=0.5)
PolygonCollider(shape=Circle(radius=), category=Category:Ship)

BoundaryWrappingSystem(radius=)

on BeforePhysics {
// ...
}

// ...
}

Click Preview to test your game. Try flying your ship to the edge of the screen. It will teleport to the other side! But if you fly all the way to the left or right, you'll notice the teleporting is not happening at the very edges of the screen, but instead on a line closer to the middle. This is because the camera is showing you beyond our intended borders of the universe.

Showing the boundaries to the player

We will now make the view of the camera match the boundaries of the universe, making it clear at what point the ship will wrap around to the other side.

  1. Switch to main.easel.
  2. Find the line that says Camera(@(0,0), radius=20)
  3. Replace it with the following highlighted code snippet:
pub game fn World.Main() {
ImageSprite(body=@(0, 0), image=@backdrop.png, radius=7, repeatX=100, repeatY=100, layer=-100)
Camera(@(0,0), radius=BoundaryRadius)
Viewport(aspectRatio=1)

ButtonRemap(KeyW, ArrowUp)
ButtonRemap(KeyA, ArrowLeft)
ButtonRemap(KeyS, ArrowDown)
ButtonRemap(KeyD, ArrowRight)

SpawnEachPlayer owner {
Subspawn unit {
Ship
}
}
}

Click Preview to test your game. Now you will see the view is limited to a square box. When you fly to the edge of the box, your ship will disappear and reappear on the other side, giving the illusion of a continuous world.

info

We just added a Viewport component to the World. An aspect ratio of 1 means the width and height of the viewport will always be the same, making the viewport a square.

Recap

In this chapter, we created a BoundaryWrappingSystem, and then added it to our ship, causing our ship to wrap around the edges of the world when it goes out of bounds. Finally, we adjusted the camera and viewport to show only the area of the world that we want players to see.

info

BoundaryWrappingSystem is an example of a system in Easel. A system is a function that adds ongoing behavior to an entity. Our BoundaryWrappingSystem gets called once, but for the rest of the entity's life, it will continue to wrap the entity around the boundaries of the world. It does this by adding an on AfterPhysics behavior which continues to execute every physics step until the entity despawns.

Systems are not a feature of the programming language, they are simply a reusable pattern used by Easel programmers to organize their code. You will be using them a lot in your own projects! See Systems to learn more about this topic.