This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
nitrogenfingers's profile picture

GameUtils- Now with Collision Detection!

Started by nitrogenfingers, 11 December 2012 - 04:58 AM
nitrogenfingers #1
Posted 11 December 2012 - 05:58 AM
GameUtils


For use with NPaintPro




What is it?

GameUtils is a small API used for creating game entities that can be either sprites (static display) or animations (dynamic, updatable display). Game entities handle the internal information about where they are stored and drawn internally, so you only need to create them and place them for them to work, and be able to interact with each other. On the top level, you code will look like you're simply creating a few objects, placing them, and updating them with input or timers.

Behind the scenes, GameUtils is specifying their positions in world space, dynamically resizing their bounds and positions to fit with the sprite provided, even comparing individual bounds and pixels to let you know if your entities have collided. The API aims to encapsulate boilerplate code like collision detection and affine transformations without enforcing limitations on how the game objects can be used like a stricter game engine development environment. You're free to use the entities however you want, implement your own custom methods on how they work- it stays out of the way, so you can concentrate on the core mechanics of your game.

GameUtils was designed specifically as a companion API to NPaintPro, and leverages it's more advanced features like animation. Having said that, images made in the packaged Paint program, or any other programs that conform to its file format will also work. Visit http://www.computerc...-145-npaintpro/ for more information about NPaintPro.

What can I do with GameUtils?
- Import Paint, NFP or NFA files into your program
- Store the position of your sprite internally- it's collision detection and draw position will all be based off of the X and Y coordinates you specify
- Animate NFA sprites, either by changing frames manually or setting the upper and lower bounds of your animation and playing it through a timed loop
- Determine if sprites are colliding with one another, with rectangle or pixel precision
- Write to the screen buffer rather than using term calls to make your program buttery-smooth

What does GameUtils do for me?
- Dynamically resizes your sprites to eliminate whitespace- it doesn't matter where the sprite is on the canvas, GameUtils will make sure the top left corner is at (1,1)
- Creates an object with all pertinent functions relating to managing and updating your sprites
- Keeps track of active frames for animations and loops through them when updated
- Hides the more complicated calculations, so you can focus on making your game!

How do I use it?
Although GameUtils can save you a lot of time and effort in making your games, it does have quite a few rules to get your head around before starting. It is recommended you skim over the source code for the API (at least the comments) to get an idea of what functions are available to you and how to use them. A series of demonstration programs have been (or will be) developed to help show how to use some of the features GameUtils offers. They can be downloaded here:

SpoilerDemonstration 1: Rectangle and Per-pixel Collision Detection

This demonstrates the ability for users to test whether or not their game objects are colliding, using the coarse-grain rectangle method for larger or imprecise collisions, and per-pixel for more detailed collisions. Per-pixel has been specially optimized so it uses rectangle precision as a coarse-grain filter by default, and works with the minimum intersection area rather than the entirety of both sprites, so in most cases it does not play a large factor in efficiency.

To run this demonstration, run the following code from your computer:

mkdir test1
cd test1
pastebin get BiZNFbAM test1
pastebin get s4qQgw3K gameutils
pastebin get PLLHJLBM obj1.nfp



Please post any questions, comments, feedback or bug reports as a reply to this topic. Enjoy!
GravityScore #2
Posted 11 December 2012 - 06:15 AM
Looks fantastic! Haven't found any bugs yet, and I can't wait for the collision detection to be implemented!

I'm a really big fan of all your work, Mr. Fingers (lol :P/>). My favourite would definitely be the 3D Print Software.
Keep up the sublime effort, and keep those marvelous programs coming! Can't wait for more… :D/>
anonimo182 #3
Posted 11 December 2012 - 10:24 AM
Nitrogen Fingers: Amazing people since long time ago…

On topic: Nice API, looking forward for all the things that are coming…
bjornir90 #4
Posted 12 December 2012 - 09:59 AM
That give me the idea for a game ! I'm waiting for the collision detection to really start working on it, but with nPaintPro this will be easy ! Thanks you alot !
nitrogenfingers #5
Posted 12 December 2012 - 12:28 PM
Excellent! Easy is what I was shooting for :P/>

