πŸ€‘ Indie game storeπŸ™Œ Free gamesπŸ˜‚ Fun games😨 Horror games
πŸ‘· Game development🎨 AssetsπŸ“š Comics
πŸŽ‰ Sales🎁 Bundles

Luke

36
Posts
5
Topics
13
Followers
31
Following
A member registered 2 years ago · View creator page β†’

Projects

Recent community posts

Oh nice! That also explains why it seemed like all the ports were being used by other programs. Glad you found out what was causing the problem! :D

I wish I knew more about debugging this sort of thing :/

All I can find about "EADDRINUSE" is that the ip:port is being used by another program or service... But it wouldn't make sense that all the ports you've tried so far wouldn't work. Hopefully someone more knowledgeable about this will be able to help you. It might be a good idea to add your OS to your original post since it might be something someone else ran into on a specific system.

If I had to guess, EADDRINUSE could be "Error, address in use"... It looks like you set the port to 80, which might be taken by another program like Skype. I'd try to change the port to something with 4 digits since some of the lower ones are reserved. I have mine set to 4237, which might be the default value since I don't think I've had to change it.

Another thing to try after changing the ports (if that doesn't work) is the 32-bit version of Superpowers. Last time I used the 64-bit version, I was having random disconnection issues.

Sup.Input.getMousePosition() gives you the window position of the cursor. The center of the game window is (0, 0), the top left is (-1, -1), and the bottom right is (1, 1). So your desync problem is actually just a misalignment and scaling issue.

If it helps any, I actually made a script a little while ago that converts the window position to world position. You just have to pass your camera to the new getMousePositionCamera() function and it returns the corrected cursor position.

// (replace line 33 in your code on github with those two lines of code VVV )

// "YourCameraName" is the name of your camera actor in the scene editor, or the name you gave it your code.
let camera = Sup.getActor("YourCameraName").camera;

// Now you just pass it to the function, and it will give you the position of the cursor.
this.destination = getMousePositionCamera(camera);

Hope this helps!

I really liked everything about this game. The music, story, and art were very enjoyable! Thanks for making such a great visual novel!

(Edited 1 time)

I ended up storing the acceptable values in an array and cycling through each one with Sup.Input.wasKeyJustPressed() in a for-loop. Works really well, although it seems SEMICOLON, ADD, and SUBTRACT/EQUALS, aren't detected at all and doesn't resond to being pressed. But In any case, I got it working :D

You could take a look at the Pac-man-like that Sparklin Labs made. I'm pretty sure it uses tile maps for collisions. You can download the project from GitHub, put it in the projects folder and restart Superpowers for it to appear in your launcher. They also have a few videos they made that goes through the entire process for making that game.

Yep I tried that. It's part of what I have currently. It works very well with letters and numbers if you convert it to uppercase before passing it to input, but it doesn't handle special characters or things that don't insert characters, like the arrow keys or shift.

(Edited 1 time)

There's a list like that in the source code too. The problem is, there's no easy way to access it since it's not stored. I was hoping to avoid it, but it seems like I might have to do it manually and check each value after all. :P

Regardless, thanks for looking into it :)

I've almost completed my keyboard configuration code, but I need a way to properly retrieve the input from the player. Currently I'm using Sup.Input.getTextEntered() and it works pretty good the way I have it setup. The problem is, characters like ";" or "," can't be used with Sup.Input.wasKeyJustPressed() because it expects "SEMICOLON" and "COMMA". Is there an easier way to retrieve "KEYNAME" besides storing the characters in an array and manually converting them to their proper input names?

Sounds like you might want to check the console (F12) while the game is running. If Superpowers runs into an error (like changing the health of an actor that doesn't exist), or an infinite loop (for, while, etc...), it will sometimes freeze when the loading bar is full, but before the game starts. Usually it'll show an error, a script name, and a line number that you can use to find out whats going on.

Hope this helps!

But cheating is fun! :^)

Yeah, I agree about changing the API. It can make things messy if done too much, and causes confusion if you forget that a project handles it differently then other ones. I tried to keep it as close to the original functionality as possible without changing it's intended functionality to avoid most confusion, I just wanted to see if I could make it simple to use :)

