Mittwoch, 4. März 2015

New Blog: benedictinerklosterbruder.blogspot.com

It's a mess here since Wuala is "closed" for me.
Not to say that there was no mess before, but now it's absolutely chaotic here. All downloads are gone, if they were not gone before (just checked one on a really old post...that download link was expired for years..)

So I decided to open a new blog.

http://benedictinerklosterbruder.blogspot.com

All files will be uploaded to OneDrive and my home server. So, there will ever be a copy no matter if my server crashes or on the other side OneDrive "closes". Except for if both happens at the same time.

Also, every download will be explicitly linked on a special download page. If you search something, you don't have to search the whole blog for "that one" download.

Plus there is a sitemap wich links to the most important (or entry-)posts. Maybe more later.

Please be patient while I do the new layout and search for my downloads and stuff.

I decided to add ONE adsense Ad at the BOTTOM of the blog (here on the bottom of a blog entry). Please click this ad if you want to give me some credit. It would be awesome if I would make a dollar *out of the internet*. ;) Thanks.

Thanks to all of you for copying my code...ehr...reading my blog. That means something to me, I never thought more than 100 people would read that but...it's 25025 now. Nice Number. ThanksALot.

I know, It's not much for the internet, but in Switzerland it's a middle-big city, so....

Again: GOTO 100 -> http://benedictinerklosterbruder.blogspot.com
And here's my homeserver: http://ben0bi.dlinkddns.com

Montag, 3. November 2014

Unity3D: 3D-Mesh LED HUD Healthbar

So, you want to achieve something like that?



Then stick to that tutorial.

I will NOT explain here, how to setup a second camera for the HUD, because you can make it your way. What I will explain here, is how to create a Healthbar (or other-bar) using "LEDs".

First, create a mesh with your LEDs in it. Every LED is an object (the mesh must have several parts in unity), wich is named after your LED-name wich you use later. I call them LED_x, where x is a number. Number has no zeroes before. (Not 01, just 1, and then 10)

You can make that mesh with Unity (empty gameObject with some spheres in it) or with your desired 3D-modeling software. Just remember, the LEDs must have all the same name with a number, defining wich LED on the bar it is. And remember for exporting that it must have several parts in unity. Don't merge the LEDs with the background-mesh...

Set all materials of the LEDs to the shader "VertexLit".

The first script we create has some static functions wich will be used later:

public class Static
{
    public const string TAG_HUDROOT = "HUDroot";

    // finds the gameobject tagged with text along the parents.
    public static Transform FindParentWithTag(Transform owner,string tag)
    {
        if (owner && owner.tag == tag)
            return owner;
        else if (!owner)
        {
            Debug.LogWarning("WARNING: No parent with tag " + tag + " found.");
            return null;
        }
        return FindParentWithTag(owner.transform.parent, tag);
    }

    // sets emmisive color on the renderer, if it has one.
    public static void SetRendererEmissiveColor(Renderer renderer, Color color,bool affectDiffuse=true)
    {
        if (!renderer)
            return;

        //renderer.material.SetColor(0, color);

        // maybe leave the diffuse color alone.
        if (affectDiffuse) 
            renderer.material.color = color;
        renderer.material.SetColor("_Emission", color);
        renderer.material.SetColor("_EmisColor", color);
    }

    // turns of the emissive color on the renderer, if it has one.
    public static void TurnOffRendererEmissiveColor(Renderer renderer,bool affectDiffuse=false)
    {
        if (!renderer)
            return;

        // maybe leave the diffuse color alone.
        if (affectDiffuse)
            renderer.material.color = Color.black;

        renderer.material.SetColor("_Emission", Color.black);
        renderer.material.SetColor("_EmisColor", Color.black);
    }
}

Now, we begin to build up our HUD.

Create a gameObject wich is centered on your HUD-cam (or has the same position or something like that). This is the HUDs root-node.

Tag it with "HUDroot" (create that tag, if it does not exist.)

Now add the script "TargetComponent" to the root node:

public class TargetComponent : MonoBehaviour
{ 
    public bool getCamTarget = true;
    public bool destroyIfNoTarget = true;
    public Transform target;
// Use this for initialization
void Start () {
        // get it every update so it changes when it changes.
        if (getCamTarget)
            GetCamTarget();  
}

// Update is called once per frame
void Update () 
    {
        if (destroyIfNoTarget && !target)
            GameObject.DestroyObject(gameObject);
    }

    public void GetCamTarget()
    {
        Camera mainCam = Camera.main;

        if (!mainCam)
            return;

        CameraController c= mainCam.GetComponent<CameraController>();

        if (!c)
        {
            Debug.LogError("ERROR: No CameraController-Script attached to the main camera.\nPlease attach it.");
            return;
        }

        target = c.target;
    }
}


This script contains the target for the whole HUD. It is mostly the player, but for
some HUD items, it could be e.g. the players target or info about some item.

