Coder Social home page Coder Social logo

unity-3d-asteroids's Introduction

Join the chat at https://gitter.im/antfarmar/Unity-3D-Asteroids

Unity 3D Asteroids

A simple Asteroids game clone in 3D. Stuck on a 2D plane. So 2.5D?

Title Screenshot

Learning & Experimenting with Unity. Trying to determine best practices.

Design Choices

  • Architecture/Frameworks: God Objects, MVC, IoC+DI, Messaging, Events, ...
  • Software Patterns: OOP, Composition, Singletons, Object Pooling, Observer, ...
  • Game Programming Patterns
  • Composition vs. OOP : Interfaces + Inheritance vs. Object Composition via Components
  • MonoBehaviour + Extensions
  • Serialization
  • Idioms: One vs. Many
  • Events: C# Delegate Events vs. UnityEvents
  • Coroutines
  • Optimizations

Workflow Choices

Unity Quirks

  • Editor/Customization
  • Interface
  • Hacks/Tricks
  • Interesting things learned about Unity
  • Software Engineering lessons learned
  • Game design & development lessons learned

Chat Room: Join the chat at https://gitter.im/antfarmar/Unity-3D-Asteroids

unity-3d-asteroids's People

Contributors

antfarmar avatar devmelon avatar saucechord avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

unity-3d-asteroids's Issues

Project license?

Hello @antfarmar -- great project you've got here! This has been a really valuable resource for learning Unity. Do you think you'd ever consider specifying a software license to permit the reuse of your code or assets in other projects? Perhaps something like the MIT license?

Even if you don't want to permit reuse or open source this project as such, I think specifying a license to clarify your stance here would be desirable.

Remove dependency to Blender

I forked your project to have a look and possibly provide some comments for you to meditate on. However, I am unable to play the game because it requires Blender. This means there are no meshes for rendering and no meshes for collision.

It would be really, really nice if you exported your .blend files as .fbx files instead, because that doesn't require Blender to be installed on the machine. As an interesting side note, Unity Cloud Build also doesn't support .blend files so it could be something keeping in mind.

Upon starting Unity, I get this error three times:

Blender could not be found.
Make sure that Blender is installed and the .blend file has Blender as its 'Open with' application!
  • asteroid1_model
  • asteroid2_model
  • ship_model

Collision Manager: Centralized Collision Resolution

Instead of collisions resolutions being dispersed throughout many classes, perhaps collisions would be better handled by a dedicated class.

e.g. Collisions.HandleCollision("Asteroid", "Ship")
(string parameters sorted alphabetically to avoid checking permutations)

Ship Movement Physics: Drag & Thrust (clamp?)

Currently the ship's rigidbody has non-zero drag.

  • it prevents fast velocities when accelerating.
  • it slows the ship down to rest when gliding.

In the original Asteroids vidya, constant velocity gliding was a feature. This could be implemented by:

  • setting the ship rigidbody's drag to zero
  • limiting/clamping it's velocity.

Asteroid Behaviour Script: Make a Base Class?

Currently 1 script is used to dictate the behaviour of both (big & small) asteroid prefabs. It also generates the spawn location and physical forces applied to it.

Asteroid Behaviours:

  • We check the object's tag to differentiate between the two in the logic.
  • Most behaviour is the same, but there are differences:
    • Big asteroids split into two smaller ones.
    • Scale differences.

Options:

  • Keep the same, since the class is small and manageable.
  • Write an Asteriod base class with common behaviours, then extend off that per asteroid type.
    • This is proper design.

Asteroid Manager:

  • could help the Game Manger layout a level by spawning asteroids
    • move asteroid pools into it
  • could clean out the AsteroidBehaviour class
    • the pooling, spawning, forces.
    • Beahviour would mostly just be OnTrigger/Collision events

TODO: Level Management

Implement a level system.

  • Use a state machine implementation
    • Using delegates or coroutines

Hot-Reloading & Non-Serializable Types

Minor Issue:

  • Hot-reloading (recompile during playmode) is not possible with the pool used.
    • Requires you to not use any types which can't be serialized.
  • ObjectPooler uses a Dictionary to reference the object pools (queues).
    • Dictionaries cannot be serialized.

Possible Fixes:

  1. Don't hot-reload.
  2. Re-implement w/o using non-serializeable types. See SerializeField manual entry for types
  3. Destroy then recreate the pools:
  • Recompiling code in Unity calls OnDisable() and OnEnable() on all objects.
  • Do it there.

String Usage: Memory Reduction

C# strings are immutable.

Hence, changing a string variable frequently (e.g. UI text for score) allocates memory at runtime and generates garbage which will invoke a GC call.

  • We can can do an explicit GC.Collect() call in between levels to clean all unreferenced memory.
  • We can use a mutable string of characters, as provided by the StringBuilder class in System.Text.

Bullets Could Inherit Ship's Velocity