A few things you might try:

  • Make sure the Z position of the map is not the same as the others. Try setting it to -5.
  • Make sure the Z position of the camera is not the same as the others. Try setting it to 5, or 10.
    The three boxes are X, Y, and Z. The one on the right is the one we want to change. This can be found in the scene editor.
  • Make sure the scene was loaded.
    This has happened to me before, so you might want to check ;)
  • If the background is being covered by other tiles even though they are transparent, make sure to put them in another layer.
    This can be done in the tilemap editor.
  • If the actors are covering the background, make sure the sprites are transparent.
    You can check this in the sprite asset.

Other than that, I'm not sure what it might be without some more info. I hope this helps you find out what's going on. :o

All of the properties in a behavior class can be accessed from within itself by using "this.propertyName". The actor it belongs to can be accessed with "this.actor". If you want a more advanced way of setting up an actor when created, you can add awake() which happens instantly, or start() which happens in the next "tick" of game logic. They are used in the same way update() is, but only called once.

class ballBehavior extends Sup.Behavior{
    private angle: number = 0;
    private position: Sup.Math.Vector3 = new Sup.Math.Vector3();
    private velocity: number = 0;

    awake() {
        // You can add code here that will be called only once when it's created.
    }

    update(){
        this.angle += this.velocity;
        
        //Constrains the angle between 0 and 2pi
        if(this.angle > Math.PI * 2) this.angle = 0 + this.angle - Math.PI * 2;
        }else if (this.angle < 0) this.angle = Math.PI - this.angle + Math.PI * 2;
        
        //Maybe a little spinback on the pointer?
        this.position = new Sup.Math.Vector3(Math.cos(this.angle) * wheelActor.getLocalScaleX() * 100 / 100, Math.sin(this.angle) * wheelActor.getLocalScaleX() * 100 / 100, 0);
            
        if(Sup.Input.wasKeyJustPressed("LEFT")) this.velocity = 0.5;
    }
}

If you want to create an actor with a behavior, you just need to use addBehavior() to give it one. You can even change it's default properties too.

// Create a new ball with a behavior.
new Sup.Actor("Ball").addBehavior(ballBehavior);

// Create a new ball with a behavior that starts with altered properties. (almost like a constructor, but every property is optional)
new Sup.Actor("Ball").addBehavior(ballBehavior, {
    angle: Math.PI,
    position: new Sup.Math.Vector3(2, 2, 2),
    velocity: 10
});

// Create a new ball with a behavior that has a different velocity. (properties are optional, so you only need to change the ones you want)
new Sup.Actor("Ball").addBehavior(ballBehavior, {velocity: 10});

If you want to modify the properties after creation, getBehavior() allows you to access the properties in an actor.

// You can do something like this...
let actor = Sup.getActor("Ball");
actor.getBehavior(ballBehavior).velocity = 0;

// Or this...
let actor = Sup.getActor("Ball").getBehavior(ballBehavior);
actor.velocity = 0;

Hope this helps! :)

Modifying Sup.Actor,getBehavior() does change the properties of the instance. If you have two actors in a scene with the same behavior and the variable "health" altering "actorA.getBehavior(BEHAVIOR).health" does not affect "actorB.getBehavior(BEHAVIOR).health".

Glad it worked out for you!

No problem ;D

Hey Lacroiix, I noticed you wanted to be able to use the startup scene setting in the options menu but my script didn't support it. I went ahead and rewrote my script so that it automatically does the work for you :D

let activeScene: string;
let loadSceneLegacy = Sup.loadScene;

function loadScene(sceneAsset: Sup.Scene)
function loadScene(sceneAssetPath: string)
function loadScene(scene: any){
    loadSceneLegacy(scene);
    if(typeof scene == "string") {
        activeScene = scene;
        Sup.log(scene);
    }else{
        activeScene = scene.path;
        Sup.log(scene.path);
    }
}

Sup.loadScene = loadScene;

Just ignore the "loadScene" function since you don't have to use it anymore. Everything is now handled by the builtin function Sup.loadScene. I left the Sup.log calls in the function so that you'd be able to see it working in the console, so you can remove those lines after you've got it working. Once you start the game, it'll instantly set the activeScene to the scene loaded.

If you want to always use the scene's name, just replace "activeScene = scene.path" with "activeScene = scene.name", which looks like what you want in this case :)