It should be out later today.

Okay not today… might be a few days yet. Work. You know how it is.
Edited on 12 December 2012 - 10:45 PM
Cranium #6
Posted 12 December 2012 - 12:43 PM
Easy for us, ridiculously complicated for you, NitrogenFingers.
Ever notice that the ease of end user use increases as the ease of developer use decreases? It's an interesting relationship indeed.
bjornir90 #7
Posted 12 December 2012 - 07:15 PM
It's obvious when we think a bit about : everything the coder make, the user don't have to do it. So the more the coder do, the less the user have to do :)/>. However it could be false for games : I can make a simple game with easy to do graphics, but it will be very difficult to win. Like the hardest game in the world :P/>
nitrogenfingers #8
Posted 17 December 2012 - 11:02 PM
Making changes to add rectangle and per-pixel collision later tonight (the latter is quite expensive so use sparingly). If you've used bounds in previous projects, you will need to update your program to meet the new changes.

From my experimenting with this it's clear that gameutils can't be responsible for a lot of optimizations necessary to keep the game running at a smooth framerate, so if you do intend to make a game with a lot of complicated features or many graphical layers I recommend taking measures yourself to enforce optimization.

Although the second I write this I can see that it may be worthwhile to create a back buffer to draw to before a render. I'll workshop this and see how it comes out (though I'm pessimistic it will be any faster). Regardless, remember occlusion is your enemy, so take all measures to identify and cull hidden pixels.
nitrogenfingers #9
Posted 18 December 2012 - 04:51 AM
Completed an update. Still no collisions yet but bounding rectangles are now in place so while you're waiting, a simple edge intersect algorithm will be easy to write.

Updates:
- Bounds are now associated with each image rather than an object. This makes the "image" table found in both sprite.image and animation.frames[index] equivalent, and can be treated the same in most methods (this will be updated in later versions of the draw, repaint etc. functions)
- Modifications made to the Bounds table. It now has the following fields:
- x: represents the coordinate of the leftmost pixel with a non-null character
- y: " " topmost pixel " "
- width: represents the length of the image between the leftmost and rightmost pixels of non-null characters
- height: " " topmost and bottom-most pixels" "
- Addition of a "dimensions" table to images. This fills the role of the old bounds table (that is, the absolute size of the image in width and height, including null characters)
- Draw methods now use dimensions rather than bounds. This has not been thoroughly tested- if this is not working correctly please let me know
- A back buffer that can be cleared, written to and printed onto any terminal display. This replaces the standard draw methods in the untested theory that it may be less expensive to write and print out than performing multiple draw calls. Again I iterate, untested theory. It may be slower. I haven't yet had the chance to confirm this. What I can confirm is it seems to remove redraw artefacts (flickering), but this seems to be at the cost of frame rate.

As you can see a lot of stuff is untested- drawing may not be working 100% and I still have no idea if the back buffer is actually more efficient or not. Feedback would be greatly appreciated.

NF
bjornir90 #10
Posted 18 December 2012 - 08:40 AM
Just one question : are you sure for the name of collision functions ? Because I don't want to rewrite all name of functions in my code ^^
nitrogenfingers #11
Posted 18 December 2012 - 05:09 PM
As of right now I expect collision functions to use the names rCollidesWith and pCollidesWith for rectangle and per pixel resepctively. These are included in the definitions of entities, so if you need a placeholder you can simply write one into the API itself or add the definition each time an entity is loaded.

