制作一款打飞机游戏26:精灵编辑器

虽然我们基本上已经重建了Axel编辑器,但我不想直接使用它。我想创建一个真正适合我们当前目的的编辑器,那就是编辑精灵(sprites)。这将是今天的一个大目标------创建一个基于模板的编辑器,用它作为我们实际编辑器的起点。

细节调整

在开始之前,有一些小细节我想修复。比如,滚动功能现在不太灵敏,尤其是在屏幕左侧边缘。我们需要让滚动对左侧边缘更敏感一些。通过调整滚动X的值,我们现在已经解决了这个问题,使得滚动更加顺畅。

消息系统优化

另一个我不喜欢的地方是,当我们导出时,它只使用一个调试系统来显示消息。我希望有一个内置的更正式的消息系统,消息可以格式化并在一段时间后自动消失。因此,我决定添加一个MSG对象来处理这些消息,并在屏幕上显示它们,每条消息显示两秒钟后自动消失。

编辑器界面优化

我注意到,当列表项很多时,滚动到底部会变得非常繁琐。因此,我决定添加鼠标滚轮滚动功能,这样可以更快速地滚动列表。通过调整状态变量m_scroll,我们已经实现了这一功能。

创建精灵编辑器

现在,我想基于之前的编辑器模板,创建一个专门用于编辑精灵的编辑器。我将其命名为"Sprite Edit"。在这个编辑器中,我将保留表格视图,但同时创建一个新的视图来编辑精灵。这个新视图将被称为"列表视图"。

列表视图实现

在列表视图中,我将显示所有精灵的列表,每个精灵占据一行。用户可以通过滚动快速浏览所有精灵,并通过选择某个精灵来编辑它。我已经实现了刷新列表和绘制列表的功能,现在用户可以看到一个简洁的精灵列表。

显示精灵预览

为了让用户能够直观地看到他们正在编辑的精灵,我决定在列表视图中添加精灵预览功能。当用户选择某个精灵时,程序将在屏幕上绘制该精灵的预览图。为了实现这一点,我使用了mspr函数来从精灵表中获取精灵数据,并在屏幕上绘制它们。

中心点标记

为了让用户更清楚地了解精灵的中心点位置,我决定在精灵预览图上添加中心点标记。我使用了一个小红点来表示精灵的中心点,并通过闪烁来引起用户的注意。此外,我还绘制了从屏幕中心到精灵中心点的虚线,以帮助用户更准确地定位精灵。

新增精灵功能

接下来,我实现了新增精灵的功能。用户可以通过点击底部的"+"按钮来创建一个新的精灵条目。为了确保新创建的精灵条目是有效的,我添加了足够的默认数据(如位置、宽度、高度和偏移量)。

编辑精灵模式

最后,我创建了一个编辑精灵的模式。在这个模式下,用户可以选择一个精灵并进入编辑状态。我将编辑精灵的UI设计为一个包含多个编辑框和按钮的菜单,用户可以通过这些控件来修改精灵的属性。

复制代码
pico-8 cartridge // http://www.pico-8.com
version 41
__lua__
function _init()
 --- customize here ---
 #include shmup_myspr.txt
 file="shmup_myspr.txt"
 arrname="myspr"
 data=myspr
 ----------------------
 
 debug={}
 msg={}
 
 _drw=draw_list
 _upd=update_list
 
 menuitem(1,"export",export)
 
 reload(0x0,0x0,0x2000,"cowshmup.p8")
 
 curx=1
 cury=1
 scrolly=0
 scrollx=0
 
 poke(0x5f2d, 1)
end