Hope this helps!

Oh hey, that's actually pretty common with the 64x version of Superpowers. If you switch over to 32x the issue usually just disappears. It used to happen to me quite frequently.

Hello! You can create new actors almost entirely from scratch, like so:

// Create an actor with code.
let newActor = new Sup.Actor("ANY NAME YOU WANT");

// You can add a behavior if you want it to do something.
newActor.addBehavior(SomeBehavior);

// This adds a new sprite renderer to the actor. You can add modelRenderers, and textRenderers too!
new Sup.SpriteRenderer(newActor, "SPRITE/PATH/GOES/HERE");

// You must set it's position in order for it to appear.
newActor.setPosition(0, 0, 0);

Or alternatively, if you've already made a prefab you can just append it to the scene:

// Add an already defined actor type to the current scene.
let newActor = Sup.appendScene("PREFAB/PATH/GOES/HERE");

// You must set it's position in order for it to appear.
newActor.setPosition(0, 0, 0);

Hopefully this helps :D

(Edited 2 times)

(I still don't know if this qualifies as a guide or not, haha)

At first getting clipboard data seemed difficult due to Electron (what Superpowers is running on) not supporting window.prompt, and the fact you couldn't access the clipboard directly due to security risks. (like stealing user info, etc...). But after Γ‰lisΓ©e pointed me in the right direction, I was able to come up with a few different solutions which eventually turned into the code below!

The way I was able to get around this was to create an input box above the game to receive the "onpaste" event. While this worked well, it didn't look very good. It moved around if the window resolution was changed and looked a bit out of place. I decided to clean up a lot of the messy code I had and ended up rewriting the clipboard system to be pretty easy to use, so I figured I'd share it with the community. :D


First you'll need to add this somewhere in a script. Just make sure you don't put it in a behavior or it might not work properly.

declare var document;
let canvas = document.getElementsByTagName("canvas")[0];

This allows access to the document (the page the game is on) and the canvas (what the game is in). This might not be the best way to get the canvas, but it was the only way I knew how to get to it.


This should be added into it's own empty script to avoid cluttering up existing code in your project.

namespace Clipboard {
    // Create a hidden input.
    let content = document.body.appendChild(document.createElement("INPUT"));
    content.setAttribute("type", "text");
    content.style.cssText = "position:absolute;width:1px;height:1px;left:0px;z-index:-1;visibility:none;";

    // Redirect the paste event to "content".
    document.onpaste = (event) => {
        content.value = "";
        content.focus();
        Sup.setTimeout(4, () => {
            canvas.focus();
        });
    };

    // Get the previous data in "content".
    export function getData(): string {
        return(content.value);
    }

    // Clear the data in "content".
    export function clear(): void {
        content.value = "";
    }

    // Continually check for content until the breakpoint is reached, or time has run out.
    function waitFor(callback: (data) => void, breakpoint: () => Boolean): void
    function waitFor(callback: (data) => void, timeout: number): void
    function waitFor(callback: (data) => void, exit: any): void {
        if((content.value!="")||((typeof exit == "number") ? exit<0 : exit())) {
            callback(content.value);
        } else {
            Sup.setTimeout(4, () => { waitFor(callback, (typeof exit == "number") ? exit-1 : exit); });
        }
    }

    // The "initialization" function to wait for input.
    export function onPaste(callback: (data) => void, breakpoint: Function): void
    export function onPaste(callback: (data) => void, timeout: number): void
    export function onPaste(callback: (data) => void, exit: any): void {
        content.value = "";
        waitFor(callback, exit);
    }
}

This will create a hidden input that will grab whatever you paste into the game using Ctrl+V, without the game losing focus. I added Clipboard.clear() and Clipboard.getData() for those who want to manually check for the content themselves, but I recommend using Clipboard.onPaste() if you want a more automated system with a bit more flexibility.


Using Clipboard.onPaste() is a bit complex, but it's pretty useful. It's a recursive function, which means it'll run in the background until it either gets something from the clipboard, the "breakpoint" tells it to stop, or it runs out of time. You'll need to make sure there's a way the breakpoint will exit or a timeout is set. Otherwise this will continue running until something is pasted which might cause lag, or other problems. So if the player decides not to paste anything and clicks a "cancel" button, be sure to make the breakpoint check if that button was pressed or removed from the scene!

callback:

Type: Function
This argument requires a function with a single argument to receive the content of the clipboard. Once something has been pasted, it'll call this function. Check out how to use anonymous functions in the TypeScript Primer, it's pretty useful!

breakpoint: (method 1)

Type: Function
This argument also requires a function, but it must return a Boolean value (true or false). While waiting for something to be pasted, it will continually run this function to check if it should stop. Upon returning True, this will quit waiting for input. This could be as simple as checking if "ESCAPE" was pressed. Again, anonymous functions are very useful for this :D

timeout: (method 2)

Type: number (in milliseconds)
If a timeout is specified instead of a breakpoint, it will countdown until the timeout reaches 0 and give up. This may not be useful for much, but I added it just so the option was there.
Example:
// Breakpoint example.
Clipboard.onPaste(
    (data) => { Sup.log(data); },
    () => { return(Sup.Input.wasKeyJustPressed("ESCAPE")); }
);

// Timeout example. (30 seconds)
Clipboard.onPaste(
    (data) => { Sup.log(data); },
    30000
);

Whether the timeout runs out or a breakpoint was reached, it will call the "callback" function and return an empty string.


Using Clipboard.get() and Clipboard.clear() are pretty self-explanatory, just clear the the clipboard to make sure it's empty, then just keep checking Clipboard.get() until it returns a value. You can also ignore Clipboard.waitFor() because you can't normally access it. I did this so Clipboard.onPaste() could clear the clipboard before waiting for content so that it's not accidentally triggered. (and you won't have to call Clipboard.clear() just to use Clipboard.onPaste()...)

