[game] Factor into actor
This commit is contained in:
parent
c7ea93f972
commit
efd6884d0b
2 changed files with 121 additions and 83 deletions
99
game/actor.ts
Normal file
99
game/actor.ts
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
import { load_texture } from "./assets";
|
||||||
|
import { btn, Button } from "./input";
|
||||||
|
import { Vec2, new_v2, vadd, vnorm, vmul } from "./vector";
|
||||||
|
import { spr, use_texture, Texture } from "./graphics";
|
||||||
|
|
||||||
|
export class Actor {
|
||||||
|
velocity: Vec2 = new_v2(0);
|
||||||
|
friction: number = 0.6;
|
||||||
|
id: string;
|
||||||
|
position: Vec2;
|
||||||
|
bounds: Vec2;
|
||||||
|
|
||||||
|
constructor(id: string, position: Vec2, bounds: Vec2) {
|
||||||
|
this.id = id;
|
||||||
|
this.position = position;
|
||||||
|
this.bounds = bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {}
|
||||||
|
|
||||||
|
update_physics() {
|
||||||
|
const velocity = vmul(this.velocity, this.friction);
|
||||||
|
// Zero if we're smaller than some epsilon.
|
||||||
|
if (Math.abs(velocity.x) < 0.01) {
|
||||||
|
velocity.x = 0;
|
||||||
|
}
|
||||||
|
if (Math.abs(velocity.y) < 0.01) {
|
||||||
|
velocity.y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const new_position = vadd(this.position, velocity);
|
||||||
|
|
||||||
|
// TODO: Collision detection
|
||||||
|
// const { w, h } = this.bounds;
|
||||||
|
|
||||||
|
this.velocity = velocity;
|
||||||
|
this.position = new_position;
|
||||||
|
}
|
||||||
|
|
||||||
|
draw(_clock: number) {}
|
||||||
|
|
||||||
|
bonk(_other: Actor) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
const robo_info = {
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
sprite: "./bot.png",
|
||||||
|
animations: [
|
||||||
|
{ start: 0, length: 1, speed: 20 },
|
||||||
|
{ start: 1, length: 4, speed: 8 },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export class Robo extends Actor {
|
||||||
|
bot_sprite: Texture | undefined = undefined;
|
||||||
|
|
||||||
|
constructor(pos: Vec2) {
|
||||||
|
super("robo", pos, new_v2(robo_info.width, robo_info.height));
|
||||||
|
load_texture(robo_info.sprite).then((texture) => {
|
||||||
|
this.bot_sprite = texture;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
// Acceleration from input
|
||||||
|
let a = new_v2(0);
|
||||||
|
if (btn(Button.Up)) {
|
||||||
|
a.y -= 1;
|
||||||
|
}
|
||||||
|
if (btn(Button.Down)) {
|
||||||
|
a.y += 1;
|
||||||
|
}
|
||||||
|
if (btn(Button.Left)) {
|
||||||
|
a.x -= 1;
|
||||||
|
}
|
||||||
|
if (btn(Button.Right)) {
|
||||||
|
a.x += 1;
|
||||||
|
}
|
||||||
|
vnorm(a);
|
||||||
|
this.velocity = vadd(this.velocity, vmul(a, 1.5));
|
||||||
|
}
|
||||||
|
|
||||||
|
draw(clock: number) {
|
||||||
|
if (this.bot_sprite != undefined) {
|
||||||
|
use_texture(this.bot_sprite);
|
||||||
|
|
||||||
|
const vel = this.velocity;
|
||||||
|
const moving = vel.x != 0 || vel.y != 0;
|
||||||
|
const anim = robo_info.animations[moving ? 1 : 0];
|
||||||
|
|
||||||
|
const { x: w, y: h } = this.bounds;
|
||||||
|
const { x, y } = this.position;
|
||||||
|
|
||||||
|
const frame = (anim.start + ((clock / anim.speed) % anim.length)) >> 0;
|
||||||
|
spr(x, y, w, h, frame * w, 0, 32, 32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
105
game/main.ts
105
game/main.ts
|
|
@ -1,16 +1,12 @@
|
||||||
import { cls, print, spr, use_texture, Texture } from "./graphics";
|
import { cls, print } from "./graphics";
|
||||||
import { load_texture } from "./assets";
|
|
||||||
import { since_start } from "./time";
|
import { since_start } from "./time";
|
||||||
import { btn, Button } from "./input";
|
import { new_v2 } from "./vector";
|
||||||
import { new_v2, vadd, vmul, vnorm } from "./vector";
|
|
||||||
import { load_world, World, Level, draw_level } from "./level";
|
import { load_world, World, Level, draw_level } from "./level";
|
||||||
|
import { Actor, Robo } from "./actor";
|
||||||
/// TODO: Support reload by saving and restoring state from init/update/restore.
|
|
||||||
|
|
||||||
/// A nice looping frame counter.
|
/// A nice looping frame counter.
|
||||||
let clock = 0;
|
let clock = 0;
|
||||||
|
|
||||||
let bot_sprite: Texture | undefined = undefined;
|
|
||||||
let world: World | undefined = undefined;
|
let world: World | undefined = undefined;
|
||||||
let level: Level | undefined = undefined;
|
let level: Level | undefined = undefined;
|
||||||
|
|
||||||
|
|
@ -18,15 +14,8 @@ let level: Level | undefined = undefined;
|
||||||
// zelda screen is 16x11 tiles
|
// zelda screen is 16x11 tiles
|
||||||
// from a feeling point of view this is sufficient, apparently :D
|
// from a feeling point of view this is sufficient, apparently :D
|
||||||
|
|
||||||
let loaded = false;
|
|
||||||
|
|
||||||
function load_assets() {
|
function load_assets() {
|
||||||
// Start this load, but then...
|
// Start this load, but then...
|
||||||
let texture_load = load_texture("./bot.png").then((n) => {
|
|
||||||
print("Bot loaded at", since_start());
|
|
||||||
bot_sprite = n;
|
|
||||||
});
|
|
||||||
|
|
||||||
let map_load = load_world("./overworld.ldtk").then((w) => {
|
let map_load = load_world("./overworld.ldtk").then((w) => {
|
||||||
print("World loaded at", since_start());
|
print("World loaded at", since_start());
|
||||||
world = w;
|
world = w;
|
||||||
|
|
@ -36,106 +25,56 @@ function load_assets() {
|
||||||
if (!level) {
|
if (!level) {
|
||||||
throw new Error("UNABLE TO FIND LEVEL AT 0,0: CANNOT START");
|
throw new Error("UNABLE TO FIND LEVEL AT 0,0: CANNOT START");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: SPAWN ACTORS BASED ON LEVEL.
|
||||||
});
|
});
|
||||||
|
|
||||||
Promise.all([texture_load, map_load]).then(() => {
|
Promise.all([map_load]).then(() => {
|
||||||
loaded = true;
|
|
||||||
print("All are loaded.");
|
print("All are loaded.");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const actors: Actor[] = [];
|
||||||
|
|
||||||
|
// TODO: Build a system whereby the signatures of the fundamental functions can be checked.
|
||||||
|
|
||||||
export function init() {
|
export function init() {
|
||||||
print("Hello world!");
|
print("Hello world!");
|
||||||
load_assets();
|
load_assets();
|
||||||
|
actors.push(new Robo(new_v2(10, 10)));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function suspend() {
|
export function suspend() {
|
||||||
return { clock };
|
return { clock };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resume(snapshot) {
|
export function resume() {}
|
||||||
if (snapshot) {
|
|
||||||
print("!Resuming!");
|
|
||||||
const { clock: new_clock } = snapshot;
|
|
||||||
if (new_clock) {
|
|
||||||
clock = new_clock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const friction = 0.6;
|
|
||||||
let robo_vel = new_v2(0);
|
|
||||||
let robo_pos = new_v2(10);
|
|
||||||
|
|
||||||
export function update() {
|
export function update() {
|
||||||
clock = (clock + 1) % 20160;
|
clock = (clock + 1) % 20160;
|
||||||
|
|
||||||
// Acceleration from input
|
for (const actor of actors) {
|
||||||
let a = new_v2(0);
|
actor.update();
|
||||||
if (btn(Button.Up)) {
|
|
||||||
a.y -= 1;
|
|
||||||
}
|
|
||||||
if (btn(Button.Down)) {
|
|
||||||
a.y += 1;
|
|
||||||
}
|
|
||||||
if (btn(Button.Left)) {
|
|
||||||
a.x -= 1;
|
|
||||||
}
|
|
||||||
if (btn(Button.Right)) {
|
|
||||||
a.x += 1;
|
|
||||||
}
|
|
||||||
vnorm(a);
|
|
||||||
a = vmul(a, 0.8); // Speed.
|
|
||||||
|
|
||||||
// Friction
|
|
||||||
let v = vmul(robo_vel, friction);
|
|
||||||
v = vadd(v, a);
|
|
||||||
|
|
||||||
// Zero if we're smaller than some epsilon.
|
|
||||||
if (Math.abs(v.x) < 0.01) {
|
|
||||||
v.x = 0;
|
|
||||||
}
|
|
||||||
if (Math.abs(v.y) < 0.01) {
|
|
||||||
v.y = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Motion
|
for (const actor of actors) {
|
||||||
let np = vadd(robo_pos, v);
|
actor.update_physics();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Collide.
|
// TODO: Bonks
|
||||||
|
// TODO: Transients
|
||||||
robo_pos = np;
|
|
||||||
robo_vel = v;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GARBAGE OBVIOUSLY
|
|
||||||
const robo_info = {
|
|
||||||
width: 32,
|
|
||||||
height: 32,
|
|
||||||
animations: [
|
|
||||||
{ start: 0, length: 1, speed: 20 },
|
|
||||||
{ start: 1, length: 4, speed: 8 },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
export function draw() {
|
export function draw() {
|
||||||
cls(0.1, 0.2, 0.3);
|
cls(0.1, 0.2, 0.3);
|
||||||
if (!loaded) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (level != undefined) {
|
if (level != undefined) {
|
||||||
draw_level(level, 0, 0);
|
draw_level(level, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bot_sprite != undefined) {
|
for (const actor of actors) {
|
||||||
// ...it gets resolved here?
|
actor.draw(clock);
|
||||||
use_texture(bot_sprite);
|
|
||||||
|
|
||||||
const moving = robo_vel.x != 0 || robo_vel.y != 0;
|
|
||||||
const anim = robo_info.animations[moving ? 1 : 0];
|
|
||||||
const frame = (anim.start + ((clock / anim.speed) % anim.length)) >> 0;
|
|
||||||
spr(robo_pos.x, robo_pos.y, 32, 32, frame * robo_info.width, 0, 32, 32);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// print("FRAME TIME:", since_last_frame());
|
// print("FRAME TIME:", since_last_frame());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue