BuyMeACoffee

Buy Me A Coffee
Mostrando las entradas con la etiqueta Programming. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Programming. Mostrar todas las entradas

martes, 21 de julio de 2015

Basic "shoot to target" in Unity 3D

First, let's create a new Unity 3d Project, and select 3D.

Let's add a terrain GameObject-3D-Terrain.
Import Characters package Assets-Import Package-Characters, select all, and click Import.
Find the ThirdPersonController in the Project pane(use the search tool if you can't find it) and add it to the scene.

Create a Cube GameObject-3d Object-Cube. Name it ShootBox.
Create a Sphere GameObject-3d Object-Sphere, set its scale to 0.5 for x,y,and z. Name it BulletPlaceHolder.
Create a folder Resources.
Drag the two recently created objects into the Resources folder.
Create a Scripts folder.
Create three scripts: Bullet.cs, Player.cs,ShooterBox.cs, and add their respective code

Bullet.cs

using UnityEngine;
using System.Collections;

public class Bullet : MonoBehaviour
{
    private float Speed = 3.5f;
    public GameObject Target = null;
    // Use this for initialization
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        if (Target != null)
        {
            float step = Random.Range(1,5) * Time.deltaTime;
            this.transform.position = Vector3.MoveTowards(this.transform.position, Target.transform.position + new Vector3(0,0.5f,0), step);
        }
    }

    public void OnTriggerEnter(Collider other)
    {
        Debug.Log(other.name);
        Player playerComponent = other.GetComponent<Player>();
        if (playerComponent != null)
        {
            int newHealth = playerComponent.Health - 1;
            if (newHealth == 0)
            {
                Time.timeScale = 0;
            }
            else
                playerComponent.Health = newHealth;
            GameObject.Destroy(this.gameObject);
        }
    }
}

Player.cs

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class Player : MonoBehaviour {
    public int Health = 100;
    public Text HealthText;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {

}

    void OnGUI()
    {
        HealthText.text = Health.ToString();
    }


}

ShooterBox.cs

using UnityEngine;
using System.Collections;

public class ShooterBox : MonoBehaviour {

// Use this for initialization
    private GameObject player;
    private float lastTimeShooted = 0;
    public int ShootIntervalInSeconds = 15;
void Start () {
        this.player = GameObject.FindGameObjectWithTag("Player");
}
// Update is called once per frame
void Update () {
        if  ((lastTimeShooted + ShootIntervalInSeconds) < Time.time)
        {
            GameObject loadedResource = Resources.Load<GameObject>("BulletPlaceHolder");
            GameObject newInstance = GameObject.Instantiate<GameObject>(loadedResource);
            newInstance.transform.position = this.transform.position;
            Bullet bullet = newInstance.GetComponent<Bullet>();
            bullet.Target = this.player;
            lastTimeShooted = Time.time;
        }
}
}

Add the Bullet.cs script to the BulletPlaceHolder prefab.
Add the ShooterBox.cs script to the ShooterBox prefab.
Add the Player.cs script to the ThirdPersonController in the scene
Create a Canvas object and add two objects to it: HealthLabel, HealthText
Go to the ThirdPersonController in the scene, in the inspector find the Health Text field below the Player script and assign the recently created HealthText object.

My experience with Visual Studio 2015 after first day of official release



The very first feature I went to test is cross platform applications,
I started with Android, mostly because I am not buying a mac for build host(blame apple business model there).

In a matter of minutes I had the base for an Android Application fully coded in C# and with simple UI created through Visual Studio UI designer.

First, I opened my existent web portal project which was a MVC 5 web site.
To this website I added a WCF service which retrieves a list of places ( Description, Property Type, Country, State, City)

Then I added a new project to the solution and I selected Android/Blank App(Android).
Then from the android project I added a web reference to the WCF service created before.
This, as usual with consumed services, creates the proxy classes and the generated types.
So far no real difference from coding against traditional .NET applications.



So far so good, but still some pending steps: create a simple UI, and bind the data to a list.
Since the designer is very friendly and the toolbox supports drag and drop, it is very straightforward.

Since what I wanted to do was just show a list of values, I selected to add a ListView, easily done in less than 30 seconds.

Now, only binding the data was pending, here is where things kind of became a little complex but only because I do not program android, so I basically had to learn the concepts behind data biding in android.



First sample I found was using an ArrayAdapter, so I tested with that, this took me around an hour because I was getting unhandled exceptions I finally found that I should use both lines:

            AndroidEnvironment.UnhandledExceptionRaiser += AndroidEnvironment_UnhandledExceptionRaiser;
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;




That worked, and made me realize I was using the wrong Id in the ArrayAdapter constructor.

Once I fixed that, the data was being displayed, one more problem though, all rows where displaying the class type info, not the field, in a traditional C# app we are usually able to fix this by using properties such as DisplayMember or TextField, apparently in android this is not the case, the easy and extremely not elegant solution is to string.format the fields, the most common solution would be to find a way to indicate the list it has several columns, apparently not as straighforward in android.

Finally I found about creating a custom layout and a custom adapter.
After using that approach, my data is shown as I originally wanted.

Note: I had to publish my WCF service to my local IIS to be able to access it by i[ from withing the emulator and my Nexus 7 tablet. I also had to modify the firewall so that it allows my local network devices to access my local IIS.


Custom Layout Code
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:minWidth="25px"
    android:minHeight="25px">
    <TextView
        android:text="Description"
        android:layout_width="0px"
        android:layout_height="wrap_content"
        android:id="@+id/Description"
        android:layout_weight="1"
        android:textSize="20sp" />
    <TextView
        android:text="PropertyType"
        android:layout_width="0px"
        android:layout_height="wrap_content"
        android:id="@+id/PropertyType"
        android:layout_weight="1"
        android:textSize="20sp"
        android:textStyle="normal" />

</LinearLayout>

Custom Adapter Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using PTIRealEstateAndroid.PTIRealEstateWS;

namespace PTIRealEstateAndroid
{
    public class GenericPropertyAdapter : BaseAdapter<PTIRealEstateWS.GenericPropertyContract>
    {
        private readonly IList<PTIRealEstateWS.GenericPropertyContract> _items;
        private readonly Context _context;

        public GenericPropertyAdapter(Context context, IList<PTIRealEstateWS.GenericPropertyContract> items)
        {
            _items = items;
            _context = context;
        }

        public override GenericPropertyContract this[int position]
        {
            get
            {
                return this._items[position];
            }
        }

        public override int Count
        {
            get
            {
                return this._items.Count;
            }
        }

        public override long GetItemId(int position)
        {
            return position;
        }

        public override View GetView(int position, View convertView, ViewGroup parent)
        {
            var item = _items[position];
            var view = convertView;

            if (view == null)
            {
                var inflater = LayoutInflater.FromContext(_context);
                view = inflater.Inflate(Resource.Layout.GenericProperty, parent, false);
            }

            view.FindViewById<TextView>(Resource.Id.Description).Text = item.Description;
            view.FindViewById<TextView>(Resource.Id.PropertyType).Text = item.PropertyType;

            return view;

        }
    }

}

Please use the comments and let us know about your experience.