function _draw()
 _drw()
 
 if #msg>0 then
  bgprint(msg[1].txt,64-#msg[1].txt*2,80,14)
  msg[1].t-=1
  if msg[1].t<=0 then
   deli(msg,1)
  end  
 end
 
 -- debug --
 cursor(4,4)
 color(8)
 for txt in all(debug) do
  print(txt)
 end
end

function _update60()
 dokeys()
 mscroll=stat(36)
 
 _upd()
end

function dokeys()
 if stat(30) then
  key=stat(31)
  if key=="p" then
   poke(0x5f30,1)
  end
 else
  key=nil
 end
 
end
-->8
--draw
function draw_edit()
 fillp(0b11001100001100111100110000110011)
 rectfill(0,0,127,127,33)
 fillp(▒)
 line(63,0,63,127,13)
 line(0,63,127,63,13)
 fillp()
 
 draw_menu()
 
 if selspr then
  mspr(selspr,63,63)
 end
 
 if (time()*2)%1<0.5 then
  pset(63,63,rnd({8,13,7,15}))
 end
end

function draw_list()
 fillp(0b11001100001100111100110000110011)
 rectfill(0,0,127,127,33)
 fillp(▒)
 line(63,0,63,127,13)
 line(0,63,127,63,13)
 fillp()
   
 draw_menu()
 
 local mymnu=menu[cury][curx]
 if mymnu.cmdy then
  mspr(mymnu.cmdy,63,63)
 end
 
 if (time()*2)%1<0.5 then
  pset(63,63,rnd({8,13,7,15}))
 end
end

function draw_table()
 cls(2)
 draw_menu()
end

function draw_menu()
 
 --spr(0,0,0,16,16)
 
	if menu then
		for i=1,#menu do
		 for j=1,#menu[i] do
		  local mymnu=menu[i][j]
		  local c=mymnu.c or 13
		  if i==cury and j==curx then
		   c=7
		   if _upd==upd_type then
		    c=0
		   end
		  end
		  
		  bgprint(mymnu.w,mymnu.x+scrollx,mymnu.y+scrolly,13)   
		  bgprint(mymnu.txt,mymnu.x+scrollx,mymnu.y+scrolly,c) 
		 end
		end
 end
 
 if _upd==upd_type then
  local mymnu=menu[cury][curx]
  
  local txt_bef=sub(typetxt,1,typecur-1)
  local txt_cur=sub(typetxt,typecur,typecur)
  local txt_aft=sub(typetxt,typecur+1)
  txt_cur=txt_cur=="" and " " or txt_cur 
  
  if (time()*2)%1<0.5 then
   txt_cur="\^i"..txt_cur.."\^-i"
  end
   
  local txt=txt_bef..txt_cur..txt_aft
		bgprint(txt,mymnu.x+scrollx,mymnu.y+scrolly,7)
 end
 
end


-->8
--update
function update_edit()
 refresh_edit()
end

function update_list()
 refresh_list()
 if btnp(⬆️) then
  cury-=1
 end
 if btnp(⬇️) then
  cury+=1
 end
 cury=(cury-1)%#menu+1
 cury-=mscroll
 cury=mid(1,cury,#menu)
 
 curx=1
 
 local mymnu=menu[cury][curx]
 if mymnu.y+scrolly>110 then
  scrolly-=4
 end
 if mymnu.y+scrolly<10 then
  scrolly+=4
 end
 scrolly=min(0,scrolly)
 
 if mymnu.x+scrollx>110 then
  scrollx-=2
 end
 if mymnu.x+scrollx<20 then
  scrollx+=2
 end
 scrollx=min(0,scrollx)
 
 if btnp(❎) then
  local mymnu=menu[cury][curx]
  if mymnu.cmd=="newline" then
   add(data,{0,0,0,0,0,0})
  elseif mymnu.cmd=="editspr" then
   selspr=mymnu.cmdy
   _upd=update_edit
   _drw=draw_edit
  end
 end
end

function update_table()
 refresh_table()

 if btnp(⬆️) then
  cury-=1
 end
 if btnp(⬇️) then
  cury+=1
 end
 cury=(cury-1)%#menu+1
 cury-=mscroll
 cury=mid(1,cury,#menu)
 
 if btnp(⬅️) then
  curx-=1
 end
 if btnp(➡️) then
  curx+=1
 end
 if cury<#menu then
  curx=(curx-2)%(#menu[cury]-1)+2
 else
  curx=1
 end
 local mymnu=menu[cury][curx]
 if mymnu.y+scrolly>110 then
  scrolly-=4
 end
 if mymnu.y+scrolly<10 then
  scrolly+=4
 end
 scrolly=min(0,scrolly)
 
 if mymnu.x+scrollx>110 then
  scrollx-=2
 end
 if mymnu.x+scrollx<20 then
  scrollx+=2
 end
 scrollx=min(0,scrollx)
 
 if btnp(❎) then
  local mymnu=menu[cury][curx]
  if mymnu.cmd=="edit" then
   _upd=upd_type
   typetxt=tostr(mymnu.txt)
   typecur=#typetxt+1
  elseif mymnu.cmd=="newline" then
   add(data,{0})  
  elseif mymnu.cmd=="newcell" then
   add(data[mymnu.cmdy],0)
  end
 end
end

function upd_type()
 if key then
  if key=="\r" then
   -- enter
   local mymnu=menu[cury][curx]
   poke(0x5f30,1)
   local typeval=tonum(typetxt)
   if typeval==nil then
    if mymnu.cmdx==#data[mymnu.cmdy] and typetxt=="" then
     --delete cell
     deli(data[mymnu.cmdy],mymnu.cmdx)
     if mymnu.cmdx==1 then
      deli(data,mymnu.cmdy)
     end
     _upd=update_table
     return
    end  
    typeval=0
   end
   
   data[mymnu.cmdy][mymnu.cmdx]=typeval
   _upd=update_table
   return
  elseif key=="\b" then
   --backspace
   if typecur>1 then
    if typecur>#typetxt then
	    typetxt=sub(typetxt,1,#typetxt-1)
	   else
			  local txt_bef=sub(typetxt,1,typecur-2)
			  local txt_aft=sub(typetxt,typecur)
			  typetxt=txt_bef..txt_aft
	   end
	   typecur-=1
   end
  else
   if typecur>#typetxt then
    typetxt..=key
   else
		  local txt_bef=sub(typetxt,1,typecur-1)
		  local txt_aft=sub(typetxt,typecur)
		  typetxt=txt_bef..key..txt_aft
   end
   typecur+=1
  end
 end
 
 if btnp(⬅️) then
  typecur-=1
 end
 if btnp(➡️) then
  typecur+=1
 end
 typecur=mid(1,typecur,#typetxt+1)
end
-->8
--tools

function bgprint(txt,x,y,c)
 print("\#0"..txt,x,y,c)
end

function split2d(s)
 local arr=split(s,"|",false)
 for k, v in pairs(arr) do
  arr[k] = split(v)
 end
 return arr
end

function mspr(si,sx,sy)
 local ms=myspr[si]
 sspr(ms[1],ms[2],ms[3],ms[4],sx-ms[5],sy-ms[6],ms[3],ms[4],ms[7]==1)
 if ms[7]==2 then
  sspr(ms[1],ms[2],ms[3],ms[4],sx-ms[5]+ms[3],sy-ms[6],ms[3],ms[4],true)
 end
 
 if ms[8] then
  mspr(ms[8],sx,sy)
 end
end
-->8
--i/o
function export()
 local s=arrname.."=split2d\""
 
 for i=1,#data do
  if i>1 then
   s..="|"
  end
  for j=1,#data[i] do
	  if j>1 then
	   s..=","
	  end
	  s..=data[i][j]
  end
 end
 
 s..="\""
 printh(s,file,true)
 add(msg,{txt="exported!",t=120})
 --debug[1]="exported!"
end
-->8
--ui
function refresh_edit()
 menu={}
end

function refresh_list()
 menu={}
 for i=1,#data do
  local lne={}
  local linemax=#data[i]
  if i==cury then
   linemax+=1  
  end
  add(lne,{
	  txt="spr "..i,
	  w="",
	  cmd="editspr",
	  cmdy=i,
	  x=2,
	  y=-4+6*i
  })
  add(menu,lne)
 end
 add(menu,{{
  txt=" + ",
  w="   ",
  cmd="newline",
  x=2,
  y=-4+6*(#data+1)+2, 
 }})
end

function refresh_table()
 menu={}
 for i=1,#data do
  local lne={}
  local linemax=#data[i]
  if i==cury then
   linemax+=1  
  end
  add(lne,{
	  txt=i,
	  w="   ",
	  cmd="",
	  x=4,
	  y=-4+8*i,
	  c=2  
  })
  for j=1,linemax do
   if j==#data[i]+1 then
			 add(lne,{
			  txt="+",
			  w=" ",
			  cmd="newcell",
			  cmdy=i,
			  x=-10+14*(j+1),
			  y=-4+8*i, 
			 })
		 else
		  add(lne,{
		   txt=data[i][j],
		   cmd="edit",
		   cmdx=j,
		   cmdy=i,
		   x=-10+14*(j+1),
		   y=-4+8*i,
		   w="   "
		  })
   end
  end
  add(menu,lne)
 end
 add(menu,{{
  txt=" + ",
  w="   ",
  cmd="newline",
  x=4,
  y=-4+8*(#data+1), 
 }})
end

__gfx__
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00700700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00077000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00077000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00700700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
__map__
0000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
相关推荐
AIVoyager3 小时前
vscode本地化显示远程图形化界面
ide·vscode·编辑器
AiFlutter6 小时前
低代码平台开发手机USB-HID调试助手
单片机·游戏·计算机外设
工藤新一¹8 小时前
C++/SDL进阶游戏开发 —— 双人塔防游戏(代号:村庄保卫战 13)
c++·游戏·游戏引擎·毕业设计·sdl·c++游戏开发·渲染库
爱学习的章鱼哥11 小时前
如何实现一个可视化的文字编辑器(C语言版)?
c语言·编辑器·文本编辑器·程序设计·easyx
苏克贝塔13 小时前
2025 VSCode中如何进行dotnet开发环境配置完整教程
ide·vscode·编辑器
Mu先生Ai世界14 小时前
AI 生成 3D 技术解析:驱动力、价值主张与核心挑战 (AI+3D 产品经理笔记 S2E01)
人工智能·游戏·3d·aigc·transformer·产品经理·vr
ykjhr_3d16 小时前
展销编辑器在未来的发展前景
编辑器