While this doesn't cover context menus (right-click > paste) it's as close as I could get to clipboard support while keeping it relatively clean and simple. Hopefully I was able to explain Clipboard.onPaste() clearly enough, since it might be a little difficult to understand at first. Hope this helps!

I thought I might share a bit of code I made a little while ago, explain it's usage, and also shed a little light on Sup.Input Ray(), since it was something I didn't quite understand when I first started. The functions below give you the position of the cursor or touch position in world space for orthographic (2D) cameras, and also accounts for different window sizes and orthographic scales.

By multiplying the mouse position by the orthographic scale and multiplying the X axis by the camera's ratio (the width compared to the height of the screen), we can add the position of the camera and it'll return positions in world space. "world space" is the position of actors in the scene, rather than positions on the screen. Screen space only really useful for menus, buttons, and other things like that.

The getTouchPositionCamera() function has an extra argument called "index", since multiple fingers can be picked up as inputs at the same time, it needs to know which one you want to check.

function getMousePositionCamera(camera: Sup.Camera): Sup.Math.Vector2{
    let position = Sup.Input.getMousePosition().multiplyScalar(camera.getOrthographicScale()*0.5);
    position.x *= camera.getWidthToHeightRatio();
    return(position.add(camera.actor.getPosition()));
}

function getTouchPositionCamera(camera: Sup.Camera, index:number): Sup.Math.Vector2{
    let position = Sup.Input.getTouchPosition(index).multiplyScalar(camera.getOrthographicScale()*0.5);
    position.x *= camera.getWidthToHeightRatio();
    return(position.add(camera.actor.getPosition()));
}

These functions are best used when coordinates are needed. This means clicking buttons, or hovering over an actor isn't recommended as there are already better suited ways to handle those (see below). The correct usage would be for things like dragging something with the cursor, moving a scrollbar, or making something follow the mouse.


For 3D games, buttons, or checking if the mouse is over an actor, I recommend using Sup.Math.ray(). It's a very easy to use and understand, but may not seem like what you need at first glance. For clarity, a ray is like a flashlight. When it's dark out, you can move around and point the flashlight in different directions and you'll see anything within the light. So when you use a ray, it will return what's currently in it's direct path.

// This creates a ray. A ray can be reused, so it's best to place it in an actors "awake" method.
let ray = new Sup.Math.Ray();

// This moves the ray to start at the CAMERA, and point towards the mouse.
// CAMERA would be the camera in your scene. An easy way to get it is Sup.getActor("YourCameraNameHere").camera
// It's best to put this in an actor's "update" method.
ray.setFromCamera(CAMERA, Sup.Input.getMousePosition());

