working score through network

This commit is contained in:
Thilo Behnke
2022-07-04 21:49:53 +02:00
parent 9ad9d16d54
commit ef5d4c1a99
11 changed files with 69 additions and 21 deletions

View File

@@ -68,7 +68,7 @@
<Canvas debug={debug} session={session} inputs={inputs} tick={tick} handleError={handleError} let:dimensions={dimensions}>
<Fps></Fps>
<Line x={dimensions.width / 2} y={0} height={dimensions.height} dashed={true}></Line>
<Score dimensions={dimensions} score={tick.score}></Score>
<Score dimensions={dimensions} score={tick?.state?.score}></Score>
</Canvas>
</div>
<div class="game-area__hud">

View File

@@ -1,15 +1,19 @@
<script lang="ts">
import {gameField} from "../store/engine";
import {networkTickEvents, sessionInputs} from "../store/session";
import {gameStateEvents, networkTickEvents, sessionInputs} from "../store/session";
import type {GameState} from "../store/model/session";
export let killLoopOnError = true;
let frame: number;
let state: GameState;
$: state = $gameStateEvents;
$: if (networkTickEvents && $networkTickEvents.hasNext) {
const tick = networkTickEvents.next();
if (tick != null) {
gameField.update(tick.objects);
gameField.update(tick.objects, state);
}
}

View File

@@ -2,12 +2,13 @@
import {sessionInputs} from "../store/session";
import type {LocalSession} from "../store/model/session";
import TickWrapper from "./TickWrapper.svelte";
import {gameField} from "../store/engine";
export let session: LocalSession;
</script>
{#if session && sessionInputs}
<TickWrapper inputs={$sessionInputs} let:tick={tick} let:inputs={inputs} let:handleError={handleError}>
<TickWrapper gameFieldStore={gameField} inputs={$sessionInputs} let:tick={tick} let:inputs={inputs} let:handleError={handleError}>
<slot inputs={inputs} tick={tick} handleError={handleError} events={[]}></slot>
</TickWrapper>
{/if}

View File

@@ -1,7 +1,6 @@
<script lang="ts">
import type {GameScore} from "../store/engine";
import Text from "./Text.svelte";
import type {GameScore} from "../store/model/session";
export let dimensions: { width: number, height: number };
export let score: GameScore;
@@ -9,7 +8,7 @@
{#if score}
<Text
text={score.player1.toString()}
text={score.player_1.toString()}
fontSize=40
fontFamily='Courier New'
align='left'
@@ -18,7 +17,7 @@
y={20}/>
<Text
text={score.player2.toString()}
text={score.player_2.toString()}
fontSize=40
fontFamily='Courier New'
align='left'

View File

@@ -39,4 +39,4 @@
}
</script>
<slot tick={gameFieldStore} inputs={inputs} handleError={handleError}></slot>
<slot tick={$gameFieldStore} inputs={inputs} handleError={handleError}></slot>

View File

@@ -68,7 +68,7 @@ export type GameFieldState = {
export type GameFieldStore = Readable<GameFieldState> & {tick: (inputs: Input[], dt: number) => void, update: (objects: GameObject[], state: GameState) => void};
function createGameFieldStore(): GameFieldStore {
const {subscribe, set} = writable<GameFieldState>({ts: 0, objects: [], state: {score: {player1: 0, player2: 0}}});
const {subscribe, set} = writable<GameFieldState>({ts: 0, objects: [], state: {score: {player_1: 0, player_2: 0}}});
const field = FieldWrapper.new();

View File

@@ -1,4 +1,4 @@
import type {GameObject, NetworkSession, Session} from "./session";
import type {GameObject, GameState, NetworkSession, Session} from "./session";
import type {Input} from "./input";
export type SessionEventPayload = {
@@ -28,6 +28,11 @@ export type TickEventPayload = {
ts: number
}
export type StatusEventPayload = {
session_id: string,
state: GameState
}
export type SessionEvenWrapper = {
topic: 'session',
event: SessionEventPayload
@@ -48,7 +53,12 @@ export type MoveEventWrapper = {
event: GameObject
}
export type GameEventWrapper = SessionEvenWrapper | InputEventWrapper | MoveEventWrapper | TickEventWrapper;
export type StatusEventWrapper = {
topic: 'status',
event: StatusEventPayload
}
export type GameEventWrapper = SessionEvenWrapper | InputEventWrapper | MoveEventWrapper | TickEventWrapper | StatusEventWrapper;
export const isSessionEvent = (event: GameEventWrapper): event is SessionEvenWrapper => {
return event.topic === 'session';
@@ -65,3 +75,7 @@ export const isMoveEvent = (event: GameEventWrapper): event is MoveEventWrapper
export const isTickEvent = (event: GameEventWrapper): event is TickEventWrapper => {
return event.topic === 'tick';
}
export const isStatusEvent = (event: GameEventWrapper): event is StatusEventWrapper => {
return event.topic === 'status';
}

View File

@@ -63,8 +63,8 @@ export function isLocalSession(session: Session): session is LocalSession {
}
export type GameScore = {
player1: number,
player2: number,
player_1: number,
player_2: number,
}
export type GameState = {

View File

@@ -1,15 +1,21 @@
import {derived, get, Readable, readable, Unsubscriber, writable} from "svelte/store";
import api from "../api/session";
import type {LocalSession, Message, NetworkSession, Session, SessionSnapshot} from "./model/session";
import type {GameState, LocalSession, Message, NetworkSession, Session, SessionSnapshot} from "./model/session";
import {isLocalSession, isNetworkSession, MessageType, SessionState, SessionType} from "./model/session";
import type {NetworkStore} from "./network";
import type {GameEventWrapper, InputEventPayload, SessionEventPayload, TickEventPayload} from "./model/event";
import {isInputEvent, isMoveEvent, isSessionEvent, isTickEvent} from "./model/event";
import type {
GameEventWrapper,
InputEventPayload,
SessionEventPayload,
StatusEventPayload,
TickEventPayload
} from "./model/event";
import {isInputEvent, isMoveEvent, isSessionEvent, isStatusEvent, isTickEvent} from "./model/event";
import {getPlayerKeyboardInputs, playerKeyboardInputs} from "./input";
import type {Subscriber} from "svelte/types/runtime/store";
import {combined} from "./utils";
import type {Input} from "./model/input";
import {init, tick} from "svelte/internal";
import {init, subscribe, tick} from "svelte/internal";
const sessionStore = writable<Session>(null);
@@ -134,6 +140,30 @@ export const networkSessionStateEvents = readable<SessionEventPayload[]>([], set
}
});
export const gameStateEvents = (function() {
const lastEvent = writable<StatusEventPayload>(null);
const unsubNetworkEvents = networkEvents.subscribe($events => {
const events = $events.filter(isStatusEvent);
if (!events.length) {
return;
}
const latest = events[events.length - 1];
lastEvent.set(latest.event);
})
const customSubscribe = (run: Subscriber<StatusEventPayload>, invalidate): Unsubscriber => {
const unsub = lastEvent.subscribe(run, invalidate);
return () => {
unsub();
unsubNetworkEvents();
}
}
return {
subscribe: customSubscribe
}
}())
export type NetworkTickEventState = {
hasNext: boolean;
events: TickEventPayload[]

View File

@@ -29,7 +29,7 @@ pub enum PongEvent {
#[derive(Debug, Serialize, Deserialize)]
pub struct MoveEventPayload {
pub session_id: String,
pub id: i32,
pub id: String,
pub orientation_x: f64,
pub orientation_y: f64,
pub shape_param_1: f64,

View File

@@ -455,7 +455,7 @@ struct ObserverSessionSnapshotDTO {
#[derive(Deserialize)]
struct GameObjectStateDTO {
pub id: i32,
pub id: String,
pub orientation_x: f64,
pub orientation_y: f64,
pub shape_param_1: f64,
@@ -471,7 +471,7 @@ impl GameObjectStateDTO {
MoveEventPayload {
session_id: session_id.to_owned(),
ts,
id: self.id,
id: self.id.clone(),
x: self.x,
y: self.y,
orientation_x: self.orientation_x,