inetraction stuff

This commit is contained in:
2026-02-26 16:37:26 +01:00
parent 1ac2de123e
commit 7835a4df02
15 changed files with 176 additions and 24 deletions

View File

@@ -1 +1,12 @@
<p>food-pantry works!</p> <div class="h-full w-full absolute bg-red-300">
<div class="py-4 container mx-auto">
<div class="flex flex-row justify-between">
<p>food-pantry works!</p>
<ff-button (click)="onClose.emit(true)">X</ff-button>
</div>
<ff-grid
[gridItems]="foods()"
(onSelect)="onFoodChosen.emit($event)"
></ff-grid>
</div>
</div>

View File

@@ -1,10 +1,19 @@
import { Component } from '@angular/core'; import { Component, inject, output, OutputEmitterRef, Signal } from '@angular/core';
import { ButtonComponent } from "../ui-elements/button/button.component";
import { Food } from '../../types/food';
import { FoodStore } from '../../api/food.store';
import { GridComponent } from "../grid/grid.component";
@Component({ @Component({
selector: 'ff-food-pantry', selector: 'ff-food-pantry',
imports: [], imports: [ButtonComponent, GridComponent],
templateUrl: './food-pantry.component.html', templateUrl: './food-pantry.component.html',
}) })
export class FoodPantryComponent { export class FoodPantryComponent {
public readonly onClose: OutputEmitterRef<true> = output<true>();
public readonly onFoodChosen: OutputEmitterRef<Food> = output<Food>();
private readonly foodStore: FoodStore = inject(FoodStore);
protected readonly foods: Signal<Food[]> = this.foodStore.foods;
} }

View File

@@ -0,0 +1,12 @@
<div class="w-full flex flex-row flex-wrap gap-3">
@for (item of gridItems(); track $index) {
<div
(click)="onSelect.emit(item)"
class="rounded-lg bg-primary-400 cursor-pointer"
[ngStyle]="{
width: size() + 'rem',
height: size() + 'rem',
}"
></div>
}
</div>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { GridComponent } from './grid.component';
describe('GridComponent', () => {
let component: GridComponent<any>;
let fixture: ComponentFixture<GridComponent<any>>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [GridComponent]
})
.compileComponents();
fixture = TestBed.createComponent(GridComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,14 @@
import { NgStyle } from '@angular/common';
import { Component, input, InputSignal, output, OutputEmitterRef } from '@angular/core';
@Component({
selector: 'ff-grid',
imports: [NgStyle],
templateUrl: './grid.component.html',
})
export class GridComponent<T> {
public readonly gridItems: InputSignal<T[]> = input.required();
public readonly size: InputSignal<number> = input<number>(5);
public readonly onSelect: OutputEmitterRef<T> = output<T>();
}

View File

@@ -1 +1,8 @@
<p>inventory works!</p> <div class="h-full w-full absolute bg-blue-300">
<div class="py-4 container mx-auto">
<div class="flex flex-row justify-between">
<p>inventory works!</p>
<ff-button (click)="onClose.emit()">X</ff-button>
</div>
</div>
</div>

View File

@@ -1,10 +1,13 @@
import { Component } from '@angular/core'; import { Component, output, OutputEmitterRef } from '@angular/core';
import { ButtonComponent } from "../ui-elements/button/button.component";
@Component({ @Component({
selector: 'ff-inventory', selector: 'ff-inventory',
imports: [], imports: [ButtonComponent],
templateUrl: './inventory.component.html', templateUrl: './inventory.component.html',
}) })
export class InventoryComponent { export class InventoryComponent {
public readonly onClose: OutputEmitterRef<void> = output<void>();
public readonly onItemChosen: OutputEmitterRef<any> = output<any>();
} }

View File

@@ -1,6 +1,6 @@
<button <button
type="button" type="button"
class="rounded-lg bg-primary-500 hover:bg-primary-700 cursor-pointer text-white px-4 py-2" class="rounded-lg bg-primary-500 hover:bg-primary-700 cursor-pointer text-white px-4 py-2 flex flex-row items-center justify-center"
> >
<ng-content></ng-content> <ng-content></ng-content>
</button> </button>

View File

@@ -1,9 +1,11 @@
import { Chibi } from "../../types/chibi/chibi";
import { EChibiInteraction } from "../../types/chibi/chibi-interaction"; import { EChibiInteraction } from "../../types/chibi/chibi-interaction";
import { EChibiStateName } from "../../types/chibi/chibi-state-name"; import { Food } from "../../types/food";
export interface IBrain { export interface IBrain {
//function for time passegs + autonomous state changes //function for time passegs + autonomous state changes
exist(chibi: Chibi): void;
resolveInteraction(state: EChibiStateName, interaction: EChibiInteraction): EChibiStateName resolveInteraction(chibi: Chibi, interaction: EChibiInteraction, item?: Food): void
} }

View File

@@ -1,12 +1,29 @@
import { Chibi } from "../../../types/chibi/chibi";
import { EChibiInteraction } from "../../../types/chibi/chibi-interaction"; import { EChibiInteraction } from "../../../types/chibi/chibi-interaction";
import { EChibiStateName } from "../../../types/chibi/chibi-state-name"; import { EChibiStateName } from "../../../types/chibi/chibi-state-name";
import { Food } from "../../../types/food";
import { IBrain } from "../brain"; import { IBrain } from "../brain";
export class Aperio implements IBrain { export class Aperio implements IBrain {
resolveInteraction(state: EChibiStateName, interaction: EChibiInteraction): EChibiStateName {
switch (state) { private hasBeenAwakeFor: number = 0;
case EChibiStateName.Sleeping: return this.resolveSleepingInteraction(interaction);
default: return EChibiStateName.Sleeping; exist(chibi: Chibi): void {
console.log('Brain is braining');
if (!EChibiStateName.Sleeping) {
this.hasBeenAwakeFor++;
if (this.hasBeenAwakeFor > 60) {
chibi.state = EChibiStateName.Sleeping;
}
}
}
resolveInteraction(chibi: Chibi, interaction: EChibiInteraction, item?: Food): void {
switch (chibi.state) {
case EChibiStateName.Sleeping: chibi.state = this.resolveSleepingInteraction(interaction); break;
case EChibiStateName.Awake: chibi.state = this.resolveAwakeInteraction(interaction, item); break;
default:
chibi.state = EChibiStateName.Sleeping; break;
} }
} }
@@ -39,4 +56,11 @@ export class Aperio implements IBrain {
} }
return EChibiStateName.Sleeping; return EChibiStateName.Sleeping;
} }
private resolveAwakeInteraction(interaction: EChibiInteraction, item?: Food): EChibiStateName {
if (EChibiInteraction.Feed) {
return EChibiStateName.Eating;
}
return EChibiStateName.Idle;
}
}; };