As of right now I intend to keep the fields of all entities consistent with all future versions. Apologies if I'm unable to enforce this but more likely features will be added rather than removed or renamed.
bjornir90 #12
Posted 18 December 2012 - 08:06 PM
Ok thanks you ! :)/>
bjornir90 #13
Posted 31 January 2013 - 05:48 AM
Is this abandonned ? :(/>
nitrogenfingers #14
Posted 31 January 2013 - 01:16 PM
No, I've just been extremely busy with other things. I'll try to have this up and running soon, including support for the new nft files.
nitrogenfingers #15
Posted 08 February 2013 - 07:12 PM
It's been a long time coming but I've finally updated GameUtils with new features! It can now be feasibly used in creating some fantastic games.

New Features:
- Rectangle collision! Check to see if your sprites are touching with this simple collision method.
- Per-pixel collision! With the high level of optimization present in this method and the way GameUtils handles sprites in general, even with two massive sprites this is usually not a large bottleneck in performance. Get collision precision right down to each individual pixel!
- Some neatening and fixing of other methods in the API

Features to come:
- Debugging features, including toggleable displays for the bounding rectangles and printouts of the positions and states of each sprite on screen and to logs (taking requests for features on this!)
- Support for NFT files
- Source rectangle draws- allows you to specify which "part" of an image to draw, rather than the entire thing. Great for things like scrolling maps: store your whole level as one huge paint file and then draw only the bit that's pertinent to where the screen is! Providing you move it relative to the player, collision detection will still work flawlessly.
FuuuAInfiniteLoop(F.A.I.L) #16
Posted 09 February 2013 - 04:24 PM
You should add gravity, and inertia so you could set the speed of an object and then you can stop that object so it will move a little more and if it was moving up, when it stops it starts to go down slowly
lieudusty #17
Posted 09 February 2013 - 04:37 PM
Amazing API!
nitrogenfingers #18
Posted 09 February 2013 - 06:08 PM
You should add gravity, and inertia so you could set the speed of an object and then you can stop that object so it will move a little more and if it was moving up, when it stops it starts to go down slowly

While those sound like really useful things, I'm shying away from adding them. The main reason for that is because I want GameUtils to be more of a replacement to common boilerplate code, and to have minimal to no effect on game logic; if the programmer working on a game finds he doesn't need gravity and inertia (as not all games do), or worse still he does but his understanding how it would work is not expressed in my implementation, he then is forced to either rewrite these routines and patch them in as replacements, or be forced to work within the constraints of my interpretation of those concepts.


I think the addition of such logic may make a valuable complimentary API (or perhaps using this API in developing a game engine), but aren't quite what I'm attempting to achieve. Thank you for your feedback :)/>
FuuuAInfiniteLoop(F.A.I.L) #19
Posted 09 February 2013 - 06:13 PM
and other thing that can be added is that we can use nfa files to use each frme as a sprite for diferent objects so less files
bjornir90 #20
Posted 09 February 2013 - 06:53 PM
Yeah ! =) i was waiting for this update for a long time !
nitrogenfingers #21
Posted 10 February 2013 - 12:44 AM
and other thing that can be added is that we can use nfa files to use each frme as a sprite for diferent objects so less files
That is already a standard feature of GameUtils.
FuuuAInfiniteLoop(F.A.I.L) #22
Posted 10 February 2013 - 05:05 AM
and using certain pixels from the images for each sprite?
nitrogenfingers #23
Posted 10 February 2013 - 11:48 AM
I don't think I'll ever implement this for collision detection- if you want to do this I recommend using layering to create a "bounding object", which is just the shape you want your shape to collide with (this implementation is very trivial, just switch frames before collision checks and switch back before draw calls). However, plans to draw only certain pixels within a rectangular area of the image is a planned feature of the next version of game utils
NeptunasLT #24
Posted 10 February 2013 - 12:30 PM
I will try
Skullblade #25
Posted 10 February 2013 - 12:49 PM
I will try
use your words…
nitrogenfingers #26
Posted 12 February 2013 - 04:36 PM
Updated today with a few changes:

- Fixed a bug with animations appearing off-centre when positions are initialized in the constructer
- Removed some debug scripts when loading sprites from file
- Allowed animations to be updated without a timer ID, this being a "forced update". Passing a nil timer ID will allow this; animating using timers should still pass through whatver ID the timer used.
- Added a "moveTo" method for sprites and animations. Access to X and Y is possible directly but this is unsafe as this refers the transformed coordinates according to the sprite's bounding box, not to relative screen space. You can still increment the X and Y values safetly enough for relative motion, but for absolute positioning on the screen it's unsafe, so moveTo is necessary. I've workshopped a few different ways of solving this issue and ironically it's the first time I've yet to come across where access restrictions feel completely necessary, but for the moment this will remain. For consistency I'd recommend using moveTo for relative motion as well.

