Chapter 4: Images and sound

After Chapter 1 you have a player that moves. This chapter is how you give it a picture and a sound without stalling the game loop.

Where files go

ActiverseImage and ActiverseSound both go through ResourcePaths: an existing file on disk first, then a classpath resource (so a packaged jar still works). Use a relative path and keep the same folder layout in your IDE and in the jar.

your-project/
  Main.java
  MyWorld.java
  Player.java
  assets/
    images/
      player.png
      world.png
      coin.png
    sounds/
      pickup.wav

Load with paths like "assets/images/player.png". Putting files next to your .java sources also works if that is the working directory; a dedicated assets folder is easier to keep straight.

A bad image path usually prints ACEHS 2A.IN (Chapter 3). The debug overlay marks missing images as MIA (Chapter 2).

Images

Supported types include png, jpg, gif, and bmp. Size the file to the actor (a 32×32 character should use a 32×32 image). Set it once in the constructor, not every tick:

public Player() {
    setImage(new ActiverseImage("assets/images/player.png"));
}

Worlds use setBackgroundImage("assets/images/world.png"). Backgrounds are optional; without one you get the panel’s default fill.

Do not call setImage every act() unless you are actually changing frames. Reloading the same file sixty times a second will hitch.

Sound

ActiverseSound loads WAV files. Construct the clip once, register it on the world with addSound (so debug and shutdown can see it), then play from a condition — never from the top of act() with no guard.

import ActiverseEngine.*;

public class Player extends Actor {
    private ActiverseSound pickup;

    public Player() {
        setImage(new ActiverseImage("assets/images/player.png"));
    }

    public void setPickupSound(ActiverseSound sound) {
        pickup = sound;
    }

    public void playPickup() {
        if (pickup != null && !pickup.isPlaying()) {
            pickup.play();
        }
    }

    @Override
    public void act() {
        if (KeyboardInfo.isLetterDown('w')) {
            move(5);
        }
    }
}
public class MyWorld extends World {
    public MyWorld() {
        super(400, 400, 1);
        setBackgroundImage("assets/images/world.png");

        Player player = new Player();
        addObject(player, 100, 100);

        ActiverseSound pickup = new ActiverseSound("assets/sounds/pickup.wav");
        addSound(pickup);
        player.setPickupSound(pickup);
    }
}

Useful methods: play(), stop(), loop(), loop(int count), pause() / resume(), setVolume(float) (0 to 1), isPlaying(). Check isPlaying() (or a key edge with KeyboardInfo.justPressed) so a held key does not restart the clip every tick.

Optional: mouse

Keyboard movement from Chapter 1 is enough for a first game. If you want clicks, call ActiverseMouseInfo.createInstance(this) in the world constructor (the world is a panel), then poll isLeftClick() / isRightClick() and getMouseLocationOnComponent() from act().

Next: Chapter 5 — other actors and collision.