View File

@@ -1,5 +1,6 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { RouterLink } from "@angular/router"; import { RouterLink } from "@angular/router";
import { TranslateableComponent } from '../../components/translateable.component';
@Component({ @Component({
selector: 'ff-home', selector: 'ff-home',

View File

@@ -1,3 +1,4 @@
@let shownMenu = interactionMenuState();
<div class="flex flex-col h-[100vh]"> <div class="flex flex-col h-[100vh]">
<div class="min-h-56 h-2/3 max-h-2/3"> <div class="min-h-56 h-2/3 max-h-2/3">
@if (chibi()) { @if (chibi()) {
@@ -12,11 +13,26 @@
</div> </div>
} }
</div> </div>
<div class="h-1/3 min-h-20 bg-primary-300"> <div class="h-1/3 min-h-20 bg-primary-300 relative">
<ff-food-pantry></ff-food-pantry> @if (shownMenu == EInteractionMenuState.Pantry) {
<ff-inventory></ff-inventory> <ff-food-pantry
<ff-button (click)="interact(EChibiInteraction.WakeUp)">{{ (onClose)="closeMenu()"
lang.game.actions.wakeUp (onFoodChosen)="interact(EChibiInteraction.Feed, $event)"
}}</ff-button> ></ff-food-pantry>
}
@if (shownMenu == EInteractionMenuState.Inventory) {
<ff-inventory (onClose)="closeMenu()"></ff-inventory>
}
<div class="flex flex-row gap-5 py-4 container mx-auto">
<ff-button (click)="openInventory()">{{
lang.game.actions.giveItem
}}</ff-button>
<ff-button (click)="openFoodPantry()">{{
lang.game.actions.feed
}}</ff-button>
<ff-button (click)="interact(EChibiInteraction.WakeUp)">{{
lang.game.actions.wakeUp
}}</ff-button>
</div>
</div> </div>
</div> </div>

View File

@@ -1,4 +1,4 @@
import { Component, computed, effect, inject, input, InputSignal, Signal } from '@angular/core'; import { Component, computed, effect, inject, input, InputSignal, signal, Signal, WritableSignal } from '@angular/core';
import { HeaderComponent } from "../../components/ui-elements/header/header.component"; import { HeaderComponent } from "../../components/ui-elements/header/header.component";
import { ERouteKey } from '../../types/route-key'; import { ERouteKey } from '../../types/route-key';
import { Chibi, ChibiId } from '../../types/chibi/chibi'; import { Chibi, ChibiId } from '../../types/chibi/chibi';
@@ -11,6 +11,14 @@ import { EChibiInteraction } from '../../types/chibi/chibi-interaction';
import { IBrain } from '../../logic/chibi-behaviour/brain'; import { IBrain } from '../../logic/chibi-behaviour/brain';
import { BRAIN_MAP } from '../../logic/chibi-behaviour/brain-map'; import { BRAIN_MAP } from '../../logic/chibi-behaviour/brain-map';
import { TranslateableComponent } from '../../components/translateable.component'; import { TranslateableComponent } from '../../components/translateable.component';
import { Food } from '../../types/food';
import { interval } from 'rxjs';
enum EInteractionMenuState {
Neutral,
Pantry,
Inventory
}
@Component({ @Component({
selector: 'ff-interactions', selector: 'ff-interactions',
@@ -25,23 +33,41 @@ export class InteractionsComponent extends TranslateableComponent {
protected readonly chibi: Signal<Chibi> = computed(() => { protected readonly chibi: Signal<Chibi> = computed(() => {
return this.chibiStore.chibis().find((chibi: Chibi) => chibi.id === this.chibiId()) as Chibi; return this.chibiStore.chibis().find((chibi: Chibi) => chibi.id === this.chibiId()) as Chibi;
}); });
protected readonly interactionMenuState: WritableSignal<EInteractionMenuState> = signal(EInteractionMenuState.Neutral);
protected readonly EInteractionMenuState: typeof EInteractionMenuState = EInteractionMenuState;
protected readonly ERouteKey: typeof ERouteKey = ERouteKey; protected readonly ERouteKey: typeof ERouteKey = ERouteKey;
protected readonly EChibiInteraction: typeof EChibiInteraction = EChibiInteraction; protected readonly EChibiInteraction: typeof EChibiInteraction = EChibiInteraction;
private brain!: IBrain; private brain!: IBrain;
constructor() { constructor() {
super();
effect(() => { effect(() => {
if (this.chibi()) { if (this.chibi()) {
this.brain = BRAIN_MAP[this.chibi().name]!; this.brain = BRAIN_MAP[this.chibi().name]!;
} }
}) })
interval(1000).subscribe(() => {
this.brain.exist(this.chibi());
})
} }
public interact(interaction: EChibiInteraction): void { public interact(interaction: EChibiInteraction, item?: Food): void {
console.log(`${interaction} ${this.chibi().name}`); console.log(`${interaction} ${this.chibi().name} and item ${item}`);
this.chibi().state = this.brain.resolveInteraction(this.chibi().state, interaction); this.brain.resolveInteraction(this.chibi(), interaction, item);
}
public openFoodPantry(): void {
this.interactionMenuState.set(EInteractionMenuState.Pantry);
}
public openInventory(): void {
this.interactionMenuState.set(EInteractionMenuState.Inventory);
}
public closeMenu(): void {
this.interactionMenuState.set(EInteractionMenuState.Neutral);
} }
} }

View File

@@ -15,7 +15,9 @@ export const ENG_TRANSLATIONS: Translation = {
foodPantry: {}, foodPantry: {},
inventory: {}, inventory: {},
actions: { actions: {
wakeUp: 'Wake up!' wakeUp: 'Wake up!',
feed: 'Feed',
giveItem: 'Give Item'
} }
} }
} }

View File

@@ -18,6 +18,8 @@ export type Translation = {
inventory: {}, inventory: {},
actions: { actions: {
wakeUp: string; wakeUp: string;
feed: string;
giveItem: string;
} }
} }
} }