item + bgm
This commit is contained in:
parent
f43d4314e9
commit
dd82b978ef
BIN
assets/M1_BGM_Ground_Play.mp3
Normal file
BIN
assets/M1_BGM_Ground_Play.mp3
Normal file
Binary file not shown.
BIN
assets/M1_BGM_Ground_PlayHurry.mp3
Normal file
BIN
assets/M1_BGM_Ground_PlayHurry.mp3
Normal file
Binary file not shown.
2
assets/SMB1 Sounds/CharaMario_Arwing_move.txt
Normal file
2
assets/SMB1 Sounds/CharaMario_Arwing_move.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
loop start: 43778 samples (0:01.368 seconds)
|
||||||
|
loop end: 66338 samples (0:02.073 seconds)
|
BIN
assets/SMB1 Sounds/CharaMario_Arwing_move.wav
Normal file
BIN
assets/SMB1 Sounds/CharaMario_Arwing_move.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/CharaMario_Common_appeal_5turn.wav
Normal file
BIN
assets/SMB1 Sounds/CharaMario_Common_appeal_5turn.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/CharaMario_Fit_Wiibo_Crounch.wav
Normal file
BIN
assets/SMB1 Sounds/CharaMario_Fit_Wiibo_Crounch.wav
Normal file
Binary file not shown.
2
assets/SMB1 Sounds/CharaMario_MarioKart_engine.txt
Normal file
2
assets/SMB1 Sounds/CharaMario_MarioKart_engine.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
loop start: 0 samples (0:00.000 seconds)
|
||||||
|
loop end: 2000 samples (0:00.063 seconds)
|
BIN
assets/SMB1 Sounds/CharaMario_MarioKart_engine.wav
Normal file
BIN
assets/SMB1 Sounds/CharaMario_MarioKart_engine.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/CharaMario_Splatoon_Swim.wav
Normal file
BIN
assets/SMB1 Sounds/CharaMario_Splatoon_Swim.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/CharaMario_Splatoon_ToHuman.wav
Normal file
BIN
assets/SMB1 Sounds/CharaMario_Splatoon_ToHuman.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/CharaMario_Splatoon_ToSquid.wav
Normal file
BIN
assets/SMB1 Sounds/CharaMario_Splatoon_ToSquid.wav
Normal file
Binary file not shown.
2
assets/SMB1 Sounds/Charamario_DonkeyKongJr_walk1.txt
Normal file
2
assets/SMB1 Sounds/Charamario_DonkeyKongJr_walk1.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
loop start: 0 samples (0:00.000 seconds)
|
||||||
|
loop end: 34616 samples (0:01.082 seconds)
|
BIN
assets/SMB1 Sounds/Charamario_DonkeyKongJr_walk1.wav
Normal file
BIN
assets/SMB1 Sounds/Charamario_DonkeyKongJr_walk1.wav
Normal file
Binary file not shown.
2
assets/SMB1 Sounds/Charamario_DonkeyKongJr_walk2.txt
Normal file
2
assets/SMB1 Sounds/Charamario_DonkeyKongJr_walk2.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
loop start: 0 samples (0:00.000 seconds)
|
||||||
|
loop end: 34616 samples (0:01.082 seconds)
|
BIN
assets/SMB1 Sounds/Charamario_DonkeyKongJr_walk2.wav
Normal file
BIN
assets/SMB1 Sounds/Charamario_DonkeyKongJr_walk2.wav
Normal file
Binary file not shown.
2
assets/SMB1 Sounds/Charamario_MarioOriginal_walk1.txt
Normal file
2
assets/SMB1 Sounds/Charamario_MarioOriginal_walk1.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
loop start: 9226 samples (0:00.288 seconds)
|
||||||
|
loop end: 35018 samples (0:01.094 seconds)
|
BIN
assets/SMB1 Sounds/Charamario_MarioOriginal_walk1.wav
Normal file
BIN
assets/SMB1 Sounds/Charamario_MarioOriginal_walk1.wav
Normal file
Binary file not shown.
2
assets/SMB1 Sounds/Charamario_MarioOriginal_walk2.txt
Normal file
2
assets/SMB1 Sounds/Charamario_MarioOriginal_walk2.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
loop start: 0 samples (0:00.000 seconds)
|
||||||
|
loop end: 26050 samples (0:00.814 seconds)
|
BIN
assets/SMB1 Sounds/Charamario_MarioOriginal_walk2.wav
Normal file
BIN
assets/SMB1 Sounds/Charamario_MarioOriginal_walk2.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_BigMarioJump.wav
Normal file
BIN
assets/SMB1 Sounds/M1_BigMarioJump.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_BreakBlock.wav
Normal file
BIN
assets/SMB1 Sounds/M1_BreakBlock.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_Cannon.wav
Normal file
BIN
assets/SMB1 Sounds/M1_Cannon.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_Cannon_fast.wav
Normal file
BIN
assets/SMB1 Sounds/M1_Cannon_fast.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_CastleClearFanfare.wav
Normal file
BIN
assets/SMB1 Sounds/M1_CastleClearFanfare.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_Coin.wav
Normal file
BIN
assets/SMB1 Sounds/M1_Coin.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_CourseClearFanfare.wav
Normal file
BIN
assets/SMB1 Sounds/M1_CourseClearFanfare.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_Fire.wav
Normal file
BIN
assets/SMB1 Sounds/M1_Fire.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_FireBall.wav
Normal file
BIN
assets/SMB1 Sounds/M1_FireBall.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_FireLong.wav
Normal file
BIN
assets/SMB1 Sounds/M1_FireLong.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_FlagScoreUp.wav
Normal file
BIN
assets/SMB1 Sounds/M1_FlagScoreUp.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_HEN_JUMP.wav
Normal file
BIN
assets/SMB1 Sounds/M1_HEN_JUMP.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_HEN_JUMP_FUWA.wav
Normal file
BIN
assets/SMB1 Sounds/M1_HEN_JUMP_FUWA.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_HEN_LARGE.wav
Normal file
BIN
assets/SMB1 Sounds/M1_HEN_LARGE.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_HitFloor.wav
Normal file
BIN
assets/SMB1 Sounds/M1_HitFloor.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_HurryUpFanfare.wav
Normal file
BIN
assets/SMB1 Sounds/M1_HurryUpFanfare.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_KickNokonoko.wav
Normal file
BIN
assets/SMB1 Sounds/M1_KickNokonoko.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_OneUp.wav
Normal file
BIN
assets/SMB1 Sounds/M1_OneUp.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_Pose.wav
Normal file
BIN
assets/SMB1 Sounds/M1_Pose.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_PowerDown.wav
Normal file
BIN
assets/SMB1 Sounds/M1_PowerDown.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_PowerUp.wav
Normal file
BIN
assets/SMB1 Sounds/M1_PowerUp.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_PowerUpItemAppear.wav
Normal file
BIN
assets/SMB1 Sounds/M1_PowerUpItemAppear.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_SmallMarioJump.wav
Normal file
BIN
assets/SMB1 Sounds/M1_SmallMarioJump.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/M1_StepNokonoko.wav
Normal file
BIN
assets/SMB1 Sounds/M1_StepNokonoko.wav
Normal file
Binary file not shown.
2
assets/SMB1 Sounds/NewMario2_GoldEffect.txt
Normal file
2
assets/SMB1 Sounds/NewMario2_GoldEffect.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
loop start: 0 samples (0:00.000 seconds)
|
||||||
|
loop end: 80563 samples (0:02.518 seconds)
|
BIN
assets/SMB1 Sounds/NewMario2_GoldEffect.wav
Normal file
BIN
assets/SMB1 Sounds/NewMario2_GoldEffect.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/SE_KILLER_POWERUP2.wav
Normal file
BIN
assets/SMB1 Sounds/SE_KILLER_POWERUP2.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/SE_MegaPowerup.wav
Normal file
BIN
assets/SMB1 Sounds/SE_MegaPowerup.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/SE_chargeshot.wav
Normal file
BIN
assets/SMB1 Sounds/SE_chargeshot.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/SePvGrabHeavy_InWater.wav
Normal file
BIN
assets/SMB1 Sounds/SePvGrabHeavy_InWater.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/SePvWaitHappy_InWater.wav
Normal file
BIN
assets/SMB1 Sounds/SePvWaitHappy_InWater.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/charge_ready.wav
Normal file
BIN
assets/SMB1 Sounds/charge_ready.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/firecharge_kari3.wav
Normal file
BIN
assets/SMB1 Sounds/firecharge_kari3.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/muon_2sec.wav
Normal file
BIN
assets/SMB1 Sounds/muon_2sec.wav
Normal file
Binary file not shown.
BIN
assets/SMB1 Sounds/swim_kinopiko.wav
Normal file
BIN
assets/SMB1 Sounds/swim_kinopiko.wav
Normal file
Binary file not shown.
|
@ -9,6 +9,9 @@ function preloadAssets() {
|
||||||
spriteSheets.characters = loadImage("assets/Mario-Character+Item.png");
|
spriteSheets.characters = loadImage("assets/Mario-Character+Item.png");
|
||||||
spriteSheets.specialweapon = loadImage("assets/Mario-Enemy.png");
|
spriteSheets.specialweapon = loadImage("assets/Mario-Enemy.png");
|
||||||
spriteSheets.tileset = loadImage("assets/Mario-Tileset.png");
|
spriteSheets.tileset = loadImage("assets/Mario-Tileset.png");
|
||||||
|
|
||||||
|
soundFormats('mp3', 'wav');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function sliceAssets() {
|
function sliceAssets() {
|
||||||
|
@ -42,6 +45,7 @@ function sliceAssets() {
|
||||||
const mj = createImage(cw,ch); mj.copy(src,215,98, cw,ch,0,0, cw,ch);
|
const mj = createImage(cw,ch); mj.copy(src,215,98, cw,ch,0,0, cw,ch);
|
||||||
const ma = createImage(cw,ch); ma.copy(src,627,98, cw,ch,0,0, cw,ch);
|
const ma = createImage(cw,ch); ma.copy(src,627,98, cw,ch,0,0, cw,ch);
|
||||||
[mi,mw1,mw2,mw3,mj,ma].forEach(img=>applyChromaKey(img));
|
[mi,mw1,mw2,mw3,mj,ma].forEach(img=>applyChromaKey(img));
|
||||||
|
|
||||||
P1imgs = { idle:[mi], walk:[mw1,mw2,mw3], jump:[mj], shoot:[ma] };
|
P1imgs = { idle:[mi], walk:[mw1,mw2,mw3], jump:[mj], shoot:[ma] };
|
||||||
|
|
||||||
// 5) 캐릭터 프레임 슬라이스 (Luigi)
|
// 5) 캐릭터 프레임 슬라이스 (Luigi)
|
||||||
|
@ -52,6 +56,7 @@ function sliceAssets() {
|
||||||
const lj = createImage(cw,ch); lj.copy(src,215,629,cw,ch,0,0,cw,ch);
|
const lj = createImage(cw,ch); lj.copy(src,215,629,cw,ch,0,0,cw,ch);
|
||||||
const la = createImage(cw,ch); la.copy(src,627,629,cw,ch,0,0,cw,ch);
|
const la = createImage(cw,ch); la.copy(src,627,629,cw,ch,0,0,cw,ch);
|
||||||
[li,lw1,lw2,lw3,lj,la].forEach(img=>applyChromaKey(img));
|
[li,lw1,lw2,lw3,lj,la].forEach(img=>applyChromaKey(img));
|
||||||
|
|
||||||
P2imgs = { idle:[li], walk:[lw1,lw2,lw3], jump:[lj], shoot:[la] };
|
P2imgs = { idle:[li], walk:[lw1,lw2,lw3], jump:[lj], shoot:[la] };
|
||||||
|
|
||||||
// 6) 아이템 및 특수 투사체 프레임
|
// 6) 아이템 및 특수 투사체 프레임
|
||||||
|
@ -60,13 +65,13 @@ function sliceAssets() {
|
||||||
const mush = createImage(ow,oh); mush.copy(src,1,2126,ow,oh,0,0,ow,oh);
|
const mush = createImage(ow,oh); mush.copy(src,1,2126,ow,oh,0,0,ow,oh);
|
||||||
const bombadd = createImage(ow,oh); bombadd.copy(spsrc, 39, 117, ow, oh, 0, 0, ow, oh);
|
const bombadd = createImage(ow,oh); bombadd.copy(spsrc, 39, 117, ow, oh, 0, 0, ow, oh);
|
||||||
const poison= createImage(ow,oh); poison.copy(src,1,2143,ow,oh,0,0,ow,oh);
|
const poison= createImage(ow,oh); poison.copy(src,1,2143,ow,oh,0,0,ow,oh);
|
||||||
const giant = createImage(2*ow,2*oh); giant.copy(src,35,2143,2*ow,2*oh,0,0,2*ow,2*oh);
|
const giant = createImage(ow,oh); giant.copy(src,52,2126,ow,oh,0,0,ow,oh);
|
||||||
const fire = createImage(ow/2,oh/2); fire.copy(src,101,2177,ow/2,oh/2,0,0,ow/2,oh/2);
|
const fire = createImage(ow/2,oh/2); fire.copy(src,101,2177,ow/2,oh/2,0,0,ow/2,oh/2);
|
||||||
const fireinch = createImage(ow, oh); fireinch.copy(spsrc, 601, 751, ow, oh, 0, 0, ow, oh);
|
const fireench = createImage(ow, oh); fireench.copy(spsrc, 601, 751, ow, oh, 0, 0, ow, oh);
|
||||||
const bomb = createImage(ow,oh); bomb.copy(src,194,2143,ow,oh,0,0,ow,oh);
|
const bomb = createImage(ow,oh); bomb.copy(src,194,2143,ow,oh,0,0,ow,oh);
|
||||||
const bm = createImage(4*ow,4*oh); bm.copy(spsrc,127,356,4*ow,4*oh,0,0,4*ow,4*oh);
|
const bm = createImage(4*ow,4*oh); bm.copy(spsrc,127,356,4*ow,4*oh,0,0,4*ow,4*oh);
|
||||||
const beffect = createImage(1.5*ow, 1.5*oh); beffect.copy(spsrc, 604, 413, 1.5*ow, 1.5*oh, 0, 0, 1.5*ow, 1.5*oh);
|
const beffect = createImage(1.5*ow, 1.5*oh); beffect.copy(spsrc, 604, 413, 1.5*ow, 1.5*oh, 0, 0, 1.5*ow, 1.5*oh);
|
||||||
[mush,bombadd,poison,giant,fire,fireinch,bomb,bm, beffect].forEach(img=>applyChromaKey(img));
|
[mush,bombadd,poison,giant,fire,fireench,bomb,bm, beffect].forEach(img=>applyChromaKey(img));
|
||||||
function applyColorFilter(img, delta) {
|
function applyColorFilter(img, delta) {
|
||||||
// img.pixels 에 접근해 기존 색상을 유지하며 R 증가, G 감소
|
// img.pixels 에 접근해 기존 색상을 유지하며 R 증가, G 감소
|
||||||
img.loadPixels();
|
img.loadPixels();
|
||||||
|
@ -91,7 +96,7 @@ function sliceAssets() {
|
||||||
applyColorFilter(bombWarn, {r: 150, g: 100, b:200} );
|
applyColorFilter(bombWarn, {r: 150, g: 100, b:200} );
|
||||||
|
|
||||||
itemimgs = {
|
itemimgs = {
|
||||||
mush:[mush], poison:[poison], giant:[giant], bombadd:[bombadd], fire_inchant:[fireinch],
|
mush:[mush], poison:[poison], giant:[giant], bombadd:[bombadd], fire_enchant:[fireench],
|
||||||
fire:[fire], bomb:[bomb], bigmissile:[bm], bomb_warning:[bombWarn], explosion:[beffect]
|
fire:[fire], bomb:[bomb], bigmissile:[bm], bomb_warning:[bombWarn], explosion:[beffect]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<script src="imageAsset.js"></script>
|
<script src="imageAsset.js"></script>
|
||||||
|
<script src="soundAsset.js"></script>
|
||||||
<script defer src="sketch.js"></script>
|
<script defer src="sketch.js"></script>
|
||||||
|
|
||||||
<body></body>
|
<body></body>
|
||||||
|
|
323
sketch.js
323
sketch.js
|
@ -7,7 +7,7 @@ let controlsP1, controlsP2;
|
||||||
let breakEffects = [];
|
let breakEffects = [];
|
||||||
let items = [];
|
let items = [];
|
||||||
let nextItemFrame = 0;
|
let nextItemFrame = 0;
|
||||||
const TILE_H = 32;
|
const TILE_SIZE = 32;
|
||||||
const mapLayout = [
|
const mapLayout = [
|
||||||
// row 0 (y = groundY[0]–16): gb1 | question | gb1
|
// row 0 (y = groundY[0]–16): gb1 | question | gb1
|
||||||
[
|
[
|
||||||
|
@ -43,12 +43,15 @@ const mapLayout = [
|
||||||
|
|
||||||
function preload() {
|
function preload() {
|
||||||
preloadAssets();
|
preloadAssets();
|
||||||
|
preloadSounds()
|
||||||
}
|
}
|
||||||
|
|
||||||
function setup() {
|
function setup() {
|
||||||
createCanvas(800, 600);
|
createCanvas(800, 600);
|
||||||
sliceAssets();
|
sliceAssets();
|
||||||
|
bgm.bgmGround.setLoop(true);
|
||||||
|
bgm.bgmGround.setVolume(0.5);
|
||||||
|
bgm.bgmGround.loop();
|
||||||
controlsP1 = {
|
controlsP1 = {
|
||||||
left: 'ArrowLeft', right: 'ArrowRight',
|
left: 'ArrowLeft', right: 'ArrowRight',
|
||||||
jump: 'ArrowUp', attack: '[', bomb: ']', down: 'ArrowDown'
|
jump: 'ArrowUp', attack: '[', bomb: ']', down: 'ArrowDown'
|
||||||
|
@ -62,10 +65,10 @@ function setup() {
|
||||||
player2 = new Player(200, 100, P2imgs, controlsP2);
|
player2 = new Player(200, 100, P2imgs, controlsP2);
|
||||||
|
|
||||||
for (let row = 0; row < groundY.length; row++) {
|
for (let row = 0; row < groundY.length; row++) {
|
||||||
const y = groundY[row] - TILE_H;
|
const y = groundY[row] - TILE_SIZE;
|
||||||
for (let seg of mapLayout[row]) {
|
for (let seg of mapLayout[row]) {
|
||||||
if (!seg.type) continue; // null인 구간은 건너뛰고
|
if (!seg.type) continue; // null인 구간은 건너뛰고
|
||||||
for (let x = seg.x1; x <= seg.x2; x += TILE_H) {
|
for (let x = seg.x1; x <= seg.x2; x += TILE_SIZE) {
|
||||||
tiles.push(new Tile(x, y, seg.type));
|
tiles.push(new Tile(x, y, seg.type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,6 +83,8 @@ function draw() {
|
||||||
player1.update(); player1.draw();
|
player1.update(); player1.draw();
|
||||||
player2.update(); player2.draw();
|
player2.update(); player2.draw();
|
||||||
|
|
||||||
|
|
||||||
|
randomSpawnItem();
|
||||||
handleProjectiles();
|
handleProjectiles();
|
||||||
handleBombs();
|
handleBombs();
|
||||||
handleSpecialProjectiles();
|
handleSpecialProjectiles();
|
||||||
|
@ -150,7 +155,7 @@ class BreakEffect {
|
||||||
draw() {
|
draw() {
|
||||||
if (!this.active) return;
|
if (!this.active) return;
|
||||||
const img = this.frames[this.currentFrame];
|
const img = this.frames[this.currentFrame];
|
||||||
image(img, this.x, this.y, TILE_H, TILE_H);
|
image(img, this.x, this.y, TILE_SIZE, TILE_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class Background {
|
class Background {
|
||||||
|
@ -204,15 +209,71 @@ class Player {
|
||||||
this.facing = "right";
|
this.facing = "right";
|
||||||
this.state = "idle";
|
this.state = "idle";
|
||||||
this.frame = 0;
|
this.frame = 0;
|
||||||
|
this._animTimer = 0;
|
||||||
|
this._animInterval = 6;
|
||||||
this.attackTimer = 0;
|
this.attackTimer = 0;
|
||||||
this.dropping = false; // drop-through state
|
this.dropping = false; // drop-through state
|
||||||
this.dropRowY = null; // current tile to drop through
|
this.dropRowY = null; // current tile to drop through
|
||||||
this.currentTileY = null; // current tile Y position for drop-through
|
this.currentTileY = null; // current tile Y position for drop-through
|
||||||
|
|
||||||
|
this.itemCount = 0;
|
||||||
|
this.bombCount = 10;
|
||||||
|
this.bigMissileCount = 0;
|
||||||
|
|
||||||
|
// 효과 타이머들 (frame 단위)
|
||||||
|
this.fireTimer = 0;
|
||||||
|
this.poisonTimer = 0;
|
||||||
|
this.giantTimer = 0;
|
||||||
|
|
||||||
|
this.deathCount = 5; // 남은 목숨
|
||||||
|
this.invulnerable = false; // 무적 플래그
|
||||||
|
this.invTimer = 0; // 무적 남은 프레임
|
||||||
|
}
|
||||||
|
|
||||||
|
applyItem(type) {
|
||||||
|
this.itemCount++;
|
||||||
|
if (this.itemCount % 2 === 0) {
|
||||||
|
this.bigMissileCount++;
|
||||||
|
}
|
||||||
|
switch(type) {
|
||||||
|
case 'mush':
|
||||||
|
this.fireTimer = 8 * 60; // 8초간 (60fps 가정)
|
||||||
|
break;
|
||||||
|
case 'poison':
|
||||||
|
this.poisonTimer = 3 * 60; // 3초간
|
||||||
|
break;
|
||||||
|
case 'giant':
|
||||||
|
this.giantTimer = 5 * 60; // 5초간
|
||||||
|
break;
|
||||||
|
case 'bombadd':
|
||||||
|
this.bombCount += 5;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
|
// (1) poison 효과: 이동 불가
|
||||||
|
if (this.poisonTimer > 0) {
|
||||||
|
this.poisonTimer--;
|
||||||
|
// 이동 벡터 강제 0
|
||||||
|
this.vx = this.vy = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (2) giant 효과: 크기 및 공격 크기 조정
|
||||||
|
if (this.giantTimer > 0) {
|
||||||
|
this.giantTimer--;
|
||||||
|
this.width = 64; this.height = 64;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 기본 크기로 복원
|
||||||
|
this.width = 32; this.height = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (3) mush 효과: fire 인챈트
|
||||||
|
if (this.fireTimer > 0) {
|
||||||
|
this.fireTimer--;
|
||||||
|
}
|
||||||
// Bomb charging
|
// Bomb charging
|
||||||
if (this.keys[this.controls.bomb] && this.bombHoldStartTime !== null) {
|
if (this.keys[this.controls.bomb] && this.bombHoldStartTime !== null) {
|
||||||
this.chargeTime = min(millis() - this.bombHoldStartTime, this.maxCharge);
|
this.chargeTime = min(millis() - this.bombHoldStartTime, this.maxCharge);
|
||||||
|
@ -272,13 +333,27 @@ class Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (landed) {
|
if (landed) {
|
||||||
if (this.attackTimer === 0) this.state = 'idle';
|
if (this.attackTimer === 0) {
|
||||||
} else {
|
if(inputVX !== 0) {
|
||||||
|
this.state = 'walk'
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
this.state = 'idle';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
this.y = nextY;
|
this.y = nextY;
|
||||||
this.onGround = false;
|
this.onGround = false;
|
||||||
if (this.attackTimer === 0) this.state = 'jump';
|
if (this.attackTimer === 0) this.state = 'jump';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.state === 'walk') {
|
||||||
|
this._animTimer++;
|
||||||
|
} else {
|
||||||
|
this._animTimer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// DOWN 키로 현재 플랫폼 행 통과
|
// DOWN 키로 현재 플랫폼 행 통과
|
||||||
if (
|
if (
|
||||||
this.keys[this.controls.down] &&
|
this.keys[this.controls.down] &&
|
||||||
|
@ -317,8 +392,20 @@ class Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
respawn() {
|
respawn() {
|
||||||
this.x = 100; this.y = 100;
|
// 목숨 하나 감소
|
||||||
this.vx = this.vy = this.knockbackVX = 0;
|
this.deathCount--;
|
||||||
|
if (this.deathCount > 0) {
|
||||||
|
// 맵 가운데 상단으로 리셋
|
||||||
|
this.x = width/2 - this.width/2;
|
||||||
|
this.y = 0;
|
||||||
|
this.vx = this.vy = this.knockbackVX = 0;
|
||||||
|
// 0.5초 무적
|
||||||
|
this.invulnerable = true;
|
||||||
|
this.invTimer = 30; // 60fps 기준 30프레임
|
||||||
|
} else {
|
||||||
|
// 목숨 모두 소진 → 게임 오버
|
||||||
|
gameOver = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jump() {
|
jump() {
|
||||||
|
@ -331,8 +418,8 @@ class Player {
|
||||||
shoot() {
|
shoot() {
|
||||||
const spawnX = this.facing === 'right' ? this.x + this.width : this.x - 16;
|
const spawnX = this.facing === 'right' ? this.x + this.width : this.x - 16;
|
||||||
const spawnY = this.y + this.height/2;
|
const spawnY = this.y + this.height/2;
|
||||||
const dir = this.facing === 'right' ? 20 : -20;
|
const dir = this.facing === 'right' ? 15 : -15;
|
||||||
projectiles.push(new Projectile(spawnX, spawnY, dir));
|
projectiles.push(new Projectile(spawnX, spawnY, dir, this.fireTimer > 0, this.giantTimer > 0));
|
||||||
this.state = 'shoot';
|
this.state = 'shoot';
|
||||||
this.attackTimer = 10;
|
this.attackTimer = 10;
|
||||||
this.frame = 0;
|
this.frame = 0;
|
||||||
|
@ -340,10 +427,14 @@ class Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
dropBomb() {
|
dropBomb() {
|
||||||
|
if (this.bombCount <= 0) return;
|
||||||
const bx = this.facing === 'right' ? this.x + this.width : this.x - 32;
|
const bx = this.facing === 'right' ? this.x + this.width : this.x - 32;
|
||||||
const by = this.y - 8;
|
const by = this.y - 8;
|
||||||
const v_bomb = this.facing === 'right' ? 5 : -5;
|
const normalizedV = 1 + map(this.chargeTime, 0, 1000, 0, 1);
|
||||||
bombs.push(new Bomb(bx, by, v_bomb));
|
const v_bombx = this.facing === 'right' ? 5 * normalizedV : -5 * normalizedV;
|
||||||
|
const v_bomby = - 2 * (normalizedV);
|
||||||
|
bombs.push(new Bomb(bx, by, v_bombx, v_bomby));
|
||||||
|
this.bombCount--;
|
||||||
this.state = 'shoot';
|
this.state = 'shoot';
|
||||||
this.attackTimer = 10;
|
this.attackTimer = 10;
|
||||||
this.frame = 0;
|
this.frame = 0;
|
||||||
|
@ -382,6 +473,13 @@ class Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
draw() {
|
draw() {
|
||||||
|
if (this.poisonTimer > 0) {
|
||||||
|
// R=255, G=B=150 정도: 연한 붉은빛으로
|
||||||
|
tint(200, 100, 255);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
noTint();
|
||||||
|
}
|
||||||
// charge gauge 그리기
|
// charge gauge 그리기
|
||||||
if (this.chargeTime > 0) {
|
if (this.chargeTime > 0) {
|
||||||
// 최대 너비를 this.width(32px)로 매핑
|
// 최대 너비를 this.width(32px)로 매핑
|
||||||
|
@ -395,6 +493,15 @@ class Player {
|
||||||
rect(this.x, this.y - 10, w, 5);
|
rect(this.x, this.y - 10, w, 5);
|
||||||
noFill();
|
noFill();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.state === 'walk') {
|
||||||
|
const seq = this.imgSet.walk; // [walk1, walk2, walk3]
|
||||||
|
this.frame = Math.floor(this._animTimer / this._animInterval) % seq.length;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// walk 외 상태는 0번 프레임 고정 (idle 이나 shoot 등)
|
||||||
|
this.frame = 0;
|
||||||
|
}
|
||||||
const img = this.imgSet[this.state][this.frame];
|
const img = this.imgSet[this.state][this.frame];
|
||||||
push();
|
push();
|
||||||
if (this.facing === 'left') {
|
if (this.facing === 'left') {
|
||||||
|
@ -405,36 +512,77 @@ class Player {
|
||||||
image(img, this.x, this.y, this.width, this.height);
|
image(img, this.x, this.y, this.width, this.height);
|
||||||
}
|
}
|
||||||
pop();
|
pop();
|
||||||
|
noTint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Projectile {
|
class Projectile {
|
||||||
constructor(x, y, vx, w=8, h=8) {
|
constructor(x, y, vx, enchanted = false, isgiant = false) {
|
||||||
this.x = x; this.y = y;
|
this.x = x;
|
||||||
this.vx = vx; this.width = w; this.height = h;
|
this.y = y;
|
||||||
this.spawnTime = millis(); this.lifetime = 10000;
|
this.vx = vx;
|
||||||
|
this.enchanted = enchanted;
|
||||||
|
this.isgiant = isgiant;
|
||||||
|
|
||||||
|
// 크기 세팅
|
||||||
|
if (enchanted) {
|
||||||
|
this.width = 16;
|
||||||
|
this.height = 16;
|
||||||
|
this.knockbackFactor = 1.0; // vx * knockbackFactor 계산 → 사실상 2배
|
||||||
|
this.sprite = itemimgs.fire_enchant[0];
|
||||||
|
}
|
||||||
|
else if(isgiant) {
|
||||||
|
this.width = 16;
|
||||||
|
this.height = 16;
|
||||||
|
this.knockbackFactor = 0.5;
|
||||||
|
this.sprite = itemimgs.fire[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
this.width = 8;
|
||||||
|
this.height = 8;
|
||||||
|
this.knockbackFactor = 0.5;
|
||||||
|
this.sprite = itemimgs.fire[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.spawnTime = millis();
|
||||||
|
this.lifetime = 10000;
|
||||||
this.shouldDestroy = false;
|
this.shouldDestroy = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
update(targets) {
|
update(targets) {
|
||||||
|
// 이동
|
||||||
this.x += this.vx;
|
this.x += this.vx;
|
||||||
|
|
||||||
|
// 충돌 & 넉백
|
||||||
for (const t of targets) {
|
for (const t of targets) {
|
||||||
if (this.hits(t)) {
|
if (!this.shouldDestroy && this.hits(t)) {
|
||||||
t.knockbackVX += this.vx * 0.5;
|
if (t.giantTimer > 0) {
|
||||||
this.shouldDestroy = true;
|
// giant 상태면 넉백 없이 그냥 삭제
|
||||||
|
this.shouldDestroy = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// giant 상태 아니면 넉백
|
||||||
|
t.knockbackVX += this.vx * this.knockbackFactor;
|
||||||
|
this.shouldDestroy = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 수명 검사
|
||||||
if (millis() - this.spawnTime > this.lifetime) {
|
if (millis() - this.spawnTime > this.lifetime) {
|
||||||
this.shouldDestroy = true;
|
this.shouldDestroy = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
draw() {
|
draw() {
|
||||||
image(itemimgs.fire[0], this.x, this.y, this.width * 2, this.height * 2);
|
image(
|
||||||
|
this.sprite,
|
||||||
|
this.x, this.y,
|
||||||
|
this.width, this.height
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
|
@ -443,9 +591,9 @@ class Projectile {
|
||||||
|
|
||||||
hits(target) {
|
hits(target) {
|
||||||
return (
|
return (
|
||||||
this.x < target.x + target.width &&
|
this.x < target.x + target.width &&
|
||||||
this.x + this.width > target.x &&
|
this.x + this.width > target.x &&
|
||||||
this.y < target.y + target.height &&
|
this.y < target.y + target.height &&
|
||||||
this.y + this.height > target.y
|
this.y + this.height > target.y
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -453,9 +601,9 @@ class Projectile {
|
||||||
|
|
||||||
|
|
||||||
class Bomb {
|
class Bomb {
|
||||||
constructor(x, y, vx) {
|
constructor(x, y, vx, vy) {
|
||||||
this.x = x; this.y = y;
|
this.x = x; this.y = y;
|
||||||
this.vx = vx; this.vy = 0;
|
this.vx = vx; this.vy = vy;
|
||||||
this.width = 32; this.height = 32;
|
this.width = 32; this.height = 32;
|
||||||
|
|
||||||
this.timer = 120;
|
this.timer = 120;
|
||||||
|
@ -539,8 +687,15 @@ class Bomb {
|
||||||
if (d < this.radius) {
|
if (d < this.radius) {
|
||||||
const angle = atan2(py - cy, px - cx);
|
const angle = atan2(py - cy, px - cx);
|
||||||
const force = map(d, 0, this.radius, 20, 5);
|
const force = map(d, 0, this.radius, 20, 5);
|
||||||
p.knockbackVX += cos(angle) * force * 2;
|
if(p.giantTimer > 0) {
|
||||||
p.vy += sin(angle) * force * 2;
|
p.knockbackVX += cos(angle) * force * 0.5;
|
||||||
|
p.vy += sin(angle) * force * 0.5;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p.knockbackVX += cos(angle) * force * 2;
|
||||||
|
p.vy += sin(angle) * force * 2;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -549,8 +704,8 @@ class Bomb {
|
||||||
if ((t.type === 'breakableblock' || t.type === 'questionblock')) {
|
if ((t.type === 'breakableblock' || t.type === 'questionblock')) {
|
||||||
const cx = this.x + this.width/2;
|
const cx = this.x + this.width/2;
|
||||||
const cy = this.y + this.height/2;
|
const cy = this.y + this.height/2;
|
||||||
const tx = t.x + TILE_H/2;
|
const tx = t.x + TILE_SIZE/2;
|
||||||
const ty = t.y + TILE_H/2;
|
const ty = t.y + TILE_SIZE/2;
|
||||||
if (dist(cx, cy, tx, ty) < this.radius) {
|
if (dist(cx, cy, tx, ty) < this.radius) {
|
||||||
// 타일 제거
|
// 타일 제거
|
||||||
tiles.splice(i, 1);
|
tiles.splice(i, 1);
|
||||||
|
@ -667,36 +822,85 @@ class BigMissile {
|
||||||
}
|
}
|
||||||
class Item {
|
class Item {
|
||||||
constructor(type, x) {
|
constructor(type, x) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.img = itemImgs[type][0];
|
this.img = itemimgs[type][0];
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = -TILE_H;
|
this.y = -TILE_SIZE;
|
||||||
this.vy = 0;
|
this.vy = 0;
|
||||||
this.width = TILE_H;
|
this.width = TILE_SIZE;
|
||||||
this.height = TILE_H;
|
this.height = TILE_SIZE;
|
||||||
this.toRemove = false;
|
this.toRemove = false;
|
||||||
|
this.stuck = false; // 착지 플래그
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 기존 hit 기능: target 오브젝트와의 겹침(충돌) 확인 */
|
||||||
|
hits(target) {
|
||||||
|
return (
|
||||||
|
this.x < target.x + target.width &&
|
||||||
|
this.x + this.width > target.x &&
|
||||||
|
this.y < target.y + target.height &&
|
||||||
|
this.y + this.height > target.y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 새로운 메서드: 타일 위 착지 판정만 담당 */
|
||||||
|
landOnTiles() {
|
||||||
|
// 아래로 떨어질 때만 검사
|
||||||
|
if (this.vy <= 0) return;
|
||||||
|
|
||||||
|
const nextY = this.y + this.vy;
|
||||||
|
for (let tile of tiles) {
|
||||||
|
const prevBot = this.y + this.height;
|
||||||
|
const currBot = nextY + this.height;
|
||||||
|
|
||||||
|
// “위→아래 궤적 교차” + 가로 범위 겹침
|
||||||
|
if (prevBot <= tile.y &&
|
||||||
|
currBot >= tile.y &&
|
||||||
|
this.x + this.width > tile.x &&
|
||||||
|
this.x < tile.x + tile.width
|
||||||
|
) {
|
||||||
|
// 딱 타일 위에 착지
|
||||||
|
this.y = tile.y - this.height;
|
||||||
|
this.vy = 0;
|
||||||
|
this.stuck = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 착지 못했으면 실제 y 갱신
|
||||||
|
this.y = nextY;
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
// 중력 떨어뜨리기
|
// 1) 폭발 같은 특별 로직이 없으므로 바로
|
||||||
this.vy += gravity;
|
// 착지 전이라면 중력+착지 판정
|
||||||
this.y += this.vy;
|
if (!this.stuck) {
|
||||||
|
this.vy += 0.5 * gravity;
|
||||||
|
this.landOnTiles();
|
||||||
|
}
|
||||||
|
|
||||||
// 화면 밖으로 나가면 제거
|
// 2) 화면 아래로 벗어나면 제거
|
||||||
if (this.y > height) this.toRemove = true;
|
if (this.y > height) {
|
||||||
|
this.toRemove = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 플레이어 충돌 검사 (player1, player2)
|
// 3) 플레이어 충돌 판정 (hits 메서드 재사용)
|
||||||
[player1, player2].forEach(p => {
|
for (let p of [player1, player2]) {
|
||||||
if (!this.toRemove && p.collides(this.x,this.y,this.width,this.height)) {
|
if (!this.toRemove && this.hits(p)) {
|
||||||
p.applyItem(this.type);
|
p.applyItem(this.type);
|
||||||
this.toRemove = true;
|
this.toRemove = true;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
draw() {
|
draw() {
|
||||||
image(this.img, this.x, this.y, this.width, this.height);
|
image(this.img, this.x, this.y, this.width, this.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
return this.toRemove;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
function handleProjectiles() {
|
function handleProjectiles() {
|
||||||
for (let i = projectiles.length - 1; i >= 0; i--) {
|
for (let i = projectiles.length - 1; i >= 0; i--) {
|
||||||
|
@ -737,4 +941,29 @@ function breakManager() {
|
||||||
breakEffects.splice(i, 1);
|
breakEffects.splice(i, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
function randomSpawnItem() {
|
||||||
|
// 1) 랜덤 타이밍에 새로운 아이템 스폰
|
||||||
|
if (frameCount >= nextItemFrame) {
|
||||||
|
// 타입 선택
|
||||||
|
const types = ['mush','poison','giant','bombadd'];
|
||||||
|
const type = random(types);
|
||||||
|
// X 위치는 화면 가로 범위 안에서 랜덤
|
||||||
|
const x = random(0, width - TILE_SIZE);
|
||||||
|
|
||||||
|
items.push(new Item(type, x));
|
||||||
|
|
||||||
|
// 다음 스폰 타이밍: 3~8초 뒤
|
||||||
|
nextItemFrame = frameCount + floor(random(3, 8) * 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) 기존 아이템들 업데이트 → 드로우 → 필요 시 제거
|
||||||
|
for (let i = items.length - 1; i >= 0; i--) {
|
||||||
|
const it = items[i];
|
||||||
|
it.update();
|
||||||
|
it.draw();
|
||||||
|
if (it.toRemove) {
|
||||||
|
items.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
17
soundAsset.js
Normal file
17
soundAsset.js
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
let effectSound = {};
|
||||||
|
let bgm = {};
|
||||||
|
|
||||||
|
function preloadSounds() {
|
||||||
|
soundFormats('mp3','wav');
|
||||||
|
bgm.bgmGround = loadSound('assets/M1_BGM_Ground_Play.mp3');
|
||||||
|
bgm.bgmGroundHurry = loadSound('assets/M1_BGM_Ground_PlayHurry.mp3');
|
||||||
|
|
||||||
|
effectSound.jump = loadSound('assets/SMB1 Sounds/M1_SmallMarioJump.wav');
|
||||||
|
effectSound.fire = loadSound('assets/SMB1 Sounds/M1_fire.wav');
|
||||||
|
effectSound.dead = loadSound('assets/SMB1 Sounds/M1_HitFloor.wav');
|
||||||
|
effectSound.getItem = loadSound('assets/SMB1 Sounds/M1_PowerUp.wav');
|
||||||
|
effectSound.breakBlock = loadSound('assets/SMB1 Sounds/M1_BreakBlock.wav');
|
||||||
|
effectSound.bomb = loadSound('assets/SMB1 Sounds/SE_chargeshot.wav');
|
||||||
|
effectSound.bigmissile = loadSound('assets/SMB1 Sounds/M1_FireLong.wav');
|
||||||
|
effectSound.victory = loadSound('assets/SMB1 Sounds/M1_CourseClearFanfare.wav');
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user