22
2012
Qix Prototype
Qix test : Qix (wikipedia), See gameplay video on c64 (youtube)
Using the same c# floodfill from here (comments section).
Diagonal movement not allowed (using part of this script from unifywiki)
Still missing collisions, enemies etc.
Just 1 bigger problem to think about:
– How do I get the position to apply floodfill to?
– Which side to fill (or fill both and check which side the enemy is.. still need to get some pixel position to “drop” the flood fill to..)
Webplayer:
http://unitycoder.com/upload/demos/Qix_prototype_unity/ (v1.0 : doesnt fill correctly)
Source: (javascript)
#pragma strict public var target:Transform; private var tex:Texture2D; private var texsize:int=64; private var f:FloodFiller = new FloodFiller(); private var MAP_SIZE:int = texsize; // only powers of two are supported private var map:byte[] = new byte[MAP_SIZE * MAP_SIZE]; private var speed : float = 20.0; private var pos:Vector3; private var oldpos:Vector3; private var gridpos:Vector3; private var drawing:boolean = false; private var startPos:Vector3; // we started drawing from here function Start () { tex = new Texture2D (texsize, texsize); target.renderer.material.mainTexture = tex; target.renderer.material.mainTexture.filterMode = FilterMode.Point; for (var y:int=0;y<texsize;y++) for (var x:int=0;x<texsize;x++) { map[texsize * x + y] = 0; tex.SetPixel(x,y, new Color(0,0,0.2,1)); if (x==0 || y== 0 || x==texsize-1 || y==texsize-1) { map[texsize * x + y] = 33; // border tex.SetPixel(x,y, Color.gray); } } tex.Apply(); pos = transform.position; gridpos = pos; oldpos = -pos; } function Update () { // get movements var moveX : float = Input.GetAxisRaw ("Horizontal") * speed; var moveY : float = Input.GetAxisRaw ("Vertical") * speed; // limit diagonal if (Mathf.Abs(moveX) > Mathf.Abs(moveY)) moveY = 0.0; else moveX = 0.0; // move transform.Translate(Vector3(moveX,0,moveY) * Time.deltaTime, Space.World); // get gridpos gridpos= new Vector3( Mathf.RoundToInt(transform.position.x) , 0 , Mathf.RoundToInt(transform.position.z)); // limit on walls transform.position.x = Mathf.Clamp(transform.position.x,0,texsize-1); transform.position.z = Mathf.Clamp(transform.position.z,0,texsize-1); // we have moved? if (gridpos!=oldpos) { // we are in empty spot if (map[texsize * gridpos.x + gridpos.z]==0) { var hit : RaycastHit; var fwd = transform.TransformDirection (-Vector3.up); if (Physics.Raycast (transform.position+Vector3(0,0.5,0), fwd, hit)) { var pixelUV:Vector2 = hit.textureCoord; pixelUV.x *= texsize; pixelUV.y *= texsize; //print (pixelUV); // TODO: separate maps? map[texsize * Mathf.RoundToInt(pixelUV.x) + Mathf.RoundToInt(pixelUV.y)] = 10; tex.SetPixel(Mathf.RoundToInt(pixelUV.x), Mathf.RoundToInt(pixelUV.y), Color.green); tex.Apply(); if (!drawing) startPos = gridpos; drawing = true; } }else{ // we are in pre-filled area // TODO: if neighbour cells are already painted, we should floodfill (because we entered 1x1 hole?) // we had been drawing before coming here if (drawing) { drawing = false; var paintpos:Vector3 = oldpos; Debug.DrawLine (startPos, gridpos, Color.red,10); if (startPos.z<gridpos.z) paintpos.z -= 1; //if (gridpos.x) paintpos.y = gridpos.y+1; //if (startPos.y<gridPos.y) paintpos.y = gridPos.y+1; print ("paintpos:"+paintpos+" gridpos:"+gridpos+" oldpos:"+oldpos); f.FloodFill(map, paintpos.x, paintpos.z,10, 99); checkAreas(); } } oldpos = gridpos; } /* if (Input.GetMouseButtonUp (0)) { // print ("fill"); f.FloodFill(map, 10, 10, 10, 99); checkAreas(); } */ } function checkAreas() { var found:boolean=false; var countArea:int=0; for (var y:int=0;y<texsize;y++) for (var x:int=0;x<texsize;x++) { var val = map[texsize * x + y]; // its still empty, so its inside building (or its wall?) if (val==0) { map[texsize * x + y] = 0; //tex.SetPixel(x,y,new Color(0,1,0,1)); found=true; countArea++; } //it was filled, clean it up if (val==99) { map[texsize * x + y] = 0; tex.SetPixel(x,y,new Color(0,0,1,1)); } } print ("countArea:"+countArea); tex.Apply(); }
FloodFiller.cs (put in Plugins/ folder)
using System; using System.Diagnostics; using System.Linq; // orig: http://pastebin.com/KHD8axSL //namespace FloodFill //{ //internal class Program public class FloodFiller { // private const int MAP_SIZE = 1024; // only powers of two are supported /* private static void Main() { var map = new byte[MAP_SIZE * MAP_SIZE]; var stopwatch = Stopwatch.StartNew(); { FloodFill(map, startX: 123, startY: 123, fromValue: 0, toValue: 1); } stopwatch.Stop(); Console.WriteLine(stopwatch.ElapsedMilliseconds); // Test results if (map.Any(item => item == 0)) { Console.WriteLine("Error"); } else { Console.WriteLine("Ok"); } Console.ReadLine(); } */ public void FloodFill(byte[] map, int startX, int startY, byte fromValue, byte toValue) { int shift = (int) Math.Round(Math.Log(map.Length, 4)); // if the array's length is (2^x * 2^x), then shift = x int startIndex = startX + (startY << shift); if (map[startIndex] >= fromValue) { return; } // initialize flood fill int size = 1 << shift; int sizeMinusOne = size - 1; int xMask = size - 1; int minIndexForVerticalCheck = size; int maxIndexForVerticalCheck = map.Length - size - 1; // initialize queue int capacity = size * 2; int mask = capacity - 1; uint tail = 0; uint head = 0; var queue = new int[capacity]; map[startIndex] = toValue; queue[tail++ & mask] = startIndex; while (tail - head > 0) { int index = queue[head++ & mask]; int x = index & xMask; //if (x > 0 && map[index - 1] == fromValue) if (x > 0 && map[index - 1] < fromValue) { map[index - 1] = toValue; queue[tail++ & mask] = index - 1; } //if (x < sizeMinusOne && map[index + 1] == fromValue) if (x < sizeMinusOne && map[index + 1] < fromValue) { map[index + 1] = toValue; queue[tail++ & mask] = index + 1; } //if (index >= minIndexForVerticalCheck && map[index - size] == fromValue) if (index >= minIndexForVerticalCheck && map[index - size] < fromValue) { map[index - size] = toValue; queue[tail++ & mask] = index - size; } //if (index <= maxIndexForVerticalCheck && map[index + size] == fromValue) if (index <= maxIndexForVerticalCheck && map[index + size] < fromValue) { map[index + size] = toValue; queue[tail++ & mask] = index + size; } } } } //}
Related Posts
5 Comments + Add Comment
Leave a comment
Recent posts
- [GreaseMonkey] Unity Forum Fixer
- UnityHub: Make Hub application background Translucent
- Customize SpriteShapeRenderer quality (but has issues)
- Editor tool: Copy selected gameobject’s names into clipboard as rows (for Excel)
- Editor tool: Replace string in selected gameobject’s names
- UnityHub: Enable built-in Login Dialog (no more browser login/logout issues!)
- Use TikTok-TTS in Unity (with WebRequest)
- Create Scene Thumbnail Image using OnSceneSaved & OnPreviewGUI
- webgl+javascript TTS
- Using Moonsharp (LUA) + Unity Webgl
- Using 3D gameobject prefabs with Unity Tilemap + NavMesh Surface
- Custom Unity Hub Project Template Preview Image/Video (using HTML+CSS in package description)
Recent Comments
- Vector3 maths for dummies! on
- UnityHub: Make Hub application background Translucent on
- UnityHub: Make Hub application background Translucent on
- Install Android SDK+JDK+NDK for Unity (without AndroidStudio or Unity Hub) on
- Install Android SDK+JDK+NDK for Unity (without AndroidStudio or Unity Hub) on
- [Asset Store] Point Cloud Viewer & Tools on
- [Asset Store] Point Cloud Viewer & Tools on
- ffmpeg stream raw video into Unity Texture2D on
Hi! This looks great!
I’m trying to make a game qix-like too. I have been working about a script I found and it works ok in corona, but I’m new in unity and I’m having problems adapting to c# and all the other unity stuff. Maybe I can help you if you share youre code. My code is based on this:
http://luis.peralta.pt/sandbox/js/flood.html
Thanks!
John
Flood fill stuff from here:
http://unitycoder.com/blog/2012/10/10/flood-fill-algorithm/
(check comments, also that Bitmap Drawing API (free) might be easy to use)
Or which part you are having problems with?
* added those old webplayer demo scripts, would need to remake them..
Thank you for the info and code!
Basically I have problems with the basics of unity I guess. How many GameObjects I need to make this code run? I understand I need one that use mesh with renderer no? What is the target on your code?
Thank you again!
script is attached to player gameobject (cube in the webplayer demo, no collider on it),
target is the plane (used CreatePlane from unity to make “Plane1x1W64L64HBL”)
Ok, I runned! It works well but fills the largest area, it should be the tinniest. I’m doing my investigations on the code. It’s a bit complicated because usually I use a 2 dimensional array and you are using a byte array. The bitwise operations are harder to understand, but I supose It’s a decision made for improving performance…
Thanks!