Problem
  • Bullets currently don't inherit the ship's velocity when fired.
  • With a thrust powerup, the ship is almost as fast as bullets.
  • Hence, bullets barely escape the ship's nozzle.
  • Velocity inheritance would also be more physically realistic.
Possible Fixes
  • Does the Rigidbody API have any simple functions for this?

TODO: Features & Polish (Long Term)

Powerups

  • Firepower
  • Thrust
  • Shield
  • Hyperspace

Enemies

  • Asteroids
  • UFOs

Foreground/Backgrounds

  • Explosions
  • Stars
  • Space debris

GUI

  • Title Screen/Wallpaper
  • Instructions/Controls
  • Lives/Health
  • Score
  • High Score
  • Credits

Sound

  • SFX
  • Music

Power-up System: Implementation

Current Implementation

The current implementation of the power-up system is fairly basic. It's design (or lack thereof) was mostly an experiment in inheritance, abstract/virtual methods, and faking GameObject states like inactive.

  • uses basic OOP principles of inheritance and overriding methods.
  • each power-up script controls granting/denying ship components its respective power in custom overridden methods.
  • this requires that each power-up remains active in the scene and gets/has component references.
  • power-up objects are never inactive, but are simply disabled/invisible.
    • i.e. only Colliders & Renderers are disabled.
    • this behaviour eliminates multiple instantiations/destroys, and can work with other designs.

A Better Implementation: Use Events

A better design would make use of more advanced techniques like _Events_. The power-up system is a perfect use case.

  • Colliding with a power-up would fire off a respective power-up event.
  • Ship script components that the power-up affects would be listeners/subscribers to the event.
  • implemented using either delegate events or Unity's event system.

Shield Powerup Fails At Screen Edges When Ship Screenwraps

Problem
  • Ship "invincibility" is purely physics driven by the shield's kinematic rigidbody.
    • No boolean flag set to prevent death.
  • Screenwraps probably mess with the physics.
    • Hence, safety can't be guaranteed.
Possible Fixes
  • Use a boolean flag to prevent death when shield is active.

FindObjectOfType<> Usage

Problem:

BulletBehaviour.cs uses the slow FindObjectOfType<> method (parses the entire Scene hierarchy) on Awake() to locate ShipShooter.cs to get the reference to its pool currently located there. Called by each bullet instance (~10). Though there's no noticeable slowdown, it's bad practice.

Link to the code.

Possible fixes:
  • Move the pool/change ownership
  • Have the ship instance register itself to the bullet instances in its pool.
    • On pool creation in Awake
      • Problem: If a pool is spent (all bullets active), the pool creates a new bullet. It won't get a reference.
    • When fired: check for null reference, assign then.
  • Have a ship instance in the editor before runtime, drag the reference in.
  • Do it in the GameManager singleton.

_Side Note:_
How to permanently link to lines of code in an actual SHA hash for a particular commit, rather than the current version of the file on master.

TODO: Use MonoBehaviour Event Messages Properly

Be sure to use _Awake, Start, OnEnable, OnDisable,_ etc, logically and properly.

  • They should do concisely what they are meant for. Nothing more, nothing less.
  • Watch _OnEnable/OnDisable_ closely.
    • Called frequently when pooling, and hot-reloading.
    • Pooling: convenient for initializing when activating pooled objects
      • initializing affects hot-reloading though
    • Hot-Reloading: calls OnDisable then OnEnable.
      • we might not want to re-initialize objects after a live recompile.
      • affect object pooling workflow.
    • Could use flags to distinguish states.

Refactoring: New Screenwrapper Implementation

I have implemented a more stable and robust screen wrapper, found in commit 48b988d.

I pretty much wrote it quickly to get the ideas out of my head and onto the screen.
It therefore has minimal regards for readability, although not entirely. So far it is 1 large Update method.

It works well ๐Ÿ‘, but readability & flow could be improved. Some duplicated code may exist as well.

So I will be improving on it's current state as time permits, mostly by refactoring it to make it read like prose.

Code Smells: Identify & Refactor

The current first-iteration playable implementation has the following Code Smells:

Application-level smells:

  • Duplicated code: identical or very similar code exists in more than one location.
    • e.g. Not many reusable methods/interfaces were used. Unity API was used directly most of the time for familiarization.

Class-level smells:

  • Large class: a class that has grown too large. See God object.
    • e.g. GameManager currently knows & does too much.
  • Lazy class / Freeloader: a class that does too little.
    • e.g. AsteroidBehaviour subclasses really don't do much at the moment.

Method-level smells:

  • Long method: a method, function, or procedure that has grown too large.
    • e.g. See duplicated code above. Most solutions were written with a direct approach.

UI Canvas: More Than 1

Currently there exists 2 UI canvases:

  • Message Canvas for text messages. (Not a prefab)
  • Score Canvas for the score text. (Is a prefab)
  1. Why? Any advantage?
  2. Could this not be done with 1 Canvas?
  3. What is the overhead & resource cost per Canvas?
  4. Is it significant or negligible?
  5. Should everything be prefabs?