// Finally you can check if the actor was hovered over by the mouse.
// ACTOR would be the actor you want to check for.
if(ray.intersectActor(ACTOR).length>0) {
    // Do something!
}

There's more ways to use rays, like getting a list of actors underneath the cursor, or even using them for an AI's line of sight. So you might want to check out the documentation for more information. It might also be a good idea to look at the API browser in Superpower, as some functions might not yet be documented. (like Sup.Math.Ray2D())

Like usual, my code might not be the most efficient, or as optimized as it could be. If you have any suggestions or examples to share, feel free to post them below.

Hope this helps

(I didn't know if this counted as a tip or a guide, since it doesn't go into full detail on the subject)

Great game! I really like the Zelda-like atmosphere feel it has :D

I just added a link to the roadmap in the introduction thread so it'd be easier to find when browsing the forum.

(Edited 3 times)

I don't think there's a built in function just yet, but until then you could just wrap the Sup.loadScene() function in another one and store the active scene manually. You can paste this somewhere in a new, empty script and it should work:

let activeScene: string;

function loadScene(sceneAsset: Sup.Scene)
function loadScene(sceneAssetPath: string)
function loadScene(scene: any){
    Sup.loadScene(scene);
    if(typeof scene == "string") {
        activeScene = scene;
    }else{
        activeScene = scene.path;
    }
}

Then you'd just use loadScene() like you normally would with Sup.loadScene() and it will store the current "active" scene for you to access when needed.

loadScene("Level1");

if(activeScene=="Level1") {
    // Do stuff :D
}

I made the function save the activeScene as the path instead of the name, since it might be useful to store it later. Like when leaving an area, you could store the activeScene in another variable. You can easily change scene.path in the last line to scene.name if you'd just like to keep just the name of the asset.

Hope this helps :D

EDIT: I updated this script here, so that it's all handled by the builtin function Sup.loadScene.

(Edited 1 time)

Using the SoundPlayer method, I was able to extend the class as SoundPlayerAdvanced, and add a Buffer interface to get auto-completion. I used Sup.log to test it, and I was able to get an array of data from the channels, along with the duration, length, and sampleRate of the buffer.

interface Buffer {
    sampleRate: number;
    length: number;
    duration: number;
    numberOfChannels: number;
    getChannelData(number);
    copyFromChannel(number);
    copyToChannel(number);
}

class SoundPlayerAdvanced extends Sup.Audio.SoundPlayer {
    buffer: Buffer;
    constructor(pathOrAsset: string|Sup.Sound, volume?: number, options?: {loop?: boolean, pitch?: number, pan?: number}) {
        super(pathOrAsset, volume, options);
        this.buffer = (this as any).__inner.buffer;
    }
}

Thanks again! :D

Thanks for all the info! :D

After looking at some articles on rhythm games, I found this. It sounds like I'd need to scan through all the sound data and calculate the average volume energy, then calculate the current energy level from the song position. Seems like this sort of game is much more complicated than I had originally thought, haha. I think getting audio data from the file may be impossible now that I've thought about it. It'd be encrypted by it's file format, so I'll just cross that out in my original post. That leaves me with the buffer.

The thing is, I don't know if the buffer contains all of the sound data, or just the data about to be played. I assumed the buffer contained a large string of numbers that represents the frequencies and volume of the entire song. What I plan on doing is grabbing large pieces of that data and processing it. The only thing I really need now is a way to access that data, and from there I can make a bunch of messy code to see what happens :p

Any ideas?

(Edited 1 time)

After you export your game from Superpowers, there should be an "index.html" file inside the folder that could probably be edited.

Yep, that should fix it! I had assumed you were having a different issue when I posted, but I'm glad you got it figured out :D

It sounds like you might need to load the scene if you haven't already. Creating a script with the code below should fix it, just be sure to replace "Main Scene" with the name of the scene you have your actor in.

Sup.loadScene("Main Scene");

You can also set the startup scene in the settings, which can be found at the bottom of the asset tree. More information on scenes here: Link

Hope this helps!

(Edited 6 times)

I usually don't need access to anything besides basic audio functions (play, stop, volume, etc), but I recently thought of a game concept that would work best if I could synchronize it to the music being played. The only things that I could think of that could accomplish this, would be to access some sort of buffer before it plays, or be able to get the current position of the song and read data from the file itself.