I will not explain here about the CameraController.
It must have a target, wich is your player. That's all.

Add your mesh (gameObject) to this root node and positionate and rotate it like you desire.

Now add the script LEDBar to your HUDs root node:
public class LEDBar : MonoBehaviour 
{

    private void TESTFUNCTION() {;;}
    /*
    private void TESTFUNCTION()
    {
        // HULL HUD
        int posOrange = (int)(ArrayCount * 0.3333f) + 1; // 1/3 is orange
        // red is just the second LED
        int posRed = (int)(ArrayCount * 0.1f) + 1; // 1/10 is red

        // first green -> full range
        TurnOnLEDs(8, 15, new Color(0.0f, 1.0f, 0.0f));
        // then orange: 1/3 range
        TurnOnLEDs(new Color(1.0f, 1.0f, 0.0f), posRed + 1, posOrange, 8, 15);
        // then red: 1/5 range
        TurnOnLEDs(new Color(1.0f, 0.0f, 0.0f), 1, posRed, 8, 15);
    }
    */


    public bool blackIfOff=false;
    public string arrayName = "LED_";

    private MeshRenderer[] LEDarray;
    // the ship wich the hud targets on.
    protected Transform target;
    // the huds root node.
    protected Transform root;


    protected void INITIALIZE()
    {
        //print("INITIALIZE");
        root = Static.FindParentWithTag(transform, Static.TAG_HUDROOT);
        if (!root)
        {
            Debug.LogError("ERROR: No HUDroot found for " + gameObject.name + "\nPlease tag the root object of your hud with " + Static.TAG_HUDROOT);
            return;
        }

        NotifyLEDs();

        // TEST TEST TEST
        TESTFUNCTION();
        // END TEST

        TargetComponent t = root.GetComponent<TargetComponent>();
        if (!t)
        {
            Debug.LogError("ERROR: No TargetComponent-Script attached to the HUDs root node.\nPlease attach it.\nIt searches for the HUDs target and sets it \"globally\" for the HUD.");
            return;
        }

        target = t.target;
// design flaw? target is null
        if (!target)
            print("WTF?");
    }

// ...so that is called in update...
    protected void FINDTARGET()
    {
        if (!target)
        {
            TargetComponent t = root.GetComponent<TargetComponent>();
            target = t.target;
        }
    }

    // Use this for initialization
    void Start () 
    {
        INITIALIZE();
    }

    // Update is called once per frame
    void Update () 
    {
        FINDTARGET();
    }

    public void NotifyLEDs()
    {
        if (!root)
        {
            Debug.LogError("ERROR: Cannot assign LEDs-Meshes because no HUD-root was found in "+gameObject.name+".\nPlease tag the root object of your HUD with " + Static.TAG_HUDROOT);
            return;
        }

        int c = RealCount;
        if (c <= 0)
        {
            Debug.LogWarning("WARNING: No HUD-Meshes found for " + arrayName + "x in " + gameObject.name+" in "+root.name+"\nHULLBar-Script needs to be in its own GameObject.");
            LEDarray = null;
            return;
        }

        // c > 0
        LEDarray = new MeshRenderer[c];

        var renderers = root.GetComponentsInChildren<MeshRenderer>();
        if (renderers.Length <= 0)
        {
            Debug.LogError("ERROR: @LEDBar.NotifyLEDs: No renderers found in " + root.name + ".");
            return;
        }

        int ii = 1;
        for (int i = 0; i < c; i++)
        {
            ii = i + 1;
            foreach (MeshRenderer r in renderers)
            {
                if(r.gameObject.name==arrayName+ii.ToString())
                    LEDarray[i]=r;
            }
        }

        BlackOut(blackIfOff);
        Debug.Log("HUD Mesh Notify: "+c+" HUD Meshes with name " + arrayName + "x found.");
    }

    // turn on leds first to last based on a range
    public void TurnOnLEDs(Color color,int lastLEDposition, float value, float maxValue)
    {
        //print("TURNON LEDS ALL VALUES");

        if (ArrayCount <= 0)
            return;

        if (lastLEDposition <= 0)
        {
            Debug.LogError("ERROR: LED range <= 0 @ LEDBar.TurnOnLEDs_#1 @" + gameObject.name);
            return;
        }

        // else count steps up and turn on each led < step.
        float LEDstep=0.0f;
        
        if(maxValue!=0)
            LEDstep = maxValue / ArrayCount;

        float rangedMaxValue = lastLEDposition * LEDstep;

        // maybe just turn on all the LEDs
        if (value >= rangedMaxValue)
        {
            //print("value > > > "+lastLEDposition);
            TurnOnLEDs(color, 1, lastLEDposition);
            return;
        }

        //print("value = " + value + " r=" + rangedMaxValue+" l="+lastLEDposition);

        float actual = 0.0f;
        for (int i = 0; i < lastLEDposition; i++)
        {
            // maybe we change index.
            int index = i+1;
            actual = i * LEDstep;
            if (value>0 && value >= actual)
                TurnOnLED(index,color);
        }
    }

    // turn on leds first to last.
    // range starts with 1!
    public void TurnOnLEDs(Color color,int first, int last)
    {
        if (ArrayCount <= 0)
            return;

        if (first <= 1)
            first = 1;

        // how many leds to light?
        int ledRange = last - first + 1;
        if (ledRange <= 0)
        {
            Debug.LogError("ERROR: LED range <= 0 @ LEDBar.TurnOnLEDs_#2 @" + gameObject.name);
            return;
        }

        for (int i = 0; i < ledRange; i++)
        {
            int index=first+i;
            TurnOnLED(index, color);
        }
    }

    // turn on ALL leds based on a range.
    // switching colors here for not messing up with the parameters (int and float above)
    public void TurnOnLEDs(float value, float maxValue,Color color)
    {
        //print("TurnOnLEDs range");
        if(ArrayCount<=0)
            return;
        TurnOnLEDs(color,ArrayCount, value, maxValue);
    }

    // index must start with 1!
    public void TurnOnLED(int index, Color color)
    {
        index -= 1;
        if (index >= ArrayCount)
            return;
        if (LEDarray[index])
            Static.SetRendererEmissiveColor(LEDarray[index], color);
        else
            Debug.LogWarning("WARNING: HUD item #" + (index + 1) + " is not assigned.\nLED name: " + arrayName + "x in " + gameObject.name);
    }


    // turn all the leds off.
    public void BlackOut(bool affectDiffuse = false)
    {
        if (ArrayCount<=0)
            return;
        foreach (MeshRenderer r in LEDarray)
            Static.TurnOffRendererEmissiveColor(r,affectDiffuse);
    }

    public int ArrayCount { get { return LEDarray.Length; } }

    // (re)count the items in the gameObject
    public int RealCount
    {
        // count all leds in the in the root node, with the same name.
        get
        {
            var renderers = root.GetComponentsInChildren<MeshRenderer>();
            if (renderers.Length<=0)
            {
                Debug.LogError("ERROR: @LEDBar.RealCount: No renderers found in "+root.name+".");
                return 0;
            }

            bool done = false;
            bool found = false;
            string arname = "";
            int count = 0;
            
            while (!done)
            {
                int c = count + 1;
                arname = arrayName + c.ToString();

                found = false;
                foreach (MeshRenderer r in renderers)
                {
                    if (r.gameObject.name == arname)
                    {
                        Debug.Log("Registering HUD object "+r.gameObject.name);
                        count++;
                        found = true;
                    }
                }

                if (!found)
                    done = true;
            }
            return count;
        }
    }
}



That's a big one. You can add as much of them to your root node as you want.
The important thing here is "arrayName", where you put the name of your LEDs WITHOUT any number. ("LED_")

You can now use BlackOut, TurnOnLEDs and TurnOnLED as you wish.

BlackOut(makeBlack=false) - turns Off all LEDs.
TurnOnLED(index) - turns on a single LED.
TurnOnLEDs(value, maxValue, Color) - turns on the LEDs based on the value and maxValue.
TurnOnLEDs(Color, first, last) - turns on the LEDs from # first to last.
-> And the other function combines that both.
ArrayCount returns the Length of the LED-array.
(RealCount counts the LEDs in the mesh-construction.)

You can now use that as base class for your HUD, and stuff the values/maxValues-scripting-stuff into the derived class, using the "target"-value.

Example class to add to your HUD:
public class HealthHUD : HUDBar
{
    void Start()
    {
         INITIALIZE();
         // ...
    }
 
     void Update()
    {
        FINDTARGET(); // there is a bug with finding the target in Start. I dunno...

        if (!target)
            return;

        BlackOut(true);  // Set all LEDs to black.

        // HULL HUD

         //Destructable is a class with health values.
        // ...make your own...
        Destructable d = target.GetComponent<Destructable>();
        if (d)
        {
            int posOrange = (int)(ArrayCount * 0.3333f) + 1; // 1/3 is orange
            // red is just the second LED
            float posRed = (int)(ArrayCount * 0.1f) + 1; // 1/10 is red

            // first green -> full range
            TurnOnLEDs(d.currentHealthPoints, d.maxHealthPoints, new Color(0.0f, 1.0f, 0.0f));
            // then orange: 1/3 range
            TurnOnLEDs(new Color(1.0f, 1.0f, 0.0f),posOrange, d.currentHealthPoints, d.maxHealthPoints);
            // then red: 1/10 range
            TurnOnLEDs(new Color(1.0f, 0.0f, 0.0f), (int)posRed, d.currentHealthPoints, d.maxHealthPoints);
        }
    }
}

Hope that helps. It's tested but not this blog entry. If you miss something, tell me.

Montag, 21. April 2014

PHP: IMG to coloured (HTML) ASCII

This little script takes an image file (on the server!) and computes a coloured ASCII (better: HTML) image out of it.

Use it like this, on a computer with php: imagescript.php?file=myfile.jpg

Have fun.
<DOCTYPE html>
<html>
<head>
<title>ASCII IMAGE</title>
<style>

body
{
color: #FFF;
background-color: #000;
line-height: 0.8;
}

</style>
</head>
<body>

<center>
<kbd>
<nobr>

<?php
// get the filename
$filename=$_GET['file'];
// get some image values
list($width, $height, $imgtype) = getimagesize($filename);

// select filetype and create image
switch($imgtype)
{
case IMAGETYPE_JPEG: $im=imagecreatefromjpeg($filename);break;
case IMAGETYPE_PNG: $im=imagecreatefrompng($filename);break;
        // add other file types as you like it.
default: $im=-1;
}

if($im!=-1)
{
// compute the for-step. Only x is needed.
$stepx=1;
        $stepy=1;

// if($height>100) {$stepy=$height/100;} // [obsolete]
if($width>100) {$stepx=$width/100;}
$stepy=$stepx; // [new]

// go through the image
for($y=0;$y<$height;$y+=$stepy)
{
for($x=0;$x<$width;$x+=$stepx)
{
// compute the color
$rgb=imagecolorat($im,$x,$y);
                        // get the hex values
$r=dechex(red($rgb));

$g=dechex(green($rgb));
$b=dechex(blue($rgb));
                        // add zeros if needed.
if(strlen($r)==1) {$r="0$r";}
if(strlen($g)==1) {$g="0$g";}
if(strlen($b)==1) {$b="0$b";}
                        // html color.   
$col="$r$g$b";
// print out a character
echo("<font color=\"#$col\">#</font>");
}
// print out a line end.
echo("<br>\n");
}
}else{
echo("File type not recognized. Sorry.");
}

// some helper functions to get color values
function red($rgb)
{
 return ($rgb >> 16) & 0xFF;
}
function green($rgb)
{
 return ($rgb >> 8) & 0xFF;
}
function blue($rgb)
{
 return $rgb & 0xFF;
}
?>

</nobr>
</kbd>
</center>
</body>

</html>

Montag, 29. Oktober 2012

How To: Program brandnew Atmega328p with Arduino UNO


Introduction

First things first: The links work again, I moved the stuff from wuala to onedrive.

This post is about how I did program my brand new Atmega328p-chips with my Arduino UNO (Rev 1 or 2). It is explained somehow on the web but it took some time to get all pieces together. So, here is the complete tutorial from wiring up the breadboard up to loading up an actual Arduino-sketch.

Ok, first things first: I have an Arduino UNO wich is suited with an Atmega328p-Chip and so I thought I just order these. I use mostly Windows machines so all software is given in MS Windows format here.

Here is the pin setting on the chip after the Arduino bootloader is installed.
stolen from: http://www.hobbytronics.co.uk/arduino-atmega328-pinout

Parts List

Here is what you need:

+ A computer. ;)
+ 1x Arduino UNO (or Duemilanove or something, try it out.)
+ 1x Atmega328 chip, DIP 28, brand new, with no bootloader or something on it.
+ A breadboard
+ 1x 10k Ohm resistor.
+ Some connections (wires) for the breadboard and arduino.

+ The Arduino IDE 1.0.1 or better. (Or maybe also worse but it did not work with IDE 1.0.0 !! It is because the software will use 9600 baud instead of 19200 if it is version 100. Even if I use explicitely 19200 baud in the sofware, it will not work.) You will find the newest version here: http://arduino.cc/en/Main/Software
 (And here is my 1.0.1-mirror: arduino-1.0.1-windows.zip

+ This mighty piece of software, wich will be uploaded on the host-Arduino. (To the Arduino UNO)
Download: ArduinoISP2c.zip

I do not know if it works with the internal clock, I just set all up like in the wiring below. Maybe you can spare the following parts:

+ 1x 16MHz crystal resonator
+ 2x 22pF capacitors

At last, the LEDs. You do not need them but they are very useful for fast detection of...stuff. ;)

+ 1x Blue LED wich represents the heartbeat of the host-software.
+ 1x Green LED wich represents succesfull transmission to the chip.
+ 1x Red LED wich represents errors or not-in-sync.
+ 1x Yellow LED wich is connected to (Arduino-)pin 8 on the breadboard-chip to test if it works.
+ 4x 100 Ohm resistors (for the LEDs, maybe you need other ones but 100Ohm suit the most LEDs for driving with the given 5V.)

Now, let's get started.

Setting up your Arduino