I'm also planning on peppering this post with screenshots of games I've made using gameutils- I've done one or two little games and am working on at least two new demonstrations for how to use the API (particularly animation features and loading), and am working on at least one "tech demo" game. So here's the first, hopefully of many more to come!
bjornir90 #27
Posted 17 February 2013 - 08:34 PM
You said that we can only draw a part of a sprite for scrolling features, but how do I do that?
nitrogenfingers #28
Posted 18 February 2013 - 11:43 AM
Not yet- this feature is upcoming.
MudkipTheEpic #29
Posted 05 March 2013 - 11:10 AM
Is there any way to scroll in this or do drawSprite(image, -number, 1) to kinda scroll? Or are you adding that later.
darkroom #30
Posted 07 March 2013 - 12:38 PM
Hey guys I was making a game with gameUtils and I was like you know what this needs…. a better buffer drawing function. So I wrote one. Basically what it does is checks if the pixels are different and if they are it changes them. This eliminates 95% of flicker.
Here you go

function drawBuffer(terminal,backgroundColor)
if not terminal then
  terminal = term
end
backgroundColor = backgroundColor or colors.lightBlue
if not backbuffer then
  error("Back buffer not yet initialized!")
end
if not terminal.setCursorPos or not terminal.setBackgroundColour or not terminal.write then
  error("Parameter cannot be used to initialize the backbuffer.")
end
if not terminal.isColour() then
  error("Parameter does not represent an advanced computer.")
end
--I used these lines alot so I put it in a function
local function modWrite(x,y,color,text)
  local color = color or colors.black
  local text = text or " "
  terminal.setCursorPos(x,y)
  terminal.setBackgroundColour(color)
  terminal.write(text)
end
if backbufferOld then
  for y=1,math.min(#backbuffer,th) do
   for x=1,tw do
    if backbuffer[y][x] == backbufferOld[y][x] then
	 if backbuffer[y][x] then
	  modWrite(x,y,backbuffer[y][x])
	 else
	  modWrite(x,y,backgroundColor)
	 end
    else
	 if backbuffer[y][x] then
	  modWrite(x,y,backbuffer[y][x])
	 else
	  modWrite(x,y,backgroundColor)
	 end
    end
   end
  end
else
  for y=1,math.min(#backbuffer, th) do
   for x=1,tw do
    if backbuffer[y][x] then
	 modWrite(x,y,backbuffer[y][x])
    end
   end
  end
end
--Performs a "deep copy" of the table so we dont get pointer problems
backbufferOld = textutils.unserialize(textutils.serialize(backbuffer))
end
CastleMan2000 #31
Posted 09 March 2013 - 05:02 AM
Hey guys I was making a game with gameUtils and I was like you know what this needs…. a better buffer drawing function. So I wrote one. Basically what it does is checks if the pixels are different and if they are it changes them. This eliminates 95% of flicker.
Here you go
-snippy
Wow, nice job. I hope that this is implemented into the actual gameutils.
makerimages #32
Posted 21 July 2013 - 12:43 PM
How does one use nextA?

This is my code, which doesnt work

--Developed by Makerimages
os.loadAPI("/apis/gameutils");--Load the animation api
local topBar=gameutils.loadSprite("/graphics/TopBar.nfp",1,1);--top bar
local w, h=term.getSize();
local loadBar=gameutils.loadAnimation("/graphics/LoadingBar.nfa",math.ceil(w/2-3),math.ceil(h/2));--loading bar
loadBar.currentFrame=1;

gameutils.initializeBuffer();
gameutils.writeToBuffer(topBar);
gameutils.writeToBuffer(loadBar);
gameutils.drawBuffer();
while true do
loadBar.nextA(loadBar);
end
loadBar has 11 frames
TorakTu #33
Posted 05 August 2013 - 01:26 PM
I just wanted to say TY so very much for this API. It will be something I can examin on how you did things. Kudos !!
MUpetzz #34
Posted 09 August 2013 - 09:35 AM
sry wrong topic
Mjaf #35
Posted 14 August 2013 - 05:14 AM
Any progress on the support for nft files?