mirror of
https://github.com/samnyan/aqua-viewer.git
synced 2026-03-21 17:24:53 -05:00
[ongeki] Basic Gacha implement
This commit is contained in:
parent
91d93e15d9
commit
b8e1acb4d6
|
|
@ -0,0 +1,207 @@
|
|||
.control {
|
||||
z-index: 1500;
|
||||
}
|
||||
|
||||
.gacha-button-group {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.gacha-button-group button {
|
||||
margin: auto;
|
||||
width: 128px;
|
||||
height: 128px;
|
||||
background-color: dimgray;
|
||||
}
|
||||
|
||||
.full-screen {
|
||||
z-index: 1000;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: url("//static.samnyan.icu/ongeki/gameUi/Evt_BattleStart_UI_CMN_Transition_bg.png") no-repeat center;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
/* Wide screen */
|
||||
.card-container {
|
||||
padding: 0 5%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
overflow: scroll;
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
|
||||
.card-container::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.result-card {
|
||||
margin: 30px 20px;
|
||||
width: 30%;
|
||||
height: fit-content;
|
||||
max-width: 200px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.result-card .overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.result-card .overlay img {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
transform: scaleX(-1);
|
||||
opacity: 60%;
|
||||
animation-duration: 3s;
|
||||
animation-name: overlay-glow;
|
||||
animation-iteration-count: infinite;
|
||||
animation-direction: normal;
|
||||
}
|
||||
|
||||
.result-card .overlay-rarity {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.result-card .overlay-rarity img {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
opacity: 0;
|
||||
animation-duration: 2.5s;
|
||||
animation-name: overlay-rarity;
|
||||
animation-iteration-count: infinite;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
|
||||
@keyframes overlay-glow {
|
||||
from {
|
||||
left: -1000%;
|
||||
}
|
||||
|
||||
to {
|
||||
left: 300%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes overlay-rarity {
|
||||
20% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 60%;
|
||||
}
|
||||
|
||||
80% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.flip {
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
|
||||
.card-image {
|
||||
transition: transform 0.8s;
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
|
||||
.card-image .image-back {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
|
||||
.card-image .image-back img {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.image-front, .image-back {
|
||||
-webkit-backface-visibility: hidden;
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
.image-front img, .image-back img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.result-card {
|
||||
margin: 30px 15px;
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.gacha-button-group button {
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-height: 500px) {
|
||||
.result-card {
|
||||
max-width: 110px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 420px) {
|
||||
.result-card {
|
||||
margin: 30px 5px;
|
||||
max-width: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Card animation part
|
||||
*/
|
||||
|
||||
.card-animation-full-screen {
|
||||
z-index: 1200;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#card_animation {
|
||||
margin: auto;
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
#image_loader {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
<mat-card *ngIf="!isStarted" [@control] class="control">
|
||||
<mat-card-content>
|
||||
<h2>Regular Gacha</h2>
|
||||
<p>This is still work in progress. Animation isn't implemented.</p>
|
||||
<div class="gacha-button-group">
|
||||
<button (click)="start(1)" mat-raised-button>Gacha<br>1x</button>
|
||||
<button (click)="start(5)" mat-raised-button>Gacha<br>5x</button>
|
||||
<button (click)="start(11)" mat-raised-button>Gacha<br>11x</button>
|
||||
</div>
|
||||
<p>Detail:<br>
|
||||
R: 70%<br>
|
||||
SR: 25%<br>
|
||||
SSR: 5%
|
||||
</p>
|
||||
<p *ngIf="cardResultList.length > 0">
|
||||
Card data saved in server: {{submitSuccessful}} , failed {{cardResultList.length - submitSuccessful}}
|
||||
</p>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
||||
<div class="full-screen">
|
||||
<div (click)="open()" *ngIf="isStarted" [@control] class="card-container">
|
||||
<div *ngFor="let item of cardResultList" class="result-card" style>
|
||||
<div [class.flip]="item.show" class="card-image">
|
||||
<div class="image-front">
|
||||
<img src="{{assets}}UI_CMN_CardBackSide.png">
|
||||
</div>
|
||||
<div class="image-back">
|
||||
<img src="{{host}}ongeki/card/UI_Card_{{item.card.id|formatNumber:6}}.png">
|
||||
</div>
|
||||
</div>
|
||||
<div class="overlay">
|
||||
<img src="{{assets}}SB_CMN_CardGet_Card_kira.png">
|
||||
</div>
|
||||
<div *ngIf="item.card.rarity == 'SR' && !item.show" class="overlay-rarity">
|
||||
<img src="{{assets}}UI_CMN_CardGlow_SR.png">
|
||||
</div>
|
||||
<div *ngIf="item.card.rarity == 'SSR' && !item.show" class="overlay-rarity">
|
||||
<img src="{{assets}}UI_CMN_CardGlow_SSR.png">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div (click)="open()" class="card-animation-full-screen">
|
||||
<canvas #card_animation height="1920" id="card_animation" width="1080"></canvas>
|
||||
</div>
|
||||
|
||||
<div id="image_loader">
|
||||
<img id="new_card_get" src="{{assets}}UI_CMN_CardGet_NEW.png">
|
||||
<img src="{{assets}}UI_CMN_CardGet_NEW_Right_Eff_00_1.png">
|
||||
<img src="{{assets}}SB_CMN_CardGet_class_N.png">
|
||||
<img src="{{assets}}SB_CMN_CardGet_Title.png">
|
||||
<img src="{{assets}}UI_CMN_CardCharacter_Mask.png">
|
||||
</div>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
import {OngekiCardGachaComponent} from './ongeki-card-gacha.component';
|
||||
|
||||
describe('OngekiCardGachaComponent', () => {
|
||||
let component: OngekiCardGachaComponent;
|
||||
let fixture: ComponentFixture<OngekiCardGachaComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [OngekiCardGachaComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(OngekiCardGachaComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core';
|
||||
import {environment} from '../../../../environments/environment';
|
||||
import {OngekiCard} from '../model/OngekiCard';
|
||||
import {ApiService} from '../../../api.service';
|
||||
import {AuthenticationService} from '../../../auth/authentication.service';
|
||||
import {MessageService} from '../../../message.service';
|
||||
import {NgxIndexedDBService} from 'ngx-indexed-db';
|
||||
import {animate, style, transition, trigger} from '@angular/animations';
|
||||
|
||||
@Component({
|
||||
selector: 'app-ongeki-card-gacha',
|
||||
templateUrl: './ongeki-card-gacha.component.html',
|
||||
styleUrls: ['./ongeki-card-gacha.component.css'],
|
||||
animations: [
|
||||
trigger('control', [
|
||||
transition(':enter', [
|
||||
style({opacity: 0}),
|
||||
animate('1s 0.5s ease-out',
|
||||
style({opacity: 1}))
|
||||
]),
|
||||
transition(':leave', [
|
||||
style({opacity: 1}),
|
||||
animate('1s ease-in',
|
||||
style({opacity: 0}))
|
||||
])
|
||||
])
|
||||
]
|
||||
})
|
||||
export class OngekiCardGachaComponent implements OnInit, AfterViewInit {
|
||||
|
||||
@ViewChild('card_animation', {static: true})
|
||||
canvas: ElementRef<HTMLCanvasElement>;
|
||||
|
||||
host = environment.assetsHost;
|
||||
assets = environment.assetsHost + 'ongeki/gameUi/';
|
||||
|
||||
isStarted = false;
|
||||
|
||||
rarity: number[] = [];
|
||||
rList: OngekiCard[] = [];
|
||||
srList: OngekiCard[] = [];
|
||||
ssrList: OngekiCard[] = [];
|
||||
|
||||
cardResultList: CardResult[] = [];
|
||||
currentShowedIndex = 0;
|
||||
|
||||
submitSuccessful = 0;
|
||||
|
||||
constructor(
|
||||
private api: ApiService,
|
||||
private auth: AuthenticationService,
|
||||
private messageService: MessageService,
|
||||
private dbService: NgxIndexedDBService
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.rarity = Array(70).fill(1);
|
||||
this.rarity = this.rarity.concat(Array(25).fill(2));
|
||||
this.rarity = this.rarity.concat(Array(5).fill(3));
|
||||
this.dbService.getAll<OngekiCard>('ongekiCard').then(
|
||||
x => {
|
||||
x.forEach(y => {
|
||||
switch (y.rarity) {
|
||||
case 'R':
|
||||
this.rList.push(y);
|
||||
break;
|
||||
case 'SR':
|
||||
this.srList.push(y);
|
||||
break;
|
||||
case 'SSR':
|
||||
this.ssrList.push(y);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
// const ctx = this.canvas.nativeElement.getContext('2d');
|
||||
//
|
||||
// const img = new Image();
|
||||
// img.onload = () => ctx.drawImage(img, 0, 0);
|
||||
// img.src = this.assets + 'UI_CMN_CardGet_NEW.png';
|
||||
}
|
||||
|
||||
start(count: number) {
|
||||
this.cardResultList = [];
|
||||
this.currentShowedIndex = 0;
|
||||
this.isStarted = true;
|
||||
this.submitSuccessful = 0;
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const rarity = this.rarity[Math.floor(Math.random() * 99)];
|
||||
console.log('rarity: ' + rarity);
|
||||
let card;
|
||||
switch (rarity) {
|
||||
case 1:
|
||||
card = this.rList[Math.floor(Math.random() * this.rList.length)];
|
||||
break;
|
||||
case 2:
|
||||
card = this.srList[Math.floor(Math.random() * this.srList.length)];
|
||||
break;
|
||||
case 3:
|
||||
card = this.ssrList[Math.floor(Math.random() * this.ssrList.length)];
|
||||
break;
|
||||
}
|
||||
console.log('card: ' + JSON.stringify(card));
|
||||
this.cardResultList.push({
|
||||
show: false,
|
||||
card
|
||||
});
|
||||
}
|
||||
this.submitCardData();
|
||||
return;
|
||||
}
|
||||
|
||||
open() {
|
||||
console.log('clicked');
|
||||
if (this.currentShowedIndex < this.cardResultList.length) {
|
||||
const card = this.cardResultList[this.currentShowedIndex];
|
||||
card.show = true;
|
||||
this.currentShowedIndex = this.currentShowedIndex + 1;
|
||||
} else {
|
||||
this.isStarted = false;
|
||||
}
|
||||
}
|
||||
|
||||
submitCardData() {
|
||||
const aimeId = this.auth.currentUserValue.extId;
|
||||
this.cardResultList.forEach(x => {
|
||||
this.api.post('api/game/ongeki/card', {
|
||||
aimeId,
|
||||
cardId: x.card.id
|
||||
}).subscribe(
|
||||
data => {
|
||||
this.submitSuccessful = this.submitSuccessful + 1;
|
||||
return;
|
||||
},
|
||||
error => this.messageService.notice(error)
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
interface CardResult {
|
||||
show: boolean;
|
||||
card: OngekiCard;
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
</p>
|
||||
<div class="action">
|
||||
<button mat-button routerLink="all">Show All Cards</button>
|
||||
<!-- <button mat-button>Gacha</button>-->
|
||||
<button mat-button routerLink="gacha">Gacha(Work in progress)</button>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import {OngekiRatingComponent} from './ongeki-rating/ongeki-rating.component';
|
|||
import {ToLevelDecimalPipe} from './util/to-level-decimal.pipe';
|
||||
import {ToBattleSpritePipe} from './util/to-battle-sprite.pipe';
|
||||
import {ToTechSpritePipe} from './util/to-tech-sprite.pipe';
|
||||
import {OngekiCardGachaComponent} from './ongeki-card-gacha/ongeki-card-gacha.component';
|
||||
|
||||
|
||||
@NgModule({
|
||||
|
|
@ -31,7 +32,8 @@ import {ToTechSpritePipe} from './util/to-tech-sprite.pipe';
|
|||
OngekiRatingComponent,
|
||||
ToLevelDecimalPipe,
|
||||
ToBattleSpritePipe,
|
||||
ToTechSpritePipe
|
||||
ToTechSpritePipe,
|
||||
OngekiCardGachaComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {OngekiRecentComponent} from './ongeki-recent/ongeki-recent.component';
|
|||
import {OngekiSongListComponent} from './ongeki-song-list/ongeki-song-list.component';
|
||||
import {OngekiBattlePointComponent} from './ongeki-battle-point/ongeki-battle-point.component';
|
||||
import {OngekiRatingComponent} from './ongeki-rating/ongeki-rating.component';
|
||||
import {OngekiCardGachaComponent} from './ongeki-card-gacha/ongeki-card-gacha.component';
|
||||
|
||||
|
||||
const routes: Routes = [
|
||||
|
|
@ -16,6 +17,7 @@ const routes: Routes = [
|
|||
{path: 'rating', component: OngekiRatingComponent},
|
||||
{path: 'card', component: OngekiCardComponent},
|
||||
{path: 'card/all', component: OngekiCardListComponent},
|
||||
{path: 'card/gacha', component: OngekiCardGachaComponent},
|
||||
];
|
||||
|
||||
export const OngekiRoutes = RouterModule.forChild(routes);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user