First, to upload software on the Arduino, please disconnect it from the breadboard. Just for the safety of the chip on the breadboard. To make that easier, we will upload the software to the Arduino just now. It is installed then and we do not need to worry about it again.

+ Open the IDE. Select the right port in the Tools-Menu if it is not already set.
+ Upload the ArduinoISP2.ino file - wich you can download above - to your Arduino. You NEED to use another version than IDE 1.0.0 - see above.
+ To program the chip (on the breadboard), we need to select the right programmer in Tools->Programmer: It is "Arduino as ISP". Double check that. ;)
+ Now upload the sketch.
+ You can now connect the breadboard to the Arduino.

That's all for that.

Schematics:

Wiring on the breadboard:
--> Note that the 10k resistor should go to positive, not to ground. It's an error here, sorry.


Here you have the raw Fritzing file: atmegaprogrammer.fzz
Fritzing is an open-source software to "draw" wirings/schematics/pcb-designs.  (http://fritzing.org)

Avrdude is included in the IDE somewhere. I downloaded it and put it into its own directory, though. It is a command line tool and I wrote some batch files to ease it up.
You can get avrdude (solo) here: avrdude-5.10.zip

You may need the WinAVR suite to get avrdude running properly.
http://winavr.sourceforge.net/

From there you need the file libusb0.dll wich is in the lib folder. Copy that to where your avrdude.exe is.

Using Avrdude

Avrdude is a command line tool where you have to give some parameters. It's almost the same with linux except that the path to the device is another. (here: com3, linux: ..../.../...)

This are the parameters wich we will use here:
-c : choose the programmer. We will use avrisp.
-p : choose the chip to program. It's m328p here.
-P : the device port of the arduino. It's com3 on my machine.
-b : the baud-rate to use. It's 19200.
-U: do some command on the chip.
-u : I don't know. I needed it. It overwrites the lock or tells to ignore not-sync-errors or something like that. o.O. All we need to know is: It works with it, it does not without it.... ;)

Ok, first check if the chip is ready.
avrdude -c avrisp -p m328p -P com3 -b 19200
Something like "All Ok" should pop up in the console.

If everything is OK, we will set the fuses. I don't know exactly what the setting "does", I only know it works. I had to get the value for the low-fuse manually but the other values are copied from another website.
The chip is set to run with the internal 8MHz oscillator. We will set it to external 16MHz quartz.
Also, the lock will be set to 0x0F and some other fuses like seen below.

Fuse Calculator: http://www.engbedded.com/fusecalc

avrdude -b 19200 -c avrisp -p m328p -P com3 -u -U efuse:w:0x05:m -U hfuse:w:0xD2:m -U lfuse:w:0xFF:m -U lock:w:0x0F:m

That's it. To check the fuses, you can use this:
avrdude -p m328p -P com3 -c avrisp -b 19200 -U hfuse:r:fusehigh.txt:s -U lfuse:r:fuselow.txt:s -F

That writes the values of the given stuff (here: hfuse, lfuse) in to the given text files. (here: fusehigh.txt, fuselow.txt)

Burn the bootloader

Now that all fuses are set, the chip is ok and using the external clock, and the IDE programmer is set to "Arduino as ISP", we can burn the bootloader to the chip on the breadboard. Just select "Tools->Burn Bootloader" in the IDE and wait some time. If nothing has gone wrong, you should now be able to upload Arduino-sketches to the chip on the breadboard.

Change the blink-sketch. [later] (short: change pin 13 to pin 8)

Upload the blink-sketch to the chip on the breadboard. [later] (short: select "Upload via programmer")

Final Check:

The yellow LED should flash now.

Hope that helped.

3D LED Binary Clock

I had two posts, deleted the one and the other one was also deleted. That was a long post. I do not want to write all that shit again...

Sorry.

Dienstag, 8. Mai 2012

Unity3D: 3rd Person FPS Player Controller

Here is my player controller script in JavaScript. It is fitted to work with the camera script in the post before.
 
Just attach it to your Player (-Prefab).

You need to add another input axis called "Run" (default is "right shift"...)
For that, click on Edit->Project-Settings->Input and rename an axis wich you do not need.

You can move your Player now with the arrow keys or WASD. You can jump with Space and run with
the right shift key. The facing direction will be rotated to the camera forward direction, wich changes with the mouse in the camera script.


You can download the script HERE.

#pragma strict

// Script by ben0bi
// regarding the ThirdPersonController from the ThirdPersonPlattformer Example Project

// The player can make jumps, doublejumps and walljumps.
// It will look where the camera looks, and turn smoothly towards it if the camera changes.
// Its "optimized" for 3rd Person FPS type games. // The script is in need for the Input Axes: "Horizontal", "Vertical", "Jump" and "Run".
// You need to add "Run" by yourself:
// In Unity: Click on Edit->Project Settings->Input - In the Inspector, name one of the axes to "Run" and
// let the positive value be "right shift". To add a new axis, just type a greater number into the size
// property at the top.

// Shooting will happen in another script.

// is the player at all controllable?
var isControllable = true;

var canJump=true;            // can the player jump? if not, he can also not doublejump and walljump
var canDoubleJump=true;        // can the player jump after a jump?
var canWallJump=true;        // can the player jump away from a wall when touching it?
var jumpHeight = 1.5;         // this is the jump height by pressing it the first time.
var doubleJumpHeight=1.0;     // this height will be added to verticalspeed one the jump button is pressed the second time.

var walkingSpeed=6.0;        // the normal walking speed.
var runningSpeed=12.0;
var speedSmoothing = 10.0;
var sidewayWalkMultiplier=0.5;

// The gravity for the character
var gravity = 20.0;

private var moveDirection:Vector3 = Vector3.zero;
private var faceDirection:Vector3 =Vector3.zero;
private var moveSpeed=0.0;
private var verticalSpeed=0.0;

// when can the player jump again?
private var jumpRepeatTime = 0.05;
private var jumping=false;
private var doubleJumping=false;
private var lastJumpButtonTime=-10.0;
// When did we touch the wall the first time during this jump (Used for wall jumping)
private var touchWallJumpTime = -1.0;
private var wallJumpTimeout = 0.15;

// Last time we performed a jump
private var lastJumpTime = -1.0;
private var jumpTimeout = 0.15;
// Is the user pressing any keys?
private var isMoving = false;
private var jumpingReachedApex=false;
// Average normal of the last touched geometry
private var wallJumpContactNormal : Vector3;

// The last collision flags returned from controller.Move
private var collisionFlags : CollisionFlags;

private var jumpButtonPressedTwice=0;

function Awake ()
{
    moveDirection = transform.TransformDirection(Vector3.forward);
}

function Update ()
{
    // kill all inputs if not controllable
    if (!isControllable) {Input.ResetInputAxes();}

    // set the jump button time variable and check for a doublejump. (=jumpButtonPressedTwice==1)
    if (Input.GetButtonDown ("Jump"))
    {
        if(jumpButtonPressedTwice==-2)    // it was set the second time..
            jumpButtonPressedTwice=1;    // thats a double jump
        else
            jumpButtonPressedTwice=-1;    // set it the first time..
        lastJumpButtonTime = Time.time;
    }
   
    // check if jump button was pressed the second time
    if(Input.GetButtonUp("Jump"))
    {
        if(jumpButtonPressedTwice==-1)    // set it the second time
            jumpButtonPressedTwice=-2;
    }
   
    UpdateSmoothedMovementDirection();

    ApplyGravity ();
   
    // Perform a wall jump logic
    // - Make sure we are jumping against wall etc.
    // - Then apply jump in the right direction)
    if (canWallJump)
        ApplyWallJump();
   
    // Apply jumping logic
    ApplyJumping();
   
    var movement = moveDirection * moveSpeed + Vector3 (0, verticalSpeed, 0);// + inAirVelocity;
    movement *= Time.deltaTime;
   
    // Move the controller
    var controller : CharacterController = GetComponent(CharacterController);
    wallJumpContactNormal = Vector3.zero;
    collisionFlags = controller.Move(movement);
   
    // rotate the character
    // TODO: lerp or slerp it (? wich one, and why?)
    transform.rotation = Quaternion.LookRotation(faceDirection);
   
    // We are in jump mode but just became grounded
    if (IsGrounded())
    {
        //lastGroundedTime = Time.time;
        //inAirVelocity = Vector3.zero;
        if (jumping || doubleJumping)
        {
            jumping = false;
            doubleJumping=false;
            jumpButtonPressedTwice=0;
            SendMessage("DidLand", SendMessageOptions.DontRequireReceiver);
        }
    }
}

function UpdateSmoothedMovementDirection()
{
    var cameraTransform = Camera.main.transform;
    var grounded = IsGrounded();
   
    // Forward vector relative to the camera along the x-z plane   
    var forward = cameraTransform.TransformDirection(Vector3.forward);
    forward.y = 0;
    forward = forward.normalized;

    // Right vector relative to the camera
    // Always orthogonal to the forward vector
    var right = Vector3(forward.z, 0, -forward.x);
    // get the input axes
    var vertical = Input.GetAxisRaw("Vertical");
    var horizontal = Input.GetAxisRaw("Horizontal");
   
    //var wasMoving = isMoving;
    isMoving = Mathf.Abs (horizontal) > 0.1 || Mathf.Abs (vertical) > 0.1;
   
    faceDirection = Vector3.Slerp(faceDirection, forward,Time.deltaTime*8);
    var targetDir=forward*vertical+right*horizontal*sidewayWalkMultiplier;
    // Grounded controls
    if (grounded)
    {
        // We store speed and direction seperately,
        // so that when the character stands still we still have a valid forward direction
        // moveDirection is always normalized, and we only update it if there is user input.
        if (faceDirection != Vector3.zero)
        {
            moveDirection = targetDir.normalized;
        }
       
        // Smooth the speed based on the current target direction
        var curSmooth = speedSmoothing * Time.deltaTime;
       
        // Choose target speed
        //* We want to support analog input but make sure you cant walk faster diagonally than just forward or sideways
        var targetSpeed = Mathf.Min(targetDir.magnitude, 1.0);
   
        // Pick speed modifier
        if (Input.GetButton ("Run"))
        {
            targetSpeed *= runningSpeed;
        }else{
            targetSpeed *= walkingSpeed;
        }
       
        moveSpeed = Mathf.Lerp(moveSpeed, targetSpeed, curSmooth);
    }
}

function ApplyGravity ()
{
    if (isControllable)    // don't move player at all if not controllable.
    {       
        // When we reach the apex of the jump we send out a message
        if (jumping && !jumpingReachedApex && verticalSpeed <= 0.0)
        {
            jumpingReachedApex = true;
            SendMessage("DidJumpReachApex", SendMessageOptions.DontRequireReceiver);
        }
       
        if (IsGrounded ())
            verticalSpeed = 0.0;
        else
            verticalSpeed -= gravity * Time.deltaTime;
    }
}

function ApplyWallJump()
{
    if(!jumping)
        return;
   
    // if the a side was hit, set the time
    if(collisionFlags==CollisionFlags.CollidedSides)
    {
        touchWallJumpTime=Time.time;
    }
   
    // The user can trigger a wall jump by hitting the button shortly before or shortly after hitting the wall the first time.
    var mayJump = lastJumpButtonTime > touchWallJumpTime - wallJumpTimeout && lastJumpButtonTime < touchWallJumpTime + wallJumpTimeout;
    if (!mayJump)
        return;
   
    // Prevent jumping too fast after each other
    if (lastJumpTime + jumpRepeatTime > Time.time)
        return;
   
    if (Mathf.Abs(wallJumpContactNormal.y) < 0.2)
    {
        wallJumpContactNormal.y = 0;
        moveDirection = wallJumpContactNormal.normalized;
        // Wall jump gives us at least trotspeed
        moveSpeed = Mathf.Clamp(moveSpeed * 1.5, walkingSpeed, runningSpeed);
        // after a walljump we cannot doublejump
        doubleJumping=true;
        DidJump();
        SendMessage("DidWallJump", null, SendMessageOptions.DontRequireReceiver);
        Camera.main.SendMessage("TurnAround", SendMessageOptions.DontRequireReceiver);
    }else{
      // cannot walljump again
        moveSpeed = 0;
    }
   
    verticalSpeed = CalculateJumpVerticalSpeed (jumpHeight);
}


function ApplyJumping()
{
    // Prevent jumping too fast after each other
    if (doubleJumping && lastJumpTime + jumpRepeatTime > Time.time)
        return;
   
    if(jumping && !doubleJumping && jumpButtonPressedTwice==1 && canDoubleJump)
    {
        // Perform a doublejump
        doubleJumping=true;
        if(verticalSpeed>0.0)
            verticalSpeed=0;
        verticalSpeed+=CalculateJumpVerticalSpeed(doubleJumpHeight);
        DidJump();
        SendMessage("DidDoubleJump", SendMessageOptions.DontRequireReceiver);
    }else{   
        if (IsGrounded())
        {
            var height=jumpHeight;   
            if (canJump && Time.time < lastJumpButtonTime + jumpTimeout)
            {
                // Jump
                // - Only when pressing the button down
                // - With a timeout so you can press the button slightly before landing
                verticalSpeed = CalculateJumpVerticalSpeed (jumpHeight);
                SendMessage("DidJump", SendMessageOptions.DontRequireReceiver);
            }
        }
    }
}

function DidJump ()
{
    jumping = true;
    jumpingReachedApex = false;
    lastJumpTime = Time.time;
    //lastJumpStartHeight = transform.position.y;
    touchWallJumpTime = -1;
    lastJumpButtonTime = -10;
}

function CalculateJumpVerticalSpeed (targetJumpHeight : float)
{
    // From the jump height and gravity we deduce the upwards speed
    // for the character to reach at the apex.
    return Mathf.Sqrt(2 * targetJumpHeight * gravity);
}

// This function responds to the "HidePlayer" message by hiding the player.
// The message is also 'replied to' by identically-named functions in the collision-handling scripts.
// - Used by the LevelStatus script when the level completed animation is triggered.
function HidePlayer()
{
    GameObject.Find("rootJoint").GetComponent(SkinnedMeshRenderer).enabled = false; // stop rendering the player.
    isControllable = false;    // disable player controls.
}

// This is a complementary function to the above. We don't use it in the tutorial, but it's included for
// the sake of completeness. (I like orthogonal APIs; so sue me!)
function ShowPlayer()
{
    GameObject.Find("rootJoint").GetComponent(SkinnedMeshRenderer).enabled = true; // start rendering the player again.
    isControllable = true;    // allow player to control the character again.
}

// returns true if the player is moving
function IsMoving ()  : boolean
{
    return Mathf.Abs(Input.GetAxisRaw("Vertical")) + Mathf.Abs(Input.GetAxisRaw("Horizontal")) > 0.5;
}

// returns if the player is on ground or not
function IsGrounded ():boolean {
    return (collisionFlags & CollisionFlags.CollidedBelow) != 0;
}

function OnControllerColliderHit (hit : ControllerColliderHit )
{
//    Debug.DrawRay(hit.point, hit.normal);
    if (hit.moveDirection.y > 0.01)
        return;
    wallJumpContactNormal = hit.normal;
}

Freitag, 4. Mai 2012

Unity3D: Quick Healthbar Script

This JavaScript script draws a healthbar over an unit if it is in the line of sight.

The Healtbar draws a green(1/1)/orange (1/2)/red(1/4) bar for the hitpoints and over that a blue armor bar (that it looks like it is protecting the hitpoints). It is surrounded by a black line. The script has a SizeInPixels property (set by 50px) - that's the width of the bar wich currently does NOT change depending on the distance.

Its just for debugging. But nice, though.

 

Usage

- Add the script to the Unit that you want to observe.
- Add an empty GameObject to the same Unit, and position it at the center of where the HealthBar should be displayed.
- Drag the created GameObject on the Position property of the HealthBar script.

Before you can run it, you will have to meet the requirements below.

Fast download including tex_WHITE --> HERE

Requirements


The script requires another script named DamageReceiver with the floats hitPoints, maxHitPoints, armorPoints and maxArmorPoints.

Also you need a blank texture with white as background color, named tex_WHITE wich MUST be placed in the Resources Folder. If it does not exist, create it.

The bold stuff MUST be named exactly like this. But you can manage the damage code like you want.

(My DamageReceiver will be posted later on.)

 

Script

public var SizeInPixels:float=50;

private var fov = 60.0;    // the field of view. If you remove this,
                        // the healthbars will also be drawn "on the opposite"
                        // of the unit from camera view.
private var hit : RaycastHit;

function inLineOfSight () : boolean {
    if (Vector3.Angle(gameObject.transform.position - Camera.main.transform.position, Camera.main.transform.forward) <= fov &&
            Physics.Linecast(Camera.main.transform.position, gameObject.transform.position, hit))
    {
        // linecast hits the gameobject
        if(hit.collider.transform == gameObject.transform)
            return true;
        // (else) it could also be a child (of the gameobject) wich was hit by the linecast.
        for(var child:Transform in gameObject.transform)
        {
            if(hit.collider.transform == child)
                return true;
        }
    }
    return false;
}

function OnGUI()
{
    if(inLineOfSight())
    {
        // get 2D position of the drawing position on the screen
        var screenPosition = Camera.main.WorldToScreenPoint(Position.position);
        // get the white texture
        var tWHITE : Texture2D=Resources.Load("tex_WHITE") as Texture2D;
        // get variables from the DamageReceiver, wich must be added to the same object.
        var component:Component = gameObject.GetComponent(DamageReceiver);
        var hitPoints=component.hitPoints;
        var maxHitPoints=component.maxHitPoints;
        var armorPoints=component.armorPoints;
        var maxArmorPoints=component.maxArmorPoints;
   
        //Set color to black and draw the background bar
        GUI.color = Color.black;
        GUI.DrawTexture(new Rect(screenPosition.x-1-SizeInPixels/2,Screen.height-screenPosition.y-1,SizeInPixels+2,4), tWHITE);
   
        // now set the color depending on the health and draw a bar with this color.
        GUI.color=Color.green;
        if(hitPoints<maxHitPoints/2)
            GUI.color = new Color(1.0f , 0.5f, 0);//Set color to Orange
        if(hitPoints<=maxHitPoints/4)
            GUI.color = Color.red;    //Set color to red
        GUI.DrawTexture(new Rect(screenPosition.x-SizeInPixels/2,Screen.height-screenPosition.y,(SizeInPixels/maxHitPoints)*hitPoints,2), tWHITE);

        // lastly draw the armor bar over all the other stuff (looks like its protecting, not?)
        GUI.color = new Color(0.2f,0.2f,1.0f);//set color to bright blue
        GUI.DrawTexture(new Rect(screenPosition.x-SizeInPixels/2,Screen.height-screenPosition.y,(SizeInPixels/maxArmorPoints)*armorPoints,2), tWHITE);
        GUI.color=Color.white;
    }
}

@script RequireComponent(DamageReceiver)