🤑 Indie game store🙌 Free games😂 Fun games😨 Horror games
👷 Game development🎨 Assets📚 Comics
🎉 Sales🎁 Bundles

DagonDev

38
Posts
16
Topics
3
Followers
9
Following
A member registered 2 years ago · View creator page →

Games

Recent community posts

Just like title says.


https://github.com/PixelVision...

https://github.com/PixelVision...

(Edited 1 time)

Btw. bug still exists. Just reminder, before you release bugfix version. :)

Edit: Github issue: https://github.com/PixelVision...

I will do that later, can't remember github creds. and have no access to mail currently. What you mean by adjusting? I don't think so.  I am only using ScrollPosition() as provided above and dynamic objects (that are drawn with DrawSprites()) have static x,y as they doesn't move (so far).

Hi, so title says all.

I have simple camera system in place that is based on player position in the world.

Camera position is set like this:

    function Init()
        glCamera.xPlayerOffset=glScreenPixelWidth/2
        glCamera.yPlayerOffset=glScreenPixelHeight/2
[...]
    function Update()
        glCamera.x=math.max(0,math.min(glPlayer.x-glCamera.xPlayerOffset,
            glTilemapPixelWidth))
        glCamera.y=math.max(0,math.min(glPlayer.y-glCamera.yPlayerOffset,
            glTilemapPixelHeight)) 

It makes sure that screen is always centered on player unless we hit bounds of map (0,0 or tilemap size).
I am scrolling stuff with ScrollPosition() and this is my order of calling stuff:

function Draw()
    Clear()
    ScrollPosition(glCamera.x,glCamera.y)
    DrawTilemap()
    DrawObjects()
end

Where DrawObjects() iterates over dynamic objects in the game and draws them using DrawSprites().

If I move player only on X axis, everything works as expected, but if I moved player over Y axis (or both) dynamic objects, drawn with DrawSprites, are somehow scrolling with camera (but only over Y axis) - and I made sure that those objects doesn't change position.

editorBridge.fps works as intended. :)

Yeah, after seeing Unity export function I feel like whole thread is over. I really like idea of sketching in GC and moving on into Unity. With that in mind I think it would be good to have some hard limitations.

The more statistics exposed, the better. :)

Somehow missed this function. Did quick test and works the same as apiBridge version.

You could paste all of this you wrote into documentation and it would help tremendously.

I was having wrong assumption that drawing to cache is faster and more desirable rather than drawing onto tiles itself, but seeing how easy it is to clear tile it now makes sense.

1. Yeah, while it is obvious in retrospective, it isn't really at the start. But I am used to thinking that if x,y args in method means diff. things depending on other argument, then it should be in separate method instead. So I wasn't expecting it.

Sure, getting good documentation is iterative process.

(Edited 3 times)

Thanks to this topic: If you want to redraw HUD part of screen, every frame, you basically lock yourself to 30fps I started thinking about Game Creator and

wondering if I am expecting something real or my own imagined fantasy console.
 
My biggest grip is how v0.7 introduced lot of limiting, hardware limitation like, decisions.
Last versions where more lenient on how stuff is done and imho that was good choice. Going back on this feels like a downgrade to me.

In my childhood I played on NES and SNES, and later on emulators, so I understand nostalgia and appeal of creating game from that times... but I have trouble seeing pros of developing with problems from that era. Of course, I am not your 8bit purist/'there is right way of doing things' type of guy. This is why I moved away from Pico8 with frustration, despite having game out and knowing how everything works. I was tired of those arbitrary decisions - most notably code limit. When i saw Game Creator, without code limit, with tool editing/creating and ability to choose/create template I thought this is what I was looking for.

I was seeing GC as a env. that takes 8bit idea as a concept, for player to decide what to do with it, rather than set of rules.
My grip is that v0.7 backed up from, what I was experiencing, is Game Creator spirit.

This isn't necessary bad, there is big group of 8bit purists, that still looks for something more than Pico8,TIC etc., and I may not be the target of GC. I just want to show my side of the coin, as I am identify myself as one wanting best of two worlds. Let's say I want to see 2017 development/way of doing things in 8bit env.

My question is: What is spirit/purpose of Game Creator? Do I have wrong impression of what GC is trying to accomplish?

(Edited 1 time)

Tough decision. I understand you trying to balance between going old style and going user convenience, but from my personal perspective, this gets detrimental to end product.

Good way, for now, would be to allow all solutions you described so user can decide what works best for his/her game.

Because if you choose to use more lenient method, purists will be angry and if I you choose 100% true way of 8bit, it will throw away all those people looking for developing game in 2017 way with limitations. (like me)

Then, making several methods is very time consuming and prone to bugs...

This thread made me think about Game Creator and I moved it to separate thread: LINK.

I found lacking in LUA Api that:

1. there is no information when I should pass pixel x,y, for drawing functions like DrawText/DrawSprite etc. , and when should I pass tile x,y.

2. There is no information where stuff,  ScrollPosition, RebuildTilemap etc., belongs to Update or Draw method and why. Looking at demos and my own experimentation it looks a bit confusing. like ScrollPosition should be done in Draw function (tilemap demo)?

Sorry I already moved past this so I can't provide code, but can confirm this behaviour was from rebuilding tilemap each frame.

I was doing this because I wanted to draw gui stuff at 0,0 space (where I have normal tilemap sprites) then draw HUD part of the game from 0,0 on tilemap and then clean tilemap to original state, so when drawing game portion of the screen gui doesn't appear there. But unless I missed something, it looks like it is bad way to approach drawing gui on tile map, so I switched to drawing GUI outside game portion of tilemap (I resized tilemap to have 1 empty screen of space for gui). I think this is how old games drawn gui, right?

Also, by asking for distinction between DrawMode.TilemapCache and DrawMode.Tile I meant what is a difference for me by using one over another.

Sure, thanks for letting me know.

Sounds good.


For now I created simple FPS calculator, which at least shows when game gets over 100% cpu consumption.

If someone want to use it:

function CalculateFPS(timeDelta)
    table.insert(FPSTable,(1/timeDelta))
    local l=#FPSTable
    if l<10 then
        return
    end
    local n=0
    for i,v in ipairs(FPSTable) do
        n=n+v
    end
    averageFPS=n/l
    table.remove(FPSTable,1)
end

Calling this function in Update function allows to check current FPS in averageFPS variable.

So I am trying to draw HUD just like it is done in need tilemap demo and if I want to redraw something from HUD space I am not drawing rest of the screen in that frame and vice versa.
My quick tests shows me that you can't draw both on same frame as it doesn't work.
I understand that every dynamic thing should be drawn with DrawSprite and not with redrawing tilemap, but I am trying to upgrade my logger debug lib (https://itch.io/t/79403/debugging-tools-logger) that would eat up sprite limit quite quickly.
Easy solution would be not to redraw HUD space every other frame, but... then you still lock drawing game space into <60 fps. What is the reasoning for how this works? And can I bypass this?

(Edited 4 times)

So I upgraded to v0.7 and I have trouble upgrading my code to get same behavior as I got from deprecated apiBridge.

I want to have ability to draw non dynamic text easily. Before v0.7 I used RebuildScreenBuffer() on each frame and then I drawn font with DrawFontToBuffer on each frame.

Now if I use RebuildTilemap() instead DrawFontToBuffer() on each frame I get wanted behaviour only if I use DrawText() with DrawMode.TilemapCache. Which isn't bad, but for some reason that text is drawn only on transparent pixels of tilemap (and there is no aboveBG bool for DrawText like it is for DrawSprite function). If I want to draw 'above' existing tilemap I need to use DrawText function with DrawMode.Tile, but then RebuildTilemap() doesn't clean it. My workaround around this is to:

1. generate 'clean' tilemap data (before calling any DrawFont) at Init() with:
    for y=0,tilemapHeight-1 do
        for x=0,tilemapWidth-1 do
            add(gl_tilemap,Tile(x,y)["spriteID"])
        end
    end
2. Clean whole tilemap with call on every frame: UpdateTiles(0,0,tilemapWidth,gl_tilemap)
3. call DrawFont with DrawMode.Tile after calling UpdateTiles

While I can make sure I don't regenerate whole tilemap every frame, but only overwritten parts, I am not sure if it is intented way, also I can't have fontSpacing with DrawMode.Tile. How I should procced with this?

Bonus question:
1. What is a difference between DrawMode.TilemapCache and DrawMode.Tile? I read new documentation but I still don't understand.

Bump

I have port some of the pico 8 functions and today I rewritten rect and rectfill methods, to be more performance friendly, which allows you to draw lines,rects and filled rects quite quickly. Check my post in this thread: pico-8-to-pixelvision8-tips

(Edited 1 time)

Yeah, I don't think I would release this as library anymore, as I am not feeling like porting just for sake of porting everything pico has, but feel free to use anything/everything from what I have written up here.

Great, looking forward to next version.

Nope, you draw it yourself, you just get data in variable.

No problem :)

