パックマンゲームの黄色いドットって、あれ食べてるからエサなんですかね?
とりあえず、wikipediaにエサとパワーエサという単語で書かれていたので、エサと呼ぶことにします。
参考 :
wikipedia「パックマン」
今回の目的
- エサと自キャラが重なったら、エサを非表示にする。
対象ファイル一覧
- js/feed.js
- js/frame.js
- js/pacman.js
ソースコード
[新規追加] js/feed.js
import { Frame } from './frame.js'
import { Pacman } from './pacman.js'
export class Feed{
static move_map(){
const num = Frame.get_pos2num(Pacman.coodinates)
const item = Frame.frame_datas[num]
switch(item){
case 'P1':
this.eat_normal_dot(num)
break
case 'P2':
this.eat_big_dot(num)
break
}
}
static eat_normal_dot(num){
Frame.frame_datas[num] = 'S5'
const elm = Frame.get_elm(num)
if(!elm){return}
elm.setAttribute('class','S5')
}
static eat_big_dot(num){
Frame.frame_datas[num] = 'S5'
const elm = Frame.get_elm(num)
if(!elm){return}
elm.setAttribute('class','S5')
}
}
[一部更新] js/frame.js
下記のコードの赤字の箇所を追記してください。
※2箇所ありますよ。
export class Frame{
constructor(){
return new Promise(resolve => {
this.resolve = resolve
Frame.stage_datas = this.stage_datas = []
this.load_asset()
})
}
static get root(){
return document.querySelector(`.frame-area`)
}
get block_size(){
return Frame.block_size
}
static get block_size(){
const s5 = document.querySelector('.S5')
return s5.offsetWidth
}
get cols_count(){
return ~~(Frame.root.offsetWidth / Frame.block_size)
}
static get_elm(num){
return Frame.root.querySelector(`[data-num='${num}']`)
}
load_asset(){
const xhr = new XMLHttpRequest()
xhr.open('get' , `assets/frame.json` , true)
xhr.setRequestHeader('Content-Type', 'text/html');
xhr.onreadystatechange = ((e) => {
if(xhr.readyState !== XMLHttpRequest.DONE){return}
if(xhr.status === 404){return}
if (xhr.status === 200) {
Frame.frame_datas =this.frame_datas = JSON.parse(e.target.response)
this.view()
this.set_collision()
this.finish()
}
}).bind(this)
xhr.send()
}
view(){
for(let i=0; i<this.frame_datas.length; i++){
const p = document.createElement('p')
p.className = this.frame_datas[i]
Frame.root.appendChild(p)
p.setAttribute('data-num' , i)
}
}
finish(){
if(this.resolve){
this.resolve(this)
}
}
static put(elm , coodinates){
if(!elm){return}
const pos = this.calc_coodinates2position(coodinates)
this.pos(elm , pos)
elm.setAttribute('data-x' , coodinates.x)
elm.setAttribute('data-y' , coodinates.y)
}
static calc_coodinates2position(coodinates){
const size = Frame.block_size
return {
x : (coodinates.x) * size,
y : (coodinates.y) * size,
}
}
static pos(elm , pos){
elm.style.setProperty('left' , `${pos.x}px` , '')
elm.style.setProperty('top' , `${pos.y}px` , '')
}
// 壁座標に1を設置
set_collision(){
const cols_count = this.cols_count
const maps = []
let row_count = 0
for(const frame_data of this.frame_datas){
maps[row_count] = maps[row_count] || []
// 移動できる
if(frame_data.match(/^P/i) || frame_data.toUpperCase() === 'S5'){
maps[row_count].push(0)
}
// 壁
else{
maps[row_count].push(1)
}
if(maps[row_count].length === cols_count){
row_count++
}
}
Frame.map = this.map = maps
}
static is_collision(map){
return Frame.map[map.y][map.x]
}
static get_pos2num(pos){
return pos.y * Frame.map[0].length + pos.x
}
static get_num2pos(num){
return {
x : num % Frame.map[0].length,
y : ~~(num / Frame.map[0].length),
}
}
static is_warp(map){
const num = Frame.get_pos2num(map)
return Frame.frame_datas[num] === 'W1' ? true : false
}
static get_another_warp_pos(map){
const warp_index_arr = Frame.filterIndex(Frame.frame_datas , 'W1')
const current_index = Frame.get_pos2num(map)
const another_num = warp_index_arr.find(e => e !== current_index)
return Frame.get_num2pos(another_num)
}
static filterIndex(datas,target){
const res_arr = []
for(let i=0; i<datas.length; i++){
if(datas[i] === target){
res_arr.push(i)
}
}
return res_arr
}
}
[一部追加] js/pacman.js
下記の赤字の箇所を追加してください。
feed.jsのモジュール処理を、自機のモーション切り替えのタイミングで行っています。
※これも2箇所あります。
import { Frame } from './frame.js'
import { Control } from './control.js'
import { Feed } from './feed.js'
export class Pacman{
// 初期表示座標処理
constructor(){
Pacman.anim_speed = 300
Pacman.coodinates = this.start_coodinates
Frame.put(this.elm, Pacman.coodinates)
this.elm.style.setProperty('--anim-speed' , `${Pacman.anim_speed}ms` , '')
}
get start_coodinates(){
return {
x : 14,
y : 23,
}
}
get elm(){
return Pacman.elm
}
static get elm(){
return document.querySelector('.pacman')
}
static move(direction){
if(Pacman.direction){
return
}
Pacman.direction = direction
this.elm.setAttribute('data-anim' , "true")
this.moving()
}
static moving(){
let next_pos = Pacman.next_pos(Pacman.direction)
//warp
if(Frame.is_warp(next_pos)){
Pacman.coodinates = Frame.get_another_warp_pos(next_pos)
next_pos = Pacman.next_pos(Pacman.direction)
}
if(Frame.is_collision(next_pos)){
this.elm.setAttribute('data-anim' , "")
delete Pacman.direction
return
}
this.elm.setAttribute('data-direction' , Pacman.direction)
this.elm.animate(
[
{
left : `${Pacman.coodinates.x * Frame.block_size}px`,
top : `${Pacman.coodinates.y * Frame.block_size}px`,
},
{
left : `${next_pos.x * Frame.block_size}px`,
top : `${next_pos.y * Frame.block_size}px`,
}
],
{
duration: Pacman.anim_speed
}
)
Promise.all(this.elm.getAnimations().map(e => e.finished)).then(()=>{
Pacman.moved(next_pos)
})
}
static moved(next_pos){
Pacman.coodinates = next_pos
Frame.put(this.elm, Pacman.coodinates)
Feed.move_map()
if(Control.direction && Control.direction !== Pacman.direction){
const temp_pos = Pacman.next_pos(Control.direction)
if(!Frame.is_collision(temp_pos)){
Pacman.direction = Control.direction
}
}
Pacman.moving()
}
static next_pos(name){
const next_pos = {
x : Pacman.coodinates.x,
y : Pacman.coodinates.y,
}
switch(name){
case 'left':
next_pos.x -= 1
break
case 'right':
next_pos.x += 1
break
case 'up':
next_pos.y -= 1
break
case 'down':
next_pos.y += 1
break
default: return
}
return next_pos
}
}
画面キャプチャ
解説
今回は,
feed.jsを追加して、frame.jsとpacman.jsに組み込みました。
ステージ記号のP1(エサ)とP2(パワーエサ)を自キャラが動く座標から判別して、同じ座標になった場合に、S5(空欄)に書き換えています。
P1とP2でそれぞれ同じ処理が書かれた関数に分けているのは、今後2つの関数で違った処理をするかもしれないな〜と思っているだけで、今の時点では、同じ関数を処理してもいいかもしれません。
でもまあ、とりあえず、エサをパクパク食べるゲームの醍醐味ができて、より完成に近づきました。
知財
パックマンは、バンダイナムコ社の登録商標です。
PAC-MAN™ & ©1980 BANDAI NAMCO Entertainment Inc.
0 件のコメント:
コメントを投稿