It looks like JavaScript has something called Web Audio, which might be what I'm looking for (but also way more complicated than Sup.Audio). Is there some way to access this API since Typescript is a superset of JavaScript? Or is there some other API that would work better? (I peeked at the source code for Sup.Audio.SoundPlayer, and it looks like this might be what it runs off of)

So basically, I'd like to know...

  • If there's a way to access the audio buffer.
  • If the file data from audio assets can be accessed with code.
  • If the song position can be retrieved.
  • If sound files can be loaded from URLs.
  • If something like Web Audio (JavaScript) can be used in TypeScript.
(Edited 2 times)

Hey, I'm Luke, a self-taught programmer / artist. I'm always trying to find ways to improve but have a bad habit of procrastinating, haha. I'm somewhat colorblind (probably an understatement), but not completely. Blue and purple is pretty much the same color, so is bright greens and yellows. Cyan is almost non-existent. It's awesome to see Superpowers finally go opensource, and I can't wait to see what people make :D

@LukeLanFaust - about.me/lukelanfaust

(Edited 3 times)

Welcome to the community!

Whether you've just discovered Superpowers or have been using it for a while, feel free to introduce yourself. It's a great way to meet new people and share your current projects. You might even find some cool games to play!

Want to learn more about Superpowers? Here's some links that'll help you get started:

Superpowers

TypeScript

Have fun!


Happy Holidays!

(Edited 1 time)

The new localization support sounds great, the more the merrier! The new site looks really good. With all these improvements, it feels like Superpowers going opensource is really happening, and I can't wait to see more people start using it :D

I saw the logo on twitter but forgot to say anything about it! I like the non-color version because it's more usable when it comes to matching the theme of individual games / colors, but the color version looks really awesome too!

The loss of a pet always sucks, and it takes a bit of time to recover from it. :( I know when I lost my dog a few years ago, spending time with family and friends, and talking about the past helped me get through most of the worse days. I hope you all feel better soon <3

It's not broken yet. That's why HORIZONTAL SCROLL-BARS EXIST. We must... keep... GOING!

Yeah, I can see how they might be a little too close. Maybe it could be moved to the lower right instead? It still be visible, but there's no way it would be hit by accident over there.

This is gonna be epic :D

I've been using Bitbucket to host my site for a few months. It's just a simple static page with links, but using Superpowers it'd be way simpler to make some changes and use SourceTree to upload it. My current method is to make changes, wait for the site to update in around 5-20 mins and make more changes. (another reason my site hasn't been updated since I first designed it in June)

(Edited 1 time)

Since this is a new thread, on a new community, I'll introduce myself too!

I'm Luke! I'm 22 and living in Idaho, United States. I've been attempting to make decent games since late 2014 but I've made pixel art for a few years before that. I didn't even know game development communities or online tutorials were really a thing until 2013 (dial-up. UGH). Oh, and I'm somewhat colorblind. I don't know what severity or what type, but I easily confuse certain shades of colors:

  • blues-purples
  • bright yellows-greens
  • medium to dark greens-oranges-browns (very slight)
  • browns-reds
  • cyan-whites/grays
  • dark reds-black in certain cases

What I consider "purple" is probably your "magenta"... or something like that :D


I've been using Superpowers since June 6th (seems like just yesterday :O) and it's improved a lot since then. I've only re-released one game with it so far (I'm really slow at making games, haha), and it was quite the learning curve coming from Game Maker Studio. I'm really glad I made the switch so far, since I've learned more about programming in general than I knew before! I really like Typescript now, and don't think I'm switching anytime soon without a good reason.

I made the switch from Game Maker because the idea of using an opensource engine seemed like the best way to go. Easily port to multiple systems, built-in development GUI, play games in your browser, use existing JavaScript libraries, collaborations... Oh, and community-made resources like plugins, bug-fixes, custom engines, documentation, tutorials, etc. I have a feeling that once Superpowers goes opensource, it's gonna be pretty successful :D

I also want to thank the Sparklin Labs team while I'm here, for all the work they've put into it so far and for the helping me out on Reddit and Twitter! I've been subscribed to their Trello board for a while now, and I know they've been working really hard to make Superpowers great :D