(Edited 1 time)

Currently I have 128x32 cells tile map and I am moving camera via ScrollTo method. This is quite cumbersome when I try to draw text and graphics for gui efficiently by drawing to tile buffer. Why? Because for texts I can only provide row and column which makes text jumping for every 8 pixels as can be seen (top right corner) on this GIF: GIF


If I could have data what spriteID is on what x,y then I could draw sprites from tilemap always on 128x128 to draw buffer and eliminate problem that scrolling introduces. It could work similar to how Sprite Builder works. When tilemap is loaded, when in Tilemap tool, add button to write sprite id for every x,y.

(Edited 1 time)

So how our machine template relates to CPU and RAM consuption? Does PV8 always use whole CPU? Or does it limit itself to some arbitrary value?
Regardless of those questions, can you give some way to track CPU consuption for each frame? Pico 8 does it like this:
(command callable in your code)

stat x
Get system status where x is:



0 Memory usage (0..1024)
1 CPU used since last flip (1.0 == 100% CPU at 30fps)

I created spritesheet consiting from colors for tile flags written here: https://pixelvision8.gitbooks.io/game-creator-inst...

This is how my spritesheet looks like: CollisionFlags

I use this spritesheet as tiles in Tiled and export as advised to tilemap-flags.png. For some reason, the brightest flag (which should be 15) is read as 14.

Rest works as intended (although I am using 0 to 4 so far)

This is my tilemap-flags.png: tilemap-flags.png

(Edited 1 time)

For now only external editor. Open file:

C:\Users\[username]\AppData\LocalLow\Pixel Vision 8\Game Creator Pro\Workspace\Game\code.lua

with your favorite editor.

Thank you! If I end up porting more functions I would like to release this as library as it is perfect example of what library should be. :)

(Edited 1 time)

Current version: v0.12

Features:

  • Prints messages, with time (in seconds), on screen as well as to normal PV8 debug.
  • Messages are printed to the buffer
  • Deals with strings, numbers and nils.
  • Tweak how much space debug takes, what color use, or how much lines can be visible at once
  • Supports tilemap scrolling

Screenshots:


Usage:

As of version v0.6.3, you don't need to make project as a tool.
  1. Save provided code as logger-debug.lua in Workspace/Lib.
  2. Copy large-font.font.png and/or small-font.font.png (depending on what font you want to use) to Workspace/Game
  3. Load debugging code with: apiBridge:LoadLib("logger-debug.lua")
  4. In your Init() method, make sure you have: apiBridge:RebuildScreenBuffer()
  5. In your Draw() method, make sure you have: apiBridge:DrawScreenBuffer()
  6. Call Logger:Init(fontName,letterSpacing,maxWidthInPixels,maxLinesDrawn,rebuildScreenBufferInUpdateMethod,useBackground,backgroundColorID) in your Init() method or whenever you need to change font or other properties. (but at least call it once)
  7. Call Logger:Update(timeDelta, cameraX,cameraY) in your Update(timeDelta) method preferably as last call there, to make sure your debug is always drawn last.
    1. cameraX and cameraY are optional and they are needed if you scroll your tilemap.
  8. Call Logger:Debug(yourMessage) whenever you need to log something.