Magic Numbers: Need to Remove

The code has several areas in which magic numbers are used due to laziness.
Never a good idea. It will cause stupid time-wasting bugs later on since the magic number is most likely dependent on/a function of some other variable.

Timed Game Tokens: Powerups, UFOs, etc.

Currently there exists 2 types of randomly spawned "timed" game tokens: powerups & UFOs. More could be added in the future, so the implementation design & architecture should be clean, clear, solid & robust.

Though these varying tokens seem disparate in nature (friend vs. enemy), they mostly share common game functionality and should be implemented and handled as such. There are various ways to go about this...

Possible Implementations

  1. Define a base class of TimedToken : GameToken that defines/implements their behaviour.
  2. As standard game tokens, but let a SpawnManager handle the details of timing/spawning.
  3. A combination of 1 & 2.
  4. ???

Asteroid Spawning: Randomized Algorithm Choice

Currently algorithm:

  • spawned randomly along edges
  • guarantees not to overlap ship, whose position is always centered (0,0,0).

Better Implementation:

  • purely random position
  • just check for ship overlap
  • allows ship to remain at its current position between levels.

TODO: Improve screen wrap quick implementation.

ScreenWrapper.cs is the script component that screen wraps any GameObject it is attached to.

It is currently implemented as a slick hack using the OnBecameInvisible() Renderer message to determine when the object leaves the viewport, but it has issues:

Issues:

  • An object is considered _visible_ when it needs to be _rendered_ in the scene.
  • So it might _not be actually visible_ by any camera, but _still needs to be rendered_ for shadows for example.
  • Also, when running in the editor, the _scene view_ cameras will also cause this function to be called.

Given these issues though, if you're not using shadows and have your scene view off or zoomed in slightly more than the game view when playtesting, you're pretty much good to go.

Also, see the wiki: Screenwrapping.

What is a collaborators role in your project?

As a collaborator, I am happy to join development of this exciting project.

As a collaborator, what is expected of me?
How can I chip in without being an annoyance?

For me specifically, I would be interested in any of the 4 following activities:

  • Reviewing commits, flagging potential issues
    • Performance
    • Maintainability
    • Readability
    • Bad practices
    • Risks feeling nagged?
  • Cleaning up, make code read like a prose
    • Provide practical reason
    • Small pull requests
    • Avoid merge conflicts
    • Risks feeling pointless effort?
  • Work toward completing open issues
    • Implement a simple solution to any issue
    • Submit pull request
    • Avoid merge conflicts
    • Risks feeling lost ownership?
  • Unit and integration tests (Unity Test Tools)
    • Explore testing for games
      • Past experience: Inherently hard
      • What causes it to be hard?
      • How to make it easier?
      • What practical value gained from it?
    • Start with high risk areas
      • Basis for bug-fixes
      • Screen wrapping?
    • Could start in separate branch to test waters
    • Risks feeling slogged down?
    • Risks feeling too much information?
    • Risks feeling too much for small project?

What do you feel? If you feel any of the points above is redundant, let's drop them. The secondary bullet points are examples of things to consider - not hard rules. The point is to get something going which we both feel provide some value for the time spent. Also, no hard feelings if you want to try something out, later find out it's a nightmare to collab and want to cancel it. I want you to always feel you are in control, so please speak your frank mind.

Do you have other suggestions? What would you feel would be fun to do together?

Scene Building vs. Runtime Instantiations

Currently key game tokens (e.g. the Ship) are instantiated at runtime (traditional method) instead of already existing in the scene. This means that there is no instance reference of them to easily drag & drop into the Inspector for other tokens that require them. Rather they are passed around as parameters, or registered, or "found", as is normally done in non-Unity games.

Since this is a Unity game, perhaps it would be best to take advantage of its features, like editor scene building & reference dragging, rather than do things in the "traditional" non-Unity way!?

It would make some things easier, but it may also encourage bad programming habits.

Poolable Components

Poolable Components are currently added to objects at runtime during instantiation by the Pooler.

  • This affects when references to the component are available.
    • Can't be on Awake!
    • Currently at OnEnable.

Choices:

  1. Leave as is. It's not a real problem yet.
  2. We could add the Component to the Prefabs of all Poolable objects:

This would allow more flexibility in where initializations take place.

Teamwork communication channel

So, I admit; I am pretty new to github.

It has great social features, but it appear to lack (or I have not found so) a place to discuss general topics or planning.

Could you please look into options for us to communicate a little bit if you want to team up?

  • Built in discussion board in Github?
  • Github plugins? (I seen there are lots, tried none)
  • Forum
  • IRC
  • Other chat networks
  • Email

Perhaps any of the above could work. Try to pick one with least amount of hassle.
It shouldn't be a chore to talk.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.