I moved to a new URL! Check it out!

posts filed under: general

Dev Log: Solo Mode Controls

Dev Log: Solo Mode Controls
Super Sky Sisters has a solo mode! But it's not for the faint of heart. It's going to be pretty tough controlling both of the sisters at the same time.

Image


Yeah, that looks pretty awful, but is probably the one of the easiest ways I can explain the controls before things get crazy. The game wasn't really designed for solo mode so I hope that most people play co-op, but I understand that not everyone has the opportunity to do so and probably wants to just blow up stuff on their own.

It is actually pretty playable in solo mode until you end up crossing player 2 with player 1. Then your brain melts because the sister on the left is controlled with the joystick on the right of your controller and vice versa, but if you can manage to overcome that madness then it should be a pretty fun way to play the game.

Dev Log: Options Menu

Dev Log: Options Menu
As I totally procrastinate on the final art tasks for Super Sky Sisters I went over the options menu again really quick to add some cool polish. In the options menu the player can configure the sound and music volumes, the quality of the graphics, the hud style, and even reassign all of their keyboard controls.

Image


I swear this game is almost done!

Doodle Post

Image

Otter Surface Example

Otter Surface Example
Just a quick post going over how I usually use Surfaces in Otter. A surface is basically a render texture, or render target. The idea of calling it a surface mostly comes from Game Maker.

By default Otter will render all of the graphics to the main surface. However you can make your own surfaces and use them in various ways. The main point of this quick example is to show how to separate HUD elements and gameplay onto different surfaces. The big advantage of doing this is you can now freely rotate and zoom the camera and the HUD will be unaffected.

Alright let's check out the codes!
class Program {
static void Main(string[] args) {
// Create a new game to play.
var game = new Game();

// Set the scroll of the surfaces to 0 so they never scroll on the camera.
Global.SurfaceGameplay.Scroll = 0;
Global.SurfaceHud.Scroll = 0;

// Start the game with a new GameScene.
game.Start(new GameScene(1000, 1000));

}
}

class GridBackground : Entity {
public GridBackground() : base() {
Layer = 10;
Surface = Global.SurfaceGameplay;
}

public override void Added() {
base.Added();

// Just render a simple grid background so when the camera scrolls we can see it.
AddGraphic(new Grid(Scene.Width, Scene.Height, 40, 40, Color.Cyan));
Graphic.Alpha = 0.4f;
}
}

class Player : Entity {
public Player(float x, float y) : base(x, y) {
// Add a basic red box for the graphic.
AddGraphic(Image.CreateRectangle(20, 20, Color.Red));
Graphic.CenterOrigin();

// Assign this entity to render to Global.SurfaceGameplay instead of the default game surface.
Surface = Global.SurfaceGameplay;

// Set up a collider for movement.
var collider = AddCollider(new BoxCollider(20, 20));

// Set up the rest of the movement stuff.
var axis = AddComponent(Axis.CreateWASD());
var movement = AddComponent(new BasicMovement(400, 400, 30));
movement.Axis = axis;
movement.Collider = collider;
}
}

class PlayerHud : Entity {
public PlayerHud() : base() {
// Basic hud test with just some text.
AddGraphic(new Text("This is the HUD!", 20));

Surface = Global.SurfaceHud;
}
}

class GameScene : Scene {
public GameScene(int width, int height) : base(width, height) {
// Add the entities to the scene when the scene is created.
Add(new Player(HalfWidth, HalfHeight));
Add(new GridBackground());
Add(new PlayerHud());
}

public override void UpdateLast() {
base.UpdateLast();

// Set the scene's camera to follow the player.
var player = GetEntity<Player>();
CenterCamera(player.X, player.Y);

// Set the surface's camera to follow the scene's camera.
Global.SurfaceGameplay.CameraX = CameraX;
Global.SurfaceGameplay.CameraY = CameraY;

// Zoom the surface up and down with the arrow keys.
if (Input.KeyDown(Key.Down)) {
Global.SurfaceGameplay.CameraZoom -= 0.005f;
}
if (Input.KeyDown(Key.Up)) {
Global.SurfaceGameplay.CameraZoom += 0.005f;
}
}

public override void Render() {
base.Render();

// Render the surfaces.
Draw.Graphic(Global.SurfaceGameplay);
Draw.Graphic(Global.SurfaceHud);
}
}

class Global {
// Keep global references to the surfaces used for rendering the game.
public static Surface SurfaceHud = new Surface(640, 480);
public static Surface SurfaceGameplay = new Surface(640, 480, Color.Gray);
}
The full version is available on pastie.

I have a simple player class, and background class which both render to the surface designated for gameplay. Then the player HUD class is assigned to render to the hud surface. The scene will then take care of rendering both of those surfaces to the game's main surface. I render in the scene's Render method because that will be the very last thing that renders in the frame.

I know some people have been having trouble understanding surfaces fully and how to use them so I hope this example helps. Surfaces can be really powerful especially when you start getting into shaders and one of my main goals for Otter was to make using surfaces as painless as possible.

Dev Log: Game Mode Arts

Dev Log: Game Mode Arts
In the continuation of adding art to the menus in the game I recently added art to the difficulty selection screen.

Image


Gonna be tough to finish the game this month as I have to travel a bit this coming weekend, but we're almost there!

Dev Log: Help Menu Arts

Dev Log: Help Menu Arts
Trying to tackle the last of my art tasks in Super Sky Sisters. If I manage to finish the art stuff, then my to do list is reduced down to just 11 things before the game is done!

The help screen is available from the main menu and has some tips and tricks for playing the game better.

Image


Image


Image


Image


After the game is done all I have to do is figure out what I'm going to do with it, but I haven't put any energy into thinking about that yet because it tends to stress me out and cause me to not work on it. My idea right now is that I can figure it out after it's all done!