If you want to draw stuff on screen buffer as well you need to set rebuildScreenBufferInUpdateMethod to false when calling Logger:Init. Make sure to call apiBridge:RebuildScreenBuffer() before calling Logger:Update(timeDelta)!


Code:

-- Debugging tools v0.12 by dagondev 
-- Changelog:
-- v0.12
-- * added hack to bigger background and reposition of debug to fight debug font drawing outside background
-- * added support for camera offset so msg is always in topright
-- * switched background color id to 0 by default and added arg to init to specify color 
-- * added ability to init without background
-- v0.11 
-- * made debugging modular to decouple it from game code.
-- * fixed bug where first char of the text would be rendered outside of background.
-- * fixed bug where debug message would be spammed to outside debug by calling print in Logger:Update instead of Logger:Debug, ups.
-- v0.1 
--- * first release 
Logger = {}
Logger.__index = Logger

----------------------
-- global constants --
----------------------
GL_FONT_WIDTH=8
GL_FONT_HEIGHT=7
GL_FONT_SPRITE_SIZE=8

----------------------
-- local variables  --
----------------------
local backgroundBufferArray={} -- table used for drawing background for each debug line
local secondsElapsed=0 -- how long debug is updating
local messageArray={} -- table used for storing messages, don't touch!
local hackOffset=1-- hack: to make sure text is always on background, lets move text one char to the right and one down

------------------------
--   debug methods    --
------------------------
-- use this method to debug something
-- note: no support for bool values atm
-- LoggerDebug("aaaa")
-- LoggerDebug(0)
-- LoggerDebug(nil)
-- LoggerDebug(thisIsBoolVar and 1 or 0)
-- LoggerDebug(thisIsBoolVar and "true" or "false")
function Logger:Debug(msg)     
    local len=#messageArray
    while(len>self.maxHeightChars) do -- remove old messages; everything above GL_DEBUG_MAX_LINES
        local first=messageArray[1]
        table.remove(messageArray,1) 
        msgs = messageArray    
        len=#messageArray
    end
    local m=math.floor(secondsElapsed).."|"..msg or "nil val"
    table.insert(messageArray,m) -- add time in seconds at which message was passed and if msg==nil write about it
    print(m)
end

function Logger:Init(fontName,letterSpacing,maxWidthInPixels,maxLinesDrawn,rebuildScreenBufferInUpdateMethod,useBackground,backgroundColorID)
    self.fontName=fontName
    self.fontWidth=GL_FONT_WIDTH
    self.fontHeight=GL_FONT_HEIGHT
    self.fontLetterSpacing=letterSpacing
    
    maxLinesDrawn=maxLinesDrawn+hackOffset
    self.maxWidthPixels=maxWidthInPixels
    self.maxWidthChars=self.maxWidthPixels/self.fontWidth
    self.maxHeightPixels=maxLinesDrawn*self.fontHeight
    self.maxHeightChars=maxLinesDrawn

    self.xPositionOnScreenPixels=apiBridge.displayWidth-self.maxWidthPixels
    self.xPositionOnScreenChars=self.xPositionOnScreenPixels/self.fontWidth
    self.yPositionOnScreenPixels=0
    self.yPositionOnScreenChars=self.yPositionOnScreenPixels/self.fontHeight

    self.rebuildScreenBufferInUpdateMethod=rebuildScreenBufferInUpdateMethod
    self.useBackground = useBackground or true
    backgroundColorID = backgroundColorID or 0

    if #backgroundBufferArray==0 and self.useBackground then -- get buffer data for one msg background
        for j=1,self.fontHeight do
            for i=1,self.maxWidthPixels do
                table.insert(backgroundBufferArray,backgroundColorID)
            end
        end
    end
