Skip to content

Commit

Permalink
v0.3.6 networked joystick (#107)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderclarktx authored Mar 27, 2024
1 parent f1378b8 commit 2c0d212
Show file tree
Hide file tree
Showing 31 changed files with 176 additions and 149 deletions.
20 changes: 12 additions & 8 deletions core/src/contrib/components/Actions.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import { Component, Entity, World } from "@piggo-gg/core";

export interface Action {
apply: (entity: Entity, world: World, player?: string) => void
validate: (entity: Entity, world: World, player?: string) => boolean
export type Action<T extends {} = {}> = {
apply: (params: T, entity: Entity, world: World, player?: string) => void
// validate: (entity: Entity, world: World, player?: string) => boolean
}

export const ValidAction = (apply: Action["apply"]): Action => ({
apply,
validate: () => true
})
export const Action = (apply: Action["apply"]): Action => {
return { apply };
}

export type InvokedAction<A extends string = string, P extends {} = {}> = {
action: A,
params: P
}

export type ActionMap<T extends string = string> = Record<T, Action>;
export type ActionMap<T extends string = string, P extends {} = {}> = Record<T, Action<P>>;

export class Actions extends Component<"actions"> {
type: "actions" = "actions";
Expand Down
12 changes: 6 additions & 6 deletions core/src/contrib/components/Clickable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ export type ClickableProps = {
width: number
height: number
active: boolean
click: Action
click: Action<{}>
}

export class Clickable extends Component<"clickable"> {
type: "clickable" = "clickable";
width: number;
height: number;
active: boolean;
click: Action;
type: "clickable" = "clickable"
width: number
height: number
active: boolean
click: Action<{}>

constructor(props: ClickableProps) {
super();
Expand Down
13 changes: 8 additions & 5 deletions core/src/contrib/components/Controller.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { Component } from "@piggo-gg/core";
import { InvokedAction, Component } from "@piggo-gg/core";

// "" is always allowed to clear the input buffer
export type ControllerMap<T extends string = string> = Record<string, T | null>
export type ControllerMap<A extends string, P extends {}> = {
keyboard: Record<string, null | InvokedAction<A, P>>
joystick?: () => null | InvokedAction<A, P>
}

// the Controller component maps inputs to Actions
export class Controller<T extends string = string> extends Component<"controller"> {
export class Controller<A extends string = string, P extends {} = {}> extends Component<"controller"> {
type: "controller" = "controller";
controllerMap: ControllerMap<T>;
controllerMap: ControllerMap<A, P>;

constructor(controllerMap: ControllerMap<T>) {
constructor(controllerMap: ControllerMap<A, P>) {
super();
this.controllerMap = controllerMap;
}
Expand Down
6 changes: 3 additions & 3 deletions core/src/contrib/components/NPC.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Component, Entity, World } from "@piggo-gg/core";
import { Component, Entity, InvokedAction, World } from "@piggo-gg/core";

export type NPCProps<T> = {
onTick: (entity: Entity, world: World) => T | null | void;
export type NPCProps<T extends string> = {
onTick: (entity: Entity, world: World) => InvokedAction<T> | null | void;
}

export class NPC<T extends string = string> extends Component<"npc"> {
Expand Down
4 changes: 2 additions & 2 deletions core/src/contrib/components/Position.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@ export class Position extends Component<"position"> {
}

rotateUp = (amount: number) => {
this.data.rotation = Math.round(this.data.rotation + amount);
this.data.rotation += amount;
return this;
}

rotateDown = (amount: number) => {
this.data.rotation = Math.round(this.data.rotation - amount);
this.data.rotation -= amount;
return this;
}
}
5 changes: 2 additions & 3 deletions core/src/contrib/components/actions/PlayerControlsEntity.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Action, Controlled, Controlling, Entity, ValidAction, World } from "@piggo-gg/core";
import { Action, Controlled, Controlling, Entity, World } from "@piggo-gg/core";

// TODO refactor
export const PlayerControlsEntity: Action = ValidAction((entity: Entity, world: World, player: string) => {
export const PlayerControlsEntity: Action = Action((_, entity: Entity, world: World, player: string) => {

// check that the entity isn't already being controlled
if (entity.components.controlled) return;
Expand Down
16 changes: 8 additions & 8 deletions core/src/contrib/components/actions/VehicleMovement.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { Entity, ActionMap, Position, ValidAction } from "@piggo-gg/core";
import { Entity, ActionMap, Position, Action } from "@piggo-gg/core";

const TURN_SPEED = 0.1;
const SLIDE_FACTOR = 1.5;
const SPEED = 2;
const SPEED = 200;

export type VehicleMovementActions = "up" | "down" | "left" | "right" | "skidleft" | "skidright";

export const VehicleMovement: ActionMap<VehicleMovementActions> = {
"up": ValidAction(({ components: { position } }: Entity<Position>) => {
"up": Action((_, { components: { position } }: Entity<Position>) => {
const x = Math.cos(position.data.rotation - Math.PI / 1.35) * SPEED;
const y = Math.sin(position.data.rotation - Math.PI / 1.35) * SPEED;
position.setVelocity({ x, y });
}),
"down": ValidAction(({ components: { position } }: Entity<Position>) => position.setVelocity({ x: 0, y: 0 })),
"left": ValidAction(({ components: { position } }: Entity<Position>) => position.rotateDown(TURN_SPEED)),
"right": ValidAction(({ components: { position } }: Entity<Position>) => position.rotateUp(TURN_SPEED)),
"skidleft": ValidAction(({ components: { position } }: Entity<Position>) => position.rotateDown(TURN_SPEED * SLIDE_FACTOR)),
"skidright": ValidAction(({ components: { position } }: Entity<Position>) => position.rotateUp(TURN_SPEED * SLIDE_FACTOR))
"down": Action((_, { components: { position } }: Entity<Position>) => position.setVelocity({ x: 0, y: 0 })),
"left": Action((_, { components: { position } }: Entity<Position>) => position.rotateDown(TURN_SPEED)),
"right": Action((_, { components: { position } }: Entity<Position>) => position.rotateUp(TURN_SPEED)),
"skidleft": Action((_, { components: { position } }: Entity<Position>) => position.rotateDown(TURN_SPEED * SLIDE_FACTOR)),
"skidright": Action((_, { components: { position } }: Entity<Position>) => position.rotateUp(TURN_SPEED * SLIDE_FACTOR))
}
96 changes: 60 additions & 36 deletions core/src/contrib/components/actions/WASDMovement.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,75 @@
import { ActionMap, Entity, Position, ValidAction, currentJoystickPosition } from "@piggo-gg/core";
import { ActionMap, ControllerMap, Entity, Position, currentJoystickPosition } from "@piggo-gg/core";

const speed = 140;
const speedDiagonal = speed / Math.sqrt(2);
const speedHorizontal = speed / 2;

export type WASDMovementActions = "up" | "down" | "left" | "right" | "upleft" | "upright" | "downleft" | "downright";

export const WASDMovementPhysics: ActionMap<WASDMovementActions> = {
"up": ValidAction((entity: Entity<Position>) => move(entity, "u", { x: -speedDiagonal, y: -speedDiagonal })),
"down": ValidAction((entity: Entity<Position>) => move(entity, "d", { x: speedDiagonal, y: speedDiagonal })),
"left": ValidAction((entity: Entity<Position>) => move(entity, "l", { x: -speedHorizontal, y: speedHorizontal })),
"right": ValidAction((entity: Entity<Position>) => move(entity, "r", { x: speedHorizontal, y: -speedHorizontal })),
"upleft": ValidAction((entity: Entity<Position>) => move(entity, "ul", { x: -speed, y: 0 })),
"upright": ValidAction((entity: Entity<Position>) => move(entity, "ur", { x: 0, y: -speed })),
"downleft": ValidAction((entity: Entity<Position>) => move(entity, "dl", { x: 0, y: speed })),
"downright": ValidAction((entity: Entity<Position>) => move(entity, "dr", { x: speed, y: 0 }))
}
type WASDParams = { animation: string, x: number, y: number };

// shout out to chatgpt (best programmer i know fr)
const move = (entity: Entity<Position>, animation: string | undefined, velocity: { x: number, y: number }) => {
const { position, renderable } = entity.components;
const getAnimationXYForJoystick = (): WASDParams => {
console.log("getAnimationXYForJoystick");
const { power, angle } = currentJoystickPosition;

// make the joystick feel stiff
const powerToApply = Math.min(1, power * 2);

if (currentJoystickPosition.power) {
const { power, angle } = currentJoystickPosition;
// Adjusting the angle to match the isometric projection
const angleAdjusted = angle + 45;
const angleRad = angleAdjusted * Math.PI / 180;

// make the joystick feel stiff
const powerToApply = Math.min(1, power * 2);
// x,y components of the vector
let cosAngle = Math.cos(angleRad);
let sinAngle = -Math.sin(angleRad);

// Adjusting the angle to match the isometric projection
const angleAdjusted = angle + 45;
const angleRad = angleAdjusted * Math.PI / 180;
// Adjusting for consistent speed in isometric projection
const magnitude = Math.sqrt(cosAngle * cosAngle + sinAngle * sinAngle);
cosAngle /= magnitude;
sinAngle /= magnitude;

// x,y components of the vector
let cosAngle = Math.cos(angleRad);
let sinAngle = -Math.sin(angleRad);
// Apply the power to the vector
const x = cosAngle * powerToApply * speed;
const y = sinAngle * powerToApply * speed;

// Adjusting for consistent speed in isometric projection
const magnitude = Math.sqrt(cosAngle * cosAngle + sinAngle * sinAngle);
cosAngle /= magnitude;
sinAngle /= magnitude;
let animation = "";

// Apply the power to the vector
velocity.x = cosAngle * powerToApply * speed;
velocity.y = sinAngle * powerToApply * speed;
}
const increment = currentJoystickPosition.angle / (360 / 8);

position.setVelocity(velocity);
((increment > 0.5) && (increment < 1.5)) ?
animation = "ur" :
((increment > 0.5) && (increment < 2.5)) ? animation = "u" :
((increment > 0.5) && (increment < 3.5)) ? animation = "ul" :
((increment > 0.5) && (increment < 4.5)) ? animation = "l" :
((increment > 0.5) && (increment < 5.5)) ? animation = "dl" :
((increment > 0.5) && (increment < 6.5)) ? animation = "d" :
((increment > 0.5) && (increment < 7.5)) ? animation = "dr" :
animation = "r";

if (renderable && animation) renderable.setAnimation(animation);
return { x, y, animation };
}

export const WASDController: ControllerMap<"move", WASDParams> = {
keyboard: {
"a,d": null, "w,s": null,
"w,a": { action: "move", params: { animation: "ul", x: -speed, y: 0 } },
"w,d": { action: "move", params: { animation: "ur", x: 0, y: -speed } },
"s,a": { action: "move", params: { animation: "dl", x: 0, y: speed } },
"s,d": { action: "move", params: { animation: "dr", x: speed, y: 0 } },
"w": { action: "move", params: { animation: "u", x: -speedDiagonal, y: -speedDiagonal } },
"s": { action: "move", params: { animation: "d", x: speedDiagonal, y: speedDiagonal } },
"a": { action: "move", params: { animation: "l", x: -speedHorizontal, y: speedHorizontal } },
"d": { action: "move", params: { animation: "r", x: speedHorizontal, y: -speedHorizontal } }
},
joystick: () => ({ action: "move", params: getAnimationXYForJoystick() })
}

export const WASDmove = (params: WASDParams, entity: Entity<Position>) => {
const { position, renderable } = entity.components;

position.setVelocity({ x: params.x, y: params.y });

if (renderable && params.animation) renderable.setAnimation(params.animation);
}

export const WASDActionMap: ActionMap<"move", WASDParams> = {
move: { apply: WASDmove }
};
4 changes: 2 additions & 2 deletions core/src/contrib/components/actions/ZombieMovement.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { ActionMap, Entity, World, Position, Renderable, ValidAction } from "@piggo-gg/core";
import { ActionMap, Entity, World, Position, Renderable, Action } from "@piggo-gg/core";

const speed = 30;
const t = (Math.PI * 2) / 16; // 22.5 degrees

export type ZombieMovementActions = "chase"

export const ZombieMovement: ActionMap<ZombieMovementActions> = {
"chase": ValidAction((entity: Entity<Position | Renderable>, world: World) => {
"chase": Action((_, entity: Entity<Position | Renderable>, world: World) => {
const { position, renderable } = entity.components;

// get the closest player entity position
Expand Down
4 changes: 2 additions & 2 deletions core/src/contrib/entities/buttons/ConnectButton.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Button, Clickable, Entity, Position, ValidAction, World, DelayClientSystem } from "@piggo-gg/core";
import { Button, Clickable, Entity, Position, World, DelayClientSystem, Action } from "@piggo-gg/core";
import { Text } from "pixi.js";

export const ConnectButton = () => Entity({
Expand All @@ -8,7 +8,7 @@ export const ConnectButton = () => Entity({
position: new Position({ x: 75, y: 5, screenFixed: true }),
clickable: new Clickable({
width: 80, height: 32, active: true,
click: ValidAction((_, world: World) => {
click: Action((_, __, world: World) => {
if (world) world.addSystemBuilders([DelayClientSystem]);
})
}),
Expand Down
4 changes: 2 additions & 2 deletions core/src/contrib/entities/buttons/DebugButton.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Entity, ValidAction, World } from "@piggo-gg/core";
import { Action, Entity, World } from "@piggo-gg/core";
import { Button, Clickable, Position } from "@piggo-gg/core";
import { Graphics, Text } from "pixi.js";

Expand All @@ -16,7 +16,7 @@ export const DebugButton = (): Entity => {
position: new Position({ x: 40, y: 5, screenFixed: true }),
clickable: new Clickable({
width: 32, height: 32, active: true,
click: ValidAction((_, world: World) => {
click: Action((_, __, world: World) => {
pressed = !pressed;
if (pressed) {
shadow.tint = 0x00ffff;
Expand Down
4 changes: 2 additions & 2 deletions core/src/contrib/entities/buttons/FullscreenButton.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Button, Clickable, Entity, Position, ValidAction, World } from "@piggo-gg/core";
import { Action, Button, Clickable, Entity, Position, World } from "@piggo-gg/core";
import { Text } from "pixi.js";

export const FullscreenButton = (id: string = "fullscreenButton") => Entity({
Expand All @@ -12,7 +12,7 @@ export const FullscreenButton = (id: string = "fullscreenButton") => Entity({
active: true,
width: 32,
height: 30,
click: ValidAction((_, world: World) => {
click: Action((_, __, world: World) => {
if (!document.fullscreenElement) {
world.renderer?.app.canvas.requestFullscreen?.();
} else {
Expand Down
10 changes: 3 additions & 7 deletions core/src/contrib/entities/characters/Skelly.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Actions, Collider, Controlled, Controller, Debug, Entity, Networked, Position, Renderable, WASDMovementActions, WASDMovementPhysics } from "@piggo-gg/core";
import { Actions, Collider, Controlled, Controller, Debug, Entity, Networked, Position, Renderable, WASDActionMap, WASDController } from "@piggo-gg/core";
import { AnimatedSprite, Text } from "pixi.js";

export const Skelly = (id: string, tint?: number) => Entity({
Expand All @@ -9,12 +9,8 @@ export const Skelly = (id: string, tint?: number) => Entity({
networked: new Networked({ isNetworked: true }),
controlled: new Controlled({ entityId: "" }),
collider: new Collider({ shape: "ball", radius: 8, mass: 600 }),
controller: new Controller<WASDMovementActions>({
"a,d": null, "w,s": null,
"w,a": "upleft", "w,d": "upright", "s,a": "downleft", "s,d": "downright",
"w": "up", "s": "down", "a": "left", "d": "right"
}),
actions: new Actions(WASDMovementPhysics),
controller: new Controller(WASDController),
actions: new Actions(WASDActionMap),
renderable: new Renderable({
anchor: { x: 0.5, y: 0.7 },
scale: 2,
Expand Down
13 changes: 10 additions & 3 deletions core/src/contrib/entities/characters/Spaceship.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,15 @@ export const Spaceship = ({ id, position }: SpaceshipProps = {}) => Entity({
}),
collider: new Collider({ shape: "cuboid", radius: 60 }),
controller: new Controller<VehicleMovementActions>({
"a,d": null, "w,s": null,
"shift,a": "skidleft", "shift,d": "skidright",
"w": "up", "s": "down", "a": "left", "d": "right"
keyboard: {
"a,d": null, "w,s": null,
"shift,a": { action: "skidleft", params: {} },
"shift,d": { action: "skidright", params: {} },
"w": { action: "up", params: {} },
"s": { action: "down", params: {} },
"a": { action: "left", params: {} },
"d": { action: "right", params: {} }
}
}),
debug: new Debug(),
actions: new Actions(VehicleMovement),
Expand All @@ -32,6 +38,7 @@ export const Spaceship = ({ id, position }: SpaceshipProps = {}) => Entity({
const texture = (await r.loadTextures("spaceship.json"))["spaceship"];
const sprite = new AnimatedSprite([texture]);
sprite.scale = { x: 2, y: 2 };
sprite.anchor.set(0.5, 0.5);
r.c = sprite;
}
})
Expand Down
6 changes: 3 additions & 3 deletions core/src/contrib/entities/characters/Zombie.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Actions, Clickable, Collider, Debug, Entity, NPC, Networked, Position, PositionProps, Projectile, Renderable, ValidAction, ZombieMovement, ZombieMovementActions } from "@piggo-gg/core";
import { Action, Actions, Clickable, Collider, Debug, Entity, NPC, Networked, Position, PositionProps, Projectile, Renderable, ZombieMovement, ZombieMovementActions } from "@piggo-gg/core";
import { AnimatedSprite } from "pixi.js";

export type ZombieProps = {
Expand All @@ -16,14 +16,14 @@ export const Zombie = ({ id, color, positionProps = { renderMode: "isometric", x
width: 32,
height: 32,
active: true,
click: ValidAction((_, world) => {
click: Action((_, __, world) => {
if (world.clientPlayerId) {
world.addEntity(Projectile({ radius: 5 }));
}
})
}),
npc: new NPC<ZombieMovementActions>({
onTick: (_) => "chase"
onTick: (_) => ({ action: "chase", params: {} })
}),
actions: new Actions(ZombieMovement),
collider: new Collider({ shape: "ball", radius: 8, mass: 300 }),
Expand Down
Loading

0 comments on commit 2c0d212

Please # to comment.