diff --git a/assets/M1_BGM_Ground_Play.mp3 b/assets/M1_BGM_Ground_Play.mp3 new file mode 100644 index 0000000..346da28 Binary files /dev/null and b/assets/M1_BGM_Ground_Play.mp3 differ diff --git a/assets/M1_BGM_Ground_PlayHurry.mp3 b/assets/M1_BGM_Ground_PlayHurry.mp3 new file mode 100644 index 0000000..5803504 Binary files /dev/null and b/assets/M1_BGM_Ground_PlayHurry.mp3 differ diff --git a/assets/SMB1 Sounds/CharaMario_Arwing_move.txt b/assets/SMB1 Sounds/CharaMario_Arwing_move.txt new file mode 100644 index 0000000..d3b5373 --- /dev/null +++ b/assets/SMB1 Sounds/CharaMario_Arwing_move.txt @@ -0,0 +1,2 @@ +loop start: 43778 samples (0:01.368 seconds) +loop end: 66338 samples (0:02.073 seconds) \ No newline at end of file diff --git a/assets/SMB1 Sounds/CharaMario_Arwing_move.wav b/assets/SMB1 Sounds/CharaMario_Arwing_move.wav new file mode 100644 index 0000000..208369b Binary files /dev/null and b/assets/SMB1 Sounds/CharaMario_Arwing_move.wav differ diff --git a/assets/SMB1 Sounds/CharaMario_Common_appeal_5turn.wav b/assets/SMB1 Sounds/CharaMario_Common_appeal_5turn.wav new file mode 100644 index 0000000..8e03cb5 Binary files /dev/null and b/assets/SMB1 Sounds/CharaMario_Common_appeal_5turn.wav differ diff --git a/assets/SMB1 Sounds/CharaMario_Fit_Wiibo_Crounch.wav b/assets/SMB1 Sounds/CharaMario_Fit_Wiibo_Crounch.wav new file mode 100644 index 0000000..60acb46 Binary files /dev/null and b/assets/SMB1 Sounds/CharaMario_Fit_Wiibo_Crounch.wav differ diff --git a/assets/SMB1 Sounds/CharaMario_MarioKart_engine.txt b/assets/SMB1 Sounds/CharaMario_MarioKart_engine.txt new file mode 100644 index 0000000..043bbb3 --- /dev/null +++ b/assets/SMB1 Sounds/CharaMario_MarioKart_engine.txt @@ -0,0 +1,2 @@ +loop start: 0 samples (0:00.000 seconds) +loop end: 2000 samples (0:00.063 seconds) \ No newline at end of file diff --git a/assets/SMB1 Sounds/CharaMario_MarioKart_engine.wav b/assets/SMB1 Sounds/CharaMario_MarioKart_engine.wav new file mode 100644 index 0000000..f09d27e Binary files /dev/null and b/assets/SMB1 Sounds/CharaMario_MarioKart_engine.wav differ diff --git a/assets/SMB1 Sounds/CharaMario_Splatoon_Swim.wav b/assets/SMB1 Sounds/CharaMario_Splatoon_Swim.wav new file mode 100644 index 0000000..b171811 Binary files /dev/null and b/assets/SMB1 Sounds/CharaMario_Splatoon_Swim.wav differ diff --git a/assets/SMB1 Sounds/CharaMario_Splatoon_ToHuman.wav b/assets/SMB1 Sounds/CharaMario_Splatoon_ToHuman.wav new file mode 100644 index 0000000..b1e2abb Binary files /dev/null and b/assets/SMB1 Sounds/CharaMario_Splatoon_ToHuman.wav differ diff --git a/assets/SMB1 Sounds/CharaMario_Splatoon_ToSquid.wav b/assets/SMB1 Sounds/CharaMario_Splatoon_ToSquid.wav new file mode 100644 index 0000000..752113c Binary files /dev/null and b/assets/SMB1 Sounds/CharaMario_Splatoon_ToSquid.wav differ diff --git a/assets/SMB1 Sounds/Charamario_DonkeyKongJr_walk1.txt b/assets/SMB1 Sounds/Charamario_DonkeyKongJr_walk1.txt new file mode 100644 index 0000000..e28b396 --- /dev/null +++ b/assets/SMB1 Sounds/Charamario_DonkeyKongJr_walk1.txt @@ -0,0 +1,2 @@ +loop start: 0 samples (0:00.000 seconds) +loop end: 34616 samples (0:01.082 seconds) \ No newline at end of file diff --git a/assets/SMB1 Sounds/Charamario_DonkeyKongJr_walk1.wav b/assets/SMB1 Sounds/Charamario_DonkeyKongJr_walk1.wav new file mode 100644 index 0000000..9ffc335 Binary files /dev/null and b/assets/SMB1 Sounds/Charamario_DonkeyKongJr_walk1.wav differ diff --git a/assets/SMB1 Sounds/Charamario_DonkeyKongJr_walk2.txt b/assets/SMB1 Sounds/Charamario_DonkeyKongJr_walk2.txt new file mode 100644 index 0000000..e28b396 --- /dev/null +++ b/assets/SMB1 Sounds/Charamario_DonkeyKongJr_walk2.txt @@ -0,0 +1,2 @@ +loop start: 0 samples (0:00.000 seconds) +loop end: 34616 samples (0:01.082 seconds) \ No newline at end of file diff --git a/assets/SMB1 Sounds/Charamario_DonkeyKongJr_walk2.wav b/assets/SMB1 Sounds/Charamario_DonkeyKongJr_walk2.wav new file mode 100644 index 0000000..8da5ce2 Binary files /dev/null and b/assets/SMB1 Sounds/Charamario_DonkeyKongJr_walk2.wav differ diff --git a/assets/SMB1 Sounds/Charamario_MarioOriginal_walk1.txt b/assets/SMB1 Sounds/Charamario_MarioOriginal_walk1.txt new file mode 100644 index 0000000..8c72b48 --- /dev/null +++ b/assets/SMB1 Sounds/Charamario_MarioOriginal_walk1.txt @@ -0,0 +1,2 @@ +loop start: 9226 samples (0:00.288 seconds) +loop end: 35018 samples (0:01.094 seconds) \ No newline at end of file diff --git a/assets/SMB1 Sounds/Charamario_MarioOriginal_walk1.wav b/assets/SMB1 Sounds/Charamario_MarioOriginal_walk1.wav new file mode 100644 index 0000000..4ed369b Binary files /dev/null and b/assets/SMB1 Sounds/Charamario_MarioOriginal_walk1.wav differ diff --git a/assets/SMB1 Sounds/Charamario_MarioOriginal_walk2.txt b/assets/SMB1 Sounds/Charamario_MarioOriginal_walk2.txt new file mode 100644 index 0000000..15ef303 --- /dev/null +++ b/assets/SMB1 Sounds/Charamario_MarioOriginal_walk2.txt @@ -0,0 +1,2 @@ +loop start: 0 samples (0:00.000 seconds) +loop end: 26050 samples (0:00.814 seconds) \ No newline at end of file diff --git a/assets/SMB1 Sounds/Charamario_MarioOriginal_walk2.wav b/assets/SMB1 Sounds/Charamario_MarioOriginal_walk2.wav new file mode 100644 index 0000000..05fd5ab Binary files /dev/null and b/assets/SMB1 Sounds/Charamario_MarioOriginal_walk2.wav differ diff --git a/assets/SMB1 Sounds/M1_BigMarioJump.wav b/assets/SMB1 Sounds/M1_BigMarioJump.wav new file mode 100644 index 0000000..9337d6d Binary files /dev/null and b/assets/SMB1 Sounds/M1_BigMarioJump.wav differ diff --git a/assets/SMB1 Sounds/M1_BreakBlock.wav b/assets/SMB1 Sounds/M1_BreakBlock.wav new file mode 100644 index 0000000..6bde11c Binary files /dev/null and b/assets/SMB1 Sounds/M1_BreakBlock.wav differ diff --git a/assets/SMB1 Sounds/M1_Cannon.wav b/assets/SMB1 Sounds/M1_Cannon.wav new file mode 100644 index 0000000..88abefd Binary files /dev/null and b/assets/SMB1 Sounds/M1_Cannon.wav differ diff --git a/assets/SMB1 Sounds/M1_Cannon_fast.wav b/assets/SMB1 Sounds/M1_Cannon_fast.wav new file mode 100644 index 0000000..dec08dd Binary files /dev/null and b/assets/SMB1 Sounds/M1_Cannon_fast.wav differ diff --git a/assets/SMB1 Sounds/M1_CastleClearFanfare.wav b/assets/SMB1 Sounds/M1_CastleClearFanfare.wav new file mode 100644 index 0000000..192e430 Binary files /dev/null and b/assets/SMB1 Sounds/M1_CastleClearFanfare.wav differ diff --git a/assets/SMB1 Sounds/M1_Coin.wav b/assets/SMB1 Sounds/M1_Coin.wav new file mode 100644 index 0000000..ebc51ac Binary files /dev/null and b/assets/SMB1 Sounds/M1_Coin.wav differ diff --git a/assets/SMB1 Sounds/M1_CourseClearFanfare.wav b/assets/SMB1 Sounds/M1_CourseClearFanfare.wav new file mode 100644 index 0000000..0541b68 Binary files /dev/null and b/assets/SMB1 Sounds/M1_CourseClearFanfare.wav differ diff --git a/assets/SMB1 Sounds/M1_Fire.wav b/assets/SMB1 Sounds/M1_Fire.wav new file mode 100644 index 0000000..621abf0 Binary files /dev/null and b/assets/SMB1 Sounds/M1_Fire.wav differ diff --git a/assets/SMB1 Sounds/M1_FireBall.wav b/assets/SMB1 Sounds/M1_FireBall.wav new file mode 100644 index 0000000..ea20140 Binary files /dev/null and b/assets/SMB1 Sounds/M1_FireBall.wav differ diff --git a/assets/SMB1 Sounds/M1_FireLong.wav b/assets/SMB1 Sounds/M1_FireLong.wav new file mode 100644 index 0000000..1768273 Binary files /dev/null and b/assets/SMB1 Sounds/M1_FireLong.wav differ diff --git a/assets/SMB1 Sounds/M1_FlagScoreUp.wav b/assets/SMB1 Sounds/M1_FlagScoreUp.wav new file mode 100644 index 0000000..0fcbb74 Binary files /dev/null and b/assets/SMB1 Sounds/M1_FlagScoreUp.wav differ diff --git a/assets/SMB1 Sounds/M1_HEN_JUMP.wav b/assets/SMB1 Sounds/M1_HEN_JUMP.wav new file mode 100644 index 0000000..922cbf3 Binary files /dev/null and b/assets/SMB1 Sounds/M1_HEN_JUMP.wav differ diff --git a/assets/SMB1 Sounds/M1_HEN_JUMP_FUWA.wav b/assets/SMB1 Sounds/M1_HEN_JUMP_FUWA.wav new file mode 100644 index 0000000..fc58245 Binary files /dev/null and b/assets/SMB1 Sounds/M1_HEN_JUMP_FUWA.wav differ diff --git a/assets/SMB1 Sounds/M1_HEN_LARGE.wav b/assets/SMB1 Sounds/M1_HEN_LARGE.wav new file mode 100644 index 0000000..aaa5836 Binary files /dev/null and b/assets/SMB1 Sounds/M1_HEN_LARGE.wav differ diff --git a/assets/SMB1 Sounds/M1_HitFloor.wav b/assets/SMB1 Sounds/M1_HitFloor.wav new file mode 100644 index 0000000..23d43bd Binary files /dev/null and b/assets/SMB1 Sounds/M1_HitFloor.wav differ diff --git a/assets/SMB1 Sounds/M1_HurryUpFanfare.wav b/assets/SMB1 Sounds/M1_HurryUpFanfare.wav new file mode 100644 index 0000000..4e78c6b Binary files /dev/null and b/assets/SMB1 Sounds/M1_HurryUpFanfare.wav differ diff --git a/assets/SMB1 Sounds/M1_KickNokonoko.wav b/assets/SMB1 Sounds/M1_KickNokonoko.wav new file mode 100644 index 0000000..502846a Binary files /dev/null and b/assets/SMB1 Sounds/M1_KickNokonoko.wav differ diff --git a/assets/SMB1 Sounds/M1_OneUp.wav b/assets/SMB1 Sounds/M1_OneUp.wav new file mode 100644 index 0000000..442799e Binary files /dev/null and b/assets/SMB1 Sounds/M1_OneUp.wav differ diff --git a/assets/SMB1 Sounds/M1_Pose.wav b/assets/SMB1 Sounds/M1_Pose.wav new file mode 100644 index 0000000..a31728a Binary files /dev/null and b/assets/SMB1 Sounds/M1_Pose.wav differ diff --git a/assets/SMB1 Sounds/M1_PowerDown.wav b/assets/SMB1 Sounds/M1_PowerDown.wav new file mode 100644 index 0000000..6d03901 Binary files /dev/null and b/assets/SMB1 Sounds/M1_PowerDown.wav differ diff --git a/assets/SMB1 Sounds/M1_PowerUp.wav b/assets/SMB1 Sounds/M1_PowerUp.wav new file mode 100644 index 0000000..38b8271 Binary files /dev/null and b/assets/SMB1 Sounds/M1_PowerUp.wav differ diff --git a/assets/SMB1 Sounds/M1_PowerUpItemAppear.wav b/assets/SMB1 Sounds/M1_PowerUpItemAppear.wav new file mode 100644 index 0000000..78e81b5 Binary files /dev/null and b/assets/SMB1 Sounds/M1_PowerUpItemAppear.wav differ diff --git a/assets/SMB1 Sounds/M1_SmallMarioJump.wav b/assets/SMB1 Sounds/M1_SmallMarioJump.wav new file mode 100644 index 0000000..797b449 Binary files /dev/null and b/assets/SMB1 Sounds/M1_SmallMarioJump.wav differ diff --git a/assets/SMB1 Sounds/M1_StepNokonoko.wav b/assets/SMB1 Sounds/M1_StepNokonoko.wav new file mode 100644 index 0000000..fa41635 Binary files /dev/null and b/assets/SMB1 Sounds/M1_StepNokonoko.wav differ diff --git a/assets/SMB1 Sounds/NewMario2_GoldEffect.txt b/assets/SMB1 Sounds/NewMario2_GoldEffect.txt new file mode 100644 index 0000000..79d59e4 --- /dev/null +++ b/assets/SMB1 Sounds/NewMario2_GoldEffect.txt @@ -0,0 +1,2 @@ +loop start: 0 samples (0:00.000 seconds) +loop end: 80563 samples (0:02.518 seconds) \ No newline at end of file diff --git a/assets/SMB1 Sounds/NewMario2_GoldEffect.wav b/assets/SMB1 Sounds/NewMario2_GoldEffect.wav new file mode 100644 index 0000000..045adf4 Binary files /dev/null and b/assets/SMB1 Sounds/NewMario2_GoldEffect.wav differ diff --git a/assets/SMB1 Sounds/SE_KILLER_POWERUP2.wav b/assets/SMB1 Sounds/SE_KILLER_POWERUP2.wav new file mode 100644 index 0000000..dd6d5ad Binary files /dev/null and b/assets/SMB1 Sounds/SE_KILLER_POWERUP2.wav differ diff --git a/assets/SMB1 Sounds/SE_MegaPowerup.wav b/assets/SMB1 Sounds/SE_MegaPowerup.wav new file mode 100644 index 0000000..ae0f24f Binary files /dev/null and b/assets/SMB1 Sounds/SE_MegaPowerup.wav differ diff --git a/assets/SMB1 Sounds/SE_chargeshot.wav b/assets/SMB1 Sounds/SE_chargeshot.wav new file mode 100644 index 0000000..9dd43b2 Binary files /dev/null and b/assets/SMB1 Sounds/SE_chargeshot.wav differ diff --git a/assets/SMB1 Sounds/SePvGrabHeavy_InWater.wav b/assets/SMB1 Sounds/SePvGrabHeavy_InWater.wav new file mode 100644 index 0000000..cb80ff6 Binary files /dev/null and b/assets/SMB1 Sounds/SePvGrabHeavy_InWater.wav differ diff --git a/assets/SMB1 Sounds/SePvWaitHappy_InWater.wav b/assets/SMB1 Sounds/SePvWaitHappy_InWater.wav new file mode 100644 index 0000000..a871000 Binary files /dev/null and b/assets/SMB1 Sounds/SePvWaitHappy_InWater.wav differ diff --git a/assets/SMB1 Sounds/charge_ready.wav b/assets/SMB1 Sounds/charge_ready.wav new file mode 100644 index 0000000..d7194ce Binary files /dev/null and b/assets/SMB1 Sounds/charge_ready.wav differ diff --git a/assets/SMB1 Sounds/firecharge_kari3.wav b/assets/SMB1 Sounds/firecharge_kari3.wav new file mode 100644 index 0000000..03e65ff Binary files /dev/null and b/assets/SMB1 Sounds/firecharge_kari3.wav differ diff --git a/assets/SMB1 Sounds/muon_2sec.wav b/assets/SMB1 Sounds/muon_2sec.wav new file mode 100644 index 0000000..b68e0d4 Binary files /dev/null and b/assets/SMB1 Sounds/muon_2sec.wav differ diff --git a/assets/SMB1 Sounds/swim_kinopiko.wav b/assets/SMB1 Sounds/swim_kinopiko.wav new file mode 100644 index 0000000..c81a45a Binary files /dev/null and b/assets/SMB1 Sounds/swim_kinopiko.wav differ diff --git a/imageAsset.js b/imageAsset.js index 2313324..5de5d6d 100644 --- a/imageAsset.js +++ b/imageAsset.js @@ -9,6 +9,9 @@ function preloadAssets() { spriteSheets.characters = loadImage("assets/Mario-Character+Item.png"); spriteSheets.specialweapon = loadImage("assets/Mario-Enemy.png"); spriteSheets.tileset = loadImage("assets/Mario-Tileset.png"); + + soundFormats('mp3', 'wav'); + } 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 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)); + P1imgs = { idle:[mi], walk:[mw1,mw2,mw3], jump:[mj], shoot:[ma] }; // 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 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)); + P2imgs = { idle:[li], walk:[lw1,lw2,lw3], jump:[lj], shoot:[la] }; // 6) 아이템 및 특수 투사체 프레임 @@ -60,13 +65,13 @@ function sliceAssets() { 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 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 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 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); - [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) { // img.pixels 에 접근해 기존 색상을 유지하며 R 증가, G 감소 img.loadPixels(); @@ -91,7 +96,7 @@ function sliceAssets() { applyColorFilter(bombWarn, {r: 150, g: 100, b:200} ); 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] }; diff --git a/index.html b/index.html index 6da61f6..a28e558 100644 --- a/index.html +++ b/index.html @@ -15,7 +15,7 @@ - + diff --git a/sketch.js b/sketch.js index b96d2b9..7e5839d 100644 --- a/sketch.js +++ b/sketch.js @@ -7,7 +7,7 @@ let controlsP1, controlsP2; let breakEffects = []; let items = []; let nextItemFrame = 0; -const TILE_H = 32; +const TILE_SIZE = 32; const mapLayout = [ // row 0 (y = groundY[0]–16): gb1 | question | gb1 [ @@ -43,12 +43,15 @@ const mapLayout = [ function preload() { preloadAssets(); + preloadSounds() } function setup() { createCanvas(800, 600); sliceAssets(); - + bgm.bgmGround.setLoop(true); + bgm.bgmGround.setVolume(0.5); + bgm.bgmGround.loop(); controlsP1 = { left: 'ArrowLeft', right: 'ArrowRight', jump: 'ArrowUp', attack: '[', bomb: ']', down: 'ArrowDown' @@ -62,10 +65,10 @@ function setup() { player2 = new Player(200, 100, P2imgs, controlsP2); 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]) { 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)); } } @@ -80,6 +83,8 @@ function draw() { player1.update(); player1.draw(); player2.update(); player2.draw(); + + randomSpawnItem(); handleProjectiles(); handleBombs(); handleSpecialProjectiles(); @@ -150,7 +155,7 @@ class BreakEffect { draw() { if (!this.active) return; 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 { @@ -204,15 +209,71 @@ class Player { this.facing = "right"; this.state = "idle"; this.frame = 0; + this._animTimer = 0; + this._animInterval = 6; this.attackTimer = 0; this.dropping = false; // drop-through state this.dropRowY = null; // current tile to 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() { + // (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 if (this.keys[this.controls.bomb] && this.bombHoldStartTime !== null) { this.chargeTime = min(millis() - this.bombHoldStartTime, this.maxCharge); @@ -272,13 +333,27 @@ class Player { } if (landed) { - if (this.attackTimer === 0) this.state = 'idle'; - } else { + if (this.attackTimer === 0) { + if(inputVX !== 0) { + this.state = 'walk' + } + else{ + this.state = 'idle'; + } + } + } + else { this.y = nextY; this.onGround = false; if (this.attackTimer === 0) this.state = 'jump'; } + if (this.state === 'walk') { + this._animTimer++; + } else { + this._animTimer = 0; + } + // DOWN 키로 현재 플랫폼 행 통과 if ( this.keys[this.controls.down] && @@ -317,8 +392,20 @@ class Player { } 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() { @@ -331,8 +418,8 @@ class Player { shoot() { const spawnX = this.facing === 'right' ? this.x + this.width : this.x - 16; const spawnY = this.y + this.height/2; - const dir = this.facing === 'right' ? 20 : -20; - projectiles.push(new Projectile(spawnX, spawnY, dir)); + const dir = this.facing === 'right' ? 15 : -15; + projectiles.push(new Projectile(spawnX, spawnY, dir, this.fireTimer > 0, this.giantTimer > 0)); this.state = 'shoot'; this.attackTimer = 10; this.frame = 0; @@ -340,10 +427,14 @@ class Player { } dropBomb() { + if (this.bombCount <= 0) return; const bx = this.facing === 'right' ? this.x + this.width : this.x - 32; const by = this.y - 8; - const v_bomb = this.facing === 'right' ? 5 : -5; - bombs.push(new Bomb(bx, by, v_bomb)); + const normalizedV = 1 + map(this.chargeTime, 0, 1000, 0, 1); + 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.attackTimer = 10; this.frame = 0; @@ -382,6 +473,13 @@ class Player { } draw() { + if (this.poisonTimer > 0) { + // R=255, G=B=150 정도: 연한 붉은빛으로 + tint(200, 100, 255); + } + else { + noTint(); + } // charge gauge 그리기 if (this.chargeTime > 0) { // 최대 너비를 this.width(32px)로 매핑 @@ -395,6 +493,15 @@ class Player { rect(this.x, this.y - 10, w, 5); 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]; push(); if (this.facing === 'left') { @@ -405,36 +512,77 @@ class Player { image(img, this.x, this.y, this.width, this.height); } pop(); + noTint(); } } class Projectile { - constructor(x, y, vx, w=8, h=8) { - this.x = x; this.y = y; - this.vx = vx; this.width = w; this.height = h; - this.spawnTime = millis(); this.lifetime = 10000; + constructor(x, y, vx, enchanted = false, isgiant = false) { + this.x = x; + this.y = y; + 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; } update(targets) { + // 이동 this.x += this.vx; + // 충돌 & 넉백 for (const t of targets) { - if (this.hits(t)) { - t.knockbackVX += this.vx * 0.5; - this.shouldDestroy = true; + if (!this.shouldDestroy && this.hits(t)) { + if (t.giantTimer > 0) { + // giant 상태면 넉백 없이 그냥 삭제 + this.shouldDestroy = true; + } + else { + // giant 상태 아니면 넉백 + t.knockbackVX += this.vx * this.knockbackFactor; + this.shouldDestroy = true; + } } } + // 수명 검사 if (millis() - this.spawnTime > this.lifetime) { this.shouldDestroy = true; } } 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() { @@ -443,9 +591,9 @@ class Projectile { hits(target) { return ( - this.x < target.x + target.width && - this.x + this.width > target.x && - this.y < target.y + target.height && + this.x < target.x + target.width && + this.x + this.width > target.x && + this.y < target.y + target.height && this.y + this.height > target.y ); } @@ -453,9 +601,9 @@ class Projectile { class Bomb { - constructor(x, y, vx) { + constructor(x, y, vx, vy) { 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.timer = 120; @@ -539,8 +687,15 @@ class Bomb { if (d < this.radius) { const angle = atan2(py - cy, px - cx); const force = map(d, 0, this.radius, 20, 5); - p.knockbackVX += cos(angle) * force * 2; - p.vy += sin(angle) * force * 2; + if(p.giantTimer > 0) { + 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')) { const cx = this.x + this.width/2; const cy = this.y + this.height/2; - const tx = t.x + TILE_H/2; - const ty = t.y + TILE_H/2; + const tx = t.x + TILE_SIZE/2; + const ty = t.y + TILE_SIZE/2; if (dist(cx, cy, tx, ty) < this.radius) { // 타일 제거 tiles.splice(i, 1); @@ -667,36 +822,85 @@ class BigMissile { } class Item { constructor(type, x) { - this.type = type; - this.img = itemImgs[type][0]; - this.x = x; - this.y = -TILE_H; - this.vy = 0; - this.width = TILE_H; - this.height = TILE_H; + this.type = type; + this.img = itemimgs[type][0]; + this.x = x; + this.y = -TILE_SIZE; + this.vy = 0; + this.width = TILE_SIZE; + this.height = TILE_SIZE; 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() { - // 중력 떨어뜨리기 - this.vy += gravity; - this.y += this.vy; + // 1) 폭발 같은 특별 로직이 없으므로 바로 + // 착지 전이라면 중력+착지 판정 + if (!this.stuck) { + this.vy += 0.5 * gravity; + this.landOnTiles(); + } - // 화면 밖으로 나가면 제거 - if (this.y > height) this.toRemove = true; + // 2) 화면 아래로 벗어나면 제거 + if (this.y > height) { + this.toRemove = true; + return; + } - // 플레이어 충돌 검사 (player1, player2) - [player1, player2].forEach(p => { - if (!this.toRemove && p.collides(this.x,this.y,this.width,this.height)) { + // 3) 플레이어 충돌 판정 (hits 메서드 재사용) + for (let p of [player1, player2]) { + if (!this.toRemove && this.hits(p)) { p.applyItem(this.type); this.toRemove = true; } - }); + } } draw() { image(this.img, this.x, this.y, this.width, this.height); } + + destroy() { + return this.toRemove; + } } function handleProjectiles() { for (let i = projectiles.length - 1; i >= 0; i--) { @@ -737,4 +941,29 @@ function breakManager() { 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); + } + } } \ No newline at end of file diff --git a/soundAsset.js b/soundAsset.js new file mode 100644 index 0000000..43f4c26 --- /dev/null +++ b/soundAsset.js @@ -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'); +} \ No newline at end of file