end
-- call this function in Update(timeDelta) 
function Logger:Update(timeDelta,cameraX,cameraY)
    cameraX=cameraX or 0
    cameraY=cameraY or 0
    secondsElapsed = secondsElapsed + timeDelta
    -- if true logger can clean screenbuffer manually as that means user is not drawing anything else on buffer. if false, user have to call apiBridge:RebuildScreenBuffer() manually to clear screen and buffer
    if self.rebuildScreenBufferInUpdateMethod then
        apiBridge:RebuildScreenBuffer()
    end
    -- we need to call drawbufferdata in different loop than drawfonttobuffer as having both in same loop makes text behind background for some reason...
    if self.useBackground then
        for n=0,(#messageArray+hackOffset) do
            apiBridge:DrawBufferData(backgroundBufferArray,self.xPositionOnScreenPixels+cameraX,n*self.fontHeight+cameraY,#backgroundBufferArray/self.fontHeight,self.fontHeight)
        end
    end
    local i=0
    local cameraCharsX = math.floor(cameraX/self.fontWidth)
    local cameraCharsY =math.floor(cameraY/GL_FONT_SPRITE_SIZE) -- for camera scrolling we need sprite height, not font
    for k,v in pairs(messageArray) do
        apiBridge:DrawFontToBuffer(v, self.xPositionOnScreenChars+cameraCharsX+hackOffset, self.yPositionOnScreenChars+i+cameraCharsY+hackOffset,self.fontName, self.fontLetterSpacing)  
        i=i+1       
    end
end 
(Edited 6 times)

List of pico8 functions ported to Game Creator. Rev.3

Incomplete, will update with new functions whenever I need to port them.

Rev.3 - rewritten rect and rectfill for better performance and clarity
It's purpose is to have easier time running your pico 8 code on Game Creator and show how you can replace pico8 functionality, not copy-paste and forget.
Ported functions:
  • foreach
  • rnd
  • flr
  • add
  • del
  • sub
  • min
  • max
  • abs
  • sin
  • cos
  • btn
  • btnp
  • spr
  • rect
  • rectfill
  • print
Unsupported (or only for specific conditions) functions:
  • fget (working only for tileX,tileY, no support for spriteID)
  • mget
  • line (working only for horizontal/vertical lines)
  • run (so far there is no api for restarting cart, your best bet is to reinstate all the variables and call Init())
Functions that aren't ported yet: (that doesn't mean they are supported, I just didn't take my time to port them)
  • clip
  • pget
  • pset
  • sget
  • sset
  • fset
  • cursor
  • color
  • cls
  • camera
  • circ
  • circfill
  • pal
  • palt
  • sspr
  • all
  • pairs
  • sfx
  • music
  • mset
  • map
  • peek
  • poke
  • memcpy
  • reload
  • cstore
  • memset
  • mid
  • atan2
  • sqrt
  • srand
  • band
  • bor
  • bxor
  • bnot
  • shl
  • shr
  • menuitem
  • cartdata
  • dget
  • dset
Code:
function foreach(t,func)    
    for i,v in ipairs(t) do func(v) end
end
function mget()
    --there is no get sprite id from x,y function in PV8
    return nil
end
function fget(tileX,tileY,flag)
    if tileY==nil then
        return nil
    --there is no get flag for specific sprite id function in PV8
    end
    local f=apiBridge:ReadFlagAt(tileX,tileY)
    if flag==nil then
        return f
    end
    return f==flag
end
function rnd(n)
    return math.random(n)
end
function flr(v)
    return math.floor(v)
end
function add(t,v)
    table.insert(t,v)
end
function del(t,v)
    local ids={}
    local n=0
    for i,val in ipairs(t) do 
        if v==val then
            add(ids,i)
            n=i
        end 
    end
    if n>0 then
        --table.remove(t,n)
        for y,id in ipairs(ids) do 
            table.remove(t,id)
        end
    end
end
function sub(text,startPos,endPos)
    return string.sub(text,startPos,endPos)
end
function min(a,b)
    return math.min(a,b)
end
function max(a,b)
    return math.max(a,b)
end
function abs(v)
    return math.abs(v)
end
function sin(a)
    return math.sin(-a*(3.1415*2))
end
function cos(a)
    return math.cos(a*(3.1415*2))
end
function btn(n)
    return apiBridge:ButtonDown(n)
end
function btnp(n)
    return btn(n) and apiBridge:ButtonReleased(n)
end
function spr(id,x,y,width,height,flipHor,flipVert)
    apiBridge:DrawSprite(id,x,y,flipHor,flipVert,true,0)
end
function InitRectColorArray()
    if lineFillTables~=nil and #lineFillTables>0 then
        return
    end    
    lineFillTables={}
    local len=apiBridge.displayWidth
    for n=1,len do
        lineFillTables[n]={n,{}}
    end
    foreach(lineFillTables, function(t)
        local size=t[1]
        for color=0,16 do
            local current={}
            for j=1,size do
                table.insert(current,color)
            end
            table.insert(t[2],current)
        end
    end)
end
function rect(x0,y0,x1,y1,color)    
    InitRectColorArray()
    local width=max(1,math.abs(x1-x0))
    local height=max(1,math.abs(y1-y0))
    local widthArray=lineFillTables[width][2][color+1]
    local heightArray=lineFillTables[height][2][color+1]
    local x=max(0,(x0<x1 and x0 or x1))
    local y=max(0,(y0<y1 and y0 or y1))
    apiBridge:DrawBufferData(widthArray,x,y,#widthArray,1)
    apiBridge:DrawBufferData(widthArray,x,y+height,#widthArray,1)
    apiBridge:DrawBufferData(heightArray,x,y,1,#heightArray)
    apiBridge:DrawBufferData(heightArray,x+width,y,1,#heightArray)
end
function rectfill(x0,y0,x1,y1,color)
    InitRectColorArray()
    
    local width=max(1,math.abs(x1-x0))
    local height=max(1,math.abs(y1-y0)
    local x=max(0,(x0<x1 and x0 or x1))
    local y=max(0,(y0<y1 and y0 or y1))
    local widthArray=lineFillTables[width][2][color+1]
    for n=0,height-1 do
        apiBridge:DrawBufferData(widthArray,x,y+n,#widthArray,1)
    end    
end
function line(x0,y0,x1,y1,col)
    local color = col or 0
    rect(x0,y0,x1,y1,color)
end
function print(str,x,y,col)
    local color = col or 0
    x = x or 0
    y= y or 0
    --Logger:Debug(x..";"..y..";"..str)
    apiBridge:DrawFontToBuffer(str,pixel_tile_conv(x),pixel_tile_conv(y), "small-font", fontSpacing)
end

Ahhh, thank you.

Wait. How do you use Sprite Builder? I don't see builder button from that screen.

Yes, spritesheet gets jumbled because it gets optimized and you have redundant sprites. Which means you need to make sure each of 8x8 tile is unique to make it look same. Although I would happy welcome ability to turn off this optimization as it is difficult to have each 8x8 unique when you have bigger sprites.

Awesome, thanks.

For me, no problem - just call them nightly. At this stage of GC dev frequent versions with bugfixes are good thing - nobody should freeze their GC version atm.

Yeah, I looked at that and I think I prefer making spritesheet have all unique tiles rather than making all of it. As I slept with this idea I think I started liking it as it really makes you think about how use this. It is just a matter of me not using exactly same spritesheet I had in pico8 which complicates porting a little, but nothing serious.

Images? For my first project I am thinking about porting my game from Pico8, I have there tile map with 128x32 tiles (8x8), I am not at home at the moment so I can't check it myself, so can I put all of it in one big png or should I cut it somehow? Or should I just wait for reworking?

Looking forward to updated documentation, this things really matter at the start, when you may have wrong assumptions about stuff.